diff --git a/app/firmwares/ITPLE.hex b/app/firmwares/ITPLE.hex index 72dfa89a3b..549da1401e 100644 --- a/app/firmwares/ITPLE.hex +++ b/app/firmwares/ITPLE.hex @@ -1,437 +1,700 @@ -:100000000C9463000C948B000C948B000C948B006C -:100010000C948B000C948B000C948B000C940703B5 -:100020000C948B000C948B000C948B000C940504A6 -:100030000C948B000C948B000C948B000C948B0014 -:100040000C94BB030C948B000C9489030C946303F5 -:100050000C948B000C948B000C948B000C948B00F4 -:100060000C948B000C948B000000000024002700EF -:100070002A0000000000250028002B0002000000DC +:100000000C9464000C948C000C948C000C948C0068 +:100010000C948C000C948C000C948C000C94340583 +:100020000C948C000C948C000C948C000C94E805BF +:100030000C948C000C948C000C948C000C948C0010 +:100040000C94EA040C948C000C94B6050C94900566 +:100050000C948C000C948C000C948C000C948C00F0 +:100060000C948C000C948C000200000000230026ED +:1000700000290000000000240027002A00000000E2 :100080000800020100000304070000000000000057 -:1000900000000000002300260029000404040404DA -:1000A0000404040202020202020303030303030125 -:1000B00002040810204080010204081020010204FC -:1000C000081020000B0511241FBECFEFD8E0DEBFC3 -:1000D000CDBF11E0A0E0B1E0ECE0FBE102C0059093 -:1000E0000D92AC32B107D9F722E0ACE2B1E001C029 -:1000F0001D92A939B207E1F710E0C3E6D0E004C0D1 -:100100002197FE010E94930BC236D107C9F70E94C6 -:100110006E050C94840D0C940000CF92DF92EF9248 -:10012000FF920F931F93CF93DF936C017A018B01A2 -:10013000C0E0D0E0CE15DF0589F0D8016D918D01CA -:10014000D601ED91FC910190F081E02DC601099559 -:10015000892B11F47E0102C02196ECCFC701DF91FB -:10016000CF911F910F91FF90EF90DF90CF90089566 -:1001700042E050E069E271E08FEB91E00C948D0079 -:10018000FC01918D828D981761F0828DDF01A80F9F -:10019000B11D5D968C91928D9F5F9F73928F90E0C1 -:1001A00008958FEF9FEF0895FC01918D828D981730 -:1001B00031F0828DE80FF11D858D90E008958FEF6D -:1001C0009FEF0895FC01918D228D892F90E0805C36 -:1001D0009F4F821B91098F73992708958FEB91E0B0 -:1001E0000E94E20021E0892B09F420E0822F08958B -:1001F000FC01848DDF01A80FB11DA35ABF4F2C91C4 -:10020000848D90E001968F739927848FA689B78992 -:100210002C93A089B1898C9180648C93938D848D6B -:10022000981306C00288F389E02D80818F7D80833A -:100230000895EF92FF920F931F93CF93DF93EC01FA -:1002400081E0888F9B8D8C8D981305C0E889F98992 -:10025000808185FD24C0F62E0B8D10E00F5F1F4FAF -:100260000F731127E02E8C8DE8120CC00FB607FC1F -:10027000FACFE889F989808185FFF5CFCE010E9408 -:10028000F800F1CF8B8DFE01E80FF11DE35AFF4F0F -:10029000F0820B8FEA89FB898081806207C0EE893A -:1002A000FF896083E889F98980818064808381E0A7 -:1002B00090E0DF91CF911F910F91FF90EF90089503 -:1002C000CF93DF93EC01888D8823C9F0EA89FB89FD -:1002D000808185FD05C0A889B9898C9186FD0FC0F4 -:1002E0000FB607FCF5CF808185FFF2CFA889B989C9 -:1002F0008C9185FFEDCFCE010E94F800E7CFDF9112 -:10030000CF91089580E090E0892B29F00E94EE00C3 -:1003100081110C9400000895833081F028F481301D -:1003200099F08230A1F008958730A9F08830B9F0B3 -:100330008430D1F4809180008F7D03C08091800053 -:100340008F7780938000089584B58F7702C084B53D -:100350008F7D84BD08958091B0008F7703C0809118 -:10036000B0008F7D8093B00008951F93CF93DF93EB -:10037000282F30E0F901E358FF4F8491F901E1554E -:10038000FF4FD491F901E556FF4FC491CC23C9F03A -:10039000162F81110E948C01EC2FF0E0EE0FFF1F51 -:1003A000EE58FF4FA591B4918FB7F894111105C085 -:1003B0009C91ED2FE095E92302C0EC91ED2BEC939D -:1003C0008FBFDF91CF911F910895909100019813F5 -:1003D00024C0ECE7F0E0E4919FEF90930001E1305E -:1003E000B9F098F0E230C9F4909170009D7F90933D -:1003F000700091E09093B0009091B100987F94606C -:100400009093B1001092B30008C010926E0005C026 -:1004100090916F009D7F90936F0060E00C94B50108 -:10042000CF93DF9390E0FC01E155FF4F2491FC0155 -:10043000E556FF4F8491882361F190E0880F991F62 -:10044000FC01E859FF4FC591D491FC01EE58FF4FD4 -:10045000A591B491611109C09FB7F8948881209546 -:1004600082238883EC912E230BC0623061F49FB706 -:10047000F8943881822F809583238883EC912E2BEA -:100480002C939FBF06C08FB7F894E8812E2B28834A -:100490008FBFDF91CF9108953FB7F89480913201DB -:1004A00090913301A0913401B091350126B5A89BFC -:1004B00005C02F3F19F00196A11DB11D3FBFBA2FF6 -:1004C000A92F982F8827820F911DA11DB11DBC0156 -:1004D000CD0142E0660F771F881F991F4A95D1F71B -:1004E00008958F929F92AF92BF92CF92DF92EF9238 -:1004F000FF926B017C010E944C024B015C01C11414 -:10050000D104E104F104F1F00E944C02DC01CB01C2 -:1005100088199909AA09BB09883E9340A105B1052C -:1005200070F321E0C21AD108E108F10888EE880EC4 -:1005300083E0981EA11CB11CC114D104E104F10494 -:1005400019F7DDCFFF90EF90DF90CF90BF90AF9085 -:100550009F908F900895FC01EE0FFF1FED55FE4F09 -:1005600020813181232B39F421E030E03183208355 -:1005700061E00C9410020895682F8FEB91E00C94C9 -:1005800019018FEF0E94BC0285E50E94BC020C9409 -:10059000B800CF92DF92FF920F931F93CF93DF9318 -:1005A0001F92CDB7DEB7162FF72E082F82E0998362 -:1005B0000E94BC028CE2C82E81E0D82E412F5F2D14 -:1005C000602F9981792FF601408351836283738371 -:1005D000812F0E94BC02F60181810E94BC02F601BB -:1005E00082810E94BC02F60183810F90DF91CF913E -:1005F0001F910F91FF90DF90CF900C94BC028FEF72 -:100600000E94BC0285E50C94BC020E940B0C1F9258 -:100610000F920FB60F9211242F933F934F935F9336 -:100620006F937F938F939F93AF93BF93EF93FF93BA -:100630008091410190914201A0914301B091440108 -:10064000892B8A2B8B2B51F180913801E091390154 -:10065000F0913A01908189278083809141019091A6 -:100660004201A0914301B0914401181619061A06DF -:100670001B06C4F48091410190914201A091430175 -:10068000B09144010197A109B10980934101909370 -:100690004201A0934301B093440104C08091000142 -:1006A0000E94E501FF91EF91BF91AF919F918F91D2 -:1006B0007F916F915F914F913F912F910F900FBE5E -:1006C0000F901F9018951F920F920FB60F92112442 -:1006D0002F933F934F935F936F937F938F939F934A -:1006E000AF93BF93EF93FF938FEB91E00E94F800DD -:1006F000FF91EF91BF91AF919F918F917F916F91FA -:100700005F914F913F912F910F900FBE0F901F90CF -:1007100018951F920F920FB60F9211242F938F935B -:100720009F93EF93FF93E091CF01F091D0018081EF -:10073000E091D501F091D60182FD12C090818091A7 -:10074000D8018F5F8F732091D901821751F0E0910A -:10075000D801F0E0E154FE4F958F8093D80101C09D -:100760008081FF91EF919F918F912F910F900FBEFC -:100770000F901F9018951F920F920FB60F92112491 -:100780002F933F938F939F93AF93BF9380915D017E -:1007900090915E01A0915F01B091600130913101B3 -:1007A00023E0230F2D3720F40196A11DB11D05C0B4 -:1007B00026E8230F0296A11DB11D209331018093DD -:1007C0005D0190935E01A0935F01B0936001809101 -:1007D000320190913301A0913401B091350101961D -:1007E000A11DB11D8093320190933301A093340178 -:1007F000B0933501BF91AF919F918F913F912F9110 -:100800000F900FBE0F901F9018951F920F920FB66A -:100810000F9211242F933F934F935F936F937F9386 -:100820008F939F93AF93BF93EF93FF93809130018A -:1008300087FF05C010928500109284001BC0209194 -:100840003001022E000C330B8091800290E02817BB -:10085000390784F480913001082E000C990BFC01BB -:10086000EE0FFF1F8E0F9F1FFC01E45AFD4F80818A -:1008700086FD15C0809130018F5F809330012091FB -:100880003001022E000C330B8091800290E028177B -:100890003907C4F4809130018C3064F113C0809129 -:1008A0003001082E000C990BFC01EE0FFF1F8E0F7C -:1008B0009F1FFC01E45AFD4F808160E08F730E940E -:1008C000B501D8CF80918400909185000496803442 -:1008D0009C4918F480E49CE905C0809184009091C3 -:1008E0008500049690938900809388008FEF809311 -:1008F00030013BC02091840030918500809130010F -:10090000082E000C990BFC01EE0FFF1F8E0F9F1F8E -:10091000FC01E45AFD4F81819281820F931F9093D5 -:1009200089008093880080913001082E000C990B7B -:10093000FC01EE0FFF1F8E0F9F1FFC01E45AFD4FBD -:10094000808186FF12C080913001082E000C990B27 -:10095000FC01EE0FFF1F8E0F9F1FFC01E45AFD4F9D -:10096000808161E08F730E94B501FF91EF91BF918B -:10097000AF919F918F917F916F915F914F913F9137 -:100980002F910F900FBE0F901F901895CF92DF926E -:10099000EF92FF920F931F93E82FF92F05C001509C -:1009A00011092109310961F1908196239417B9F356 -:1009B00005C0015011092109310911F190819623D7 -:1009C0009413F7CFC12CD12CE12CF12C0AC08FEF5E -:1009D000C81AD80AE80AF80A0C151D052E053F05A5 -:1009E00079F080818623841791F36C2D7D2D8E2DD7 -:1009F0009F2D1F910F91FF90EF90DF90CF90089562 -:100A000060E070E080E090E01F910F91FF90EF9028 -:100A1000DF90CF9008951092C2011092C10188EE2C -:100A200093E0A0E0B0E08093C3019093C401A09351 -:100A3000C501B093C6018DE191E09093C001809310 -:100A4000BF0185EC90E09093CC018093CB0184ECC6 -:100A500090E09093CE018093CD0180EC90E0909354 -:100A6000D0018093CF0181EC90E09093D2018093EC -:100A7000D10182EC90E09093D4018093D30186EC75 -:100A800090E09093D6018093D5011092D8011092F6 -:100A9000D9011092DA011092DB0180918002A1E865 -:100AA000B2E09FEF48EB5BE08C3078F48C93282F1A -:100AB00030E0F901EE0FFF1F2E0F3F1FF901E45A3E -:100AC000FD4F528341838F5F01C09C93139622E0B8 -:100AD000A939B20749F7809380020895CF93DF9335 -:100AE00000D01F92CDB7DEB7789484B5826084BD04 -:100AF00084B5816084BD85B5826085BD85B5816022 -:100B000085BD80916E00816080936E00109281009F -:100B1000809181008260809381008091810081605A -:100B2000809381008091800081608093800080911B -:100B3000B10084608093B1008091B00081608093A7 -:100B4000B00080917A00846080937A0080917A006E -:100B5000826080937A0080917A00816080937A002D -:100B600080917A00806880937A001092C100E091B1 -:100B7000CF01F091D00182E08083E091CF01F0912C -:100B8000D0011082E091CB01F091CC011082E09174 -:100B9000CD01F091CE0180E180831092D701E091E8 -:100BA000D301F091D40186E08083E091D101F091EE -:100BB000D201808180618083E091D101F091D201E6 -:100BC000808188608083E091D101F091D2018081A1 -:100BD00080688083E091D101F091D20180818F7D86 -:100BE000808310E061E0812F0E94100260E0812F7D -:100BF0000E94B5011F5F1E30A9F768EC70E080E02D -:100C000090E00E9471027CE7272E70E0372E8FEB78 -:100C100091E00E94E200892B09F40BC48FEB91E074 -:100C20000E94E2001816190694F78FEB91E00E94DB -:100C3000C00090919D01853561F491110AC08091A9 -:100C40009C018F3FE1F481E080939B0180939D01A3 -:100C500016C080939C01992391F0E0919B01E230B2 -:100C600019F480939A0107C0E33028F090919A011B -:100C7000915090939A01F0E0EA59FE4F8083809161 -:100C80009B018F5F843318F480939B0104C0109202 -:100C90009B0110929D0180919D01882309F4B7CF9B -:100CA00080919A018111B3CF80919B01843008F427 -:100CB000AECF10929D018091690180936501809172 -:100CC0006B01D0906C01ED2CF12C90916A01923067 -:100CD00009F485C0933009F4A7C3913009F0A6C385 -:100CE000873009F05BC08091A20110916D018111E4 -:100CF0001DC09093A201F0920401E0920301812FA4 -:100D000090E09093020180930101F701EE0FFF1F25 -:100D1000ED55FE4F21E030E031832083880F991F8D -:100D2000FC01ED55FE4F3183208329C0212F30E097 -:100D30008091030190910401E816F90641F4809135 -:100D40000101909102012817390709F46FC3F0924D -:100D50000401E09203013093020120930101F701A5 -:100D6000EE0FFF1FED55FE4F81E090E091838083F1 -:100D7000220F331FF901ED55FE4F9183808361E00F -:100D80008D2D0E94100260E0812F0E94100262E30C -:100D900070E080E090E00E94710248C3209103015E -:100DA00030910401C701880F991FE216F30639F04C -:100DB0002091010130910201E216F30651F41092E4 -:100DC000A20110929E0110929F011092A001109218 -:100DD000A101FC01ED55FE4F1182108227C3209125 -:100DE000030130910401E216F30639F0209101016C -:100DF00030910201E216F30651F41092A201109212 -:100E00009E0110929F011092A0011092A1018430C6 -:100E100009F471C228F4813029F1833049F104C307 -:100E2000853009F480C0883009F0FEC22FB7F894ED -:100E300060915D0170915E0180915F019091600110 -:100E40002FBF0E94150C20E030E04AE754E40E94D6 -:100E5000990B609361017093620180936301909399 -:100E60006401E2C2C7010E94AB0260916D0157C0EC -:100E7000C7010E94AB0210916D01A12EB12C61E05F -:100E80008D2D0E941002112309F446C01F3F09F462 -:100E900045C0F701E358FF4FE491E330F9F048F41F -:100EA000E130B9F0E230A1F584B5806284BD18BDAF -:100EB000BBC2E730E9F0E83019F1E43049F5809140 -:100EC0008000806280938000B0928B00A0928A00A4 -:100ED000ABC284B5806884BD17BDA6C28091800076 -:100EE000806880938000B0928900A09288009CC2A4 -:100EF0008091B00080688093B0001093B30094C2DA -:100F00008091B00080628093B0001093B4008CC2D6 -:100F100020E8A216B10414F460E001C061E08D2D58 -:100F20000E94B50181C2C7010E94AB0280916D0190 -:100F30008093360180916E01809337018091360154 -:100F4000909137019A83898380916F018093360154 -:100F50008091700180933701009136011091370123 -:100F6000101611060CF0C3C1809100018D1104C050 -:100F7000F101F491FB837DC08F3F09F055C2D092FF -:100F80000001F10184918F3F09F44EC2813021F1BB -:100F9000823009F447C081116BC014BC15BC84B504 -:100FA000826084BD85B5816085BDF701E556FF4F40 -:100FB000E491F0E0EE0FFF1FEE58FF4F8591949102 -:100FC0009093400180933F01F701E155FF4FE49179 -:100FD000E0933E011B8250C010928000109281006D -:100FE0008091810088608093810080918100816080 -:100FF00080938100F701E556FF4FE491F0E0EE0F9A -:10100000FF1FEE58FF4F8591949190933D0180937F -:101010003C01F701E155FF4FE491E0933B01F1E022 -:10102000FB832AC01092B0001092B1008091B000F2 -:1010300082608093B0008091B10081608093B100A4 -:10104000F701E556FF4FE491F0E0EE0FFF1FEE5879 -:10105000FF4F8591949190933A0180933901F70164 -:10106000E155FF4FE491E093380122E02B8304C067 -:101070008B838B8187FDD8C161E08D2D0E9410028A -:10108000E981FA814F01A12CB12C8B818D7F09F070 -:10109000B9C060E072E18AE790E0A50194010E9486 -:1010A000340D29013A0169017A01F1E0CF1AD10822 -:1010B000E108F1082FEFC216D104E104F10409F0B0 -:1010C00008F44DC060E472E48FE090E0A501940163 -:1010D0000E94340D69017A0181E0C81AD108E10843 -:1010E000F1089B81923001F5EFEFCE16D104E104B7 -:1010F000F10409F008F40EC360E970ED83E090E0BC -:10110000A50194010E94340D69017A01F1E0CF1A22 -:10111000D108E108F1082FEFC216D104E104F1046F -:1011200009F0D0F583E067C08FEFC816D104E10461 -:10113000F104B9F0B0F068E478EE81E090E0A50148 -:1011400094010E94340D69017A0191E0C91AD10815 -:10115000E108F108EB81EE2309F483C2D2C281E0F9 -:1011600001C082E02B81211146C011C0D301C20110 -:101170002AE0B595A795979587952A95D1F76C01A3 -:101180007D01E1E0CE1AD108E108F10885E095B5CE -:10119000987F892B85BD66C068E478EE81E090E099 -:1011A000A50194010E94340D69017A01F1E0CF1A82 -:1011B000D108E108F1082FEFC216D104E104F104CF -:1011C00009F008F44CC264E274EF80E090E0A501FD -:1011D00094010E94340D69017A01F1E0CF1AD1081F -:1011E000E108F1082FEFC216D104E104F10411F077 -:1011F00008F059C285E09091B100987F892B8093C7 -:10120000B10030C060E072E18AE790E0A50194018E -:101210000E94340D69017A0181E0C81AD108E10801 -:10122000F108C114D10491E0E906F10488F068E402 -:1012300078EE81E090E0A50194010E94340D6901EF -:101240007A01E1E0CE1AD108E108F10893E001C08B -:1012500091E0FB81F13031F480918100887F892B0E -:101260008093810029813A81220F331FD8010E9487 -:101270008C0B28EE33E040E050E00E94530D8B8150 -:10128000813099F0823019F18111CEC0C7BC209312 -:10129000490130934A0140934B0150934C01809196 -:1012A0006E00826080936E00BFC0D0928900C092B1 -:1012B00088002093450130934601409347015093A5 -:1012C000480180916F00826080936F00ADC0C09232 -:1012D000B300209341013093420140934301509366 -:1012E0004401809170008260809370009DC08D2DBC -:1012F0000E94E50199C0C7010E94AB0210916D01E7 -:10130000153B08F091C0EDE4F1E080E090E0219120 -:1013100031912E153F0581F0232B41F4FC01EE0F96 -:10132000FF1FE35BFE4FF182E08206C0019688302A -:10133000910569F780E090E0FC01EE0FFF1F8E0F32 -:101340009F1FFC01EF57FD4F00810C3008F06CC06F -:1013500061E08D2D0E941002E02EF12CC701880F54 -:10136000991FFC01EE0DFF1DE45AFD4F2D2D2F732B -:101370003081307CD32ED22AD08220E030E0F901B7 -:10138000EE0FFF1FE20FF31FE45AFD4F408146FDB1 -:1013900014C02F5F3F4F2C30310589F71092800029 -:1013A00022E0209381001092850010928400B19A6F -:1013B00020916F00226020936F008E0D9F1DFC0115 -:1013C000E45AFD4F808180648083A12FB0E0A53B6B -:1013D000B10514F0A4EBB0E020E437E00E948C0BE0 -:1013E00024EB30E040E050E00E94340DDA01C90106 -:1013F000805E9D4FAF4FBF4F9C01213699E039076A -:1014000014F020E639E022503109220F331F4FB784 -:10141000F894C701880F991F8E0D9F1D845A9D4F08 -:10142000FC01328321834FBF0E94C10210929B01B5 -:10143000EECB6FE070E080E090E00E94710263EA22 -:10144000862E61E0962E00E010E0F401C190D1906C -:101450004F01C114D10409F03AC0F02E60E0802F92 -:101460000E9410020E94FF02F801E358FF4F84918E -:10147000F801E155FF4FE490F801E556FF4FB490B5 -:10148000BB2099F081110E948C01EB2DF0E0EE0F52 -:10149000FF1FEF56FF4FA591B491EC91EE2291E022 -:1014A00080E009F490E0C92ED82EB601DD0C880B3F -:1014B000990B0E94170C0E94C9028F2D0E94BC023A -:1014C00081E00E94BC020E94B8000E94C1020F5F2E -:1014D0001F4F0E30110509F0B8CF49E0E42E41E06E -:1014E000F42E10E0F701819191917F01892B39F55C -:1014F0000E94FF02812F806480937C0080917A009B -:10150000806480937A0080917A0086FDFCCF6091A0 -:1015100078008091790070E0782B072E000C880B02 -:10152000990B0E94170C0E94C902812F0E94BC02D5 -:1015300082E00E94BC020E94B8000E94C1021F5FAC -:10154000183081F68091A201882309F47FC01091A0 -:10155000030160E0812F0E94B50183E090E00197D4 -:10156000F1F761E0812F0E94B50183E290E00197DD -:10157000F1F760E0812F0E94B50180910101909107 -:1015800002019927FC01E155FF4F6491FC01E556EA -:10159000FF4FE491F0E0EE0FFF1FEF56FF4F8591F4 -:1015A000949100E315E720E030E0462F0E94C60446 -:1015B000611571058105910549F0DC01CB010196AA -:1015C000A11DB11DBC01CD019F7003C060E070E0A2 -:1015D000CB010E94150C20E030E048EE51E40E945F -:1015E000990B20E030E040E05FE30E94760C6B0155 -:1015F0007C0120E030E0A9010E94100C811109C09B -:10160000C0909E01D0909F01E090A001F090A101B8 -:1016100008C0C0929E01D0929F01E092A001F0927A -:10162000A1010E94FF02C701B6010E94C902809178 -:1016300003010E94BC02809101010E94BC0287E06C -:101640000E94BC020E94B8000E94C1026AE070E0E1 -:1016500080E090E00E9471020E948201D4CA84E07E -:10166000CACDEFEFCE16D104E104F104D1F0C8F0F9 -:1016700062E17AE780E090E0A50194010E94340DD8 -:1016800069017A0181E0C81AD108E108F1089FEFE9 -:10169000C916D104E104F10411F008F067CD84E02B -:1016A00076CD83E074CD62E17AE780E090E0A50139 -:1016B00094010E94340D69017A01F1E0CF1AD1083A -:1016C000E108F1082FEFC216D104E104F104B9F0EA -:1016D000B0F0D301C2015AE0B595A79597958795CB -:1016E0005A95D1F76C017D01E1E0CE1AD108E108ED -:1016F000F108FB81FF2309F449CD87E07CCD86E02A -:1017000031CD8FEFC816D104E104F10409F058F689 -:1017100084E028CD82E06FCD0E94750DB7FF08955B -:10172000821B930B0895EE0FFF1F0590F491E02D9F -:1017300009940E94AD0B0C94FA0C0E94F30C58F023 -:101740000E94EC0C40F029F45F3F29F00C94E30C6C -:1017500051110C942E0D0C94E90C0E940B0D68F3A2 -:101760009923B1F3552391F3951B550BBB27AA275A -:1017700062177307840738F09F5F5F4F220F331F94 -:10178000441FAA1FA9F335D00E2E3AF0E0E832D05C -:1017900091505040E695001CCAF72BD0FE2F29D05F -:1017A000660F771F881FBB1F261737074807AB0731 -:1017B000B0E809F0BB0B802DBF01FF2793585F4FA6 -:1017C0003AF09E3F510578F00C94E30C0C942E0DEA -:1017D0005F3FE4F3983ED4F3869577956795B79588 -:1017E000F7959F5FC9F7880F911D9695879597F993 -:1017F0000895E1E0660F771F881FBB1F621773070C -:101800008407BA0720F0621B730B840BBA0BEE1F20 -:1018100088F7E095089581E090E0F8940C94840DA9 -:101820000E94520C08F481E00895E89409C097FBE7 -:101830003EF490958095709561957F4F8F4F9F4FA7 -:101840009923A9F0F92F96E9BB279395F6958795EB -:1018500077956795B795F111F8CFFAF4BB0F11F4AE -:1018600060FF1BC06F5F7F4F8F4F9F4F16C0882355 -:1018700011F096E911C0772321F09EE8872F762F8B -:1018800005C0662371F096E8862F70E060E02AF0CC -:101890009A95660F771F881FDAF7880F96958795B8 -:1018A00097F90895990F0008550FAA0BE0E8FEEF8D -:1018B00016161706E807F907C0F012161306E40714 -:1018C000F50798F0621B730B840B950B39F40A260D -:1018D00061F0232B242B252B21F408950A2609F4EB -:1018E000A140A6958FEF811D811D08950E94890C4E -:1018F0000C94FA0C0E94EC0C38F00E94F30C20F0CF -:10190000952311F00C94E30C0C94E90C11240C9425 -:101910002E0D0E940B0D70F3959FC1F3950F50E0B3 -:10192000551F629FF001729FBB27F00DB11D639F91 -:10193000AA27F00DB11DAA1F649F6627B00DA11D37 -:10194000661F829F2227B00DA11D621F739FB00DDD -:10195000A11D621F839FA00D611D221F749F33274D -:10196000A00D611D231F849F600D211D822F762FE6 -:101970006A2F11249F5750409AF0F1F088234AF0C3 -:10198000EE0FFF1FBB1F661F771F881F915050402F -:10199000A9F79E3F510580F00C94E30C0C942E0D9A -:1019A0005F3FE4F3983ED4F3869577956795B795B6 -:1019B000F795E7959F5FC1F7FE2B880F911D9695D0 -:1019C000879597F9089597F99F6780E870E060E040 -:1019D00008959FEF80EC089500240A9416161706C8 -:1019E00018060906089500240A9412161306140610 -:1019F00005060895092E0394000C11F4882352F073 -:101A0000BB0F40F4BF2B11F460FF04C06F5F7F4F2A -:101A10008F4F9F4F089557FD9058440F551F59F011 -:101A20005F3F71F04795880F97FB991F61F09F3FCB -:101A300079F087950895121613061406551FF2CFF4 -:101A40004695F1DF08C0161617061806991FF1CF44 -:101A500086957105610508940895E894BB2766276B -:101A60007727CB0197F90895052E97FB1EF4009474 -:101A70000E944B0D57FD07D00E94530D07FC03D069 -:101A80004EF40C944B0D50954095309521953F4F59 -:101A90004F4F5F4F089590958095709561957F4F5A -:101AA0008F4F9F4F0895A1E21A2EAA1BBB1BFD0169 -:101AB0000DC0AA1FBB1FEE1FFF1FA217B307E4072D -:101AC000F50720F0A21BB30BE40BF50B661F771F85 -:101AD000881F991F1A9469F7609570958095909565 -:101AE0009B01AC01BD01CF010895A29FB001B39F3E -:101AF000C001A39F700D811D1124911DB29F700D17 -:0C1B0000811D1124911D0895F894FFCF61 -:101B0C00FF0C000D000100000000000000000000B0 -:101B1C000000000000000000000000000019018D12 -:0C1B2C0000E200C000D40060010D0A00BF +:100090000001020408102040800102040810200121 +:1000A000020408102000000000250028002B000496 +:1000B000040404040404040202020202020303030F +:1000C00003030300E9063F1211241FBECFEFD8E05F +:1000D000DEBFCDBF11E0A0E0B1E0E4E3FBE202C08F +:1000E00005900D92AC36B107D9F722E0ACE6B1E04D +:1000F00001C01D92A63EB207E1F710E0C3E6D0E0D2 +:1001000004C02197FE010E945414C236D107C9F7DA +:100110000E94AE070C948D150C9400008F929F9254 +:10012000AF92BF92CF92DF92EF92FF92CF93209146 +:10013000B6023091B70282179307E8F54B01AA2463 +:10014000BB24C82DC52ED62EE72EFF24BC2DA42FF0 +:100150002091BC02222361F0829E40011124C92D0E +:100160002C9D60011124BD2D249FF0011124AF2F7F +:10017000E091C202E090BD02F090BE023091BF0259 +:10018000E31323C09C01220F331F820F931F8E0D98 +:100190009F1DE091BF02E80FF92FF11DC083E09190 +:1001A000C002E80FF92FF11DB0832091C102820F28 +:1001B000911DFC01A083CF91FF90EF90DF90CF9035 +:1001C000BF90AF909F908F900895880F991F880FD0 +:1001D000991F8E0D9F1D472F5527662777272223AE +:1001E00049F030E0249F7001259FF00C349FF00C03 +:1001F00011244F2DE80FF92FF11D4083CACF833012 +:1002000081F028F4813099F08230A9F00895873088 +:10021000A9F08830C9F08430B1F4809180008F7DDE +:1002200003C0809180008F7780938000089584B50B +:100230008F7784BD089584B58F7DFBCF8091B0000A +:100240008F778093B00008958091B0008F7DF9CFB3 +:100250001F93CF93DF93282F30E0F901E358FF4F2E +:100260008491F901EF56FF4FD491F901E155FF4F09 +:10027000C491CC23A9F0162F81110E94FF00EC2F0E +:10028000F0E0EE0FFF1FEB55FF4FA591B4918FB734 +:10029000F894EC91111108C0D095DE23DC938FBF48 +:1002A000DF91CF911F910895DE2BF8CFCF93DF938D +:1002B00090E0FC01EF56FF4F249181559F4FFC01C8 +:1002C00084918823D1F090E0880F991FFC01ED58AC +:1002D000FF4FA591B491FC01EB55FF4FC591D4910F +:1002E00061110EC09FB7F8948C91E22FE0958E2398 +:1002F0008C932881E223E8839FBFDF91CF910895FB +:100300008FB7F894EC91E22BEC938FBFF6CF8091EE +:10031000BA029091BB0297FD0CC061E00E945601A9 +:1003200060E08091BA020E94280181E08093B502CA +:1003300008951092B50280E008953FB7F894809137 +:10034000EE019091EF01A091F001B091F10126B57D +:10035000A89B05C02F3F19F00196A11DB11D3FBFFD +:10036000BA2FA92F982F8827BC01CD01620F711DCC +:10037000811D911D42E0660F771F881F991F4A95C6 +:10038000D1F708950F931F93CF93DF93CDB7DEB7C7 +:1003900029970FB6F894DEBF0FBECDBF8091BD0286 +:1003A0009091BE02892B09F47CC00E949D010091AE +:1003B000C3021091C4022091C5023091C602601799 +:1003C00071078207930740F46093C3027093C402DD +:1003D0008093C5029093C6020091C3021091C4029B +:1003E0002091C5023091C602601B710B820B930BEA +:1003F0006C32714081059105C0F2F8948091B80289 +:100400009091B9029A838983E091BD02F091BE0276 +:10041000DF011196808189879091B402E091C70233 +:10042000F091C8028091C902992309F445C09081D6 +:10043000982B98879081809589238F838F818C83D7 +:1004400088E08B8358856F8149853B812C81898128 +:100450009A81508347FD252F3A952083262F39F026 +:10046000441F00C000006083000000C0F2CF38E0ED +:100470004D9160830000019761F7F093C802E0930B +:10048000C70249873B832C839A83898378940E948F +:100490009D016093C3027093C4028093C502909340 +:1004A000C60229960FB6F894DEBF0FBECDBFDF910E +:1004B000CF911F910F9108959081982B98879081EB +:1004C000809589238F838F818E8388E08D835885E3 +:1004D0006F8149853D812E8189819A81508347FDB5 +:1004E000252F00C000C0208300C000C000C000C095 +:1004F00000C060830000262F3A9541F0441F0000A1 +:1005000000C000C000C000C000C0E8CF38E04D917E +:1005100000C0608300C0019709F7F093C802E09320 +:10052000C70249873D832E83AFCF8F929F92AF92B0 +:10053000BF92CF92DF92EF92FF924B015C010E943B +:100540009D016B017C010E949D016C197D098E0942 +:100550009F09683E734081059105A8F321E0821A46 +:100560009108A108B10888EEC80E83E0D81EE11CEE +:10057000F11C81149104A104B10429F7FF90EF90BC +:10058000DF90CF90BF90AF909F908F9008952FB73E +:10059000F8946091EA017091EB018091EC019091E7 +:1005A000ED012FBF08959091000189130BC0E8E67B +:1005B000F0E0E4919FEF90930001E13049F028F0E2 +:1005C000E23061F060E00C94280110926E00FACFE6 +:1005D00090916F009D7F90936F00F4CF9091700089 +:1005E0009D7F9093700091E09093B0009091B10046 +:1005F000987F94609093B1001092B300E3CFAF92D4 +:10060000BF92CF92DF92EF92FF920F931F93CF93FF +:10061000DF936C017B018B01040F151FEB015E0161 +:10062000AE18BF08C017D10759F06991D601ED91F6 +:10063000FC910190F081E02DC6010995892B79F795 +:10064000C501DF91CF911F910F91FF90EF90DF9047 +:10065000CF90BF90AF90089542E050E068E671E01F +:1006600082EF91E00C94FF02FC01538D448D252F05 +:1006700030E0842F90E0821B930B541710F0CF963C +:10068000089501970895FC01918D828D981761F06E +:10069000A28DAE0FBF2FB11D5D968C91928D9F5F85 +:1006A0009F73928F90E008958FEF9FEF0895FC0164 +:1006B000918D828D981731F0828DE80FF11D858D17 +:1006C00090E008958FEF9FEF0895FC01918D228DAA +:1006D000892F90E0805C9F4F821B91098F7399272F +:1006E000089582EF91E00E94650321E0892B09F4CF +:1006F00020E0822F089580E090E0892B29F00E946D +:10070000710381110C9400000895FC01A48DA80FC1 +:10071000B92FB11DA35ABF4F2C91848D90E0019643 +:100720008F739927848FA689B7892C93A089B18963 +:100730008C91837080648C93938D848D981306C004 +:100740000288F389E02D80818F7D80830895EF9268 +:10075000FF920F931F93CF93DF93EC0181E0888F7B +:100760009B8D8C8D98131AC0E889F989808185FF4B +:1007700015C09FB7F894EE89FF896083E889F989ED +:1007800080818370806480839FBF81E090E0DF91EF +:10079000CF911F910F91FF90EF900895F62E0B8D42 +:1007A00010E00F5F1F4F0F731127E02E8C8D8E11FD +:1007B0000CC00FB607FCFACFE889F989808185FF64 +:1007C000F5CFCE010E948503F1CFEB8DEC0FFD2F0D +:1007D000F11DE35AFF4FF0829FB7F8940B8FEA891F +:1007E000FB8980818062CFCFCF93DF93EC01888D2E +:1007F0008823B9F0AA89BB89E889F9898C9185FD9C +:1008000003C0808186FD0DC00FB607FCF7CF8C9129 +:1008100085FFF2CF808185FFEDCFCE010E94850359 +:10082000E9CFDF91CF910895FC01EE0FFF1FEC5D42 +:10083000FE4F20813181232B39F421E030E03183D8 +:10084000208361E00C9456010895682F82EF91E0B7 +:100850000C94A7038FEF0E94250485E50E942504D0 +:100860000C942C030F931F93CF93DF938B01D82FFE +:10087000C92F82E00E942504C801AD2FBC2F8093B0 +:100880006C0190936D01A0936E01B0936F010E9473 +:100890002504812F0E9425048D2F0E9425048C2F72 +:1008A000DF91CF911F910F910C9425048FEF0E943F +:1008B000250485E50C942504BF92CF92DF92EF9238 +:1008C000FF920F931F93CF93DF93EC01C12CD12C98 +:1008D0007601662361F08981CA80D12CF12CE12C4C +:1008E000FE2CED2CDC2CCC24E82A8B81C82ABD847C +:1008F0008E858B15A0F00B2D10E0B701A601C80165 +:100900000E948E00000F111F000F111FF801EC56FE +:10091000FE4FC082D182E282F382B394E9CFDF91AD +:10092000CF911F910F91FF90EF90DF90CF90BF90EC +:100930000C94C201FC011082148260E00C945C04EF +:10094000AF92BF92CF92DF92EF92FF920F931F93DD +:10095000CF93DF93EC01C701D80182339105A10544 +:10096000B10520F482E390E0A0E0B0E03881698333 +:100970004A832B838D839E83AF83B887332371F0A3 +:100980006C81CE01DF91CF911F910F91FF90EF907D +:10099000DF90CF90BF90AF900C945C04A114B10491 +:1009A000C104D10421F40E94C7025B016C01A98635 +:1009B000BA86CB86DC8681E088838C8361E0E1CFD8 +:1009C000E4EBF2E04481558170E060E0818592853E +:1009D0000C9486151F920F920FB60F9211242F932D +:1009E0003F938F939F93AF93BF938091EA01909130 +:1009F000EB01A091EC01B091ED013091E90123E010 +:100A0000230F2D3758F50196A11DB11D2093E90143 +:100A10008093EA019093EB01A093EC01B093ED0178 +:100A20008091EE019091EF01A091F001B091F10160 +:100A30000196A11DB11D8093EE019093EF01A0934B +:100A4000F001B093F101BF91AF919F918F913F91D0 +:100A50002F910F900FBE0F901F90189526E8230F2F +:100A60000296A11DB11DD2CF1F920F920FB60F9209 +:100A700011242F933F934F935F936F937F938F93A3 +:100A80009F93AF93BF93EF93FF93809176019091E3 +:100A90007701A0917801B0917901892B8A2B8B2B5A +:100AA000D1F190917101E0917201F0917301808117 +:100AB000892780838091760190917701A0917801B8 +:100AC000B0917901181619061A061B069CF480913C +:100AD000760190917701A0917801B0917901019709 +:100AE000A109B1098093760190937701A0937801D1 +:100AF000B0937901FF91EF91BF91AF919F918F9149 +:100B00007F916F915F914F913F912F910F900FBE09 +:100B10000F901F901895809100010E94D302EACF98 +:100B20001F920F920FB60F9211242F933F934F9362 +:100B30005F936F937F938F939F93AF93BF93EF9345 +:100B4000FF9382EF91E00E948503FF91EF91BF91A7 +:100B5000AF919F918F917F916F915F914F913F9155 +:100B60002F910F900FBE0F901F9018951F920F920C +:100B70000FB60F9211242F938F939F93EF93FF93B0 +:100B8000E0910202F09103028081E0910802F0916D +:100B9000090282FD1BC0908180910B028F5F8F73D1 +:100BA00020910C02821741F0E0910B02F0E0EE5030 +:100BB000FE4F958F80930B02FF91EF919F918F9144 +:100BC0002F910F900FBE0F901F9018958081F4CF3A +:100BD0001F920F920FB60F9211242F933F934F93B2 +:100BE0005F936F937F938F939F93AF93BF93CF93B5 +:100BF000DF93EF93FF9380917001C091B302D0E037 +:100C000087FF24C0109285001092840080917001AB +:100C10008F5F8093700180917001082E000C990BFA +:100C20008C179D0724F4809170018C30C4F1809161 +:100C3000840090918500049680349C4908F47AC021 +:100C40008091840090918500049676C08091700117 +:100C5000082E000C990B8C179D07C4F6E0917001CB +:100C60008E2FEE0F990BFC01EE0FFF1FE80FF91FFF +:100C7000E157FD4F808186FFC9CFE09170018E2F33 +:100C8000EE0F990BFC01EE0FFF1FE80FF91FE15764 +:100C9000FD4F808160E08F730E942801B7CF2091C3 +:100CA000840030918500E09170018E2FEE0F990B3A +:100CB000FC01EE0FFF1FE80FF91FE157FD4F818187 +:100CC0009281820F931F9093890080938800E09116 +:100CD00070018E2FEE0F990BFC01EE0FFF1FE80F36 +:100CE000F91FE157FD4F808186FF11C0E09170012F +:100CF0008E2FEE0F990BFC01EE0FFF1FE80FF91F6F +:100D0000E157FD4F808161E08F730E942801FF91C0 +:100D1000EF91DF91CF91BF91AF919F918F917F9193 +:100D20006F915F914F913F912F910F900FBE0F9058 +:100D30001F90189580E49CE9909389008093880027 +:100D40008FEF80937001E3CFCF92DF92EF92FF920B +:100D50000F931F93E82FF92F05C0015011092109A6 +:100D6000310961F1908196239417B9F305C00150C0 +:100D700011092109310911F1908196239413F7CFBC +:100D8000C12CD12CE12CF12C0AC08FEFC81AD80A43 +:100D9000E80AF80A0C151D052E053F0579F080813B +:100DA0008623841791F36C2D7D2D8E2D9F2D1F9101 +:100DB0000F91FF90EF90DF90CF90089560E070E08A +:100DC00080E090E01F910F91FF90EF90DF90CF9027 +:100DD00008951092F5011092F40188EE93E0A0E0DE +:100DE000B0E08093F6019093F701A093F801B093DF +:100DF000F9018AE591E09093F3018093F20185EC8B +:100E000090E09093FF018093FE0184EC90E090933A +:100E100001028093000280EC90E0909303028093A3 +:100E2000020281EC90E0909305028093040282EC30 +:100E300090E0909307028093060286EC90E09093F6 +:100E400009028093080210920B0210920C02109279 +:100E50000D0210920E02EAECF2E022EE32E04FEFC9 +:100E600068EB7BE08091B3028C3008F06CC091E0BD +:100E7000980F9093B302808390E0DC01AA0FBB1F10 +:100E8000A80FB91FA157BD4F12967C936E9311976F +:100E900033962E173F0731F71092B5021092BC021D +:100EA0001092C3021092C4021092C5021092C602A0 +:100EB00081E08093C2028093BF021092C00292E050 +:100EC0009093C1028093B4028CE090E09093B902B9 +:100ED0008093B8020E9461149093BE028093BD0279 +:100EE000009799F12CE0FC0111922A95E9F784E032 +:100EF00090E09093B7028093B60289E090E09093DF +:100F0000BB028093BA028091B502882341F061E070 +:100F100089E00E94560160E089E00E942801E8EB28 +:100F2000F0E0E491F0E0EE0FFF1FEB55FF4F8591ED +:100F300094919093C8028093C702EAE9F0E0E491AB +:100F4000E093C90208954083A3CF1092B902109292 +:100F5000B8021092B7021092B602CFCFCF93DF93B0 +:100F6000CDB7DEB7A6970FB6F894DEBF0FBECDBFE4 +:100F7000789484B5826084BD84B5816084BD85B574 +:100F8000826085BD85B5816085BD80916E00816080 +:100F900080936E0010928100809181008260809326 +:100FA0008100809181008160809381008091800028 +:100FB0008160809380008091B10084608093B10053 +:100FC0008091B00081608093B00080917A0084604D +:100FD00080937A0080917A00826080937A00809179 +:100FE0007A00816080937A0080917A008068809393 +:100FF0007A001092C100E0910202F091030282E0B7 +:101000008083E0910202F09103021082E091FE01E0 +:10101000F091FF011082E0910002F091010280E165 +:10102000808310920A02E0910602F091070286E0A6 +:101030008083E0910402F0910502808180618083C9 +:10104000E0910402F0910502808188608083E09144 +:101050000402F0910502808180688083E09104029F +:10106000F091050280818F7D808310E061E0812F07 +:101070000E94560160E0812F0E9428011F5F1E30F0 +:10108000A9F781E191E00E949A0482E091E00E9438 +:101090009A040E9487010E94E0040E94C20168EC49 +:1010A00070E080E090E00E94950209EC10E01C8F57 +:1010B0000B8F82EF91E00E946503892B11F40C9451 +:1010C0008C102B8D3C8D215031093C8F2B8F232B85 +:1010D00011F40C948C1082EF91E00E9443039091E4 +:1010E000DB01853509F067C0911165C08091DA0197 +:1010F0008F3F29F481E08093D9018093DB018091B7 +:10110000D9018F5F843308F06EC08093D90180913C +:10111000DB01882371F28091D8018111CACF8091BF +:10112000D901843030F21092DB01E091A9010091E5 +:10113000AA01E02EF12C2091A801223009F492C0DE +:10114000233011F40C948110213009F061C0E73094 +:1011500009F061C01091AB01812F90E03091E00166 +:10116000311146C02093E001F0922301E092220168 +:101170009093210180932001F701EE0FFF1FEC5D9A +:10118000FE4F21E030E031832083FC01EE0FFF1F92 +:10119000EC5DFE4F3183208361E0802F0E94560179 +:1011A00060E0812F0E94560162E370E080E090E0F1 +:1011B0000E9495022DC08093DA01992309F49FCFF4 +:1011C000E091D901E23039F48093D801F0E0EC5598 +:1011D000FE4F808394CFE330C8F39091D8019150B3 +:1011E0009093D801F3CF1092D9011092DB018FCFE9 +:1011F0002091220130912301E216F30609F0B4CFC9 +:1012000020912001309121018217930709F0ACCF82 +:101210001092D9014ECF2091220130912301C701B4 +:10122000880F991FE216F30639F0209120013091C2 +:101230002101E216F30681F41092E0011092DC0124 +:101240001092DD011092DE011092DF018C5D9E4F45 +:10125000DC011D921C92DCCF8C5D9E4FFC01118243 +:101260001082D6CF8091220190912301E816F906D1 +:1012700039F08091200190912101E816F90651F48E +:101280001092E0011092DC011092DD011092DE015B +:101290001092DF01E150EF3008F054C00E2E000C28 +:1012A000FF0BEB5AF64F0C9454146409A2096D0914 +:1012B000ED0BC609A209A209AF0CB20C4D0D040E2C +:1012C000590E0D10EA0C3D0DC7010E9414046091E7 +:1012D000AB01802F0E94280135C0C7010E94140471 +:1012E0001091AB0161E0802F0E945601111102C0E4 +:1012F00060E0EFCF1F3F11F461E0EBCFF701E3585F +:10130000FF4FE491E33031F138F4E130B9F0E230ED +:10131000E1F017FDF1CFECCFE73041F1E83071F1AA +:10132000E430B9F780918000806280938000812F43 +:1013300090E090938B0080938A0004C084B580680D +:1013400084BD17BD0E942A0463CF84B5806284BD2A +:1013500018BDF8CF80918000806880938000812F35 +:1013600090E09093890080938800ECCF8091B0004A +:1013700080688093B0001093B300E4CF8091B000F8 +:1013800080628093B0001093B400DCCFC7010E944C +:1013900014048091AB01809392018091AC01809301 +:1013A000930120919201309193013A8B298B809186 +:1013B000AD01809392018091AE01809393012090C2 +:1013C000920130909301121413040CF002C2809128 +:1013D00000018013BAC0E8E6F0E0149117FDB2CF27 +:1013E00061E0802F0E945601112319F0123009F09C +:1013F00099C149895A892A01712C612C60E072E1F6 +:101400008AE790E0A30192010E94731349015A01F7 +:101410007A01690151E0C51AD108E108F1088FEF9E +:10142000C816D104E104F10409F00CF44EC160E4E3 +:1014300072E48FE090E0A30192010E9473136901AE +:101440007A0191E0C91AD108E108F108123009F0D7 +:10145000F3C082E0AFEFCA16D104E104F10409F051 +:101460000CF46CC060E970ED83E090E0A3019201A0 +:101470000E94731369017A01B1E0CB1AD108E10827 +:10148000F10883E0EFEFCE16D104E104F10409F096 +:101490000CF454C068E478EE81E090E0A30192017E +:1014A0000E94731369017A0181E0C81AD108E1082A +:1014B000F10884E09FEFC916D104E104F104F1F1D1 +:1014C000ECF164E274EF80E090E0A30192010E94ED +:1014D000731369017A0181E0C81AD108E108F108A3 +:1014E00085E02FEFC216D104E104F10439F130F1A7 +:1014F00062E17AE780E090E0A30192010E94731319 +:1015000069017A01A1E0CA1AD108E108F10886E070 +:10151000BFEFCB16D104E104F10481F078F075013E +:1015200064012AE0F594E794D794C7942A95D1F7FB +:10153000F1E0CF1AD108E108F10887E09091B100FD +:10154000987F892B8093B100C7C08F3F09F0FACEF6 +:1015500000930001E8E6F0E014911F3F09F4F2CE99 +:10156000113031F150F0123009F442C017FDEACECB +:1015700061E0802F0E94560139CF14BC15BC84B5A0 +:10158000826084BD85B5816085BDF701E155FF4F5F +:10159000E491F0E0EE0FFF1FEB55FF4F8591949122 +:1015A000F701EF56FF4FE491E093750110E018CF7B +:1015B0001092800010928100809181008860809359 +:1015C000810080918100816080938100F701E15565 +:1015D000FF4FE491F0E0EE0FFF1FEB55FF4F8591B9 +:1015E0009491F701EF56FF4FE491E0937401F8CE28 +:1015F0001092B0001092B1008091B0008260809390 +:10160000B0008091B10081608093B100F701E15595 +:10161000FF4FE491F0E0EE0FFF1FEB55FF4F859178 +:1016200094919093730180937201F701EF56FF4FED +:10163000E491E0937101D4CEFFEFCF16D104E10421 +:10164000F10409F00CF46CC068E478EE81E090E0FD +:10165000A30192010E94731369017A0101E0C01A8B +:10166000D108E108F10884E011113BCF83E00FEFCE +:10167000C016D104E104F10459F154F162E17AE7B2 +:1016800080E090E0A30192010E94731369017A0146 +:10169000E1E0CE1AD108E108F10884E0FFEFCF16AF +:1016A000D104E104F104A1F098F0750164019AE01D +:1016B000F594E794D794C7949A95D1F701E0C01AAE +:1016C000D108E108F10885E003C081E0111136CFAF +:1016D00095B5987F892B85BD29893A89220F331FBB +:1016E000D1010E945A1428EE33E040E050E00E94FD +:1016F0009D13113009F44BC0123009F45AC0111176 +:1017000021CEC7BC20937E0130937F01409380019E +:101710005093810180916E00826080936E0012CEA2 +:1017200082E0D4CFA989BA892D01712C612C60E0A7 +:1017300072E18AE790E0A3019D010E9473136901A1 +:101740007A01B1E0CB1AD108E108F10891E0C114A7 +:10175000D104E1E0EE06F10484F068E478EE81E083 +:1017600090E0A30192010E94731369017A01F1E0F4 +:10177000CF1AD108E108F10893E0113009F0ACCF9D +:1017800080918100887F892B80938100A5CFD092A2 +:101790008900C092880020937A0130937B014093A6 +:1017A0007C0150937D0180916F00826080936F0077 +:1017B000C9CDC092B3002093760130937701409356 +:1017C000780150937901809170008260809370005D +:1017D000B9CD802F0E94D302B5CDC7010E94140459 +:1017E000B090AB0114EB1B1508F4ACCDE2E8F1E0CE +:1017F00090E080E021913191E216F30651F0232B25 +:1018000009F066C0FC01EE0FFF1FEE57FE4FF1829C +:10181000E082FC01EE0FFF1FE80FF91FE653FD4FBA +:10182000F0802BE02F1508F05BC0818192813BE0B6 +:101830003F1508F487CDE8E5CE2EE2E0DE2EC91A8A +:10184000D10897FDD394CC0CDD1CCC0CDD1C08E832 +:1018500010E0081B110987FD1395000F111F000FE1 +:10186000111F2801012E000C6608770896010D2C27 +:10187000000C440B550B2419350946095709AB2DAB +:10188000B0E00E94921324EB30E040E050E00E9470 +:101890007313420E531E641E751E401651062CF023 +:1018A00086014C145D040CF4820102501109000FF2 +:1018B000111F2FB7F8948F2D90E0FC01EE0FFF1F42 +:1018C000E80FF91FE157FD4F128301832FBF3ACD77 +:1018D00001968830910509F08DCF90E080E099CF96 +:1018E00061E0802F0E9456018F2D90E0AC01440FE3 +:1018F000551FFA01E80FF91FE157FD4F202F2F73F5 +:101900000081007C022B008330E020E0F901EE0F23 +:10191000FF1FE20FF31FE157FD4F608166FD14C00A +:101920002F5F3F4F2C30310589F71092800022E065 +:10193000209381001092850010928400B19A20912A +:101940006F00226020936F00840F951FFC01E15708 +:10195000FD4F80818064808390E080E068CF0E94AA +:10196000C702F0CC89E090E00E941404809101014C +:10197000811129C00E9487010E94E0040E94C201D7 +:101980001092940110929501109296011092970175 +:10199000109298011092990110929A0110929B0155 +:1019A00010929C0110929D0110929E0110929F0135 +:1019B0001092A0011092A1011092A2011092A30115 +:1019C00081E08093010181E191E00E949A0482E02C +:1019D00091E060C089E090E00E9414048091AB0126 +:1019E0003090AD018090AE019090AF019091B00128 +:1019F000909392019091B101909393014090920144 +:101A000050909301052C000C6608770842E34416B9 +:101A100051046104710428F452E3452E512C612CC9 +:101A2000712C8230D9F40E94C702698B7A8B8B8B20 +:101A30009C8B5B016C0183017201292D482D632D64 +:101A400081E191E00E94A004A988BA88CB88DC8853 +:101A5000292D482D632D82E091E00CC0A12CB12CE2 +:101A6000650183017201292D482D632D8111F3CF6A +:101A700081E191E00E94A00465CC89E090E00E94A1 +:101A800014048091AB01823009F49DCF81119FCF66 +:101A900081E191E00E949A0455CC89E090E00E9497 +:101AA00014042091AB01E090AD014090AE01842D73 +:101AB00090E0B0E0A0E04090AC012E3F09F044C0BF +:101AC000042D10E02E2D243008F023E0E22EF12C1E +:101AD00068012091AF01DC01992788272C013D0185 +:101AE000522A8091B001482AA090B602B090B70265 +:101AF0000A151B05B8F4C701801B910B019631F044 +:101B0000800F911F8A159B0508F45C01CA14DB0441 +:101B100048F4B301A201C6010E948E005FEFC51A0E +:101B2000D50AF4CFF801EE0FFF1FEE0FFF1FEC56A2 +:101B3000FE4FE016F1060CF451C0419251926192B1 +:101B400071920F5F1F4FF5CFC22ED12C512C712CEB +:101B5000612C3201552444245E28482A592A6A2AD5 +:101B60007B2A8FEFC816D104F1F50091B6021091CF +:101B7000B7020115110591F00430110510F004E0D1 +:101B800010E0F12CE12CB301A201C7010E948E00EC +:101B90009FEFE91AF90A0E151F05A9F74092940163 +:101BA000509295016092960170929701409298012F +:101BB0005092990160929A0170929B0140929C010F +:101BC00050929D0160929E0170929F014092A001EF +:101BD0005092A1016092A2017092A3010E94C201E1 +:101BE00010920101AFCBB301A201C6010E948E0089 +:101BF000F601EE0FFF1FEE0FFF1FEC56FE4F408267 +:101C0000518262827382EACF89E090E00E941404DC +:101C10008091AB01809392018091AC0180939301FC +:101C200080919201909193018F3F910519F014F0EA +:101C30008FEF90E097FD80E011E0180F2091BC023B +:101C40001217A1F1E090BD02F090BE02215070E0A9 +:101C500060E061F08F3FF1F430E050E040E06FEF82 +:101C60007FEF80E090E00E947313B901F70140918B +:101C7000B8025091B902CF018E199F0984179507B8 +:101C800098F44081469FC001479F900D1124908396 +:101C90003196EDCF812F90E0982F88270197622F02 +:101CA00070E00E944014E2CF1093BC020E94C20177 +:101CB00049CB89E090E00E9414040091AB010AA393 +:101CC0001091AD011F8F1091AC01153008F014E098 +:101CD0002091B6023091B7023CA32BA30091C2021F +:101CE00008A30091BF0209A36090BD027090BE02DC +:101CF0000091BC0238A1232F30E03EA32DA359A1AF +:101D0000452F50E05E8B4D8B8091C002A82FB0E034 +:101D1000B88FAF8B8091C102E82FF0E0FA8FE98F86 +:101D2000202F30E050E040E0298B3A8B4B8B5C8BCE +:101D3000AE014F5F5F4F5A015E8F4D8F512C412C8A +:101D4000312C212C8BA19CA1C12CD12C76012816E1 +:101D5000390608F071C098A1A9A19A13A8C0410141 +:101D6000880C991C820C931CED89FE89E80DF91DE5 +:101D7000E60DF71D002309F447C0608170E0762F5F +:101D80006627072E000C880B990B29893A894B8905 +:101D90005C890E949D137901DD24CC24EF89F88DA4 +:101DA000E80DF91DE60DF71D608170E0762F6627BE +:101DB000072E000C880B990B29893A894B895C897D +:101DC0000E949D13542F432F322F2227C22AD32A39 +:101DD000E42AF52AE98DFA8D8E0E9F1EF301E80D97 +:101DE000F91D608170E0762F6627072E000C880BA6 +:101DF000990B29893A894B895C890E949D13C22AD3 +:101E0000D32AE42AF52A18C08081EF89F88DE80DDD +:101E1000F91DE60DF71DC080D12CF12CE12CFE2C14 +:101E2000ED2CDC2CCC24E82AE98DFA8DE80DF91D87 +:101E3000E60DF71D8081C82AAD8DBE8DCD92DD9255 +:101E4000ED92FD92BE8FAD8FBFEF2B1A3B0AE4E0FF +:101E50004E0E511CF4E02F16310409F073CF0E948E +:101E6000E004C12ED12C0AA110E010160CF0B3C072 +:101E700000E084E0E82EF12CEC18FD082F8D2130D5 +:101E800009F09EC0D5014D915D916D917C91C70186 +:101E9000800F911F837099270E948E000F5F1F4F44 +:101EA000F4E0AF0EB11C0430110541F797CE8DA1BF +:101EB0009EA1840D951D860D971D002309F45FC01A +:101EC000DC016C9170E0762F6627072E000C880BE2 +:101ED000990B29893A894B895C890E949D13F22EBE +:101EE000EE24DD24CC24ED89FE89E40DF51DE60DFC +:101EF000F71D608170E0762F6627072E000C880B97 +:101F0000990B29893A894B895C890E949D13A90103 +:101F100033272227C22AD32AE42AF52AE98DFA8D0B +:101F2000E40DF51DE60DF71D608170E0762F662744 +:101F3000072E000C880B990B29893A894B895C89FB +:101F40000E949D13C22AD32AE42AF52AEF89F88D2C +:101F5000E40DF51DE60DF71D608170E0762F662714 +:101F6000072E000C880B990B29893A894B895C89CB +:101F70000E949D13542F432F322F222740CFFC0164 +:101F80008081ED89FE89E40DF51DE60DF71DC08009 +:101F9000D12CF12CE12C7601DD24CC24F82AE98D1A +:101FA000FA8DE40DF51DE60DF71D8081C82AEF8935 +:101FB000F88DE40DF51DE60DF71D8081D82A3CCF84 +:101FC000C8018C199D0997FD69CFF50140815181A8 +:101FD0006281738161CF00E0C601800F911F2F8D58 +:101FE000213091F4D5014D915D916D917C9183707B +:101FF00099270E948E000F5F1F4FF4E0AF0EB11CB7 +:102000000430110549F7EACD84309105A0F7F501B8 +:102010004081518162817381ECCF89E090E00E9420 +:1020200014042091AB018091AC01853008F08370DD +:1020300090E012160CF044C004E010E0081B190BED +:10204000C801A4E9B1E024EA31E04D915D916D91C0 +:102050007D91FC01E370FF27EE0FFF1FEE0FFF1FC6 +:1020600001E010E00C0F1D1FE00FF11F40835183B2 +:102070006283738301962A173B0739F70E94E004B5 +:102080008E010F5F1F4F74E9E72E71E0F72ED12C00 +:10209000C12CD8014D915D916D917D918D01F7011C +:1020A00041935193619371937F01C6010E948E0009 +:1020B000FFEFCF1ADF0A24E0C216D10451F78ECD0C +:1020C000A4E9B1E030E020E04D915D916D917D910A +:1020D000FC01E20FF31FE370FF27EE0FFF1FEE0F6F +:1020E000FF1F01E010E00C0F1D1FE00FF11F4083E8 +:1020F0005183628373832F5F3F4F2430310521F773 +:10210000BDCF81E191E00E949A0482E091E00E94BB +:102110009A040E94E004CACD0E94C7026B017C01B0 +:102120008091E5019091E601A091E701B091E8016D +:1021300097018601081B190B2A0B3B0BD901C8011B +:102140000A97A105B10508F46EC0C092E501D092CE +:10215000E601E092E701F092E8010E94C7024B011C +:102160005C0180911101882369F180911A0190919D +:102170001B01A0911C01B0911D01B501A401481BD8 +:10218000590B6A0B7B0B8091160190911701A0915E +:102190001801B0911901481759076A077B0790F099 +:1021A00080921A0190921B01A0921C01B0921D0115 +:1021B0006091150181E068276093150181E191E04C +:1021C0000E945C0480910201882369F180910B01D7 +:1021D00090910C01A0910D01B0910E01B501A401E7 +:1021E000481B590B6A0B7B0B8091070190910801EA +:1021F000A0910901B0910A01481759076A077B07A6 +:1022000090F080920B0190920C01A0920D01B0927F +:102210000E016091060181E068276093060182E06B +:1022200091E00E945C048091E1019091E201A09113 +:10223000E301B091E401A7019601281B390B4A0B79 +:102240005B0BDA01C90184369105A105B10508F4DB +:10225000FDC0C092E101D092E201E092E301F09270 +:10226000E40164E2E62E61E0F62E10E000E0D70122 +:10227000CD90DD907D01C114D10409F03AC0902EBB +:1022800060E0802F0E9456010E945604F801E35836 +:10229000FF4F8491F801EF56FF4FA490F801E155EC +:1022A000FF4FB490BB2099F081110E94FF00EB2DED +:1022B000F0E0EE0FFF1FE759FF4FA591B491EC91AD +:1022C000AE2291E080E009F490E0C92ED82EB6014C +:1022D000DD0C880B990B0E9456120E943204892D46 +:1022E0000E94250481E00E9425040E942C030E9484 +:1022F0002A040F5F1F4F0E30110509F0B8CF46E4D6 +:10230000E42E41E0F42E10E0F701819191917F01DC +:10231000892B29F50E945604812F806480937C00CC +:1023200080917A00806480937A0080917A0086FDA3 +:10233000FCCF6091780070917900072E000C880B1B +:10234000990B0E9456120E943204812F0E9425048C +:1023500082E00E9425040E942C030E942A041F5F31 +:10236000183091F68091E001882309F46FC0109134 +:10237000220160E0812F0E94280183E090E0019714 +:10238000F1F761E0812F0E94280183E290E001973C +:10239000F1F760E0812F0E94280180912001909147 +:1023A00021019927FC01EF56FF4F6491FC01E15593 +:1023B000FF4FE491F0E0EE0FFF1FE759FF4F8591CB +:1023C000949100E315E720E030E0462F0E94A40638 +:1023D000611571058105910529F06F5F7F4F8F4F62 +:1023E0009F4F9F700E94541220E030E048EE51E46D +:1023F0000E94CE1320E030E040E05FE30E94B5127F +:102400006B017C0120E030E0A9010E944F12811194 +:102410002DC0C090DC01D090DD01E090DE01F09095 +:10242000DF010E945604C701B6010E943204809168 +:1024300022010E942504809120010E94250487E04A +:102440000E9425040E942C030E942A0480E090E050 +:10245000892B11F40C9455080E947103882311F400 +:102460000C9455080E9400000C945508C092DC01A1 +:10247000D092DD01E092DE01F092DF01D2CF8091B7 +:10248000BD029091BE020E94FD148091BA0290910B +:10249000BB0297FD03C060E00C94560108950E94B2 +:1024A000911208F481E00895E89409C097FB3EF486 +:1024B00090958095709561957F4F8F4F9F4F992391 +:1024C000A9F0F92F96E9BB279395F695879577950F +:1024D0006795B795F111F8CFFAF4BB0F11F460FFCF +:1024E0001BC06F5F7F4F8F4F9F4F16C0882311F027 +:1024F00096E911C0772321F09EE8872F762F05C03B +:10250000662371F096E8862F70E060E02AF09A95D5 +:10251000660F771F881FDAF7880F9695879597F9CA +:102520000895990F0008550FAA0BE0E8FEEF161664 +:102530001706E807F907C0F012161306E407F507B7 +:1025400098F0621B730B840B950B39F40A2661F02B +:10255000232B242B252B21F408950A2609F4A140CE +:10256000A6958FEF811D811D08950E94C8120C94BD +:1025700039130E942B1338F00E94321320F0952358 +:1025800011F00C9422130C94281311240C946D1345 +:102590000E944A1370F3959FC1F3950F50E0551FA9 +:1025A000629FF001729FBB27F00DB11D639FAA27A8 +:1025B000F00DB11DAA1F649F6627B00DA11D661FF7 +:1025C000829F2227B00DA11D621F739FB00DA11D18 +:1025D000621F839FA00D611D221F749F3327A00DD2 +:1025E000611D231F849F600D211D822F762F6A2F6E +:1025F00011249F5750409AF0F1F088234AF0EE0FD3 +:10260000FF1FBB1F661F771F881F91505040A9F7FF +:102610009E3F510580F00C9422130C946D135F3F84 +:10262000E4F3983ED4F3869577956795B795F7953B +:10263000E7959F5FC1F7FE2B880F911D96958795B3 +:1026400097F9089597F99F6780E870E060E0089532 +:102650009FEF80EC089500240A94161617061806BA +:102660000906089500240A94121613061406050696 +:102670000895092E0394000C11F4882352F0BB0F27 +:1026800040F4BF2B11F460FF04C06F5F7F4F8F4F8A +:102690009F4F089557FD9058440F551F59F05F3FC5 +:1026A00071F04795880F97FB991F61F09F3F79F074 +:1026B00087950895121613061406551FF2CF4695F6 +:1026C000F1DF08C0161617061806991FF1CF869578 +:1026D0007105610508940895E894BB27662777275C +:1026E000CB0197F90895052E97FB1EF400940E94E4 +:1026F0008A1357FD07D00E949D1307FC03D04EF4A8 +:102700000C948A1350954095309521953F4F4F4F2B +:102710005F4F089590958095709561957F4F8F4F8D +:102720009F4F08950E94BF13A59F900DB49F900DD9 +:10273000A49F800D911D11240895A1E21A2EAA1BB9 +:10274000BB1BFD010DC0AA1FBB1FEE1FFF1FA21761 +:10275000B307E407F50720F0A21BB30BE40BF50B5E +:10276000661F771F881F991F1A9469F760957095E7 +:10277000809590959B01AC01BD01CF010895A29F6A +:10278000B001B39FC001A39F700D811D1124911D45 +:10279000B29F700D811D1124911D08950E94E213B6 +:1027A0000C9439130E94321358F00E942B1340F0FE +:1027B00029F45F3F29F00C94221351110C946D13EE +:1027C0000C9428130E944A1368F39923B1F35523FC +:1027D00091F3951B550BBB27AA2762177307840734 +:1027E00038F09F5F5F4F220F331F441FAA1FA9F3CA +:1027F00035D00E2E3AF0E0E832D091505040E695B8 +:10280000001CCAF72BD0FE2F29D0660F771F881F18 +:10281000BB1F261737074807AB07B0E809F0BB0B0B +:10282000802DBF01FF2793585F4F3AF09E3F51051F +:1028300078F00C9422130C946D135F3FE4F3983EF0 +:10284000D4F3869577956795B795F7959F5FC9F708 +:10285000880F911D9695879597F90895E1E0660F89 +:10286000771F881FBB1F621773078407BA0720F002 +:10287000621B730B840BBA0BEE1F88F7E09508956B +:10288000AA1BBB1B51E107C0AA1FBB1FA617B70796 +:1028900010F0A61BB70B881F991F5A95A9F78095B2 +:1028A0009095BC01CD010895EE0FFF1F0590F491A6 +:1028B000E02D09940E94BF13B7FF0895821B930B6C +:1028C00008950F931F93CF93DF938230910510F4F7 +:1028D00082E090E0E091E402F091E50230E020E057 +:1028E000B0E0A0E0309799F42115310509F44AC011 +:1028F000281B390B24303105D8F58A819B8161155D +:10290000710589F1FB0193838283FE0111C040812F +:1029100051810281138148175907E0F04817590780 +:1029200099F4109761F012960C93129713961C93DA +:102930003296CF01DF91CF911F910F9108950093AF +:10294000E4021093E502F4CF2115310551F042174E +:10295000530738F0A901DB019A01BD01DF01F8013D +:10296000C1CFEF01F9CF9093E5028093E402CDCF80 +:10297000FE01E20FF31F81939193225031093983B5 +:102980002883D7CF2091E2023091E302232B41F438 +:1029900020914201309143013093E3022093E202FF +:1029A00020914001309141012115310541F42DB7AD +:1029B0003EB74091440150914501241B350BE091F5 +:1029C000E202F091E302E217F307A0F42E1B3F0BA3 +:1029D0002817390778F0AC014E5F5F4F2417350791 +:1029E00048F04E0F5F1F5093E3024093E202819341 +:1029F00091939FCFF0E0E0E09CCFCF93DF930097DF +:102A0000E9F0FC01329713821282A091E402B091A6 +:102A1000E502ED0130E020E01097A1F42081318142 +:102A2000820F931F2091E2023091E30228173907A9 +:102A300009F061C0F093E302E093E202DF91CF91ED +:102A40000895EA01CE17DF07E8F54A815B819E0110 +:102A500041155105B1F7E901FB83EA834991599189 +:102A6000C40FD51FEC17FD0761F480819181029698 +:102A7000840F951FE90199838883828193819B83C9 +:102A80008A83F0E0E0E012968D919C911397009775 +:102A9000B9F52D913C911197CD010296820F931FAC +:102AA0002091E2023091E3022817390739F6309776 +:102AB00051F51092E5021092E402B093E302A09364 +:102AC000E202BCCFD383C28340815181840F951F22 +:102AD000C817D90761F44E5F5F4F88819981480F0D +:102AE000591F518340838A819B819383828321155F +:102AF000310509F0B0CFF093E502E093E4029ECFF8 +:102B0000FD01DC01C0CF13821282D7CFDC0101C0EE +:102B10006D9341505040E0F7089510E0C3E6D0E0D7 +:102B200004C0FE010E9454142196C436D107C9F78F +:042B3000F894FFCF47 +:102B3400FF010000000000F401000000000000009C +:102B4400010000000000F401000000000000020386 +:102B54000C000D0000000000000000000000000058 +:102B64000000000000000100000000000000000060 +:102B74000000E602800000000000000000000000E9 +:102B840000000000000000000000A703FF0234035F +:0C2B9400F4036503430357030D0A00001F :00000001FF diff --git a/app/firmwares/examples/ITPLE/ITPLE.ino b/app/firmwares/examples/ITPLE/ITPLE.ino index 1c2e9364fe..0c8c74891c 100644 --- a/app/firmwares/examples/ITPLE/ITPLE.ino +++ b/app/firmwares/examples/ITPLE/ITPLE.ino @@ -7,12 +7,12 @@ * Updated : Ander, Mark Yan * Date : 01/09/2016 * Description : Firmware for Makeblock Electronic modules with Scratch. + * Refactored with millis() for non-blocking operation. * Copyright (C) 2013 - 2016 Maker Works Technology Co., Ltd. All right reserved. **********************************************************************************/ -// 서보 라이브러리 #include +#include -// 동작 상수 #define ALIVE 0 #define DIGITAL 1 #define ANALOG 2 @@ -22,8 +22,18 @@ #define PULSEIN 6 #define ULTRASONIC 7 #define TIMER 8 +#define NEOPIXEL_INIT 9 +#define NEOPIXEL_COLOR 10 +#define NEOPIXEL_BRIGHTNESS 11 +#define NEOPIXEL_SHIFT 12 +#define NEOPIXEL_ROTATE 13 +// Added for firmware-side blinking +#define NEOPIXEL_BLINK 14 +#define NEOPIXEL_BLINK_STOP 15 + +#define NEOPIXEL_PIN 9 +#define NEOPIXEL_COUNT 4 -// 상태 상수 #define GET 1 #define SET 2 #define RESET 3 @@ -41,22 +51,20 @@ union{ short shortVal; }valShort; -// 전역변수 선언 시작 -Servo servos[8]; +Servo servos[8]; +Adafruit_NeoPixel strip = Adafruit_NeoPixel(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); +boolean neopixelInitialized = true; -//울트라 소닉 포트 int trigPin = 13; int echoPin = 12; -//포트별 상태 int analogs[8]={0,0,0,0,0,0,0,0}; -int digitals[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +int digitals[14]={0,0,0,0,0,0,0,0,0,1,0,0,0,0}; int servo_pins[8]={0,0,0,0,0,0,0,0}; -// 울트라소닉 최종 값 float lastUltrasonic = 0; -// 버퍼 +// Buffer char buffer[52]; unsigned char prevc=0; @@ -67,15 +75,105 @@ double lastTime = 0.0; double currentTime = 0.0; uint8_t command_index = 0; +uint32_t neoPixelColors[4] = {0,0,0,0}; boolean isStart = false; boolean isUltrasonic = false; -// 전역변수 선언 종료 + +// --- 변수 추가: Non-blocking 타이머용 --- +unsigned long previousSensorTime = 0; +// sendPinValues() 함수를 실행할 간격 (밀리초) +// 중요: pulseIn() 등 blocking 함수가 있으므로 간격을 100ms로 늘림 +const unsigned long sensorInterval = 100; + +unsigned long previousBlinkUpdateTime = 0; +// 네오픽셀 깜박이기 업데이트 간격 (명령 밀림 방지를 위해 빈도 제한) +const unsigned long blinkUpdateInterval = 10; // 10ms마다 체크 (초당 100회) +// --- + +// --- NeoPixel Blink State (millis 기반 비동기 무한 깜박이기) --- +typedef struct { + boolean active; + uint8_t r; + uint8_t g; + uint8_t b; + boolean isOn; // 현재 ON 상태인가 + unsigned long interval; // 토글 간격(ms) + unsigned long lastMillis; // 마지막 토글 시각 + uint8_t startIdx; // LED 시작 인덱스 (포함) + uint8_t endIdx; // LED 끝 인덱스 (포함) +} BlinkState; + +BlinkState blinkLeft = { false, 0, 0, 0, false, 500, 0, 2, 3 }; +BlinkState blinkRight = { false, 0, 0, 0, false, 500, 0, 0, 1 }; + +void blinkApplyRange(BlinkState *s, boolean on) { + uint32_t color = on ? strip.Color(s->r, s->g, s->b) : 0; + for (uint8_t i = s->startIdx; i <= s->endIdx; i++) { + strip.setPixelColor(i, color); + neoPixelColors[i] = color; + } + strip.show(); +} + +void startBlink(BlinkState *s, uint8_t r, uint8_t g, uint8_t b, unsigned long intervalMs, unsigned long syncTime = 0) { + // 이미 진행 중이면 색/간격만 갱신하고 현재 상태 유지 + if (s->active) { + s->r = r; s->g = g; s->b = b; + s->interval = (intervalMs < 50) ? 50 : intervalMs; + blinkApplyRange(s, s->isOn); + return; + } + + // 새로 시작 (즉시 켜기) + s->r = r; s->g = g; s->b = b; + s->interval = (intervalMs < 50) ? 50 : intervalMs; + s->lastMillis = (syncTime > 0) ? syncTime : millis(); + s->active = true; + s->isOn = true; + blinkApplyRange(s, true); +} + +void stopBlink(BlinkState *s) { + // STOP 명령: 즉시 LED 끄기 및 상태 리셋 + s->active = false; + s->isOn = false; + // LED 강제 끄기 + blinkApplyRange(s, false); +} + +void resetBlinkStates() { + // 모든 깜박이기 상태 초기화 (연결 끊김 시 호출) + stopBlink(&blinkLeft); + stopBlink(&blinkRight); +} + +void updateBlinkStates() { + unsigned long now = millis(); + // Left + if (blinkLeft.active && (now - blinkLeft.lastMillis >= blinkLeft.interval)) { + blinkLeft.lastMillis = now; + blinkLeft.isOn = !blinkLeft.isOn; + blinkApplyRange(&blinkLeft, blinkLeft.isOn); + } + // Right + if (blinkRight.active && (now - blinkRight.lastMillis >= blinkRight.interval)) { + blinkRight.lastMillis = now; + blinkRight.isOn = !blinkRight.isOn; + blinkApplyRange(&blinkRight, blinkRight.isOn); + } +} void setup(){ Serial.begin(57600); initPorts(); - delay(200); + + // Initialize NeoPixel before serial communication starts + strip.begin(); + strip.clear(); + strip.show(); + + delay(200); // 셋업 중의 딜레이는 허용 } void initPorts() { @@ -83,19 +181,45 @@ void initPorts() { pinMode(pinNumber, OUTPUT); digitalWrite(pinNumber, LOW); } + // 깜박이기 상태도 초기화 + resetBlinkStates(); } +// ===== 수정된 loop() 함수 ===== void loop(){ - while (Serial.available()) { - if (Serial.available() > 0) { - char serialRead = Serial.read(); - setPinValue(serialRead&0xff); - } - } + // 1. 시리얼 수신을 최우선 처리 (명령 밀림 방지) + // 버퍼가 비워질 때까지 최대한 빠르게 읽고 처리 + // 한 loop() 사이클에서 여러 명령을 처리할 수 있도록 충분히 반복 + int processedBytes = 0; + while (Serial.available() && processedBytes < 200) { + char serialRead = Serial.read(); + setPinValue(serialRead&0xff); + processedBytes++; + } + + // 2. 네오픽셀 깜박이기 상태 업데이트 (빈도 제한) + unsigned long currentMillis = millis(); + if (currentMillis - previousBlinkUpdateTime >= blinkUpdateInterval) { + previousBlinkUpdateTime = currentMillis; + updateBlinkStates(); + } + + // 3. 센서 값 전송을 주기적으로 확인 (Non-blocking) + // pulseIn() 등 blocking 함수가 있으므로 간격을 넉넉히 설정 + if (currentMillis - previousSensorTime >= sensorInterval) { + previousSensorTime = currentMillis; // 다음 주기를 위해 시간 갱신 + sendPinValues(); + } + + // 기존 delay() 호출 제거 + /* delay(15); sendPinValues(); delay(10); + */ } +// ===== loop() 함수 수정 끝 ===== + void setPinValue(unsigned char c) { if(c==0x55&&isStart==false){ @@ -123,7 +247,7 @@ void setPinValue(unsigned char c) { isStart=false; } - if(isStart&&dataLen==0&&index>3){ + if(isStart&&dataLen==0&&index>3){ isStart = false; parseData(); index=0; @@ -152,7 +276,7 @@ void parseData() { digitals[echoPin] = 1; pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); - delay(50); + delay(50); // 핀 모드 변경 시 안정화를 위한 딜레이 (유지) } else { int trig = readBuffer(6); int echo = readBuffer(7); @@ -161,9 +285,9 @@ void parseData() { echoPin = echo; digitals[trigPin] = 1; digitals[echoPin] = 1; - pinMode(trigPin, OUTPUT); + pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); - delay(50); + delay(50); // 핀 모드 변경 시 안정화를 위한 딜레이 (유지) } } } else if(port == trigPin || port == echoPin) { @@ -175,21 +299,24 @@ void parseData() { } break; case SET:{ - runModule(device); + runModule(device, port); callOK(); } break; case RESET:{ + // 연결 끊김 시 모든 상태 초기화 + resetBlinkStates(); + // 네오픽셀 끄기 + strip.clear(); + strip.show(); callOK(); } break; } } -void runModule(int device) { +void runModule(int device, int pin) { //0xff 0x55 0x6 0x0 0x1 0xa 0x9 0x0 0x0 0xa - int port = readBuffer(6); - int pin = port; if(pin == trigPin || pin == echoPin) { setUltrasonicMode(false); @@ -233,6 +360,203 @@ void runModule(int device) { lastTime = millis()/1000.0; } break; + case NEOPIXEL_INIT: { + setPortWritable(9); + if (!neopixelInitialized) { + strip.begin(); + strip.clear(); + strip.show(); + for(int i=0;i<4;i++){ + neoPixelColors[i] = 0; + } + neopixelInitialized = true; + } + // 깜박이기 동작이 있었다면 모두 중지 + stopBlink(&blinkLeft); + stopBlink(&blinkRight); + break; + } + case NEOPIXEL_BLINK: { + setPortWritable(9); + uint8_t side = readBuffer(7); // 255: 전체, 0: 왼쪽, 1: 오른쪽 + uint8_t count = readBuffer(8); // 호환성 유지용으로 수신만, 사용하지 않음 (무한 깜박임) + uint8_t r = readBuffer(9); + uint8_t g = readBuffer(10); + uint8_t b = readBuffer(11); + unsigned long interval = (unsigned long)readShort(12); + if (interval < 50) interval = 50; + + // side == 255(or legacy 2) => 전체 + if (side == 2) { + unsigned long syncTime = millis(); // 양쪽 동기화를 위한 공통 시각 + startBlink(&blinkLeft, r, g, b, interval, syncTime); + startBlink(&blinkRight, r, g, b, interval, syncTime); + } else if (side == 0) { + startBlink(&blinkLeft, r, g, b, interval); + } else { + startBlink(&blinkRight, r, g, b, interval); + } + break; + } + case NEOPIXEL_BLINK_STOP: { + setPortWritable(9); + uint8_t side = readBuffer(7); // 255: 전체, 0: 왼쪽, 1: 오른쪽 + if (side == 2) { + stopBlink(&blinkLeft); + stopBlink(&blinkRight); + } else if (side == 0) { + stopBlink(&blinkLeft); + } else { + stopBlink(&blinkRight); + } + break; + } + case NEOPIXEL_COLOR: { + setPortWritable(9); + int num = readBuffer(7); + + // num이 254이면 범위 LED 설정 (RANGE 명령) + if (num == 254) { + int start = readBuffer(8); + int end = readBuffer(9); + int r = readBuffer(10); + int g = readBuffer(11); + int b = readBuffer(12); + + if(end > 3) end = 3; + if(start < 0) start = 0; + strip.fill(strip.Color(r,g,b), start, end-start+1); + for(int i=start;i<=end;i++){ + neoPixelColors[i] = strip.Color(r,g,b); + } + } + // num이 255이면 모든 LED를 같은 색으로 설정 (ALL 명령) + else if (num == 255) { + int r = readBuffer(8); + int g = readBuffer(9); + int b = readBuffer(10); + + strip.fill(strip.Color(r, g, b), 0, 4); + for(int i=0;i<4;i++){ + neoPixelColors[i] = strip.Color(r,g,b); + } + } + // 개별 LED 설정 + else { + int r = readBuffer(8); + int g = readBuffer(9); + int b = readBuffer(10); + + strip.setPixelColor(num, strip.Color(r, g, b)); + neoPixelColors[num] = strip.Color(r,g,b); + } + strip.show(); + neopixelInitialized = false; + break; + } + case NEOPIXEL_BRIGHTNESS: { + setPortWritable(9); + int brightness = readShort(7); + if (brightness < 0) brightness = 0; + if (brightness > 255) brightness = 255; + strip.setBrightness(brightness); + strip.show(); + break; + } + + case NEOPIXEL_SHIFT: { + setPortWritable(9); + int direction = (int8_t)readBuffer(7); // 1: 오른쪽, -1: 왼쪽 + int steps = readBuffer(8); + int isRotate = readBuffer(9); // 0: shift, 1: rotate + + // steps 범위 체크 + if (steps < 0) steps = 0; + if (steps > NEOPIXEL_COUNT) steps = NEOPIXEL_COUNT; + + // 현재 LED 색상을 임시 배열에 저장 + uint32_t tempColors[NEOPIXEL_COUNT]; + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + tempColors[i] = strip.getPixelColor(i); + } + + // 모든 LED 초기화 + strip.clear(); + + // 1번(idx 0)이 오른쪽 끝, 4번(idx 3)이 왼쪽 끝 + if (direction > 0) { + // 오른쪽으로: 색상이 1번 방향으로 이동 (인덱스 감소) + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + int newPos = i - steps; + if (isRotate == 1) { + // 회전: 순환 + newPos = (newPos + NEOPIXEL_COUNT) % NEOPIXEL_COUNT; + strip.setPixelColor(newPos, tempColors[i]); + } else { + // 이동: 범위 체크 + if (newPos >= 0) { + strip.setPixelColor(newPos, tempColors[i]); + } + } + } + } else { + // 왼쪽으로: 색상이 4번 방향으로 이동 (인덱스 증가) + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + int newPos = i + steps; + if (isRotate == 1) { + // 회전: 순환 + newPos = newPos % NEOPIXEL_COUNT; + strip.setPixelColor(newPos, tempColors[i]); + } else { + // 이동: 범위 체크 + if (newPos < NEOPIXEL_COUNT) { + strip.setPixelColor(newPos, tempColors[i]); + } + } + } + } + + strip.show(); + neopixelInitialized = false; + break; + } + + case NEOPIXEL_ROTATE: { + setPortWritable(9); + int direction = (int8_t)readBuffer(7); + int steps = readBuffer(8); + + if (steps < 0) steps = 0; + if (steps > NEOPIXEL_COUNT) steps %= NEOPIXEL_COUNT; + + uint32_t tempColors[NEOPIXEL_COUNT]; + + // 1번(idx 0)이 오른쪽 끝, 4번(idx 3)이 왼쪽 끝 + if (direction > 0) { + // 오른쪽으로 회전: 색상이 1번 방향으로 이동 (인덱스 감소) + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + int newPos = (i - steps + NEOPIXEL_COUNT) % NEOPIXEL_COUNT; + tempColors[newPos] = neoPixelColors[i]; + } + } else { + // 왼쪽으로 회전: 색상이 4번 방향으로 이동 (인덱스 증가) + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + int newPos = (i + steps) % NEOPIXEL_COUNT; + tempColors[newPos] = neoPixelColors[i]; + } + } + + strip.clear(); + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + neoPixelColors[i] = tempColors[i]; + strip.setPixelColor(i, neoPixelColors[i]); + } + strip.show(); + + + neopixelInitialized = false; + break; + } } } @@ -271,6 +595,9 @@ void sendUltrasonic() { delayMicroseconds(10); digitalWrite(trigPin, LOW); + // + // *** 주의: pulseIn()은 blocking 함수입니다. *** + // 최대 30000 마이크로초(30ms) 동안 여기서 대기할 수 있습니다. float value = pulseIn(echoPin, HIGH, 30000) / 29.0 / 2.0; if(value == 0) { @@ -399,4 +726,3 @@ void callDebug(char c){ writeSerial(c); writeEnd(); } - diff --git a/app/modules/ITPLE.js b/app/modules/ITPLE.js index 92e67fd308..81884fd0eb 100644 --- a/app/modules/ITPLE.js +++ b/app/modules/ITPLE.js @@ -10,18 +10,13 @@ function Module() { PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, - NEOPIXELINIT: 9, - NEOPIXELCOLOR: 10, - DHTINIT: 21, - DHTTEMP: 22, - DHTHUMI: 23, - NOTONE: 24, - PMINIT: 31, - PMVALUE: 32, - LCDINIT: 41, - LCD: 42, - LCDCLEAR: 43, - LCDEMOTICON: 44, + NEOPIXEL_INIT: 9, + NEOPIXEL_COLOR: 10, + NEOPIXEL_BRIGHTNESS: 11, + NEOPIXEL_SHIFT: 12, + NEOPIXEL_ROTATE: 13, + NEOPIXEL_BLINK: 14, + NEOPIXEL_BLINK_STOP: 15, }; this.actionTypes = { @@ -36,12 +31,15 @@ function Module() { }; this.digitalPortTimeList = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + this.neopixelLastData = {}; // 각 LED의 마지막 색상 저장 + this.neopixelShiftLastTime = 0; // SHIFT 마지막 실행 시간 + this.neopixelRotateLastTime = 0; // ROTATE 마지막 실행 시간 + this.neopixelDuplicateCheckTime = 100; // 중복 체크 유효 시간 (ms) + this.neopixelBlinkTasks = {}; // 사이드별 깜박이기 작업 관리 this.sensorData = { ULTRASONIC: 0, - DHTTEMP: 0, - DHTHUMI: 0, - PMVALUE: 0, DIGITAL: { 0: 0, 1: 0, @@ -74,6 +72,13 @@ function Module() { this.lastTime = 0; this.lastSendTime = 0; this.isDraing = false; + + // BLINK 명령 throttling을 위한 캐시 + this.lastBlinkCommand = { + left: { time: 0, data: null }, + right: { time: 0, data: null }, + all: { time: 0, data: null } + }; } var sensorIdx = 0; @@ -132,8 +137,18 @@ Module.prototype.handleRemoteData = function (handler) { if (getDatas) { var keys = Object.keys(getDatas); keys.forEach(function (key) { - var isSend = false; var dataObj = getDatas[key]; + var deviceType = parseInt(key); // 문자열 키를 숫자로 변환 (예: "7" -> 7) + + // --- [수정됨] millis() 펌웨어 최적화 --- + // DIGITAL(1)과 ANALOG(2)는 펌웨어에서 자동으로 스트리밍되므로 GET 요청 불필요. + // ULTRASONIC(7)은 펌웨어에서 센서를 초기화하는 '트리거'로 GET 요청이 필요함. + if (deviceType !== self.sensorTypes.ULTRASONIC) { + return; // ULTRASONIC 외의 모든 GET 요청은 무시 + } + // --- [수정 끝] --- + + var isSend = false; if (typeof dataObj.port === 'string' || typeof dataObj.port === 'number') { var time = self.digitalPortTimeList[dataObj.port]; if (dataObj.time > time) { @@ -154,14 +169,16 @@ Module.prototype.handleRemoteData = function (handler) { } if (isSend) { - if (!self.isRecentData(dataObj.port, key, dataObj.data)) { + // deviceType을 숫자로 전달 + if (!self.isRecentData(dataObj.port, deviceType, dataObj.data)) { self.recentCheckData[dataObj.port] = { - type: key, + type: deviceType, // 숫자형 deviceType 저장 data: dataObj.data, }; buffer = Buffer.concat([ buffer, - self.makeSensorReadBuffer(key, dataObj.port, dataObj.data), + // deviceType을 숫자로 전달 + self.makeSensorReadBuffer(deviceType, dataObj.port, dataObj.data), ]); } } @@ -173,52 +190,265 @@ Module.prototype.handleRemoteData = function (handler) { setKeys.forEach(function (port) { var data = setDatas[port]; if (data) { - if (self.digitalPortTimeList[port] < data.time) { + + // 네오픽셀 포트 확인 (100~103: COLOR, 200: INIT, 201: BRIGHTNESS, 202: ALL, 203: RANGE, 204: SHIFT, 205: ROTATE) + var portNum = parseInt(port, 10); + var isNeopixelColorPort = (portNum >= 100 && portNum <= 103); + var isNeopixelInitPort = (portNum === 200); + var isNeopixelBrightnessPort = (portNum === 201); + var isNeopixelAllPort = (portNum === 202); + var isNeopixelRangePort = (portNum === 203); + var isNeopixelShiftPort = (portNum === 204); + var isNeopixelRotatePort = (portNum === 205); + var isNeopixelBlinkPort = (portNum === 206); + var isNeopixelBlinkStopPort = (portNum === 207); + var isNeopixelVirtualPort = isNeopixelColorPort || isNeopixelInitPort || isNeopixelBrightnessPort || isNeopixelAllPort || isNeopixelRangePort || isNeopixelShiftPort || isNeopixelRotatePort || isNeopixelBlinkPort || isNeopixelBlinkStopPort; + + var shouldSend = false; + + // NEOPIXEL_INIT는 특별 처리: 깜박이기 작업 중지 + if (isNeopixelInitPort) { + self.stopNeopixelBlinkTask(-1); + } + + // 시간 기반 중복 체크 (isRecentData에서 네오픽셀은 항상 false 반환) + var lastTime = self.digitalPortTimeList[port] || 0; + if (lastTime < data.time) { self.digitalPortTimeList[port] = data.time; + shouldSend = !self.isRecentData(port, data.type, data.data); + } - if (!self.isRecentData(port, data.type, data.data)) { + if (shouldSend) { + // 네오픽셀 COLOR는 isRecentData 내부에서 neopixelLastData에 저장 + // INIT과 BRIGHTNESS는 recentCheckData에 저장 + if (!isNeopixelColorPort) { self.recentCheckData[port] = { type: data.type, data: data.data, }; - buffer = Buffer.concat([ - buffer, - self.makeOutputBuffer(data.type, port, data.data), - ]); } + + // 네오픽셀 가상 포트를 실제 포트(9)로 변환 + var actualPort = isNeopixelVirtualPort ? 9 : port; + + var outputBuffer = self.makeOutputBuffer(data.type, actualPort, data.data); + + buffer = Buffer.concat([ + buffer, + outputBuffer, + ]); } } }); } if (buffer.length) { + // 버퍼 크기 제한: 명령 밀림 방지 (반복 블록에서 빠른 종료를 위해) + // 최대 10개까지만 유지 (오래된 명령 제거) + if (this.sendBuffers.length > 10) { + console.log('[ITPLE] Send buffer overflow, dropping old commands'); + this.sendBuffers = this.sendBuffers.slice(-5); // 최근 5개만 유지 + } this.sendBuffers.push(buffer); } }; +// --- NeoPixel Blink Scheduler (Background) --- +Module.prototype.startNeopixelBlinkTask = function (side, count, r, g, b, interval) { + var self = this; + // 파라미터 보정 + if (side !== 0 && side !== 1 && side !== -1) { + side = -1; // 기본 전체 + } + // count가 0이면 무한 깜박임 (255로 처리) + count = parseInt(count || 1); + if (count === 0) { + count = 255; // 무한 깜박임을 255로 표현 + } else { + count = Math.max(1, count); + } + r = Math.min(255, Math.max(0, parseInt(r || 0))); + g = Math.min(255, Math.max(0, parseInt(g || 0))); + b = Math.min(255, Math.max(0, parseInt(b || 0))); + interval = Math.max(100, Number(interval || 500)); // 최소 100ms + + // 전체(-1)인 경우 양쪽을 각각 시작 + if (side === -1) { + this.stopNeopixelBlinkTask(-1); + this.startNeopixelBlinkTask(0, count, r, g, b, interval); + this.startNeopixelBlinkTask(1, count, r, g, b, interval); + return; + } + + var key = side === 0 ? 'left' : 'right'; + + // 기존 작업이 있다면 중지 + this.stopNeopixelBlinkTask(side); + + // LED 맵핑: 왼쪽(3,4) -> 인덱스 [2,3], 오른쪽(0,1) -> 인덱스 [0,1] + var ledNumbers = side === 0 ? [2, 3] : [0, 1]; + + var state = { + side: side, + key: key, + ledNumbers: ledNumbers, + count: count, + r: r, + g: g, + b: b, + isOn: false, + done: false, + toggles: 0, // off로 바뀔 때 1회로 카운트 + timer: null, + infinite: (count === 255), // 255는 무한 깜박임 + }; + + // 즉시 1회 켜기 + this._applyNeopixelColorToList(ledNumbers, r, g, b); + state.isOn = true; + + // 주기적 토글 + state.timer = setInterval(function () { + if (state.done) { return; } + if (state.isOn) { + // 끄기 + self._applyNeopixelColorToList(ledNumbers, 0, 0, 0); + state.isOn = false; + state.toggles += 1; + // 무한 깜박임이 아닐 때만 카운트 체크 + if (!state.infinite && state.toggles >= state.count) { + // 완료 + state.done = true; + self.stopNeopixelBlinkTask(side); + } + } else { + // 켜기 + self._applyNeopixelColorToList(ledNumbers, r, g, b); + state.isOn = true; + } + }, interval); + + this.neopixelBlinkTasks[key] = state; +}; + +Module.prototype.stopNeopixelBlinkTask = function (side) { + if (side === -1) { + this.stopNeopixelBlinkTask(0); + this.stopNeopixelBlinkTask(1); + return; + } + var key = side === 0 ? 'left' : 'right'; + var task = this.neopixelBlinkTasks[key]; + if (task && task.timer) { + clearInterval(task.timer); + } + if (task) { + // 종료 시 LED 끄기 보장 + this._applyNeopixelColorToList(task.ledNumbers, 0, 0, 0); + } + delete this.neopixelBlinkTasks[key]; +}; + +Module.prototype._applyNeopixelColorToList = function (ledNumbers, r, g, b) { + var self = this; + // 연속된 LED 번호인지 확인 + var sorted = ledNumbers.slice().sort(function(a, b) { return a - b; }); + var isContiguous = sorted.length > 1 && sorted.every(function(num, idx) { + return idx === 0 || num === sorted[idx - 1] + 1; + }); + + if (isContiguous && sorted.length > 1) { + // 연속된 LED는 RANGE 명령 사용 (단일 버퍼) + var buf = self.makeOutputBuffer(self.sensorTypes.NEOPIXEL_COLOR, 9, { + num: 254, // RANGE 명령 + start: sorted[0], + end: sorted[sorted.length - 1], + r: r, + g: g, + b: b + }); + self.sendBuffers.push(buf); + // 캐시 업데이트 + sorted.forEach(function(num) { + self.neopixelLastData[num.toString()] = { r: r, g: g, b: b, lastCommand: 'color' }; + }); + } else { + // 불연속 LED는 개별 명령 사용 + ledNumbers.forEach(function (num) { + var buf = self.makeOutputBuffer(self.sensorTypes.NEOPIXEL_COLOR, 9, { num: num, r: r, g: g, b: b }); + self.sendBuffers.push(buf); + // 캐시 업데이트 + self.neopixelLastData[num.toString()] = { r: r, g: g, b: b, lastCommand: 'color' }; + }); + } +}; + Module.prototype.isRecentData = function (port, type, data) { var that = this; var isRecent = false; - - if ( - type == this.sensorTypes.ULTRASONIC || - type == this.sensorTypes.DHTTEMP || - type == this.sensorTypes.DHTHUMI || - type == this.sensorTypes.PMVALUE - ) { + var currentTime = new Date().getTime(); + + // BLINK 명령에 대한 특별한 throttling (반복 블록에서 빠른 종료를 위해) + if (type == this.sensorTypes.NEOPIXEL_BLINK) { + var sideKey = 'all'; + if (data && data.side !== undefined) { + if (data.side === 0) sideKey = 'left'; + else if (data.side === 1) sideKey = 'right'; + else sideKey = 'all'; + } + + var lastBlink = this.lastBlinkCommand[sideKey]; + var throttleTime = 50; // 50ms 이내의 중복 명령 무시 + + // 동일한 내용의 BLINK 명령이 짧은 시간 내에 반복되면 무시 + if (lastBlink.data && (currentTime - lastBlink.time) < throttleTime) { + var isSame = lastBlink.data.side === data.side && + lastBlink.data.count === data.count && + lastBlink.data.r === data.r && + lastBlink.data.g === data.g && + lastBlink.data.b === data.b && + lastBlink.data.interval === data.interval; + if (isSame) { + return true; // 중복이므로 전송 안 함 + } + } + + // 새 명령이므로 캐시 업데이트 + this.lastBlinkCommand[sideKey] = { + time: currentTime, + data: JSON.parse(JSON.stringify(data)) // deep copy + }; + return false; // 전송 + } + + // BLINK_STOP은 항상 즉시 전송 (빠른 종료를 위해) + if (type == this.sensorTypes.NEOPIXEL_BLINK_STOP) { + // STOP 명령이 들어오면 BLINK 캐시도 초기화 + this.lastBlinkCommand = { + left: { time: 0, data: null }, + right: { time: 0, data: null }, + all: { time: 0, data: null } + }; + return false; // 항상 전송 + } + + // 다른 NeoPixel 명령어는 중복 체크 없이 항상 전송 + if (type == this.sensorTypes.NEOPIXEL_COLOR || + type == this.sensorTypes.NEOPIXEL_INIT || + type == this.sensorTypes.NEOPIXEL_BRIGHTNESS || + type == this.sensorTypes.NEOPIXEL_SHIFT || + type == this.sensorTypes.NEOPIXEL_ROTATE) { + return false; // 항상 전송 + } + + if (type == this.sensorTypes.ULTRASONIC) { var portString = port.toString(); var isGarbageClear = false; Object.keys(this.recentCheckData).forEach(function (key) { var recent = that.recentCheckData[key]; if (key === portString) { } - if ( - key !== portString && - (recent.type == that.sensorTypes.ULTRASONIC || - recent.type == that.sensorTypes.DHTTEMP || - recent.type == that.sensorTypes.DHTHUMI || - recent.type == that.sensorTypes.PMVALUE) - ) { + if (key !== portString && (recent.type == that.sensorTypes.ULTRASONIC)) { delete that.recentCheckData[key]; isGarbageClear = true; } @@ -229,7 +459,10 @@ Module.prototype.isRecentData = function (port, type, data) { } else { isRecent = true; } - } else if (port in this.recentCheckData && type != this.sensorTypes.TONE) { + } else if ( + port in this.recentCheckData && + type != this.sensorTypes.TONE + ) { if (this.recentCheckData[port].type === type && this.recentCheckData[port].data === data) { isRecent = true; } @@ -243,7 +476,8 @@ Module.prototype.requestLocalData = function () { if (!this.isDraing && this.sendBuffers.length > 0) { this.isDraing = true; - this.sp.write(this.sendBuffers.shift(), function () { + var bufferToSend = this.sendBuffers.shift(); + this.sp.write(bufferToSend, function () { if (self.sp) { self.sp.drain(function () { self.isDraing = false; @@ -266,6 +500,7 @@ Module.prototype.handleLocalData = function (data) { if (data.length <= 4 || data[0] !== 255 || data[1] !== 85) { return; } + var readData = data.subarray(2, data.length); var value; switch (readData[0]) { @@ -304,25 +539,14 @@ Module.prototype.handleLocalData = function (data) { self.sensorData.ULTRASONIC = value; break; } - case self.sensorTypes.DHTTEMP: { - self.sensorData.DHTTEMP = value; - //console.log(value); - break; - } - case self.sensorTypes.DHTHUMI: { - self.sensorData.DHTHUMI = value; - console.log(value); - break; - } - case self.sensorTypes.PMVALUE: { - self.sensorData.PMVALUE = value; - //console.log(value); - break; - } case self.sensorTypes.TIMER: { self.sensorData.TIMER = value; break; } + case self.sensorTypes.NEOPIXEL_INIT: { + self.sensorData.NEOPIXEL_INIT = value; + break; + } default: { break; } @@ -351,16 +575,7 @@ Module.prototype.makeSensorReadBuffer = function (device, port, data) { 10, ]); //console.log(buffer); - } else if (device == this.sensorTypes.DHTTEMP) { - buffer = new Buffer([255, 85, 5, sensorIdx, this.actionTypes.GET, device, port, 10]); - //console.log(buffer); - } else if (device == this.sensorTypes.DHTHUMI) { - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.GET, device, port, 10]); - console.log(buffer); - } else if (device == this.sensorTypes.PMVALUE) { - buffer = new Buffer([255, 85, 5, sensorIdx, this.actionTypes.GET, device, port, 10]); - //console.log(buffer); - } else if (!data) { + }else if (!data) { buffer = new Buffer([255, 85, 5, sensorIdx, this.actionTypes.GET, device, port, 10]); } else { value = new Buffer(2); @@ -404,192 +619,149 @@ Module.prototype.makeOutputBuffer = function (device, port, data) { buffer = Buffer.concat([buffer, value, time, dummy]); break; } - case this.sensorTypes.TONE: { - } - case this.sensorTypes.NOTONE: { + case this.sensorTypes.NEOPIXEL_INIT: { value.writeInt16LE(data); - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); buffer = Buffer.concat([buffer, value, dummy]); - //console.log(buffer); break; } - case this.sensorTypes.NEOPIXELINIT: { - value.writeInt16LE(data); - - //console.log(port); - //console.log(value); - - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, value, dummy]); - break; - } - - case this.sensorTypes.NEOPIXELCOLOR: { - var num = new Buffer(2); - var r = new Buffer(2); - var g = new Buffer(2); - var b = new Buffer(2); - + case this.sensorTypes.NEOPIXEL_COLOR: { if ($.isPlainObject(data)) { - num.writeInt16LE(data.num); - r.writeInt16LE(data.r); - g.writeInt16LE(data.g); - b.writeInt16LE(data.b); + // 범위 명령 (num === 254) + if (data.num === 254) { + buffer = new Buffer(14); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 10; + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // 실제 Arduino 포트는 9번 + buffer[7] = data.num || 0; // 254 + buffer[8] = data.start || 0; + buffer[9] = data.end || 0; + buffer[10] = data.r || 0; + buffer[11] = data.g || 0; + buffer[12] = data.b || 0; + buffer[13] = 10; + } else { + buffer = new Buffer(12); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 8; + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // 실제 Arduino 포트는 9번 + buffer[7] = data.num || 0; + buffer[8] = data.r || 0; + buffer[9] = data.g || 0; + buffer[10] = data.b || 0; + buffer[11] = 10; + } } else { - num.writeInt16LE(0); - r.writeInt16LE(0); - g.writeInt16LE(0); - b.writeInt16LE(0); + buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, 9]); + buffer = Buffer.concat([buffer, value, dummy]); } - - buffer = new Buffer([255, 85, 12, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, num, r, g, b, dummy]); - console.log(buffer); - break; - } - case this.sensorTypes.DHTINIT: { - value.writeInt16LE(data); - - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, value, dummy]); - //console.log(buffer); - break; - } - case this.sensorTypes.PMINIT: { - value.writeInt16LE(data); - - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, value, dummy]); - //console.log(buffer); break; } - - case this.sensorTypes.LCDINIT: { + case this.sensorTypes.NEOPIXEL_BRIGHTNESS: { value.writeInt16LE(data); buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); buffer = Buffer.concat([buffer, value, dummy]); - //console.log(buffer); break; } - - case this.sensorTypes.LCD: { - var row = new Buffer(2); - var col = new Buffer(2); - + case this.sensorTypes.NEOPIXEL_SHIFT: { if ($.isPlainObject(data)) { - row.writeInt16LE(data.row); - col.writeInt16LE(data.col); + buffer = new Buffer(11); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 7; + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // 실제 Arduino 포트는 9번 + buffer[7] = data.direction || 1; // 1: 오른쪽, -1: 왼쪽 + buffer[8] = data.steps || 0; + buffer[9] = 0; // 0: shift + buffer[10] = 10; } else { - row.writeInt16LE(0); - col.writeInt16LE(0); + buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, 9]); + buffer = Buffer.concat([buffer, value, dummy]); } - var text0 = new Buffer(2); - var text1 = new Buffer(2); - var text2 = new Buffer(2); - var text3 = new Buffer(2); - var text4 = new Buffer(2); - var text5 = new Buffer(2); - var text6 = new Buffer(2); - var text7 = new Buffer(2); - var text8 = new Buffer(2); - var text9 = new Buffer(2); - var text10 = new Buffer(2); - var text11 = new Buffer(2); - var text12 = new Buffer(2); - var text13 = new Buffer(2); - var text14 = new Buffer(2); - var text15 = new Buffer(2); + break; + } + case this.sensorTypes.NEOPIXEL_ROTATE: { if ($.isPlainObject(data)) { - text0.writeInt16LE(data.text0); - text1.writeInt16LE(data.text1); - text2.writeInt16LE(data.text2); - text3.writeInt16LE(data.text3); - text4.writeInt16LE(data.text4); - text5.writeInt16LE(data.text5); - text6.writeInt16LE(data.text6); - text7.writeInt16LE(data.text7); - text8.writeInt16LE(data.text8); - text9.writeInt16LE(data.text9); - text10.writeInt16LE(data.text10); - text11.writeInt16LE(data.text11); - text12.writeInt16LE(data.text12); - text13.writeInt16LE(data.text13); - text14.writeInt16LE(data.text14); - text15.writeInt16LE(data.text15); + buffer = new Buffer(11); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 7; + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // 실제 Arduino 포트는 9번 + buffer[7] = data.direction || 1; // 1: 오른쪽, -1: 왼쪽 + buffer[8] = data.steps || 0; + buffer[9] = 1; // 1: rotate (shift와 구분) + buffer[10] = 10; } else { - text0.writeInt16LE(0); - text1.writeInt16LE(0); - text2.writeInt16LE(0); - text3.writeInt16LE(0); - text4.writeInt16LE(0); - text5.writeInt16LE(0); - text6.writeInt16LE(0); - text7.writeInt16LE(0); - text8.writeInt16LE(0); - text9.writeInt16LE(0); - text10.writeInt16LE(0); - text11.writeInt16LE(0); - text12.writeInt16LE(0); - text13.writeInt16LE(0); - text14.writeInt16LE(0); - text15.writeInt16LE(0); + buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, 9]); + buffer = Buffer.concat([buffer, value, dummy]); } - - buffer = new Buffer([255, 85, 40, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([ - buffer, - row, - col, - text0, - text1, - text2, - text3, - text4, - text5, - text6, - text7, - text8, - text9, - text10, - text11, - text12, - text13, - text14, - text15, - dummy, - ]); - - //console.log(buffer); break; } - - case this.sensorTypes.LCDCLEAR: { - value.writeInt16LE(data); - buffer = new Buffer([255, 85, 6, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, value, dummy]); - console.log(buffer); + case this.sensorTypes.NEOPIXEL_BLINK: { + // Payload: side(int8), count(uint8), r, g, b, interval(uint16) + if ($.isPlainObject(data)) { + var side = (typeof data.side === 'number') ? data.side : -1; + var sideByte = side < 0 ? 255 : side; // -1 => 255 + var count = data.count || 1; + var r = data.r || 0; + var g = data.g || 0; + var b = data.b || 0; + var interval = Math.max(100, parseInt(data.interval || 500, 10)); + buffer = new Buffer(15); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 11; // 4 (idx,action,device,port) + 7 payload + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // actual port + buffer[7] = sideByte & 0xFF; + buffer[8] = count & 0xFF; + buffer[9] = r & 0xFF; + buffer[10] = g & 0xFF; + buffer[11] = b & 0xFF; + buffer[12] = interval & 0xFF; + buffer[13] = (interval >> 8) & 0xFF; + buffer[14] = 10; + } else { + // minimal packet with defaults + buffer = new Buffer(9); + buffer[0] = 255; buffer[1] = 85; buffer[2] = 5; buffer[3] = sensorIdx; buffer[4] = this.actionTypes.SET; buffer[5] = device; buffer[6] = 9; buffer[7] = 255; buffer[8] = 10; + } break; } - - case this.sensorTypes.LCDEMOTICON: { - var row = new Buffer(2); - var col = new Buffer(2); - var emoticon = new Buffer(2); - + case this.sensorTypes.NEOPIXEL_BLINK_STOP: { + // Payload: side(int8) if ($.isPlainObject(data)) { - row.writeInt16LE(data.row); - col.writeInt16LE(data.col); - emoticon.writeInt16LE(data.emoticon); + var side = (typeof data.side === 'number') ? data.side : -1; + var sideByte = side < 0 ? 255 : side; // -1 => 255 + buffer = new Buffer(9); + buffer[0] = 255; + buffer[1] = 85; + buffer[2] = 5; // 4 + 1 + buffer[3] = sensorIdx; + buffer[4] = this.actionTypes.SET; + buffer[5] = device; + buffer[6] = 9; // actual port + buffer[7] = sideByte & 0xFF; + buffer[8] = 10; } else { - row.writeInt16LE(0); - col.writeInt16LE(0); - emoticon.writeInt16LE(0); + buffer = new Buffer([255, 85, 5, sensorIdx, this.actionTypes.SET, device, 9, 255, 10]); } - - buffer = new Buffer([255, 85, 10, sensorIdx, this.actionTypes.SET, device, port]); - buffer = Buffer.concat([buffer, row, col, emoticon, dummy]); - console.log(buffer); break; } } @@ -612,17 +784,60 @@ Module.prototype.getDataByBuffer = function (buffer) { Module.prototype.disconnect = function (connect) { var self = this; - connect.close(); - if (self.sp) { - delete self.sp; + console.log('[ITPLE] disconnect called'); + // Stop all blink tasks + this.stopNeopixelBlinkTask(0); + this.stopNeopixelBlinkTask(1); + // Send NEOPIXEL_INIT to turn off all LEDs before closing + if (this.sp) { + console.log('[ITPLE] Sending NEOPIXEL_INIT before disconnect'); + var initBuffer = this.makeOutputBuffer(this.sensorTypes.NEOPIXEL_INIT, 9, 0); + this.sp.write(initBuffer, function() { + console.log('[ITPLE] NEOPIXEL_INIT sent, draining...'); + self.sp.drain(function() { + console.log('[ITPLE] Drain complete, closing connection'); + connect.close(); + if (self.sp) { + delete self.sp; + } + }); + }); + } else { + console.log('[ITPLE] No serial port, closing directly'); + connect.close(); } + // Reset NeoPixel data on disconnect + this.neopixelLastData = {}; }; Module.prototype.reset = function () { + console.log('[ITPLE] reset called, sp exists:', !!this.sp); + // Stop all blink tasks on reset + this.stopNeopixelBlinkTask(0); + this.stopNeopixelBlinkTask(1); + // Send NEOPIXEL_INIT to turn off all LEDs + if (this.sp) { + console.log('[ITPLE] Sending NEOPIXEL_INIT in reset'); + var initBuffer = this.makeOutputBuffer(this.sensorTypes.NEOPIXEL_INIT, 9, 0); + try { + this.sp.write(initBuffer, function(err) { + if (err) { + console.log('[ITPLE] Error writing INIT in reset:', err); + } else { + console.log('[ITPLE] NEOPIXEL_INIT sent in reset'); + } + }); + } catch (e) { + console.log('[ITPLE] Exception in reset write:', e); + } + } this.lastTime = 0; this.lastSendTime = 0; - this.sensorData.PULSEIN = {}; + this.sendBuffers = []; + this.recentCheckData = {}; + this.neopixelLastData = {}; + this.digitalPortTimeList = {}; }; module.exports = new Module(); diff --git a/app/modules/altino.js b/app/modules/altino.js index 6199b11d52..ee353f42d0 100644 --- a/app/modules/altino.js +++ b/app/modules/altino.js @@ -148,6 +148,43 @@ Module.prototype.checkInitialData = function(data, config) { return true; }; +function GetBitMergeResultSigned_12Bit(byH, byL) { + var nTempH = byH; + var nTempL = byL; + + nTempH = (nTempH << 8) | byL; + + if ((nTempH & 0x8000) == 0x8000) + { + nTempH = ~(nTempH - 1); + nTempH = 0 - (nTempH & 0xFFFF); + } + else + { + nTempH &= 0x7FFF; + } + + return nTempH = nTempH >> 4; +} + +function GetBitMergeResultSigned_16Bit(byH, byL) { + var nTempH = byH; + var nTempL = byL; + + nTempH = (nTempH << 8) | byL; + + if ((nTempH & 0x8000) == 0x8000) + { + nTempH = ~(nTempH - 1); + nTempH = 0 - (nTempH & 0xFFFF); + } + else + { + nTempH &= 0x7FFF; + } + + return nTempH = nTempH; +} // 하드웨어 데이터 처리 Module.prototype.handleLocalData = function(data) { // data: Native Buffer @@ -193,13 +230,13 @@ Module.prototype.handleLocalData = function(data) { // data: Native Buffer sensordata.cds = buf[43] * 256 + buf[44]; //cds - sensordata.accx = buf[25] * 256 + buf[26]; //acc x - sensordata.accy = buf[27] * 256 + buf[28]; //acc y - sensordata.accz = buf[29] * 256 + buf[30]; //acc z + sensordata.accx = GetBitMergeResultSigned_12Bit(buf[25], buf[26]); //acc x + sensordata.accy = GetBitMergeResultSigned_12Bit(buf[27], buf[28]); //acc y + sensordata.accz = GetBitMergeResultSigned_12Bit(buf[29], buf[30]); //acc z - sensordata.magx = buf[31] * 256 + buf[32]; //mag x - sensordata.magy = buf[33] * 256 + buf[34]; //mag y - sensordata.magz = buf[35] * 256 + buf[36]; //mag z + sensordata.magx = GetBitMergeResultSigned_16Bit(buf[31], buf[32]); //mag x + sensordata.magy = GetBitMergeResultSigned_16Bit(buf[33], buf[34]); //mag y + sensordata.magz = GetBitMergeResultSigned_16Bit(buf[35], buf[36]); //mag z sensordata.stvar = buf[45] * 256 + buf[46]; //steering var @@ -209,9 +246,9 @@ Module.prototype.handleLocalData = function(data) { // data: Native Buffer sensordata.remote = buf[51]; //remote control - sensordata.gyrox = buf[37] * 256 + buf[38]; //gyro sensor x - sensordata.gyroy = buf[39] * 256 + buf[40]; //gyro sensor y - sensordata.gyroz = buf[41] * 256 + buf[42]; //gyro sensor z + sensordata.gyrox = GetBitMergeResultSigned_16Bit(buf[37], buf[38]); //gyro sensor x + sensordata.gyroy = GetBitMergeResultSigned_16Bit(buf[39], buf[40]); //gyro sensor y + sensordata.gyroz = GetBitMergeResultSigned_16Bit(buf[41], buf[42]); //gyro sensor z motordata.cnt = 0; } diff --git a/app/modules/altino_neo.js b/app/modules/altino_neo.js new file mode 100644 index 0000000000..1b1bd00384 --- /dev/null +++ b/app/modules/altino_neo.js @@ -0,0 +1,383 @@ +function Module() { + this.tx_d = new Array(26); + this.rx_d = new Array(54); + + this.sensordata = { + tof1: 0, + tof2: 0, + tof3: 0, + tof4: 0, + tof5: 0, + tof6: 0, + accx: 0, + accy: 0, + accz: 0, + magx: 0, + magy: 0, + magz: 0, + gyrox: 0, + gyroy: 0, + gyroz: 0, + roll: 0, + pitch: 0, + yaw: 0, + temp: 0, + lefttorque: 0, + righttorque: 0, + cds: 0, + bat: 0, + }; + + + this.motordata = { + rightmotor: 0, + leftmotor: 0, + steering: 0, + led1: 0, + led2: 0, + note: 0, + ascii: 0, + dot1: 0, + dot2: 0, + dot3: 0, + dot4: 0, + dot5: 0, + dot6: 0, + dot7: 0, + dot8: 0, + // ir: 0 + }; +} + +var ALTINO = { + RIGHT_WHEEL: 'rightWheel', + LEFT_WHEEL: 'leftWheel', + STEERING: 'steering', + ASCII: 'ascii', + LED1: 'led1', + LED2: 'led2', + NOTE: 'note', + DOT1: 'dot1', + DOT2: 'dot2', + DOT3: 'dot3', + DOT4: 'dot4', + DOT5: 'dot5', + DOT6: 'dot6', + DOT7: 'dot7', + DOT8: 'dot8', + // IR: 'ir' +}; + +Module.prototype.init = function(handler, config) { + //console.log(this.motoring.lcdTxt); +}; + +Module.prototype.lostController = function() {} + +Module.prototype.eventController = function(state) { + if (state === 'connected') { + clearInterval(this.sensing); + } +} + +Module.prototype.setSerialPort = function(sp) { + this.sp = sp; +}; + + +Module.prototype.requestInitialData = function(sp) { + var tx_d = this.tx_d; + tx_d[0] = 0x02; // Start + tx_d[1] = 20; // Data length + tx_d[2] = 0; // Checksum + tx_d[3] = 0; // Comm ID H + tx_d[4] = 0; // Comm ID L + tx_d[5] = 0; // Steering + tx_d[6] = 0; // Drive Right H + tx_d[7] = 0; // Drive Right L + tx_d[8] = 0; // Drive Left H + tx_d[9] = 0; // Drive Left L + tx_d[10] = 0; // Dot Matrix Mode + tx_d[11] = 0; // Dotmatrix Line 0 + tx_d[12] = 0; // Dotmatrix Line 1 + tx_d[13] = 0; // Dotmatrix Line 2 + tx_d[14] = 0; // Dotmatrix Line 3 + tx_d[15] = 0; // Dotmatrix Line 4 + tx_d[16] = 0; // Dotmatrix Line 5 + tx_d[17] = 0; // Dotmatrix Line 6 + tx_d[18] = 0; // Dotmatrix Line 7 + tx_d[19] = 0; // Buzzer + tx_d[20] = 0; // Led H + tx_d[21] = 0; // Led L + tx_d[22] = 0; // Reserved + tx_d[23] = 0; // Reserved + tx_d[24] = 0; // Reserved + tx_d[25] = 0x03; // End + return tx_d; +}; + +Module.prototype.checkInitialData = function(data, config) { + return true; +}; + + +// 하드웨어 데이터 처리 +Module.prototype.handleLocalData = function(data) { // data: Native Buffer + var rx_check_sum = 0; + var sensordata = this.sensordata; + var motordata = this.motordata; + + for (var i = 0; i < data.length; i++) { + var str = data[i]; + this.rx_d[i] = parseInt(str, 10); + } + + if((this.rx_d[0] == 0x02) && (this.rx_d[53] == 0x03)) + { + if((this.rx_d[3] == 0x01) && (this.rx_d[4] == 0x01)) { + // motordata.ir = 0; + sensordata.tof1 = this.rx_d[5] * 256 + this.rx_d[6]; // tof1 + sensordata.tof2 = this.rx_d[7] * 256 + this.rx_d[8]; // tof2 + sensordata.tof3 = this.rx_d[9] * 256 + this.rx_d[10]; // tof3 + sensordata.tof4 = this.rx_d[11] * 256 + this.rx_d[12]; // tof4 + sensordata.tof5 = this.rx_d[13] * 256 + this.rx_d[14]; // tof5 + sensordata.tof6 = this.rx_d[15] * 256 + this.rx_d[16]; // tof6 + + // sensordata.accx = this.rx_d[17] * 256 + this.rx_d[18]; // acc-x + // sensordata.accy = this.rx_d[19] * 256 + this.rx_d[20]; // acc-y + // sensordata.accz = this.rx_d[21] * 256 + this.rx_d[22]; // acc-z + + // sensordata.magx = this.rx_d[23] * 256 + this.rx_d[24]; // mag-x + // sensordata.magy = this.rx_d[25] * 256 + this.rx_d[26]; // mag-y + // sensordata.magz = this.rx_d[27] * 256 + this.rx_d[28]; // mag-z + + // sensordata.gyrox = this.rx_d[29] * 256 + this.rx_d[30]; // gyro-x + // sensordata.gyroy = this.rx_d[31] * 256 + this.rx_d[32]; // gyro-y + // sensordata.gyroz = this.rx_d[33] * 256 + this.rx_d[34]; // gyro-z + + // sensordata.roll = this.rx_d[35] * 256 + this.rx_d[36]; // AHRS Roll + // sensordata.pitch = this.rx_d[37] * 256 + this.rx_d[38]; // AHRS Pitch + // sensordata.yaw = this.rx_d[39] * 256 + this.rx_d[40]; // AHRS Yaw + + + sensordata.accx = ((this.rx_d[17] << 8) | this.rx_d[18]) << 16 >> 16; // acc-x + sensordata.accy = ((this.rx_d[19] << 8) | this.rx_d[20]) << 16 >> 16; // acc-y + sensordata.accz = ((this.rx_d[21] << 8) | this.rx_d[22]) << 16 >> 16; // acc-z + + sensordata.magx = ((this.rx_d[23] << 8) | this.rx_d[24]) << 16 >> 16; // mag-x + sensordata.magy = ((this.rx_d[25] << 8) | this.rx_d[26]) << 16 >> 16; // mag-y + sensordata.magz = ((this.rx_d[27] << 8) | this.rx_d[28]) << 16 >> 16; // mag-z + + sensordata.gyrox = ((this.rx_d[29] << 8) | this.rx_d[30]) << 16 >> 16; // gyro-x + sensordata.gyroy = ((this.rx_d[31] << 8) | this.rx_d[32]) << 16 >> 16; // gyro-y + sensordata.gyroz = ((this.rx_d[33] << 8) | this.rx_d[34]) << 16 >> 16; // gyro-z + + sensordata.roll = ((this.rx_d[35] << 8) | this.rx_d[36]) << 16 >> 16; // AHRS Roll + sensordata.pitch = ((this.rx_d[37] << 8) | this.rx_d[38]) << 16 >> 16; // AHRS Pitch + sensordata.yaw = ((this.rx_d[39] << 8) | this.rx_d[40]) << 16 >> 16; // AHRS Yaw + + sensordata.temp = this.rx_d[41] * 256 + this.rx_d[42]; // Temp + sensordata.lefttorque = this.rx_d[43] * 256 + this.rx_d[44]; // Left Wheel Torque + sensordata.righttorque = this.rx_d[45] * 256 + this.rx_d[46]; // Right Wheel Torque + sensordata.cds = this.rx_d[47] * 256 + this.rx_d[48]; // CDS + sensordata.bat = this.rx_d[49] * 256 + this.rx_d[50]; // Battery + } + } +}; + +// Web Socket(엔트리)에 전달할 데이터 +Module.prototype.requestRemoteData = function(handler) { + var sensordata = this.sensordata; + for (var key in sensordata) { + handler.write(key, sensordata[key]); + } +}; + +// Web Socket 데이터 처리 +Module.prototype.handleRemoteData = function(handler) { + var motordata = this.motordata; + var newValue; + + // if(handler.e(ALTINO.IR)) { + // newValue = handler.read(ALTINO.IR); + + // if (motordata.ir != newValue) { + // motordata.ir = newValue; + // } + // } + + if (handler.e(ALTINO.RIGHT_WHEEL)) { + newValue = handler.read(ALTINO.RIGHT_WHEEL); + var dir = true; + if (newValue < 0) dir = false; + + newValue = Math.abs(newValue); + + if (newValue > 1000) newValue = 1000; + + if(dir == false) newValue = ~newValue; + + if (motordata.rightmotor != newValue) { + motordata.rightmotor = newValue; + } + console.log(newValue); + + } + + if (handler.e(ALTINO.LEFT_WHEEL)) { + newValue = handler.read(ALTINO.LEFT_WHEEL); + var dir = true; + if (newValue < 0) dir = false; + + newValue = Math.abs(newValue); + + if (newValue > 1000) newValue = 1000; + + if(dir == false) newValue = ~newValue; + + if (motordata.leftmotor != newValue) { + motordata.leftmotor = newValue; + } + + } + + if (handler.e(ALTINO.STEERING)) { + newValue = handler.read(ALTINO.STEERING); + + if(newValue > 127) newValue = 127; + if(newValue < -127) newValue = -127; + + if (motordata.steering != newValue) { + motordata.steering = newValue; + } + } + + if (handler.e(ALTINO.ASCII)) { + newValue = handler.read(ALTINO.ASCII); + if (motordata.ascii != newValue) { + motordata.ascii = newValue; + } + } + + if (handler.e(ALTINO.LED1)) { + newValue = handler.read(ALTINO.LED1); + if (motordata.led1 != newValue) { + motordata.led1 = newValue; + } + } + + if (handler.e(ALTINO.LED2)) { + newValue = handler.read(ALTINO.LED2); + if (motordata.led2 != newValue) { + motordata.led2 = newValue; + } + } + + if (handler.e(ALTINO.DOT1)) { + newValue = handler.read(ALTINO.DOT1); + if (motordata.dot1 != newValue) { + motordata.dot1 = newValue; + } + } + if (handler.e(ALTINO.DOT2)) { + newValue = handler.read(ALTINO.DOT2); + if (motordata.dot2 != newValue) { + motordata.dot2 = newValue; + } + } + if (handler.e(ALTINO.DOT3)) { + newValue = handler.read(ALTINO.DOT3); + if (motordata.dot3 != newValue) { + motordata.dot3 = newValue; + } + } + if (handler.e(ALTINO.DOT4)) { + newValue = handler.read(ALTINO.DOT4); + if (motordata.dot4 != newValue) { + motordata.dot4 = newValue; + } + } + if (handler.e(ALTINO.DOT5)) { + newValue = handler.read(ALTINO.DOT5); + if (motordata.dot5 != newValue) { + motordata.dot5 = newValue; + } + } + if (handler.e(ALTINO.DOT6)) { + newValue = handler.read(ALTINO.DOT6); + if (motordata.dot6 != newValue) { + motordata.dot6 = newValue; + } + } + if (handler.e(ALTINO.DOT7)) { + newValue = handler.read(ALTINO.DOT7); + if (motordata.dot7 != newValue) { + motordata.dot7 = newValue; + } + } + if (handler.e(ALTINO.DOT8)) { + newValue = handler.read(ALTINO.DOT8); + if (motordata.dot8 != newValue) { + motordata.dot8 = newValue; + } + } + + if (handler.e(ALTINO.NOTE)) { + newValue = handler.read(ALTINO.NOTE); + if (motordata.note != newValue) { + motordata.note = newValue; + } + } + +}; + + +// 하드웨어에 전달할 데이터 +Module.prototype.requestLocalData = function() { + var motordata = this.motordata; + var tx_d = this.tx_d; + + tx_d[0] = 0x02; // Start + tx_d[1] = 20; // Data length + tx_d[2] = 0; // Checksum + tx_d[3] = 0x01; // Comm ID H + tx_d[4] = 0x01; // Comm ID L + tx_d[5] = motordata.steering; // Steering + tx_d[6] = (motordata.rightmotor & 0xFF00) >> 8; // Drive Right H + tx_d[7] = motordata.rightmotor & 0xFF; // Drive Right L + tx_d[8] = (motordata.leftmotor & 0xFF00) >> 8; // Drive Left H + tx_d[9] = motordata.leftmotor & 0xFF; // Drive Left L + tx_d[10] = motordata.ascii; // Dot Matrix Mode + tx_d[11] = motordata.dot1; // Dotmatrix Line 0 + tx_d[12] = motordata.dot2; // Dotmatrix Line 1 + tx_d[13] = motordata.dot3; // Dotmatrix Line 2 + tx_d[14] = motordata.dot4; // Dotmatrix Line 3 + tx_d[15] = motordata.dot5; // Dotmatrix Line 4 + tx_d[16] = motordata.dot6; // Dotmatrix Line 5 + tx_d[17] = motordata.dot7; // Dotmatrix Line 6 + tx_d[18] = motordata.dot8; // Dotmatrix Line 7 + tx_d[19] = motordata.note; // Buzzer + tx_d[20] = motordata.led1; // Led H + tx_d[21] = motordata.led2; // Led L + tx_d[22] = 0; + tx_d[23] = 0; + tx_d[24] = 0; + tx_d[25] = 0x03; // End + + + var checksum = 0; + for(var i = 3; i < 25; i++){ + checksum += tx_d[i]; + } + + tx_d[2] = checksum & 0xFF; + + console.log(motordata.rightmotor); + return tx_d; +}; + +Module.prototype.reset = function () { +}; + +module.exports = new Module(); + diff --git a/app/modules/altino_neo.json b/app/modules/altino_neo.json new file mode 100644 index 0000000000..1ca51eda1a --- /dev/null +++ b/app/modules/altino_neo.json @@ -0,0 +1,22 @@ +{ + "id": "180401", + "name": { + "en": "Altino Neo", + "ko": "알티노 네오" + }, + "category": "robot", + "platform": ["win32", "darwin"], + "icon": "altino_neo.png", + "module": "altino_neo.js", + "url": "http://saeon.co.kr/", + "email": "saeon@saeon.co.kr", + "reconnect": true, + "selectPort": true, + "hardware": { + "type": "bluetooth", + "control": "slave", + "vendor": "Microsoft", + "duration": 100, + "baudRate": 115200 + } +} diff --git a/app/modules/altino_neo.png b/app/modules/altino_neo.png new file mode 100644 index 0000000000..e6e03128fb Binary files /dev/null and b/app/modules/altino_neo.png differ diff --git a/build/entry-hw.nsi b/build/entry-hw.nsi index a44325abf7..86b29e1f9d 100644 --- a/build/entry-hw.nsi +++ b/build/entry-hw.nsi @@ -14,7 +14,7 @@ !define PRODUCT_NAME "Entry_HW" !define PROTOCOL_NAME "entryhw" !define APP_NAME "Entry_HW.exe" -!define PRODUCT_VERSION "1.9.69" +!define PRODUCT_VERSION "1.9.72" !define PRODUCT_PUBLISHER "EntryLabs" !define PRODUCT_WEB_SITE "https://www.playentry.org/" diff --git a/package.json b/package.json index d81237b39f..aef83505e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "entry-hw", - "version": "1.9.69", + "version": "1.9.72", "description": "엔트리 하드웨어 연결 프로그램", "author": "EntryLabs", "main": "./app/src/index.bundle.js",