diff --git a/app/drivers/CH34x_Install_Windows_v3_4/CH34x_Install_Windows_v3_4.EXE b/app/drivers/CH34x_Install_Windows_v3_4/CH34x_Install_Windows_v3_4.EXE deleted file mode 100644 index de980ea2e..000000000 Binary files a/app/drivers/CH34x_Install_Windows_v3_4/CH34x_Install_Windows_v3_4.EXE and /dev/null differ diff --git a/app/firmwares/examples/arduino_nano/arduino_nano.ino b/app/firmwares/examples/arduino_nano/arduino_nano.ino index 1c2e9364f..fd5acc37d 100644 --- a/app/firmwares/examples/arduino_nano/arduino_nano.ino +++ b/app/firmwares/examples/arduino_nano/arduino_nano.ino @@ -398,5 +398,4 @@ void callDebug(char c){ writeSerial(0x55); writeSerial(c); writeEnd(); -} - +} \ No newline at end of file diff --git a/app/firmwares/examples/coding_box/coding_box.ino b/app/firmwares/examples/coding_box/coding_box.ino deleted file mode 100644 index 0a7c74339..000000000 --- a/app/firmwares/examples/coding_box/coding_box.ino +++ /dev/null @@ -1,522 +0,0 @@ -#include -// 서보 라이브러리 -#include -#include "I2C_LCD.h" - -//핀 -#define RGB_R_PIN 8 -#define RGB_G_PIN 13 -#define RGB_B_PIN 12 - -// 동작 상수 -#define ALIVE 0 -#define DIGITAL 1 -#define ANALOG 2 -#define PWM 3 -#define SERVO_PIN 4 -#define TONE 5 -#define PULSEIN 6 -#define ULTRASONIC 7 -#define TIMER 8 -#define LCD_PRINT 9 -#define LCD_CLEAR 10 -#define LCD_INIT 11 - -#define FLOAT 2 -#define SHORT 3 - -// 상태 상수 -#define GET 1 -#define SET 2 -#define RESET 3 - -// val Union -union { - byte byteVal[4]; - float floatVal; - long longVal; -} val; - -// valShort Union -union { - byte byteVal[2]; - short shortVal; -} valShort; - -typedef struct { - int pin; - int value; -} SoftwarePWM; - -SoftwarePWM RGBLeds[3] = { - {RGB_R_PIN, 0}, - {RGB_G_PIN, 255}, - {RGB_B_PIN, 0} -}; - -// 전역변수 선언 시작 -Servo servos[8]; - -I2C_LCD lcd(0x20, 16, 2); - -//울트라 소닉 포트 -int trigPin = 13; -int echoPin = 12; - -//포트별 상태 -int analogs[6] = {0, 0, 0, 0, 0, 0}; -int digitals[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -int servo_pins[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - -// 울트라소닉 최종 값 -float lastUltrasonic = 0; - -// 버퍼 -char buffer[52]; -unsigned char prevc = 0; - -byte index = 0; -byte dataLen; - -double lastTime = 0.0; -double currentTime = 0.0; - -uint8_t command_index = 0; - -const int CYCLE_LENGTH = 1000000 / 300; - -boolean isStart = false; -boolean isUltrasonic = false; -// 전역변수 선언 종료 -int lcdAddress = 0; - - -byte findI2CAddress() { - byte error, address = 0, foundAddress; - - for (address = 1; address < 127; address++ ) { - Wire.beginTransmission(address); - error = Wire.endTransmission(); - - if (error == 0) { - foundAddress = address; - } else if (error == 4) { - // foundAddress = address; - } - } - return foundAddress; -} - -void setup() { - Wire.begin(); - Serial.begin(115200); - - initLCD(); - initPorts(); - delay(200); -} -void initLCD() { - lcdAddress = findI2CAddress(); - lcd.setAddress(lcdAddress); - lcd.init(); - lcd.backlight(); - lcd.setCursor(0, 0); - lcd.print("CodingBox"); -} -void initPorts() { - for (int pinNumber = 0; pinNumber < 14; pinNumber++) { - pinMode(pinNumber, OUTPUT); - digitalWrite(pinNumber, LOW); - } -} - -void loop() { - while (Serial.available()) { - if (Serial.available() > 0) { - char serialRead = Serial.read(); - setPinValue(serialRead & 0xff); - } - } - - // loopRGB(); - // RGBLeds[2].value = map(analogRead(0), 0, 1024, 0, 255); - - delay(15); - sendPinValues(); - delay(10); -} - -void setPinValue(unsigned char c) { - // 새로운 데이터 스트림이 들어올 경우, 새로운 데이터 스트림 처리를 위한 시작을 준비합니다. - if (c == 0x55 && isStart == false) { - if (prevc == 0xff) { - index = 1; - isStart = true; - } - } else { - prevc = c; - if (isStart) { - // 두번째 index 데이터는 데이터길이므로, 데이터길이변수에 저장합니다. - if (index == 2) { - dataLen = c; - // index가 2이상일 경우 길이변수를 -1합니다. - } else if (index > 2) { - dataLen--; - } - - writeBuffer(index, c); - } - } - - index++; - - // 버퍼 용량이상이 되면, 초기화합니다. - if (index > 51) { - index = 0; - isStart = false; - } - - // 시작중이고, 데이터길이가 0(모든 데이터를 읽었을 경우), index가 3이상(0,1 시작헤더, 2길이)일경우는 명령을 파싱합니다. - if (isStart && dataLen == 0 && index > 3) { - // 시작플래그를 비활성화합니다. - isStart = false; - // 버퍼에 저장된 데이터를 파싱합니다. - parseData(); - // index를 초기화합니다. - index = 0; - } -} - -unsigned char readBuffer(int index) { - return buffer[index]; -} - -void loopRGB() { - float dutyCycle; - int onTime; - int offTime; - - for (int i = 0; i < 3; i++) { - dutyCycle = RGBLeds[i].value / 255.0; - onTime = dutyCycle * CYCLE_LENGTH; - offTime = CYCLE_LENGTH - onTime; - - if (onTime > 0) { - digitalWrite(RGBLeds[i].pin, HIGH); - delayMicroseconds(onTime); - } - digitalWrite(RGBLeds[i].pin, LOW); - delayMicroseconds(offTime); - } -} - -void parseData() { - isStart = false; - int idx = readBuffer(3); - command_index = (uint8_t)idx; - int action = readBuffer(4); - int device = readBuffer(5); - int port = readBuffer(6); - switch (action) { - case GET: { - if (device == ULTRASONIC) { - if (!isUltrasonic) { - setUltrasonicMode(true); - trigPin = readBuffer(6); - echoPin = readBuffer(7); - digitals[trigPin] = 1; - digitals[echoPin] = 1; - pinMode(trigPin, OUTPUT); - pinMode(echoPin, INPUT); - delay(50); - } else { - int trig = readBuffer(6); - int echo = readBuffer(7); - if (trig != trigPin || echo != echoPin) { - digitals[trigPin] = 0; - digitals[echoPin] = 0; - trigPin = trig; - echoPin = echo; - digitals[trigPin] = 1; - digitals[echoPin] = 1; - pinMode(trigPin, OUTPUT); - pinMode(echoPin, INPUT); - delay(50); - } - } - } else if (port == trigPin || port == echoPin) { - setUltrasonicMode(false); - digitals[port] = 0; - } else { - setUltrasonicMode(false); - digitals[port] = 0; - } - } - break; - case SET: { - runModule(device); - callOK(); - } - break; - case RESET: { - lcd.clear(); - callOK(); - } - break; - } -} - -void runModule(int device) { - //0xff 0x55 0x6 0x0 0x1 0xa 0x9 0x0 0x0 0xa - int port = readBuffer(6); - int pin = port; - - if (pin == trigPin || pin == echoPin) { - setUltrasonicMode(false); - } - - switch (device) { - case DIGITAL: { - setPortWritable(pin); - int v = readBuffer(7); - digitalWrite(pin, v); - } - break; - case PWM: { - setPortWritable(pin); - int v = readBuffer(7); - analogWrite(pin, v); - } - break; - case TONE: { - setPortWritable(pin); - int hz = readShort(7); - int ms = readShort(9); - if (ms > 0) { - tone(pin, hz, ms); - } else { - noTone(pin); - } - } - break; - case SERVO_PIN: { - setPortWritable(pin); - int v = readBuffer(7); - if (v >= 0 && v <= 180) { - Servo sv = servos[searchServoPin(pin)]; - sv.attach(pin); - sv.write(v); - } - } - break; - case LCD_PRINT: { - int row = readBuffer(7); - int column = readBuffer(8); - int len = readBuffer(9); - String txt = readString(len, 10); - - lcd.setCursor(column, row); - lcd.print(txt); - } - break; - case LCD_CLEAR: { - lcd.clear(); - } - break; - case LCD_INIT: { - initLCD(); - } - break; - case TIMER: { - lastTime = millis() / 1000.0; - } - break; - } -} - -/* 아두이노에서 엔트리로 데이터 전송아두이노에서 엔트리로 데이터 전송 - 디지털, 아날로그, 초음파센서등 정보 전송 -*/ -void sendPinValues() { - int pinNumber = 0; - //디지털핀 상태 전송 - for (pinNumber = 0; pinNumber < 12; pinNumber++) { - if (digitals[pinNumber] == 0) { - sendDigitalValue(pinNumber); - callOK(); - } - } - //아날로그핀 상태 전송 - for (pinNumber = 0; pinNumber < 6; pinNumber++) { - if (analogs[pinNumber] == 0) { - sendAnalogValue(pinNumber); - callOK(); - } - } - // 초음파센서가 활성화 되어있을 겨우 초음파센서 데이터 전송 - if (isUltrasonic) { - sendUltrasonic(); - callOK(); - } -} - -void setUltrasonicMode(boolean mode) { - isUltrasonic = mode; - if (!mode) { - lastUltrasonic = 0; - } -} - -/** 초음파센서 데이터 전송(엔트리->PC) -*/ -void sendUltrasonic() { - digitalWrite(trigPin, LOW); - delayMicroseconds(2); - digitalWrite(trigPin, HIGH); - delayMicroseconds(10); - digitalWrite(trigPin, LOW); - - float value = pulseIn(echoPin, HIGH, 30000) / 29.0 / 2.0; - - if (value == 0) { - value = lastUltrasonic; - } else { - lastUltrasonic = value; - } - writeHead(); - sendFloat(value); - writeSerial(trigPin); - writeSerial(echoPin); - writeSerial(ULTRASONIC); - writeEnd(); -} - -/** 디지털 데이터 전송(엔트리->PC) -*/ -void sendDigitalValue(int pinNumber) { - pinMode(pinNumber, INPUT); - writeHead(); - sendFloat(digitalRead(pinNumber)); - writeSerial(pinNumber); - writeSerial(DIGITAL); - writeEnd(); -} - -/** 아날로그 데이터 전송(엔트리->PC) - 헤드 헤드 데이터길이? 아날로그값 아날로그핀번호 타입 종단 바이트 - 0xFF 0x55 2 xx x 0x2 0x0A -*/ -void sendAnalogValue(int pinNumber) { - writeHead(); - sendFloat(analogRead(pinNumber)); - writeSerial(pinNumber); - writeSerial(ANALOG); - writeEnd(); -} - -void writeBuffer(int index, unsigned char c) { - buffer[index] = c; -} - -void writeHead() { - writeSerial(0xff); - writeSerial(0x55); -} - -void writeEnd() { - Serial.println(); -} - -void writeSerial(unsigned char c) { - Serial.write(c); -} - -void sendString(String s) { - int l = s.length(); - writeSerial(4); - writeSerial(l); - for (int i = 0; i < l; i++) { - writeSerial(s.charAt(i)); - } -} - -void sendFloat(float value) { - writeSerial(FLOAT); - val.floatVal = value; - writeSerial(val.byteVal[0]); - writeSerial(val.byteVal[1]); - writeSerial(val.byteVal[2]); - writeSerial(val.byteVal[3]); -} - -void sendShort(double value) { - writeSerial(SHORT); - valShort.shortVal = value; - writeSerial(valShort.byteVal[0]); - writeSerial(valShort.byteVal[1]); -} - -short readShort(int idx) { - valShort.byteVal[0] = readBuffer(idx); - valShort.byteVal[1] = readBuffer(idx + 1); - return valShort.shortVal; -} - -float readFloat(int idx) { - val.byteVal[0] = readBuffer(idx); - val.byteVal[1] = readBuffer(idx + 1); - val.byteVal[2] = readBuffer(idx + 2); - val.byteVal[3] = readBuffer(idx + 3); - return val.floatVal; -} - -long readLong(int idx) { - val.byteVal[0] = readBuffer(idx); - val.byteVal[1] = readBuffer(idx + 1); - val.byteVal[2] = readBuffer(idx + 2); - val.byteVal[3] = readBuffer(idx + 3); - return val.longVal; -} - -String readString(int len, int startIdx) { - String str = ""; - - for (int i = startIdx; i < (startIdx + len); i++) { - str += (char) readBuffer(i); - } - - return str; -} -int searchServoPin(int pin) { - for (int i = 0; i < 8; i++) { - if (servo_pins[i] == pin) { - return i; - } - if (servo_pins[i] == 0) { - servo_pins[i] = pin; - return i; - } - } - return 0; -} - -void setPortWritable(int pin) { - if (digitals[pin] == 0) { - digitals[pin] = 1; - pinMode(pin, OUTPUT); - } -} - -void callOK() { - writeSerial(0xff); - writeSerial(0x55); - writeEnd(); -} - -void callDebug(char c) { - writeSerial(0xff); - writeSerial(0x55); - writeSerial(c); - writeEnd(); -} - diff --git a/app/firmwares/playcodingbox.hex b/app/firmwares/playcodingbox.hex new file mode 100644 index 000000000..0f936fee4 --- /dev/null +++ b/app/firmwares/playcodingbox.hex @@ -0,0 +1,580 @@ +:100000000C9463000C948B000C948B000C948B006C +:100010000C948B000C948B000C948B000C94D108E6 +:100020000C948B000C948B000C948B000C94A40A01 +:100030000C948B000C948B000C948B000C948B0014 +:100040000C9487080C948B000C9453090C942D0984 +:100050000C948B000C948B000C948B000C948B00F4 +:100060000C9485090C948B000200000000240027EA +:10007000002A0000000000250028002B00000000DE +:1000800000230026002900040404040404040402DC +:100090000202020202030303030303010204081025 +:1000A00020408001020408102001020408102000F2 +:1000B0000000080002010000030407000000000027 +:1000C00000000000600B11241FBECFEFD8E0DEBFA0 +:1000D000CDBF11E0A0E0B1E0EAE9F3E202C0059093 +:1000E0000D92A638B107D9F723E0A6E8B1E001C028 +:1000F0001D92AF3AB207E1F710E0C3E6D0E004C0CA +:100100002197FE010E94C511C236D107C9F70E948E +:10011000D70B0C94CB110C940000833081F028F4A1 +:10012000813099F08230A9F008958730A9F08830A5 +:10013000C9F08430B1F4809180008F7D03C080913C +:1001400080008F7780938000089584B58F7784BD79 +:10015000089584B58F7DFBCF8091B0008F77809319 +:10016000B00008958091B0008F7DF9CFCF93DF93D9 +:10017000282F30E0F901E155FF4F8491F901E55650 +:10018000FF4FD491F901E957FF4FC491CC23A1F05F +:1001900081110E948D00EC2FF0E0EE0FFF1FE3585D +:1001A000FF4FA591B491EC91ED2381E090E009F42B +:1001B00080E0DF91CF91089580E090E0FACF1F9327 +:1001C000CF93DF93282F30E0F901E155FF4F849161 +:1001D000F901E556FF4FD491F901E957FF4FC4915A +:1001E000CC23A9F0162F81110E948D00EC2FF0E096 +:1001F000EE0FFF1FED58FF4FA591B4918FB7F89404 +:10020000EC91111108C0D095DE23DC938FBFDF91F4 +:10021000CF911F910895DE2BF8CFCF93DF9390E01D +:10022000FC01E556FF4F249189579F4FFC018491B3 +:100230008823D1F090E0880F991FFC01E759FF4F08 +:10024000A591B491FC01ED58FF4FC591D491611176 +:100250000EC09FB7F8948C91E22FE0958E238C937B +:100260002881E223E8839FBFDF91CF9108958FB764 +:10027000F894EC91E22BEC938FBFF6CF1F93CF93C2 +:10028000DF93182FEB0161E00E940D01209739F4F4 +:1002900060E0812FDF91CF911F910C94DF00CF3F61 +:1002A000D10511F461E0F5CFE12FF0E0E155FF4F0A +:1002B000E491E33031F140F4E130B1F0E230E1F0CB +:1002C000C038D1057CF7E4CFE73029F1E83059F1A7 +:1002D000E430B1F780918000806280938000D093F9 +:1002E0008B00C0938A0004C084B5806884BDC7BDFC +:1002F000DF91CF911F91089584B5806284BDC8BD00 +:10030000F7CF80918000806880938000D09389002F +:10031000C0938800EDCF8091B00080688093B000DA +:10032000C093B300E5CF8091B00080628093B000AD +:10033000C093B400DDCF8E3008F08E50877080649B +:1003400080937C0080917A00806480937A00809111 +:100350007A0086FDFCCF8091780090917900089515 +:100360003FB7F8948091750290917602A091770240 +:10037000B091780226B5A89B05C02F3F19F00196D1 +:10038000A11DB11D3FBFBA2FA92F982F8827BC01EF +:10039000CD01620F711D811D911D42E0660F771F17 +:1003A000881F991F4A95D1F708958F929F92AF9217 +:1003B000BF92CF92DF92EF92FF924B015C010E94BD +:1003C000B0016B017C010E94B0016C197D098E099E +:1003D0009F09683E734081059105A8F321E0821AC8 +:1003E0009108A108B10888EEC80E83E0D81EE11C70 +:1003F000F11C81149104A104B10429F7FF90EF903E +:10040000DF90CF90BF90AF909F908F900895089508 +:1004100008959091000189130BC0E8E6F0E0E491A3 +:100420009FEF90930001E13049F028F0E23061F055 +:1004300060E00C94DF0010926E00FACF90916F0094 +:100440009D7F90936F00F4CF909170009D7F90936B +:10045000700091E09093B0009091B100987F94600B +:100460009093B1001092B300E3CF4F925F926F92DE +:100470007F928F929F92AF92BF92CF92DF92EF9234 +:10048000FF920F931F93CF93DF9300D000D01F9262 +:10049000CDB7DEB78B0129833A834B835C83909180 +:1004A00000018917C9F09F3F09F47CC00F900F909D +:1004B0000F900F900F90DF91CF911F910F91FF90B0 +:1004C000EF90DF90CF90BF90AF909F908F907F90F4 +:1004D0006F905F904F900895E8E6F0E094919D83CF +:1004E00097FDE4CF61E00E940D018D81882321F00A +:1004F0009D81923009F04EC14801B12CA12C60E0E1 +:1005000072E18AE790E0A50198010E94FD0F2901A0 +:100510003A017A01690181E0C81AD108E108F108BD +:100520009FEFC916D104E104F10409F00CF401C1F4 +:1005300060E472E48FE090E0A50198010E94FD0F55 +:1005400069017A0181E0C81AD108E108F1089D81AA +:10055000923009F0A2C08FEFC816D104E104F10473 +:1005600009F00CF4D4C160E970ED83E090E0A501DE +:1005700098010E94FD0F69017A0191E0C91AD10822 +:10058000E108F1088FEFC816D104E104F10411F07D +:100590000CF06FC183E09091B100987F892B80931C +:1005A000B100CFC080930001E8E6F0E094919D8314 +:1005B0009F3F09F47BCF913041F150F0923009F424 +:1005C00046C09D8197FD72CF61E00E940D0190CFE2 +:1005D00014BC15BC94B5926094BD95B5916095BD61 +:1005E000282F30E0F901E957FF4FE491F0E0EE0FDA +:1005F000FF1FED58FF4F45915491F901E556FF4F0C +:10060000E491E093F0011D826DCF10928000109272 +:100610008100909181009860909381009091810079 +:10062000916090938100282F30E0F901E957FF4F46 +:10063000E491F0E0EE0FFF1FED58FF4F459154910C +:10064000F901E556FF4FE491E093EF014BCF109293 +:10065000B0001092B1009091B00092609093B00001 +:100660009091B10091609093B100282F30E0F90192 +:10067000E957FF4FE491F0E0EE0FFF1FED58FF4FF9 +:10068000459154915093FA014093F901F901E556CF +:10069000FF4FE491E093FB0125CF9FEFC916D104F2 +:1006A000E104F10409F00CF473C068E478EE81E031 +:1006B00090E0A50198010E94FD0F69017A0181E097 +:1006C000C81AD108E108F1089D81992309F4EAC00C +:1006D0009FEFC916D104E104F10409F00CF4E0C065 +:1006E000EAC064E274EF80E090E0A50194010E940A +:1006F000FD0F69017A0181E0C81AD108E108F1080B +:1007000085E09FEFC916D104E104F10409F008F473 +:1007100042CF62E17AE780E090E0A50194010E9477 +:10072000FD0F69017A0181E0C81AD108E108F108DA +:10073000D5C081E09D8191112ECF95B5987F892BF1 +:1007400085BDD801AA0FBB1F29813A814B815C81ED +:100750000E941C1028EE33E040E050E00E94271079 +:100760008D81813009F44AC0823009F459C0811169 +:100770009DCEC7BC2093F5013093F6014093F7015D +:100780005093F80180916E00826080936E008ECE4F +:1007900082E0D0CFB12CA12C60E072E18AE790E03A +:1007A000A50198010E94FD0F69017A0181E0C81A34 +:1007B000D108E108F108C114D10491E0E906F1047F +:1007C00064F491E08D81813009F0BBCF809181008C +:1007D000887F892B80938100B4CF68E478EE81E034 +:1007E00090E0A50198010E94FD0F69017A0181E066 +:1007F000C81AD108E108F10893E0E4CFD09289004B +:10080000C09288002093F1013093F2014093F301EC +:100810005093F40180916F00826080936F0046CE08 +:10082000C092B3002093FC013093FD014093FE0180 +:100830005093FF018091700082608093700036CEEB +:1008400084E09FEFC916D104E104F10409F008F433 +:1008500074CF730162019AE0F594E794D794C7943A +:100860009A95D1F781E0C81AD108E108F10885E02E +:1008700064CF68E478EE81E090E0A50198010E94E1 +:10088000FD0F69017A0191E0C91AD108E108F10868 +:100890008FEFC816D104E104F10411F00CF021CF60 +:1008A00084E079CE83E09FEFC916D104E104F1041E +:1008B00009F00CF442CF62E17AE780E090E0A50114 +:1008C00094010E94FD0F69017A0181E0C81AD108E4 +:1008D000E108F1089D81992309F4B2CF86E09FEFEA +:1008E000C916D104E104F10409F008F454CE7301EF +:1008F00062012AE0F594E794D794C7942A95D1F73A +:1009000081E0C81AD108E108F10887E044CE82E00E +:1009100042CEAF92BF92CF92DF92EF92FF920F93AF +:100920001F93CF93DF936C017B018B01040F151F85 +:10093000EB015E01AE18BF08C017D10759F06991ED +:10094000D601ED91FC910190F081E02DC601099551 +:10095000892B79F7C501DF91CF911F910F91FF90FE +:10096000EF90DF90CF90BF90AF900895FC01538D32 +:10097000448D252F30E0842F90E0821B930B541779 +:1009800010F0CF96089501970895FC01918D828D06 +:10099000981761F0A28DAE0FBF2FB11D5D968C919F +:1009A000928D9F5F9F73928F90E008958FEF9FEFDE +:1009B0000895FC01918D828D981731F0828DE80F9A +:1009C000F11D858D90E008958FEF9FEF0895FC0154 +:1009D000918D228D892F90E0805C9F4F821B910921 +:1009E0008F739927089589EC92E00E94E70421E033 +:1009F000892B09F420E0822F089580E090E0892B74 +:100A000029F00E94F30481110C9400000895FC0168 +:100A1000A48DA80FB92FB11DA35ABF4F2C91848D5F +:100A200090E001968F739927848FA689B7892C93BC +:100A3000A089B1898C91837080648C93938D848D0F +:100A4000981306C00288F389E02D80818F7D808312 +:100A50000895EF92FF920F931F93CF93DF93EC01D2 +:100A600081E0888F9B8D8C8D98131AC0E889F98955 +:100A7000808185FF15C09FB7F894EE89FF89608358 +:100A8000E889F98980818370806480839FBF81E0D9 +:100A900090E0DF91CF911F910F91FF90EF9008951B +:100AA000F62E0B8D10E00F5F1F4F0F731127E02EF6 +:100AB0008C8D8E110CC00FB607FCFACFE889F9892E +:100AC000808185FFF5CFCE010E940705F1CFEB8D28 +:100AD000EC0FFD2FF11DE35AFF4FF0829FB7F89402 +:100AE0000B8FEA89FB8980818062CFCF682F89ECE8 +:100AF00092E00C942905CF93DF93EC01888D882335 +:100B0000B9F0AA89BB89E889F9898C9185FD03C070 +:100B1000808186FD0DC00FB607FCF7CF8C9185FF55 +:100B2000F2CF808185FFEDCFCE010E940705E9CF8E +:100B3000DF91CF9108952091CC01260F3327331FE9 +:100B400021323105ECF420919F02FC0190E080E01D +:100B5000243069F082E00895A091CC012191AC018C +:100B600044555E4FA40FB52FB11D2C9301968617E7 +:100B700098F38091CC01680F6093CC0180E00895D8 +:100B800081E0089510929F0281E080939E0210926E +:100B9000790261E082E10E94DF0061E083E10E946E +:100BA000DF00E9EBF0E080818E7F808380818D7FA4 +:100BB000808388E48093B80085E48093BC00089526 +:100BC000CF93DF9391E09093AB018823B9F0C0916C +:100BD000B800D091BA008091BC008A7B8093BC00A1 +:100BE00060E082E10E94DF0060E083E10E94DF00BC +:100BF0000E94C205D093BA00C093B800DF91CF9194 +:100C00000895CF92DF92EF92FF920F931F93CF93AD +:100C1000DF93D091C80281E0D13208F09CC0C0912E +:100C2000C7020E94B0016B017C0180919F0281117B +:100C30006CC082E080939F0281E080939E028FEFE0 +:100C400080939D0210929C02D0939B02A7EAB2E08F +:100C5000EBE7F2E080E0D8138DC010927A02809129 +:100C60007A02CC0FC82BC0937A028091790281302E +:100C700009F084C0109279020E94B0016B017C01DE +:100C800080917A028093BB008091A1029091A20290 +:100C9000A091A302B091A402892B8A2B8B2BA1F0E7 +:100CA0000E94B0010091A1021091A2022091A30222 +:100CB0003091A4026C197D098E099F090617170748 +:100CC0002807390708F442C08091BC0083FDD8CFC3 +:100CD00085EC8093BC000E94B0016B017C01809187 +:100CE0009F02823009F44CC080919D028F3F09F42D +:100CF00069C080919D02803209F466C080919D0296 +:100D0000803309F463C084E026C08091A1029091F1 +:100D1000A202A091A302B091A402892B8A2B8B2B53 +:100D200009F483CF0E94B0010091A1021091A202A8 +:100D30002091A3023091A4026C197D098E099F09AC +:100D4000061717072807390708F06FCF8091A00210 +:100D50000E94E00585E01092A6021092C80210924F +:100D6000A502DF91CF911F910F91FF90EF90DF903F +:100D7000CF9008959D9191938F5F6DCF85EEA9CF10 +:100D80008091A1029091A202A091A302B091A4022D +:100D9000892B8A2B8B2B09F4A2CF0E94B0010091E2 +:100DA000A1021091A2022091A3023091A4026C1919 +:100DB0007D098E099F09061717072807390708F0CC +:100DC0008ECFC4CF80E0C7CF82E0C5CF83E0C3CF52 +:100DD0000895E091050280910402E81730F4F0E0F4 +:100DE000E557FE4F808190E008958FEF9FEF0895C3 +:100DF00090910502809104022FEF3FEF981748F47D +:100E0000E92FF0E0E557FE4F208130E09F5F90939F +:100E10000502C90108958091040290910502891B81 +:100E2000990B0895CF92DF92EF92FF920F931F9349 +:100E3000CF93DF937C01CB018A012091A50222236D +:100E400089F0EB016B01C40ED51ECC15DD0569F0F0 +:100E50006991D701ED91FC910190F081E02DC701DE +:100E60000995F3CF642F0E949B05C801DF91CF91B4 +:100E70001F910F91FF90EF90DF90CF900895CF9347 +:100E8000DF931F92CDB7DEB769832091A50222239D +:100E9000F9F02091C802203258F021E030E0FC0146 +:100EA0003383228390E080E00F90DF91CF9108950B +:100EB0008091A602E82FF0E0E955FD4F99819083DB +:100EC0008F5F8093A6028093C80281E090E0ECCF10 +:100ED00061E0CE0101960E949B05F7CF682F86E660 +:100EE00093E00C943F0790E080E00895FC01EE0F42 +:100EF000FF1FEC5AFD4F20813181232B39F421E073 +:100F000030E03183208361E00C940D0108958FEF70 +:100F100090E00E94760585E590E00E9476058DE0E0 +:100F200090E00E9476058AE090E00C947605682FA8 +:100F300089EC92E00C942905EF92FF920F931F9396 +:100F4000CF93DF93162FE72EF82E092F82E00E9411 +:100F50009707C6E8D1E0812F9E2DAF2DB02F888353 +:100F60009983AA83BB830E94970789810E94970770 +:100F70008A810E9497078B81DF91CF911F910F91FA +:100F8000FF90EF900C949707CF92DF92EF92FF9231 +:100F9000CF93DF93EC016A017B018FEF90E00E9419 +:100FA000760585E590E00E94760584E090E00E9459 +:100FB000760590E080E00E947605CE010E947605DD +:100FC000C0928601D0928701E0928801F092890157 +:100FD00044E050E066E871E089EC92E00E94890408 +:100FE0008DE090E00E9476058AE090E0DF91CF915D +:100FF000FF90EF90DF90CF900C947605FC0101906C +:101000000020E9F73197AF01481B590BBC0189EC6F +:1010100092E00C9489048F929F92AF92BF920F93AB +:101020001F93CF93DF93CDB7DEB7A1970FB6F89498 +:10103000DEBF0FBECDBF19A2423008F44AE08E01D8 +:101040000F5D1F4F842E912CB12CA12CA501940172 +:101050000E942710E62FB901CA01EA30F4F4E05DDE +:10106000D801EE938D01232B242B252B79F790E0CB +:1010700080E0109719F0CD010E94FE07A1960FB6EF +:10108000F894DEBF0FBECDBFDF91CF911F910F91BE +:10109000BF90AF909F908F900895E95CE1CF85ED70 +:1010A0008093BC008091A1029091A202A091A30222 +:1010B000B091A4020796A11DB11D23E0B695A79596 +:1010C000979587952A95D1F72091BC0024FD03C000 +:1010D00010929F0208954091A1025091A202609146 +:1010E000A3027091A402452B462B472B69F300976E +:1010F000A105B10541F02AE22A95F1F700C0019758 +:10110000A109B109E1CF8091A0020C94E0051F92E2 +:101110000F920FB60F9211242F933F938F939F93AB +:10112000AF93BF938091710290917202A09173026C +:10113000B09174023091700223E0230F2D3758F5DF +:101140000196A11DB11D20937002809371029093AE +:101150007202A0937302B093740280917502909111 +:101160007602A0917702B09178020196A11DB11D7F +:101170008093750290937602A0937702B0937802E1 +:10118000BF91AF919F918F913F912F910F900FBE83 +:101190000F901F90189526E8230F0296A11DB11DF0 +:1011A000D2CF1F920F920FB60F9211242F933F931D +:1011B0004F935F936F937F938F939F93AF93BF935F +:1011C000EF93FF938091FC019091FD01A091FE01AE +:1011D000B091FF01892B8A2B8B2BD1F19091FB01D0 +:1011E000E091F901F091FA01808189278083809153 +:1011F000FC019091FD01A091FE01B091FF01181634 +:1012000019061A061B069CF48091FC019091FD01C1 +:10121000A091FE01B091FF010197A109B10980934E +:10122000FC019093FD01A093FE01B093FF01FF919B +:10123000EF91BF91AF919F918F917F916F915F914E +:101240004F913F912F910F900FBE0F901F901895C7 +:10125000809100010E940902EACF1F920F920FB6FF +:101260000F9211242F933F934F935F936F937F932C +:101270008F939F93AF93BF93EF93FF9389EC92E08B +:101280000E940705FF91EF91BF91AF919F918F91C0 +:101290007F916F915F914F913F912F910F900FBE72 +:1012A0000F901F9018951F920F920FB60F92112456 +:1012B0002F938F939F93EF93FF93E091D902F09137 +:1012C000DA028081E091DF02F091E00282FD1BC032 +:1012D00090818091E2028F5F8F732091E3028217E9 +:1012E00041F0E091E202F0E0E753FD4F958F8093EB +:1012F000E202FF91EF919F918F912F910F900FBE7E +:101300000F901F9018958081F4CF1F920F920FB607 +:101310000F9211242F933F934F935F936F937F937B +:101320008F939F93AF93BF93EF93FF938091B900F7 +:10133000887F803609F44AC0F0F5883209F4A7C0E6 +:1013400018F5803109F49BC0B8F4882309F4F9C07A +:10135000883009F494C0FF91EF91BF91AF919F91B4 +:101360008F917F916F915F914F913F912F910F904E +:101370000FBE0F901F901895883109F488C08032F5 +:1013800051F780939D0214C0803409F49DC040F44D +:101390008033B9F38833F9F680939D0285ECB0C0B1 +:1013A000803509F485C0883509F496C0883499F6EB +:1013B0000E944F08D0CF883909F48CC038F588379F +:1013C00029F050F4883611F0803729F683E08093B5 +:1013D0009F021092EE0157C0883809F47BC0803913 +:1013E00019F0803809F0B7CF8091EE01803208F013 +:1013F00071C0E091EE0181E08E0F8093EE0180914B +:10140000BB00F0E0E253FE4F80833DC0803B39F0EB +:10141000E0F4803A09F479C0883A09F09CCF84E07E +:1014200080939F021092CD011092CC01E0910202B4 +:10143000F091030209958091CC0181110FC081E0E8 +:101440008093CC011092AC0109C0803C09F4A6CF76 +:10145000883C09F4A3CF883B09F07DCFE091CD0112 +:1014600081E08E0F8093CD01F0E0E455FE4F808146 +:101470008093BB009091CD018091CC0129C08091D7 +:101480007A028093BB0085EC8093BC0064CF90917E +:101490009C0280919B02981758F5E0919C0281E094 +:1014A0008E0F80939C02F0E0E558FD4F8081E9CFDC +:1014B000E0919C0281E08E0F80939C028091BB00A2 +:1014C000F0E0E558FD4F808390919C0280919B0253 +:1014D0009817C8F285E8D8CFE0919C0281E08E0F82 +:1014E00080939C028091BB00F0E0E558FD4F808323 +:1014F00080919E0281115CCF81E08093790284EA21 +:101500008093BC0010929F0226CF85EC8093BC0094 +:1015100010929F028091EE01803230F4E091EE0152 +:10152000F0E0E253FE4F10826091EE0170E0E09136 +:101530000002F09101028EEC91E009951092EE010B +:101540000ACF10929D0234CF1F920F920FB60F92C6 +:1015500011242F933F934F935F936F937F938F93B8 +:101560009F93AF93BF93CF93DF93EF93FF938091BC +:101570008A01C0919603D0E087FF24C010928500B5 +:101580001092840080918A018F5F80938A018091FC +:101590008A01082E000C990B8C179D0724F480916A +:1015A0008A018C30C4F1809184009091850004966A +:1015B00080349C4908F47AC0809184009091850021 +:1015C000049676C080918A01082E000C990B8C1726 +:1015D0009D07C4F6E0918A018E2FEE0F990BFC0156 +:1015E000EE0FFF1FE80FF91FEE58FC4F808186FFBA +:1015F000C9CFE0918A018E2FEE0F990BFC01EE0FFF +:10160000FF1FE80FF91FEE58FC4F808160E08F73D9 +:101610000E94DF00B7CF2091840030918500E091D7 +:101620008A018E2FEE0F990BFC01EE0FFF1FE80FC2 +:10163000F91FEE58FC4F81819281820F931F909386 +:10164000890080938800E0918A018E2FEE0F990B1C +:10165000FC01EE0FFF1FE80FF91FEE58FC4F8081D1 +:1016600086FF11C0E0918A018E2FEE0F990BFC01CD +:10167000EE0FFF1FE80FF91FEE58FC4F808161E06D +:101680008F730E94DF00FF91EF91DF91CF91BF91A7 +:10169000AF919F918F917F916F915F914F913F910A +:1016A0002F910F900FBE0F901F90189580E49CE92A +:1016B00090938900809388008FEF80938A01E3CF15 +:1016C0001092CC021092CB0288EE93E0A0E0B0E042 +:1016D0008093CD029093CE02A093CF02B093D0021C +:1016E00021E131E03093CA022093C90225EC30E0B9 +:1016F0003093D6022093D50224EC30E03093D80208 +:101700002093D70220EC30E03093DA022093D90204 +:1017100021EC30E03093DC022093DB0222EC30E05D +:101720003093DE022093DD0226EC30E03093E002BD +:101730002093DF021092E2021092E3021092E40280 +:101740001092E502109269031092680380936A0375 +:1017500090936B03A0936C03B0936D0383E291E0CD +:101760009093670380936603E7E9F3E02FEA33E0A1 +:101770004FEF68EB7BE0809196038C30B0F491E002 +:10178000980F90939603808390E0DC01AA0FBB1F13 +:10179000A80FB91FAE58BC4F12967C936E93119749 +:1017A00033962E173F0739F708954083F9CFCF932B +:1017B000DF93CDB7DEB72A970FB6F894DEBF0FBE22 +:1017C000CDBF789484B5826084BD84B5816084BDCA +:1017D00085B5826085BD85B5816085BD80916E00CF +:1017E000816080936E001092810080918100826000 +:1017F000809381008091810081608093810080913D +:1018000080008160809380008091B100846080932B +:10181000B1008091B00081608093B00080917A0027 +:10182000846080937A0080917A00826080937A004D +:1018300080917A00816080937A0080917A0080683C +:1018400080937A001092C100E091D902F091DA02FF +:1018500082E08083E091D502F091D6021082E0917F +:10186000D702F091D80280E180831092E102E091EA +:10187000DD02F091DE0286E08083E091DB02F091F0 +:10188000DC02808180618083E091DB02F091DC02E8 +:10189000808188608083E091DB02F091DC028081AE +:1018A00080688083E091DB02F091DC0280818F7D93 +:1018B000808310920502109204021092A6021092E8 +:1018C000C8020E94C20587E092E0909303028093D1 +:1018D000020288E092E0909301028093000211E0FE +:1018E0001093A50280E78093C70281E290E00E94F6 +:1018F0006E070E9401061093A5021092A602109294 +:10190000C80281E890E00E946E070E9401061093D1 +:10191000A5021092A6021092C80287EE90E00E94E3 +:101920006E070E94010610E061E0812F0E940D0108 +:1019300060E0812F0E94DF001F5F1E30A9F768EC76 +:1019400070E080E090E00E94D501DD24D39414EB98 +:10195000412E512C612C712C1E0129E0220E311CCC +:1019600000E7C02E89EC92E00E94E704892B09F47D +:10197000D3C289EC92E00E94E7041816190694F786 +:1019800089EC92E00E94C50490915302853509F0DC +:1019900051C091114FC0809152028F3F21F4D092DB +:1019A0005102D0925302809151028F5F843308F02C +:1019B00059C08093510280915302882399F28091FB +:1019C00050028111CFCF80915102843058F2109291 +:1019D0005302E0912102EE2EF12C90902202809190 +:1019E0002002823009F47AC0833009F432C1813098 +:1019F000F1F4E1113CC08FEF90E00E94760585E59F +:101A000090E00E94760582E090E00E94760590E0EA +:101A100080E00E94760590E080E00E9476058DE0EF +:101A200090E00E9476058AE090E00E947605109290 +:101A3000510298CF80935202992309F4B4CFE091D8 +:101A40005102E23039F480935002F0E0E45EFD4F41 +:101A50008083A9CFE330C8F39091500291509093C6 +:101A60005002F3CF1092510210925302A4CFE230F1 +:101A700099F0E730A9F0E130D1F6892D0E94B60047 +:101A8000BC01990F880B990B0E943911AB01BC0165 +:101A9000C7010E94C407CBCF892D0E949B01F0CFC4 +:101AA0002FB7F89460917102709172028091730265 +:101AB000909174022FBF0E94371120E030E04AE776 +:101AC00054E40E94C51020911802309119024091EF +:101AD0001A0250911B020E945810D8CF092D10E015 +:101AE000E150E03108F0B5C00E2E000CFF0BE558B8 +:101AF000F24F0C94C5118B0D290E920D310E9C0DD9 +:101B0000290EF60E120F250FC60D630F4B0F630F34 +:101B1000630F7C0F4B0FC8010E9476076091230270 +:101B2000892DC5C1C8010E9476076091230270E02B +:101B3000892D0E943E018DC0C8010E9476078091C8 +:101B400023028093160280912402809317026091F1 +:101B500016027091170280912502809316028091DF +:101B60002602809317022091160230911702121656 +:101B7000130644F4032E000C440B550B892D0E94D0 +:101B8000350267C0892D0E94090263C0A3E2B2E05A +:101B90008E010F5F1F4FF80178018D9181932E16F2 +:101BA0003F06D9F781E391E00E94FE078BE491E0C4 +:101BB0000E94FE07812C912C54018EE491E00E943A +:101BC000FE074AE0C501B4010E940B0889E691E0D6 +:101BD0000E94FE07F80161918F0170E090E080E0C3 +:101BE00042E00E940B088BE491E00E94FE07FFEFA9 +:101BF0008F1A9F0AAF0ABF0A28E082169104A10437 +:101C0000B104D9F6D092A502C092C7021092A602E2 +:101C10001092C80290E080E00E946E0748E050E019 +:101C2000B70186E693E00E9412070E940106182F72 +:101C3000882391F083E591E00E94FE07612F70E018 +:101C400090E080E04AE00E940B088BE491E00E9463 +:101C5000FE070E948707EBCE8CE691E00E94FE070C +:101C6000F4CFC8010E947607309123023A87353BB2 +:101C700080F7E6E0F2E090E080E0219131910217F8 +:101C8000130751F0232B09F0A9C0FC01EE0FFF1F31 +:101C9000EA5FFD4F11830083FC01EE0FFF1FE80F89 +:101CA000F91FE956FC4F8081898781819281E985FE +:101CB000EC3008F040C061E0892D0E940D01F985EB +:101CC0008F2F90E0AC01440F551FFA01E80FF91F68 +:101CD000EE58FC4F292D2F73922E2081207C922AC2 +:101CE000908230E020E0F901EE0FFF1FE20FF31FBA +:101CF000EE58FC4F608166FD14C02F5F3F4F2C30C3 +:101D0000310589F71092800022E020938100109223 +:101D1000850010928400B19A20916F002260209378 +:101D20006F00840F951FFC01EE58FC4F808180648A +:101D3000808390E080E048E5E42E42E0F42EE91A4A +:101D4000F10897FDF394EE0CFF1CEE0CFF1C08E865 +:101D500010E0081B110987FD1395000F111F000FDC +:101D6000111F4801012E000CAA08BB0897010F2C77 +:101D7000000C440B550B281939094A095B098A855F +:101D8000A82FB0E00E941C10A30192010E94FD0F39 +:101D9000BA01A901480D591D6A1D7B1DE985EC306A +:101DA00008F057CF401751072CF087014E155F05FB +:101DB0000CF48A0102501109000F111F2FB7F8947B +:101DC000F9858F2F90E0FC01EE0FFF1FE80FF91F40 +:101DD000EE58FC4F128301832FBF3BCF0196883012 +:101DE000910509F04ACF90E080E056CF2FB7F894E4 +:101DF00060917102709172028091730290917402ED +:101E00002FBF0E94371120E030E04AE754E40E94DF +:101E1000C510609318027093190280931A02909370 +:101E20001B0217CFE0902402F12C0091250210E054 +:101E30006091230270E083E00E943E01B70185E0DB +:101E40000E943E01B80186E074CE80912302809307 +:101E500016028091240280931702609116027091FD +:101E600017028091250280931602809126028093AA +:101E700017022091160230911702161617064CF41D +:101E80001216130634F4032E000C440B550B84E099 +:101E900076CE84E078CE6091230270E080912402B7 +:101EA000811108C08AE00E943E0160E08BE00E9440 +:101EB000DF00CFCE813009F0CCCE8BE00E943E0116 +:101EC00060E08AE0F4CF0091230210E0892D0E94A7 +:101ED0009B015C01BC01990F880B990B0E94391181 +:101EE000AB01BC01C7010E94C40761E0A016B106A6 +:101EF0000CF016CE60E014CE82E00E94B600BC0169 +:101F0000990F880B990B0E943911AB01BC018FE02E +:101F100090E00E94C4079DCE6FE070E080E090E00A +:101F20000E94D50104E512E0F12CF8018191919114 +:101F30008F01892B09F560E08F2D0E940D018FEF35 +:101F40000E94970785E50E9497078F2D0E94B60093 +:101F5000BC01990F880B990B0E9439110E949C07B4 +:101F60008F2D0E94970781E00E9497078BE491E0F4 +:101F70000E94FE070E948707F394FEE0FF12D5CF70 +:101F800001E011E0F12CF801819191918F01892BF1 +:101F9000E9F48FEF0E94970785E50E9497078F2D40 +:101FA0000E949B01BC01990F880B990B0E9439116B +:101FB0000E949C078F2D0E94970782E00E9497073E +:101FC0008BE491E00E94FE070E948707F394F6E0FD +:101FD000FF12D9CF6AE070E080E090E00E94D50166 +:101FE00020E030E0232B09F4BDCC0E94F3048823C9 +:101FF00009F4B8CC0E940000B5CC052E97FB1EF466 +:1020000000940E94141057FD07D00E94271007FC6F +:1020100003D04EF40C9414105095409530952195B2 +:102020003F4F4F4F5F4F0895909580957095619504 +:102030007F4F8F4F9F4F08950E944910A59F900D8D +:10204000B49F900DA49F800D911D11240895A1E2CD +:102050001A2EAA1BBB1BFD010DC0AA1FBB1FEE1F22 +:10206000FF1FA217B307E407F50720F0A21BB30B6D +:10207000E40BF50B661F771F881F991F1A9469F7E9 +:1020800060957095809590959B01AC01BD01CF0145 +:102090000895A29FB001B39FC001A39F700D811D41 +:1020A0001124911DB29F700D811D1124911D089561 +:1020B0005058BB27AA270E9470100C948B110E94C5 +:1020C0007D1138F00E94841120F039F49F3F19F4FB +:1020D00026F40C947A110EF4E095E7FB0C9474113D +:1020E000E92F0E949C1158F3BA17620773078407FF +:1020F000950720F079F4A6F50C94BE110EF4E09546 +:102100000B2EBA2FA02D0B01B90190010C01CA01B1 +:10211000A0011124FF27591B99F0593F50F4503E5C +:1021200068F11A16F040A22F232F342F4427585F4E +:10213000F3CF469537952795A795F0405395C9F766 +:102140007EF41F16BA0B620B730B840BBAF091501E +:10215000A1F0FF0FBB1F661F771F881FC2F70EC0BD +:10216000BA0F621F731F841F48F487957795679590 +:10217000B795F7959E3F08F0B0CF9395880F08F07C +:102180009927EE0F9795879508950E94D9100C9482 +:102190008B110E94841158F00E947D1140F029F4A7 +:1021A0005F3F29F00C94741151110C94BF110C94E1 +:1021B0007A110E949C1168F39923B1F3552391F38E +:1021C000951B550BBB27AA2762177307840738F0A6 +:1021D0009F5F5F4F220F331F441FAA1FA9F335D003 +:1021E0000E2E3AF0E0E832D091505040E695001CB7 +:1021F000CAF72BD0FE2F29D0660F771F881FBB1F71 +:10220000261737074807AB07B0E809F0BB0B802D4E +:10221000BF01FF2793585F4F3AF09E3F510578F07A +:102220000C9474110C94BF115F3FE4F3983ED4F307 +:10223000869577956795B795F7959F5FC9F7880F4E +:10224000911D9695879597F90895E1E0660F771FA0 +:10225000881FBB1F621773078407BA0720F0621B31 +:10226000730B840BBA0BEE1F88F7E0950895E89482 +:1022700009C097FB3EF490958095709561957F4FCE +:102280008F4F9F4F9923A9F0F92F96E9BB2793957C +:10229000F695879577956795B795F111F8CFFAF48C +:1022A000BB0F11F460FF1BC06F5F7F4F8F4F9F4FBD +:1022B00016C0882311F096E911C0772321F09EE81B +:1022C000872F762F05C0662371F096E8862F70E081 +:1022D00060E02AF09A95660F771F881FDAF7880F5B +:1022E0009695879597F9089597F99F6780E870E02C +:1022F00060E008959FEF80EC089500240A9416167C +:10230000170618060906089500240A9412161306E3 +:10231000140605060895092E0394000C11F4882371 +:1023200052F0BB0F40F4BF2B11F460FF04C06F5F8D +:102330007F4F8F4F9F4F089557FD9058440F551F63 +:1023400059F05F3F71F04795880F97FB991F61F037 +:102350009F3F79F087950895121613061406551FAE +:10236000F2CF4695F1DF08C0161617061806991F1A +:10237000F1CF86957105610508940895E894BB270F +:1023800066277727CB0197F90895EE0FFF1F059079 +:0A239000F491E02D0994F894FFCFBA +:10239A00FF00000000000000000000000000000034 +:1023AA000029058904B6047B05E704C504D904009D +:1023BA000000003F0712077307E8060B07F806E953 +:1023CA0006526563656976656420444F545F4D41E2 +:1023DA005452495820446174613A000D0A00526F00 +:1023EA00772000493243205472616E736D697373AA +:1023FA00696F6E204572726F723A2000493243202B +:10240A005472616E736D697373696F6E205375636D +:06241A006365737300000E +:00000001FF diff --git a/app/modules/playcodingbox.js b/app/modules/playcodingbox.js new file mode 100644 index 000000000..9b8026ffd --- /dev/null +++ b/app/modules/playcodingbox.js @@ -0,0 +1,371 @@ +function Module() { + this.sp = null; + this.sensorTypes = { + ALIVE: 0, + DIGITAL: 1, + ANALOG: 2, + PWM: 3, + SERVO_PIN: 4, + TONE: 5, + TIMER: 7, + RGB_LED: 8, + BUZZER: 9, + DOT_MATRIX: 10, + GAS_SENSOR: 11, + MAGNETIC_SENSOR: 12, + SOUND_SENSOR: 13, + TEMP_SENSOR: 14, + PIR_SENSOR: 15, + MOTOR_FAN: 16, + BUTTON_SENSOR: 17, + + }; + + this.actionTypes = { + GET: 1, + SET: 2, + RESET: 3, + }; + + this.sensorValueSize = { + FLOAT: 2, + SHORT: 3, + }; + + this.digitalPortTimeList = new Array(14).fill(0); + this.sensorData = { + DIGITAL: {}, + ANALOG: {}, + TIMER: 0, + }; + this.defaultOutput = {}; + this.recentCheckData = {}; + this.sendBuffers = []; + this.isDraing = false; +} + +var sensorIdx = 0; + +Module.prototype.init = function(handler, config) {}; + +Module.prototype.setSerialPort = function(sp) { + this.sp = sp; +}; + +Module.prototype.requestInitialData = function() { + // 핸드셰이크 요청: 0xff 0x55 0x04 0x00 0x01 0x00 + return Buffer.from([0xff, 0x55, 0x04, 0x00, this.actionTypes.GET, this.sensorTypes.ALIVE]); + console.log('Handshake request sent:', buffer); + return buffer; + +}; + +Module.prototype.checkInitialData = function(data, config) { + console.log('Handshake response received:', data); + // 데이터가 0xff 0x55로 시작하고 ALIVE 응답인지 확인 + return data.length > 2 && data[0] === 0xff && data[1] === 0x55; +}; +0 +Module.prototype.afterConnect = function(that, cb) { + that.connected = true; + if (cb) { + cb('connected'); + } +}; + +Module.prototype.validateLocalData = function(data) { + return true; +}; + +Module.prototype.requestRemoteData = function(handler) { + Object.keys(this.sensorData).forEach((key) => { + handler.write(key, this.sensorData[key]); + }); +}; + +Module.prototype.handleRemoteData = function(handler) { + const getDatas = handler.read('GET'); + const setDatas = handler.read('SET') || this.defaultOutput; + let buffer = Buffer.alloc(0); + + if (getDatas) { + Object.keys(getDatas).forEach((key) => { + const dataObj = getDatas[key]; + if (dataObj.port !== undefined && this.isNewData(dataObj.port, key, dataObj.data)) { + this.recentCheckData[dataObj.port] = { + type: key, + data: dataObj.data, + }; + buffer = Buffer.concat([ + buffer, + this.makeSensorReadBuffer(key, dataObj.port, dataObj.data), + ]); + } + }); + } + + if (setDatas) { + Object.keys(setDatas).forEach((port) => { + const data = setDatas[port]; + if (data && this.isNewData(port, data.type, data.data)) { + this.recentCheckData[port] = { + type: data.type, + data: data.data, + }; + buffer = Buffer.concat([ + buffer, + this.makeOutputBuffer(data.type, port, data.data), + ]); + } + }); + } + + if (buffer.length) { + this.sendBuffers.push(buffer); + } +}; + +Module.prototype.isNewData = function(port, type, data) { + return ( + !(port in this.recentCheckData) || + this.recentCheckData[port].type !== type || + this.recentCheckData[port].data !== data + ); +}; + +Module.prototype.requestLocalData = function() { + if (!this.isDraing && this.sendBuffers.length > 0) { + this.isDraing = true; + this.sp.write(this.sendBuffers.shift(), () => { + this.sp.drain(() => { + this.isDraing = false; + }); + }); + } + return null; +}; + +Module.prototype.handleLocalData = function(data) { + const datas = this.getDataByBuffer(data); + + datas.forEach((data) => { + if (!data || data.length <= 4 || data[0] !== 255 || data[1] !== 85) { + return; // 잘못된 데이터 무시 + } + const readData = data.subarray(2, data.length); + + // 데이터 길이 확인 + if ( + (readData[0] === this.sensorValueSize.FLOAT && readData.length < 5) || + (readData[0] === this.sensorValueSize.SHORT && readData.length < 3) + ) { + console.error("Incomplete buffer received:", readData); + return; + } + + let value; + try { + switch (readData[0]) { + case this.sensorValueSize.FLOAT: + value = readData.readFloatLE(1); + break; + case this.sensorValueSize.SHORT: + value = readData.readInt16LE(1); + break; + default: + value = 0; + break; + } + } catch (err) { + console.error("Error reading buffer:", err); + return; // 버퍼 읽기 오류 처리 + } + + const type = readData[readData.length - 1]; + const port = readData[readData.length - 2]; + + // 데이터 타입별 처리 + switch (type) { + case this.sensorTypes.BUZZER: + break; + + case this.sensorTypes.DIGITAL: + this.sensorData.DIGITAL[port] = value; + break; + + case this.sensorTypes.ANALOG: + this.sensorData.ANALOG[port] = value; + break; + + case this.sensorTypes.TIMER: + this.sensorData.TIMER = value; + break; + case this.sensorTypes.BUTTON_SENSOR: { + // BUTTON_SENSOR 추가 처리 + this.sensorData.BUTTON_SENSOR = this.sensorData.BUTTON_SENSOR || {}; + this.sensorData.BUTTON_SENSOR[port] = value; // 버튼 상태 저장 (0 또는 1) + break; + } + + + + case this.sensorTypes.SOUND_SENSOR: + case this.sensorTypes.GAS_SENSOR: + case this.sensorTypes.TEMP_SENSOR: { + const sensorValue = value; // 센서의 현재 값 + const triggerValue = readData.readInt16LE(1); // 트리거 값 + this.sensorData.ANALOG[port] = sensorValue; // Entry에 값 송신 + if (sensorValue >= triggerValue) { + digitalWrite(port, HIGH); // 트리거 값 이상 시 HIGH + } else { + digitalWrite(port, LOW); // 트리거 값 미만 시 LOW + } + break; + } + + case this.sensorTypes.ALIVE: + console.log("Handshake successful"); + break; + + + + default: + console.error("Unknown type received:", type); + break; + } + }); +}; + + + +Module.prototype.makeSensorReadBuffer = function(device, port, data) { + const dummy = Buffer.from([10]); + let buffer; + + switch (device) { + case this.sensorTypes.SOUND_SENSOR: { // 사운드 센서 추가 + buffer = Buffer.from([255, 85, 5, sensorIdx, this.actionTypes.GET, device, port, 10]); + break; + } + default: { + if (!data) { + buffer = Buffer.from([255, 85, 5, sensorIdx, this.actionTypes.GET, device, port, 10]); + } else { + const value = Buffer.alloc(2); + value.writeInt16LE(data); + buffer = Buffer.from([255, 85, 7, sensorIdx, this.actionTypes.GET, device, port]); + buffer = Buffer.concat([buffer, value, dummy]); + } + } + } + sensorIdx = (sensorIdx + 1) % 255; + return buffer; +}; + +Module.prototype.makeOutputBuffer = function(device, port, data) { + const dummy = Buffer.from([10]); + let buffer; + switch (device) { + + case this.sensorTypes.DIGITAL: + case this.sensorTypes.PWM: + case this.sensorTypes.RGB_LED: { + const value = Buffer.alloc(2); + value.writeInt16LE(data); + buffer = Buffer.from([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); + buffer = Buffer.concat([buffer, value, dummy]); + break; + } + case this.sensorTypes.DOT_MATRIX: { + + const matrixData = Buffer.from(data); + buffer = Buffer.from([ + 255, 85, 8 + matrixData.length, + sensorIdx, + this.actionTypes.SET, + device, + port, + ]); + buffer = Buffer.concat([buffer, matrixData, dummy]); + break; + } + + case this.sensorTypes.SERVO_PIN: { + const value = Buffer.alloc(2); + value.writeInt16LE(data); + buffer = Buffer.from([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); + buffer = Buffer.concat([buffer, value, dummy]); + break; + } + case this.sensorTypes.MOTOR_FAN: { + const speed = Buffer.alloc(1); + speed.writeUInt8(data.speed); + + const direction = Buffer.alloc(1); + direction.writeUInt8(data.direction); + + buffer = Buffer.from([255, 85, 7, sensorIdx, this.actionTypes.SET, device, port]); + buffer = Buffer.concat([buffer, speed, direction, dummy]); + break; + } + case this.sensorTypes.BUZZER: + const noteIndex = data.noteIndex; + const octave = data.octave; + const duration = Buffer.alloc(2); + duration.writeInt16LE(data.duration); + + buffer = Buffer.from([255, 85, 8, sensorIdx, this.actionTypes.SET, device, port]); + buffer = Buffer.concat([buffer, Buffer.from([noteIndex, octave]), duration, dummy]); + break; + case this.sensorTypes.TONE: + const value = Buffer.alloc(2); + const time = Buffer.alloc(2); + value.writeInt16LE(data.value); + time.writeInt16LE(data.duration); + buffer = Buffer.from([255, 85, 8, sensorIdx, this.actionTypes.SET, device, port]); + buffer = Buffer.concat([buffer, value, time, dummy]); + break; + default: + buffer = Buffer.alloc(0); + break; + } + sensorIdx = (sensorIdx + 1) % 255; + return buffer; +}; + +Module.prototype.getDataByBuffer = function(buffer) { + const datas = []; + let lastIndex = 0; + + buffer.forEach((value, idx) => { + if (value === 0x0D && buffer[idx + 1] === 0x0A) { + const data = buffer.subarray(lastIndex, idx); + if (data[0] === 0xFF && data[1] === 0x55) { + datas.push(data); + } + lastIndex = idx + 2; + } + }); + + return datas; +}; + + +Module.prototype.disconnect = function(connect) { + connect.close(); + if (this.sp) { + delete this.sp; + } +}; + +Module.prototype.reset = function() { + this.sensorData = { + DIGITAL: {}, + ANALOG: {}, + TIMER: 0, + }; + this.recentCheckData = {}; + this.sendBuffers = []; +}; + +module.exports = new Module(); diff --git a/app/modules/playcodingbox.json b/app/modules/playcodingbox.json new file mode 100644 index 000000000..1025384c1 --- /dev/null +++ b/app/modules/playcodingbox.json @@ -0,0 +1,26 @@ +{ + "id": "660101", + "name": { + "en": "PlayCodingBox", + "ko": "플레이코딩박스" + }, + "category": "board", + "platform": ["win32", "darwin"], + "icon": "playcodingbox.png", + "module": "playcodingbox.js", + "driver": { + "win32-ia32": "arduino/dpinst-x86.exe", + "win32-x64": "arduino/dpinst-amd64.exe" + }, + "reconnect": true, + "firmware": "playcodingbox", + "hardware": { + "type": "serial", + "control": "slave", + "duration": 32, + "vendor": ["Arduino", "wch.cn", "FTDI"], + "baudRate": 115200, + "firmwarecheck": false, + "byteDelimiter": [13, 10] + } +} diff --git a/app/modules/playcodingbox.png b/app/modules/playcodingbox.png new file mode 100644 index 000000000..337affede Binary files /dev/null and b/app/modules/playcodingbox.png differ