From c63fa018f5618951ab3bcd7c2aec923d7575ad3d Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Sat, 23 Aug 2014 23:59:49 +0200 Subject: [PATCH 001/660] Improved documentation and minor fixes removed examples compiled with outdated MySensors protocol and instead included documentation how to add self-compiled sketches --- Bootloader/Readme.md | 1 + NodeJsController/BlinkGreen.hex | 71 - NodeJsController/BlinkRed.hex | 71 - .../DallasTemperatureSensor.cpp.hex | 1222 ----------------- .../DallasTemperatureSensor.ino | 69 - NodeJsController/NodeJsController.js | 4 +- NodeJsController/{Readme.html => Readme.md} | 19 +- 7 files changed, 12 insertions(+), 1445 deletions(-) create mode 100644 Bootloader/Readme.md delete mode 100644 NodeJsController/BlinkGreen.hex delete mode 100644 NodeJsController/BlinkRed.hex delete mode 100644 NodeJsController/DallasTemperatureSensor.cpp.hex delete mode 100644 NodeJsController/DallasTemperatureSensor/DallasTemperatureSensor.ino rename NodeJsController/{Readme.html => Readme.md} (91%) diff --git a/Bootloader/Readme.md b/Bootloader/Readme.md new file mode 100644 index 0000000..810b16a --- /dev/null +++ b/Bootloader/Readme.md @@ -0,0 +1 @@ +See NodeJsController/Readme.md for usage instructions... \ No newline at end of file diff --git a/NodeJsController/BlinkGreen.hex b/NodeJsController/BlinkGreen.hex deleted file mode 100644 index 00c3de6..0000000 --- a/NodeJsController/BlinkGreen.hex +++ /dev/null @@ -1,71 +0,0 @@ -:100000000C9461000C947E000C947E000C947E0095 -:100010000C947E000C947E000C947E000C947E0068 -:100020000C947E000C947E000C947E000C947E0058 -:100030000C947E000C947E000C947E000C947E0048 -:100040000C949A000C947E000C947E000C947E001C -:100050000C947E000C947E000C947E000C947E0028 -:100060000C947E000C947E00000000002400270009 -:100070002A0000000000250028002B0000000000DE -:1000800023002600290004040404040404040202DA -:100090000202020203030303030301020408102007 -:1000A0004080010204081020010204081020000012 -:1000B0000007000201000003040600000000000029 -:1000C000000011241FBECFEFD8E0DEBFCDBF11E08E -:1000D000A0E0B1E0E4E5F4E002C005900D92A030AC -:1000E000B107D9F711E0A0E0B1E001C01D92A9303D -:1000F000B107E1F70E9418020C9428020C9400004A -:1001000087E061E00E94C4016AEF70E080E090E067 -:100110000E941D0187E060E00E94C4016AEF70E068 -:1001200080E090E00E941D01089587E061E00E9458 -:10013000850108951F920F920FB60F9211242F93ED -:100140003F938F939F93AF93BF93809104019091BE -:100150000501A0910601B0910701309108010196B7 -:10016000A11DB11D232F2D5F2D3720F02D57019696 -:10017000A11DB11D209308018093040190930501F6 -:10018000A0930601B09307018091000190910101B5 -:10019000A0910201B09103010196A11DB11D8093B0 -:1001A000000190930101A0930201B0930301BF915C -:1001B000AF919F918F913F912F910F900FBE0F9014 -:1001C0001F901895789484B5826084BD84B5816051 -:1001D00084BD85B5826085BD85B5816085BDEEE64F -:1001E000F0E0808181608083E1E8F0E0108280812E -:1001F00082608083808181608083E0E8F0E080819C -:1002000081608083E1EBF0E0808184608083E0EBBB -:10021000F0E0808181608083EAE7F0E080818460A3 -:1002200080838081826080838081816080838081FF -:10023000806880831092C1000895EF92FF920F931F -:100240001F93CF93DF937B018C013FB7F89480918C -:10025000000190910101A0910201B091030126B526 -:10026000A89B05C02F3F19F00196A11DB11D3FBFEE -:10027000BA2FA92F982F8827820F911DA11DB11D7C -:1002800052E0880F991FAA1FBB1F5A95D1F7EC01A6 -:1002900030C00E9427023FB7F894809100019091EE -:1002A0000101A0910201B091030126B5A89B05C0F0 -:1002B0002F3F19F00196A11DB11D3FBFBA2FA92FE5 -:1002C000982F8827820F911DA11DB11D32E0880F44 -:1002D000991FAA1FBB1F3A95D1F78C1B9D0B885EF7 -:1002E0009340B8F20894E108F10801091109C851D6 -:1002F000DC4FE114F1040105110559F6DF91CF91AE -:100300001F910F91FF90EF900895CF93DF93482FA7 -:1003100050E0CA0186569F4FFC0134914A575F4F07 -:10032000FA018491882369F190E0880F991FFC01FC -:10033000E859FF4FA591B491FC01EE58FF4FC591CC -:10034000D491662351F42FB7F8948C91932F909504 -:1003500089238C93888189230BC0623061F42FB785 -:10036000F8948C91932F909589238C938881832B7B -:1003700088832FBF06C09FB7F8948C91832B8C93F2 -:100380009FBFDF91CF910895482F50E0CA01825559 -:100390009F4FFC012491CA0186569F4FFC01949106 -:1003A0004A575F4FFA013491332309F440C02223A6 -:1003B00051F1233071F0243028F42130A1F02230A3 -:1003C00011F514C02630B1F02730C1F02430D9F433 -:1003D00004C0809180008F7703C0809180008F7D62 -:1003E0008093800010C084B58F7702C084B58F7D64 -:1003F00084BD09C08091B0008F7703C08091B000A8 -:100400008F7D8093B000E32FF0E0EE0FFF1FEE58DA -:10041000FF4FA591B4912FB7F894662321F48C91E6 -:100420009095892302C08C91892B8C932FBF0895BE -:10043000CF93DF930E94E2000E949500C0E0D0E0DD -:100440000E9480002097E1F30E940000F9CF0895F8 -:04045000F894FFCF4E -:00000001FF diff --git a/NodeJsController/BlinkRed.hex b/NodeJsController/BlinkRed.hex deleted file mode 100644 index 3f2c259..0000000 --- a/NodeJsController/BlinkRed.hex +++ /dev/null @@ -1,71 +0,0 @@ -:100000000C9461000C947E000C947E000C947E0095 -:100010000C947E000C947E000C947E000C947E0068 -:100020000C947E000C947E000C947E000C947E0058 -:100030000C947E000C947E000C947E000C947E0048 -:100040000C949A000C947E000C947E000C947E001C -:100050000C947E000C947E000C947E000C947E0028 -:100060000C947E000C947E00000000002400270009 -:100070002A0000000000250028002B0000000000DE -:1000800023002600290004040404040404040202DA -:100090000202020203030303030301020408102007 -:1000A0004080010204081020010204081020000012 -:1000B0000007000201000003040600000000000029 -:1000C000000011241FBECFEFD8E0DEBFCDBF11E08E -:1000D000A0E0B1E0E4E5F4E002C005900D92A030AC -:1000E000B107D9F711E0A0E0B1E001C01D92A9303D -:1000F000B107E1F70E9418020C9428020C9400004A -:1001000086E061E00E94C4016AEF70E080E090E068 -:100110000E941D0186E060E00E94C4016AEF70E069 -:1001200080E090E00E941D01089586E061E00E9459 -:10013000850108951F920F920FB60F9211242F93ED -:100140003F938F939F93AF93BF93809104019091BE -:100150000501A0910601B0910701309108010196B7 -:10016000A11DB11D232F2D5F2D3720F02D57019696 -:10017000A11DB11D209308018093040190930501F6 -:10018000A0930601B09307018091000190910101B5 -:10019000A0910201B09103010196A11DB11D8093B0 -:1001A000000190930101A0930201B0930301BF915C -:1001B000AF919F918F913F912F910F900FBE0F9014 -:1001C0001F901895789484B5826084BD84B5816051 -:1001D00084BD85B5826085BD85B5816085BDEEE64F -:1001E000F0E0808181608083E1E8F0E0108280812E -:1001F00082608083808181608083E0E8F0E080819C -:1002000081608083E1EBF0E0808184608083E0EBBB -:10021000F0E0808181608083EAE7F0E080818460A3 -:1002200080838081826080838081816080838081FF -:10023000806880831092C1000895EF92FF920F931F -:100240001F93CF93DF937B018C013FB7F89480918C -:10025000000190910101A0910201B091030126B526 -:10026000A89B05C02F3F19F00196A11DB11D3FBFEE -:10027000BA2FA92F982F8827820F911DA11DB11D7C -:1002800052E0880F991FAA1FBB1F5A95D1F7EC01A6 -:1002900030C00E9427023FB7F894809100019091EE -:1002A0000101A0910201B091030126B5A89B05C0F0 -:1002B0002F3F19F00196A11DB11D3FBFBA2FA92FE5 -:1002C000982F8827820F911DA11DB11D32E0880F44 -:1002D000991FAA1FBB1F3A95D1F78C1B9D0B885EF7 -:1002E0009340B8F20894E108F10801091109C851D6 -:1002F000DC4FE114F1040105110559F6DF91CF91AE -:100300001F910F91FF90EF900895CF93DF93482FA7 -:1003100050E0CA0186569F4FFC0134914A575F4F07 -:10032000FA018491882369F190E0880F991FFC01FC -:10033000E859FF4FA591B491FC01EE58FF4FC591CC -:10034000D491662351F42FB7F8948C91932F909504 -:1003500089238C93888189230BC0623061F42FB785 -:10036000F8948C91932F909589238C938881832B7B -:1003700088832FBF06C09FB7F8948C91832B8C93F2 -:100380009FBFDF91CF910895482F50E0CA01825559 -:100390009F4FFC012491CA0186569F4FFC01949106 -:1003A0004A575F4FFA013491332309F440C02223A6 -:1003B00051F1233071F0243028F42130A1F02230A3 -:1003C00011F514C02630B1F02730C1F02430D9F433 -:1003D00004C0809180008F7703C0809180008F7D62 -:1003E0008093800010C084B58F7702C084B58F7D64 -:1003F00084BD09C08091B0008F7703C08091B000A8 -:100400008F7D8093B000E32FF0E0EE0FFF1FEE58DA -:10041000FF4FA591B4912FB7F894662321F48C91E6 -:100420009095892302C08C91892B8C932FBF0895BE -:10043000CF93DF930E94E2000E949500C0E0D0E0DD -:100440000E9480002097E1F30E940000F9CF0895F8 -:04045000F894FFCF4E -:00000001FF diff --git a/NodeJsController/DallasTemperatureSensor.cpp.hex b/NodeJsController/DallasTemperatureSensor.cpp.hex deleted file mode 100644 index a714a35..0000000 --- a/NodeJsController/DallasTemperatureSensor.cpp.hex +++ /dev/null @@ -1,1222 +0,0 @@ -:100000000C94AE020C94311F0C945E1F0C94D6021B -:100010000C94D6020C94D6020C9455140C94D6026F -:100020000C94D6020C94D6020C94D6020C94D602F0 -:100030000C94D6020C94D6020C94D6020C94D602E0 -:100040000C948B1F0C94D6020C9461220C94E42225 -:100050000C94D6020C94D6020C94D6020C94D602C0 -:100060000C94D6020C94D602303B303B25643B25E1 -:10007000643B0072643D636C6561720A0069643DB3 -:1000800025640A0066756C6C0A006E6577207061E5 -:1000900072656E743D25642C20643D25640A0076EB -:1000A000657273696F6E206D69736D61746368004A -:1000B000726561643A2025642D25642D25642073C2 -:1000C0003D25642C633D25642C743D25642C70749F -:1000D0003D25642C6C3D25643A25730A0073656EDA -:1000E000643A2025642D25642D25642D2564207314 -:1000F0003D25642C633D25642C743D25642C70746F -:100100003D25642C6C3D25642C73743D25733A2584 -:10011000730A00726571206E6F64652069640A005D -:10012000636865636B2077697265730A00257320C5 -:10013000737461727465642C2069642025640A00FC -:100140000001020304050A0B0C0D0E0F111213140B -:100150001516A702AD02B302BB02C402CE02D7023B -:10016000DE02E602ED02F402FC02504120506F77FD -:10017000657209203D2025530D0A00435243204C4F -:10018000656E67746809203D2025530D0A004D6F88 -:1001900064656C0909203D2025530D0A00446174F3 -:1001A00061205261746509203D2025530D0A0044E9 -:1001B000594E50442F4645415455524500434F4EE9 -:1001C0004649470052465F53455455500052465FDA -:1001D000434800454E5F52584144445200454E5FEB -:1001E00041410052585F50575F50302D36005458EF -:1001F0005F414444520052585F414444525F503280 -:100200002D350052585F414444525F50302D31002B -:100210000D0A00253032780020307800255309255A -:1002200063203D000D0A002030782530327800250B -:1002300053092563203D004F4253455256455F54B4 -:10024000583D253032783A20504F4C535F434E543E -:100250003D2578204152435F434E543D25780D0A99 -:10026000005354415455530909203D20307825301E -:1002700032782052585F44523D25782054585F44CC -:10028000533D2578204D41585F52543D25782052EA -:10029000585F505F4E4F3D25782054585F46554C6F -:1002A0004C3D25780D0A00314D42505300324D42ED -:1002B0005053003235304B425053006E5246323468 -:1002C0004C3031006E524632344C30312B00446990 -:1002D0007361626C65640038206269747300313642 -:1002E00020626974730050415F4D494E0050415F78 -:1002F0004C4F570050415F484947480050415F4DBF -:10030000415800005EBCE2613FDD83C29C7E20A3B9 -:10031000FD1F419DC3217FFCA2401E5F01E3BD3E46 -:100320006082DC237D9FC1421CFEA0E1BF5D038093 -:10033000DE3C62BEE0025CDF81633D7C22C09E1D2C -:1003400043A1FF4618FAA427799BC584DA3866E5ED -:10035000BB5907DB856739BAE406581947A5FB780E -:1003600026C49A653BD987045AB8E6A7F91B45C647 -:10037000987A24F8A6441A99C7257B3A6486D85BF4 -:1003800005E7B98CD2306EEDB3510F4E10F2AC2FA1 -:100390007193CD114FADF3702ECC92D38D6F31B2DE -:1003A000EC0E50AFF1134DCE90722C6D33D18F0CFB -:1003B00052B0EE326C8ED0530DEFB1F0AE4C1291C4 -:1003C000CF2D73CA947628ABF517490856B4EA695D -:1003D00037D58B5709EBB536688AD495CB2977F496 -:1003E000AA4816E9B7550B88D6346A2B7597C94ABF -:1003F00014F6A8742AC896154BA9F7B6E80A54D77C -:10040000896B3500000000240027002A000000004E -:1004100000250028002B00000000002300260029F2 -:10042000000404040404040404020202020202039D -:1004300003030303030102040810204080010204A7 -:10044000081020010204081020000000070002012B -:100450000000030406000000000000000000407AD5 -:1004600010F35A00A0724E18090010A5D4E800003D -:10047000E87648170000E40B54020000CA9A3B00DB -:100480000000E1F505000080969800000040420F52 -:10049000000000A08601000000102700000000E816 -:1004A00003000000006400000000000A00000000DB -:1004B000000100000000002C76D888DC674F08237C -:1004C000DFC1DFAE59E1B1B796E5E3E453C63AE6E2 -:1004D00051997696E8E6C28426EB898C9B62ED40C2 -:1004E0007C6FFCEFBC9C9F40F2BAA56FA5F4900511 -:1004F0005A2AF75C936B6CF9676DC11BFCE0E40D45 -:1005000047FEF520E6B500D0ED902E030094357738 -:10051000050080841E080000204E0A000000C80C60 -:10052000333333330F986E12831141EF8D211489C9 -:100530003BE65516CFFEE6DB18D1844B381BF77C23 -:100540001D901DA4BBE424203284725E228100C968 -:10055000F124ECA1E53D27003F09972211241FBE9D -:10056000CFEFD8E0DEBFCDBF11E0A0E0B1E0E4EE18 -:10057000FBE402C005900D92A036B107D9F713E055 -:10058000A0E6B1E001C01D92A930B107E1F715E086 -:10059000CCE5D5E004C02297FE010E94A125C83514 -:1005A000D107C9F70E940A230C94F0250C9400008F -:1005B000EF92FF920F931F93F22FF02E47FD02C090 -:1005C000E4E001C0E4E1242F332727FD309537FF15 -:1005D00003C0309521953F4F4F2D512F0F2FEE2EF9 -:1005E0000E9455068F2D912F1F910F91FF90EF9034 -:1005F0000895FC0188279927E89421912032E9F396 -:10060000293010F02E30C8F32B3241F02D3239F45E -:10061000689404C00E94DA03820F911D2191205337 -:100620002A30C0F31EF4909581959F4F08951F9333 -:10063000FC0199278827BC01E89411911032E9F355 -:10064000193010F01E30C8F31B3251F01D3249F43E -:10065000689406C00E94C503610F711D811D911D24 -:10066000119110531A30B0F33EF490958095709527 -:1006700061957F4F8F4F9F4F1F910895FB01DC01C4 -:1006800001900D920020E1F70895FB01DC0141503B -:10069000504048F001900D920020C9F701C01D9212 -:1006A00041505040E0F70895A0E0B0E0EAE5F3E003 -:1006B0000C94C3257C01EB018A01690109C0CE01BC -:1006C0002196F6010995F70181937F0101501040B1 -:1006D00001151105A1F7CDB7DEB7E8E00C94DF25D1 -:1006E000FB019F01E8944230C4F04532B4F44A3033 -:1006F00029F497FB1EF4909581959F4F642F7727DF -:100700000E94A525805D8A330CF0895D8193CB0121 -:100710000097A1F716F45DE251931082C9010C9481 -:10072000A508FA01CF93FF93EF93223044F12532CD -:1007300034F5C22FE894CA3049F497FB3EF4909503 -:100740008095709561957F4F8F4F9F4F2C2F33274A -:1007500044275527FF93EF930E947D25EF91FF914A -:10076000605D6A330CF0695D6193B901CA01605044 -:1007700070408040904051F716F4CDE2C193108252 -:100780008F919F91CF910C94A508592F482F372F07 -:10079000262F660F771F881F991F660F771F881FE8 -:1007A000991F620F731F841F951F660F771F881F85 -:1007B000991F08957AE0979F902D879F802D910D26 -:1007C00011240895FA01CF93FF93EF932230CCF0D8 -:1007D0002532BCF4C22F2C2F332744275527FF93F3 -:1007E000EF930E947D25EF91FF91605D6A330CF0DD -:1007F000695D6193B901CA016050704080409040CA -:1008000051F710828F919F91CF910C94A508FB0115 -:100810009F01423074F0453264F4642F77270E94C0 -:10082000A525805D8A330CF0895D8193CB0100970B -:10083000A1F71082C9010C94A508AEE0B0E0E3E294 -:10084000F4E00C94C7250D891E898F89988D97FF38 -:1008500002C080E090E801979E838D831A8309830C -:100860008EE08C839E01255E3F4FCE010196698DFF -:100870007A8DA9010E9478044D815E8157FD0AC0DE -:100880002F813885421753070CF49A01020F131F6A -:10089000F80110822E96E4E00C94E325AEE0B0E07F -:1008A000E4E5F4E00C94C7258C0177FF02C060E01A -:1008B00070E8615070407E836D831A8309838EE0F7 -:1008C0008C83CE010196BA01A9010E9478042D8182 -:1008D0003E8137FD09C0EF81F8852E173F070CF4E4 -:1008E000F901E00FF11F10822E96E4E00C94E3254D -:1008F000ABE0B0E0EEE7F4E00C94B9253C012B014D -:100900005A01FC0117821682838181FD03C06FEFBB -:100910007FEFC6C19AE0892E1E010894211C311C6C -:10092000F3012381F20123FD859123FF81912F01A2 -:10093000882309F4B2C1853239F423FD859123FF60 -:1009400081912F01853229F490E0B3010E94B5080E -:10095000E7CF982FFF24EE249924FFE1FF15D0F074 -:100960009B3269F09C3228F4903259F0933291F422 -:100970000EC09D3249F0903369F441E024C052E04A -:10098000F52A84E0F82A28C098E0F92A25C0E0E199 -:10099000FE2A22C0F7FC29C0892F80538A3070F4C8 -:1009A000F6FE05C0989C902C1124980E15C0E89C6A -:1009B000E02C1124E80EF0E2FF2A0EC09E3229F44A -:1009C000F6FC6BC140E4F42A07C09C3619F450E8E9 -:1009D000F52A02C0983649F4F20123FD959123FFD0 -:1009E00091912F01992309F0B8CF892F8554833035 -:1009F00018F08052833038F444E050E0A40EB51E65 -:100A00005FE359830FC0933631F0933779F0933514 -:100A100009F056C020C0F5018081898342E050E092 -:100A2000A40EB51E610101E010E012C0F501C08006 -:100A3000D180F6FC03C06FEF7FEF02C0692D70E03C -:100A400042E050E0A40EB51EC6010E949A088C0137 -:100A50005FE7F52214C0F501C080D180F6FC03C029 -:100A60006FEF7FEF02C0692D70E042E050E0A40E0E -:100A7000B51EC6010E948F088C0150E8F52AF3FECE -:100A800007C01AC080E290E0B3010E94B508EA9462 -:100A90008E2D90E008171907A8F30EC0F601F7FC99 -:100AA0008591F7FE81916F0190E0B3010E94B50836 -:100AB000E110EA94015010400115110579F7EAC0E0 -:100AC000943611F0993669F5F7FE08C0F5012081DA -:100AD00031814281538184E090E00AC0F501808138 -:100AE00091819C01442737FD4095542F82E090E08E -:100AF000A80EB91E9FE6F92257FF09C050954095F0 -:100B0000309521953F4F4F4F5F4FE0E8FE2ACA01D5 -:100B1000B901A1012AE030E00E94E108D82ED218E4 -:100B200040C0953729F41F2D1F7E2AE030E01DC0FC -:100B30001F2D197F9F3661F0903720F4983509F00A -:100B4000ACC00FC0903739F0983709F0A6C004C088 -:100B500028E030E00AC0106114FD146020E130E0AC -:100B600004C014FD166020E132E017FF08C0F50153 -:100B7000608171818281938144E050E008C0F50179 -:100B800080819181BC0180E090E042E050E0A40EC1 -:100B9000B51EA1010E94E108D82ED2188FE7F82EC9 -:100BA000F122F6FE0BC05EEFF522D91438F4F4FE04 -:100BB00007C0F2FC05C08FEEF82202C01D2D01C057 -:100BC000192DF4FE0DC0FE01ED0DF11D8081803365 -:100BD00019F499EEF92208C01F5FF2FE05C003C0A8 -:100BE0008F2D867809F01F5F0F2DF3FC14C0F0FEE7 -:100BF0000FC01E1510F09D2C0BC09D2C9E0C911A41 -:100C00001E2D06C080E290E0B3010E94B5081F5F70 -:100C10001E15C0F304C01E1510F4E11A01C0EE2425 -:100C200004FF0FC080E390E0B3010E94B50802FF0B -:100C30001DC001FD03C088E790E00EC088E590E08C -:100C40000BC0802F867891F001FF02C08BE201C0BB -:100C500080E2F7FC8DE290E0B3010E94B50806C087 -:100C600080E390E0B3010E94B5089A94D914C0F3D0 -:100C7000DA94F101ED0DF11D808190E0B3010E9445 -:100C8000B508DD20A9F706C080E290E0B3010E941C -:100C9000B508EA94EE20C1F743CEF301668177816F -:100CA000CB012B96E2E10C94D525A9E0B0E0EBE571 -:100CB000F6E00C94BD256A01122FA02EBE2C2BE36A -:100CC000201718F42CE3922E02C0902E9394AE01BC -:100CD0004F5F5F4F27E0092D0E94B707BC01898154 -:100CE000E82EFF24C70189709070019711F4ADE2DE -:100CF00009C0B1FE02C0ABE205C0B0FC02C0A0E07A -:100D000001C0A0E2E3FE3BC0AA2311F423E001C02E -:100D100024E0211710F020E002C0121B212FEB2C41 -:100D2000B4FE02C0322F0AC0F601322F80E202C0A8 -:100D3000819331503323E1F7C20ED11CAA2319F05D -:100D4000F601A1936F01F6013196E2FE05C09EE423 -:100D5000D6019C9381E404C09EE6D6019C9381E673 -:100D600011968C9391833296DF01832F90E202C01B -:100D70009D9381508823E1F7E30FF11D40C0E2FE0F -:100D800042C0AA2311F423E001C024E0211710F08F -:100D900020E002C0121B212FEB2CB4FE02C0922FC8 -:100DA0000AC0F601922F80E202C0819391509923EC -:100DB000E1F7C20ED11CAA2319F0F601A1936F012D -:100DC000F6013196E2FE08C089E4D6018C938EE4E8 -:100DD00011968C9386E407C089E6D6018C938EE643 -:100DE00011968C9386E681833296DF01892F20E26B -:100DF00002C02D9381508823E1F7E90FF11D108285 -:100E00002EEF3FEFAFC0161617061CF041E050E082 -:100E100003C0AB014F5F5F4FAA2019F480E090E060 -:100E200003C08A2D90E0019620E030E0AA2311F063 -:100E300021E030E0240F351F280F391F812F90E06B -:100E40002817390714F020E002C0121B212F4B2D68 -:100E500050E0CA0180719070B4FC0DC0B3FC0BC0AF -:100E6000F601322F40E202C0419331503323E1F7C3 -:100E7000C20ED11C01C0322FAA2319F0F601A19392 -:100E80006F01892B11F0132F0AC0F601132F80E395 -:100E900002C0819311501123E1F7C30ED11C092D1B -:100EA000060FBA8090E1892E912C8E209F20E4FEBF -:100EB00004C0F1E3BF1609F40150101614F001E06C -:100EC00003C0093008F008E09B0177FF02C020E072 -:100ED00030E0CB010196821B930BFE013196E80FA7 -:100EE000F91F8EE2F82E3B01601A71088A2D90E0FE -:100EF00044275527481B590B8FEF2F3F380719F40C -:100F0000D601FD926D01621773072CF0621673060D -:100F100014F4808101C080E32150304031962417C1 -:100F2000350724F0D6018D936D01E6CF26173707DC -:100F300049F4B5E3BB1528F0BB1621F481149104E4 -:100F400009F481E3F6018193D601812F90E202C07A -:100F50009C93815011968823D9F7E10FF11D1082DF -:100F600020E030E0C9012996EEE00C94D925283024 -:100F700008F027E03327DA01990F311D87FD9160D2 -:100F800000966105710539F432602E5F3D9330E3C0 -:100F90002A95E1F708959F3F30F08038710561058B -:100FA00009F03C5F3C5F3D93913008F08068911DF3 -:100FB000DF93CF931F930F93FF92EF92192F987F98 -:100FC0009695E92F96959695E90FFF27E954FB4FE3 -:100FD00099273327EE24FF24A701E7010590089401 -:100FE000079428F4360FE71EF81E491F511D660F9F -:100FF000771F881F991F0694A1F70590079428F47E -:10100000E70EF81E491F561FC11D770F881F991F35 -:10101000661F0694A1F70590079428F4F80E491F5F -:10102000561FC71FD11D880F991F661F771F069473 -:10103000A1F70590079420F4490F561FC71FD81F2A -:10104000990F661F771F881F0694A9F78491109542 -:10105000177041F0D695C79557954795F794E79443 -:101060001A95C1F7EDE5F4E0689415901591359166 -:101070006591959105907FE27395E118F10A430B14 -:10108000560BC90BD009C0F7E10CF11E431F561FC8 -:10109000C91FD01D7EF4703311F48A95E6CFE89411 -:1010A000015030F0080F0AF40027021708F4202F2F -:1010B0002395022F7A3328F079E37D932A95E9F777 -:1010C00010C07D932A9589F6069497956795379574 -:1010D00017951794E118F10A430B560BC90BD00969 -:1010E00098F023957E9173957A3308F070E37C93A2 -:1010F0002013B8F77E9170617D9330F0839571E392 -:101100007D9370E32A95E1F71124EF90FF900F9102 -:101110001F91CF91DF91992787FD90950895FC014C -:101120000590615070400110D8F7809590958E0F12 -:101130009F1F0895FC016150704001900110D8F785 -:10114000809590958E0F9F1F0895DC01FC01672FFD -:1011500071917723E1F7329704C07C916D9370838E -:101160006291AE17BF07C8F308950F931F93CF93F3 -:10117000DF938C01EB018B8181FF1BC082FF0DC0CF -:101180002E813F818C819D812817390764F4E88185 -:10119000F9810193F983E88306C0E885F985802FFA -:1011A0000995892B31F48E819F8101969F838E83CF -:1011B00002C00FEF1FEFC801DF91CF911F910F9178 -:1011C0000895FA01AA27283051F1203181F1E894DD -:1011D0006F936E7F6E5F7F4F8F4F9F4FAF4FB1E02A -:1011E0003ED0B4E03CD0670F781F891F9A1FA11D25 -:1011F000680F791F8A1F911DA11D6A0F711D811D26 -:10120000911DA11D20D009F468943F912AE0269FEA -:1012100011243019305D3193DEF6CF010895462F49 -:101220004770405D4193B3E00FD0C9F7F6CF462F2A -:101230004F70405D4A3318F0495D31FD4052419393 -:1012400002D0A9F7EACFB4E0A69597958795779550 -:101250006795BA95C9F700976105710508959B01D7 -:10126000AC010A2E06945795479537952795BA9560 -:10127000C9F7620F731F841F951FA01D08950F9358 -:101280001F9300E611E0C80163E00E94C61D8EE6D0 -:1012900091E0B8010E941D1980E891E069E04AE000 -:1012A0000E94F71389E392E060E040E00E94410A67 -:1012B0001F910F910895CF92DF92EF92FF920F93BB -:1012C0001F93CF93DF9380E891E00E94870D8EE615 -:1012D00091E00E94121A87EFC82E81E0D82EC0E05C -:1012E000D0E056C080E891E00E94290B882331F0BD -:1012F0008EE691E06C2F0E94351B05C08EE691E0D2 -:101300006C2F0E945C1B20E030E040E251E40E9420 -:101310001A250E943724882777FD8095982F0E94F0 -:101320006A2420E030E040E251E40E94CF237B01B8 -:101330008C01F6016081718182819381A8019701FE -:101340000E94CB238823F9F0C801B70120E030E0E8 -:101350004EEF52EC0E94CB238823A9F089E392E060 -:101360006C2F0E94460AB801A70121E00E94550A8D -:10137000BC0180E891E040E00E942F12F601E0827B -:10138000F18202831383219684E090E0C80ED91E77 -:101390008091370290913802C817D90724F4C031E0 -:1013A000D10509F09FCF609140017091410180917A -:1013B0004201909143010E94262080E891E00E9422 -:1013C000870D609144017091450180E891E00E9491 -:1013D0008E0CDF91CF911F910F91FF90EF90DF90D6 -:1013E000CF900895AF92BF92CF92EF92FF920F935A -:1013F000CF93DF938EE691E00E946B1B80E891E033 -:1014000060E070E04FEF20E00FEFE3E0EE2EF12C14 -:101410005CE4C52E32E0A32EB12C0E94C11280E8FC -:1014200091E060E071E043E151E020E00E94BF11F3 -:101430008EE691E00E942B198093370210923802B9 -:10144000C0E0D0E008C080E891E06C2F46E020E0EA -:101450000E940D1221968091370290913802C81790 -:10146000D9071CF4C031D10571F7DF91CF910F91ED -:10147000FF90EF90CF90BF90AF900895FC01148241 -:101480000895FC011482668345830895FC016683F8 -:101490000895FC01808187708860808381818F70CE -:1014A000806181836783CF010895CF92DF92EF92AD -:1014B000FF920F931F937C01F7E0CF2ED12CC80E23 -:1014C000D91ECB01BA0142E086010E94D802F60182 -:1014D00001900020E9F73197EC19FD09EE0FEE0FAE -:1014E000EE0FD7018C918770E82BEC9311968C91BD -:1014F00011978F7011968C93C7011F910F91FF90D8 -:10150000EF90DF90CF900895CF93DF93EC01DB0154 -:101510000D900020E9F71197A61B4A2F50E09A0181 -:10152000B3E0220F331FBA95E1F788818770822BD1 -:10153000888389818F708983A93110F049E150E057 -:10154000CE0107960E944503CE01DF91CF91089509 -:10155000FC01818182958F7090E0009731F00197B6 -:1015600011F080E0089587810895CF0107960E94C9 -:10157000F9020895FC01818182958F7090E00097B7 -:1015800061F0059729F020E030E040E050E00EC027 -:10159000278130854185528509C0CF0107960E9479 -:1015A0001703AC01CB01DA019C01AD01B901CA01FD -:1015B0000895CF93DF93FC01EB01818182958F70B9 -:1015C00031F43796CB01BF010E943E0336C061154E -:1015D000710599F18330B9F0843028F4813041F0FD -:1015E000823059F508C08430A9F0853031F51CC02F -:1015F000878190E002C087819085BE014AE050E07B -:101600000E9470031AC0878190854AE050E00E94D2 -:10161000070413C06781708581859285AE012AE039 -:1016200030E00E94910309C06781708581859285B1 -:10163000AE012AE030E00E94E203CE01DF91CF91BB -:1016400008959C01F999FECF32BD21BDF89A80B56D -:101650000895FC0181890895EF92FF920F931F93E3 -:10166000DF93CF93CDB7DEB7CC52D1400FB6F8940D -:10167000DEBF0FBECDBFC95CDE4FE880F980C75327 -:10168000D140CB5CDE4FA881B981C553D14054967F -:101690008C91882389F1EDB7FEB73A970FB6F8948D -:1016A000FEBF0FBEEDBF31968E010F5F1F4FADB76E -:1016B000BEB712961C930E9311978BE291E0938321 -:1016C000828388E690E09583848383E090E097832B -:1016D000868389E090E0918780870E941D04EDB7A2 -:1016E000FEB73A960FB6F894FEBF0FBEEDBF88E680 -:1016F00092E0B8010E946223FE01E75CFE4FCB5CE2 -:10170000DE4FA881B981C553D14054968C919E017A -:101710002F5F3F4F882359F0C9016CE370E0A701A8 -:101720009F010E944E048AE08CAF1DAE07C0C90124 -:101730006BE271E0A7019F010E944E0488E692E0EF -:10174000BE016F5F7F4F0E94622388E692E00E9495 -:10175000EF21C45DDE4F0FB6F894DEBF0FBECDBFE4 -:10176000CF91DF911F910F91FF90EF900895CF934C -:10177000DF93EB010CC08AE592E069E070E040E0A5 -:1017800050E020E030E00E940714C054DF41809117 -:10179000480190914901892B89F08FE1C034D80725 -:1017A00054F7B3C08AE592E068E070E040E050E0B2 -:1017B00020E030E00E940714C05ADF4080914801C9 -:1017C00090914901892B81F087E0C03DD80764F0F2 -:1017D0008AE592E067E070E040E050E020E030E031 -:1017E0000E940714C05DD740809148019091490143 -:1017F000892B81F083E0C83ED80764F08AE592E047 -:1018000066E070E040E050E020E030E00E94071425 -:10181000C85ED3408091480190914901892B81F0A5 -:1018200081E0C43FD80764F08AE592E065E070E0AB -:1018300040E050E020E030E00E940714C45FD14057 -:101840008091480190914901892B79F0CA3FD105D7 -:1018500064F08AE592E064E070E040E050E020E06F -:1018600030E00E940714CA5FD040809148019091F7 -:101870004901892B79F0CD37D10564F08AE592E0F2 -:1018800063E070E040E050E020E030E00E940714A8 -:10189000C857D0408091480190914901892B71F03F -:1018A000C034D1055CF08AE592E062E070E040E08F -:1018B00050E020E030E00E940714EC97809148014E -:1018C00090914901892B71F0C032D1055CF08AE515 -:1018D00092E061E070E040E050E020E030E00E9403 -:1018E00007146E978091480190914901892B99F0D6 -:1018F00060978CF08AE592E060E070E040E050E0B4 -:1019000020E030E00E94071406C08FE0C03AD807FC -:101910000CF454CF47CFDF91CF910895EF92FF920F -:101920000F931F938C017B0188E692E00E94EF21C8 -:10193000C8010E942C1881E090E0909349018093A7 -:101940004801C801B7010E94B70B1F910F91FF908A -:10195000EF9008955F926F927F928F929F92AF92D5 -:10196000BF92CF92DF92EF92FF920F931F93CF938C -:10197000DF937C01562EEA01822E8881982E969460 -:1019800096949694D7011E969C919B83887F826043 -:101990008883DE2CCF2CC7010E941118C7010E943A -:1019A000411830E040E050E060E070E080E090E01E -:1019B000052DF1E03D3F08F4F0E0E1E0423E08F49F -:1019C000E0E031EEA32EAF0EE060F1E0593A08F40A -:1019D000F0E028EAB22EBE0EE1E0B8EABB1608F04D -:1019E000E0E0FE2BA1E0693A08F4A0E0BF2FB85573 -:1019F000E1E0B83A08F0E0E0AE2BF1E0772309F43B -:101A0000F0E0E1E0882309F4E0E08D2D9C2D1CEF4F -:101A100095014B2F5A2F6F2F7E2F0E945216892D22 -:101A200090E04A9714F040E202C0492D495F8D2DA5 -:101A30009C2DBE01282D0E940516682E8D2D9C2DF3 -:101A40000E945C18BA80AB809C808E8019817D805A -:101A50000881662029F497E1C92E91E0D92E04C0AF -:101A60008CE1C82E81E0D82EB701695A7F4FCE0194 -:101A70000E94D90AEDB7FEB77A970FB6F894FEBF69 -:101A80000FBEEDBF3196ADB7BEB71296FC92EE9287 -:101A900011972DED30E033832283B4821582A68224 -:101AA0001782508611869286138684861586212F8A -:101AB00030E02770307037872687708A118A129538 -:101AC0001F70128B138A069506950695048B158A4E -:101AD000D78AC68A918F808F0E942C0BEDB7FEB7F4 -:101AE0007A960FB6F894FEBF0FBEEDBF862DDF913C -:101AF000CF911F910F91FF90EF90DF90CF90BF900B -:101B0000AF909F908F907F906F905F9008954F92CD -:101B10005F926F927F928F929F92AF92BF92CF927D -:101B2000DF92EF92FF920F931F93DF93CF930F9269 -:101B3000CDB7DEB74C01582E492C8E010F5F1F4FD9 -:101B4000B8010E94F217882309F4D5C28981873031 -:101B500008F0D1C2C4010E940215482F65E1662E2B -:101B6000712C680C791CC401B3010E94F815C401E2 -:101B70006981A80121E00E949414D40155960C912A -:101B800006950695069510E0F401E00FF11F148EFE -:101B9000F401E788D08CC18CB38CF688A28CB40198 -:101BA000695A7F4FC3010E94D90A2DB73EB726510B -:101BB00030400FB6F8943EBF0FBE2DBFEDB7FEB755 -:101BC0003196ADB7BEB712969C928E92119720EBCC -:101BD00030E033832283E4821582D6821782C08666 -:101BE0001186B28613862F2D30E02770307035872E -:101BF0002487A6861786F2945FE0F522F08A118A80 -:101C0000138B028B958B848B0E942C0BF40185899E -:101C100087702DB73EB72A5E3F4F0FB6F8943EBF90 -:101C20000FBE2DBF8230B1F000D000D0ADB7BEB72F -:101C300012969C928E9211978FE990E014969C9345 -:101C40008E9313970E942C0B80E00F900F900F90B3 -:101C50000F9052C2F4012689022F0770128DE78877 -:101C6000F08C318D9289992379F1033069F5173021 -:101C700059F50E94D31F7370807090700E942620C7 -:101C8000D4011E968C911E9757968C935797599610 -:101C9000EC9259978FEF5B968C935B9788E05A96FE -:101CA0008C935A9756968C915697807F8360569660 -:101CB0008C935697C30150966C910E94490AAC01CF -:101CC000C4016E2D21E0F5C1F4018685381709F0B5 -:101CD000DBC123FF21C0D401D696759681E2019025 -:101CE0000D928150E1F7D401D7968C91D797877FD9 -:101CF000D7968C93D7971E968C911E97D8968C93D7 -:101D0000D89757968C915797DA968C93B4016A5C62 -:101D10007F4FC4010E945011F4018289882319F178 -:101D20008785F81601F12E2D30E081E790E0880ECE -:101D3000991ED401ED91FC918FE89FEF880E991EBA -:101D4000E20FF31F80818F1571F0F082F999FECFB9 -:101D50001FBA2D5F3F4F32BD21BDF0BC0FB6F894C6 -:101D6000FA9AF99A0FBE033009F081C1183009F0D0 -:101D700053C0D40154968C91882309F04DC0C301FF -:101D80000E94A80A482F282F30E0F401808990E0B3 -:101D90000197281739070CF0AEC14F5F408B278998 -:101DA0002787F999FECF1FBA81E090E092BD81BDEF -:101DB00020BD0FB6F894FA9AF99A0FBED401509646 -:101DC0003C91F999FECF1FBA82E090E092BD81BDAF -:101DD00030BD0FB6F894FA9AF99A0FBEEDB7FEB778 -:101DE00038970FB6F894FEBF0FBEEDBF3196ADB772 -:101DF000BEB712969C928E9211978AE890E09383D8 -:101E0000828324831582368317820E942C0B80E004 -:101E1000EDB7FEB73896A3C0EE2009F028C1163002 -:101E200009F4A3C0173038F4113009F40FC114308D -:101E300009F061C112C01A3009F4B0C01D3009F0B8 -:101E40005AC128E088E190E00FB6F894A8958093F5 -:101E500060000FBE20936000FFCFD4011E968C91CE -:101E60008F3F09F048C1C3010E94A80AF401868788 -:101E70008F3FA9F400D000D0ADB7BEB712969C92A8 -:101E80008E92119784E890E014969C938E9313970A -:101E90000E942C0B0F900F900F900F90FFCF282FC8 -:101EA00030E040E050E060E070E080E090E0E22E62 -:101EB00001E03D3F08F400E011E0423E08F410E08C -:101EC0000F511060E1E0593A08F4E0E01855F1E0F4 -:101ED000183A08F0F0E0EF2BF1E0693A08F4F0E08E -:101EE000BE2FB855E1E0B83A08F0E0E0FE2BA1E0E3 -:101EF000772309F4A0E0E1E0882309F4E0E0852DF0 -:101F0000942D61E04CEFF42E2B2F3F2F4A2F5E2FA4 -:101F10000E947317F4012685F999FECF1FBA12BCEF -:101F200011BC20BD0FB6F894FA9AF99A0FBE00D0F2 -:101F300000D000D0EDB7FEB73196ADB7BEB7129660 -:101F40009C928E9211978DE790E0938382832483F5 -:101F500015820E942C0B80E0EDB7FEB736960FB6C7 -:101F6000F894FEBF0FBEEDBFC7C0C3010E94A80A10 -:101F700020E08D3409F421E0D40151968C915197E1 -:101F8000821709F4B8C051962C93F999FECF1FBA65 -:101F900083E091E092BD81BD20BDA8C0F40182899B -:101FA000882309F4A8C0C3010E94A80A833409F059 -:101FB000A2C000D000D0ADB7BEB712969C928E9250 -:101FC000119783E790E014969C938E9313970E9449 -:101FD0002C0B20E030E00F900F900F900F90D40169 -:101FE000AF58BF4F9FEFED91FC911197E20FF31F98 -:101FF00080818F3F81F09083F999FECF1FBA2D5FCA -:102000003F4F32BD21BD2350304090BD0FB6F894F4 -:10201000FA9AF99A0FBE2F5F3F4F2230310519F718 -:10202000F4018685878B118E8FEF838F8AE0828FF4 -:102030008689807F8360868BC3016FE171E00E9497 -:10204000840ABC01C4010E94501155C023E730E04E -:10205000820E931ED4010D911C910115110509F4F6 -:102060004AC0C3010E94BA0AF801099544C0E5E7D5 -:10207000F0E08E0E9F1ED401ED91FC91309711F08F -:10208000C301099581E038C09923A9F18981813084 -:1020900091F584010F581F4FD801ED91FC91E30F8A -:1020A000F11D6081862F81508E3F30F4C401A30161 -:1020B00020E00E94AA0C1FC0C401F4016785A3019F -:1020C00020E00E94AA0C6E2D70E0D801ED91FC91E9 -:1020D000E60FF71F80818F1571F0F082F999FECF1E -:1020E0001FBA6D5F7F4F72BD61BDF0BC0FB6F89433 -:1020F000FA9AF99A0FBE80E00F90CF91DF911F916D -:102100000F91FF90EF90DF90CF90BF90AF909F9096 -:102110008F907F906F905F904F900895EF92FF9215 -:102120000F931F93CF93DF93EC010E94D31F7B018A -:102130008C0103C0CE010E94870D0E94D31F6E192F -:102140007F09800B910B605D77408040904090F359 -:10215000DF91CF911F910F91FF90EF900895EF9233 -:10216000FF920F931F938C0100591F4FF8011082AB -:10217000005710409FEFF801908B8685878B918FD9 -:10218000938F87E0828F8689807F8360868B75E15D -:10219000E72EF12CE00EF11EC7016FE171E00E9405 -:1021A000840AC8016FEFA70121E00E94AA0CC801B0 -:1021B0000E948E101F910F91FF90EF900895EF9263 -:1021C000FF920F931F93CF93DF93EC0100D000D0C9 -:1021D000EDB7FEB79283818383E191E0948383839B -:1021E0000E942C0B0F900F900F900F908E85282F30 -:1021F00030E040E050E060E070E080E090E0E22E0F -:1022000001E03D3F08F400E011E0423E08F410E038 -:102210000F511060E1E0593A08F4E0E01855F1E0A0 -:10222000183A08F0F0E0EF2BF1E0693A08F4F0E03A -:10223000BE2FB855E1E0B83A08F0E0E0FE2BA1E08F -:10224000772309F4A0E0E1E0882309F4E0E0CE017F -:1022500061E02CEFF22E2B2F3F2F4A2F5E2F0E9492 -:1022600073178E858F8B198E8FEF8B8F83E08A8FFC -:102270008E89807F83608E8BCE0145966FE171E001 -:102280000E94840ABC01CE010E945011CE010E941E -:102290008E10DF91CF911F910F91FF90EF900895D5 -:1022A0001F93CF93DF93EC01DB0120E011968C911B -:1022B00011978770833009F421E08E858F3F59F4A0 -:1022C000222329F015968C911597833021F0CE01A9 -:1022D0000E94DF102CC08A89882331F114969C91CA -:1022E0001497CF58DF4FE881F981C157D040E90FEB -:1022F000F11D6081862F81508E3F30F4992321F0AB -:10230000CE01AD0120E00DC0222371F015968C9115 -:102310001597843049F49F3F39F4CE016FEFAD013A -:1023200021E00E94AA0C27C08C89882311F080E04C -:1023300022C0CE016F85AD0120E00E94AA0C182FAB -:10234000882329F011E0C059DF4F188213C08B8910 -:10235000882351F0C059DF4F8881C057D040863064 -:1023600018F0CE010E94AF10FE01E059FF4F8081AE -:102370008F5F8083812FDF91CF911F910895FF920E -:102380000F931F93CF93DF93EC018A01F22E611517 -:102390007105E1F08E858F8B198E8FEF8B8F8BE01F -:1023A0008A8F30E02170307053E0220F331F5A952E -:1023B000E1F78E89807F8360822B8E8BCE014596DC -:1023C0000E94840ABC01CE010E9450110115110522 -:1023D000F1F08E858F8B198E8FEF8B8F8CE08A8F2B -:1023E0002F2D30E02170307043E0220F331F4A95CB -:1023F000E1F78E89807F8360822B8E8BCE0145969C -:10240000B8010E94840ABC01CE010E945011DF91E4 -:10241000CF911F910F91FF9008950F931F938C01FF -:10242000FC018685878B118E638F428F30E021708F -:10243000307063E0220F331F6A95E1F78689807F51 -:10244000822B868BC801459660E271E00E94840A67 -:10245000BC01C8010E9450111F910F910895DC0129 -:10246000FB011E968C911E97828350E04170507044 -:1024700083E0440F551F8A95E1F78181807F816059 -:10248000842B8183CD010E945011811181E0089538 -:102490000F931F938C0180E091E00E9419230F5845 -:1024A0001F4FF8018083918363E070E040E051E0CA -:1024B00021E23BE00E9454031F910F910895EF9297 -:1024C000FF920F931F93CF93DF93EC01E62EF42E30 -:1024D0008901C059DF4F1882C057D040CE010E94F9 -:1024E0009518CE010E947A14882389F400D000D078 -:1024F000EDB7FEB7D283C18380E291E094838383FA -:102500000E942C0B0F900F900F900F90FFCFCE01D9 -:1025100061E00E94EE15CE0162E040E00E940C17DF -:10252000CE010E943817CE016F2D0E941F16CE01DA -:102530006E2D0E94F316CE01B8010E94C216CE0184 -:1025400065E04FE00E94E415CE0162E070E00E9479 -:10255000A716CE010E945417CE0162E0EE24EA9441 -:102560002CEFF22E01EE18EA28EA30E040E050E0CD -:102570000E947317DF91CF911F910F91FF90EF9001 -:1025800008958F929F92AF92BF92CF92DF92EF9277 -:10259000FF920F931F93CF93DF93EC014B01D42E47 -:1025A000122F88E692E040E052EC61E070E026E015 -:1025B0000E9451211C8A1A8A112311F081E08A8B12 -:1025C000CB58DF4F99828882C557D0408A898823AB -:1025D00019F0CE010E944812CE01B7014C2D950191 -:1025E0000E945F12CE010E9660E070E043E050E082 -:1025F00021E23BE00E945403CE01419663E271E088 -:1026000041E050E021E23BE00E94540389898F3F82 -:1026100011F481E0898B0F3F19F00F871B8A02C0EC -:1026200081E08B8B8FEFD812DE868B89882331F087 -:102630008F858F3F19F4CE010E94AF108E858F3F9A -:1026400019F4CE010E94DF108A89882319F420E34F -:1026500031E002C027E331E0ADB7BEB718970FB63F -:10266000F894BEBF0FBEADBFEDB7FEB73196129660 -:10267000DC93CE9311978DE291E09383828335832F -:1026800024838E85868317820E942C0BDC2ECD2E10 -:102690008DB79EB708960FB6F8949EBF0FBE8DBF3C -:1026A0008E85282F30E040E050E060E070E080E070 -:1026B00090E0E22E01E03D3F08F400E011E0423EF0 -:1026C00008F410E00F511060E1E0593A08F4E0E03E -:1026D0001855F1E0183A08F0F0E0EF2BF1E0693A14 -:1026E00008F4F0E0BE2FB855E1E0B83A08F0E0E0B9 -:1026F000FE2BA1E0772309F4A0E0E1E0882309F4B0 -:10270000E0E08D2D9C2D60E04CEFF42E2B2F3F2F21 -:102710004A2F5E2F0E9473178E85282F30E040E0ED -:1027200050E060E070E080E090E0E22E01E03D3FAC -:1027300008F400E011E0423E08F410E00F51106090 -:10274000E1E0593A08F4E0E01855F1E0183A08F0F1 -:10275000F0E0EF2BF1E0693A08F4F0E0BE2FB85555 -:10276000E1E0B83A08F0E0E0FE2BA1E0772309F4BD -:10277000A0E0E1E0882309F4E0E08D2D9C2D61E0EC -:102780003CEFF32E2B2F3F2F4A2F5E2F0E94731703 -:102790008A89882311F441E101C042E1CE016FEF43 -:1027A00020E00E940D128E858F8B198E8FEF8B8FFC -:1027B00086E08A8F8E89807F83608E8BCE014596DE -:1027C0006F850E94490ABC01CE010E945011CE01C2 -:1027D0000E948E10DF91CF911F910F91FF90EF908B -:1027E000DF90CF90BF90AF909F908F9008950F9300 -:1027F0001F938C010E946914C80145960E943E0AED -:10280000C801C6960E943E0A1F910F910895411576 -:10281000510529F480917A008F7780937A006A308D -:102820007105B9F063FD02C0E8E001C0E8E2862F5F -:102830008770E82B88E190E00FB6F894A895809314 -:1028400060000FBEE0936000809160008064809320 -:102850006000232BA1F483B7817F846083BFF89449 -:1028600083B7816083BF85B7806685BF8F7D85BF55 -:102870007894889583B78E7F83BF78940EC083B792 -:10288000817F846083BFF89483B7816083BF78942D -:10289000889583B78E7F83BF7894452B29F48091E8 -:1028A0007A00806880937A0008951F920F920FB685 -:1028B0000F9211248F9388E10FB6F89480936000F3 -:1028C000109260000FBE8F910F900FBE0F901F905F -:1028D0001895FC01608341831282138280E2848315 -:1028E0001582168217821086118612861386148628 -:1028F00015860895FC0183810895FF920F931F931D -:102900008C01F62E81E00E94E71880E00E94F0180A -:1029100084E00E94F518F80181816F2D0E94CD207E -:102920001F910F91FF900895EF92FF920F931F93C5 -:10293000CF93DF93EC01162F042FF52EE22E60E0EB -:102940000E947D141770186A1EBD0DB407FEFDCFDE -:10295000802F9F2D9C01F9012E2D213208F020E2BD -:102960008EB508C080818EBD0DB407FEFDCF3196B7 -:102970008EB521502223B1F7CE0161E00E947D1473 -:10298000DF91CF911F910F91FF90EF900895CF931A -:10299000DF93EC0160E00E947D1480E58EBD0DB4F4 -:1029A00007FEFDCF8EB583E78EBD0DB407FEFDCFCC -:1029B0008EB5CE0161E00E947D14DF91CF91089524 -:1029C0001F93CF93DF93EC01162F60E00E947D14DC -:1029D0001EBD0DB407FEFDCF1EB5CE0161E00E9405 -:1029E0007D14812FDF91CF911F9108956FEF0E9489 -:1029F000E014089561EE0E94E014089562EE0E94D2 -:102A0000E01408951F93CF93DF93EC0160E00E94E0 -:102A10007D1480E68EBD0DB407FEFDCF8EB58FEF21 -:102A20008EBD0DB407FEFDCF1EB5CE0161E00E9444 -:102A30007D14113220F0CE010E94FE1410E0812F8F -:102A4000DF91CF911F910895EF92FF920F931F9303 -:102A5000CF93DF93EC01F62EE72E9C81142F941771 -:102A600008F4192F8D81882311F000E002C0092F8E -:102A7000011BCE0160E00E947D1481E68EBD0DB485 -:102A800007FEFDCF8F2D9E2D9C01F901FEB49FEF17 -:102A900007C09EBD0DB407FEFDCF8EB581931150CA -:102AA0001123B9F707C08EBD0DB407FEFDCF9EB54B -:102AB000015001C08FEF0023B1F7CE0161E00E9409 -:102AC0007D148F2DDF91CF911F910F91FF90EF908B -:102AD0000895DF92EF92FF920F931F93CF93DF93AE -:102AE000EC01E62ED72EF22E9C81142F941708F4B9 -:102AF000192F8D81882311F000E002C0092F011BDE -:102B0000CE0160E00E947D14FEBC0DB407FEFDCF37 -:102B10008E2D9D2D9C01F901FEB408C080818EBDD3 -:102B20000DB407FEFDCF31968EB511501123B1F7CC -:102B300006C01EBC0DB407FEFDCF8EB501500023AC -:102B4000C1F7CE0161E00E947D148F2DDF91CF91FE -:102B50001F910F91FF90EF90DF900895CF93DF9337 -:102B6000EC01222311F420EA01C020EBCE010E94E7 -:102B70006915888161E00E94CD20888160E00E9413 -:102B8000CD20DF91CF9108950F931F93CF93DF93C3 -:102B9000EC01162F042F60E00E947D141F7110625B -:102BA0001EBD0DB407FEFDCF1EB50EBD0DB407FE54 -:102BB000FDCF8EB5CE0161E00E947D14812FDF91A3 -:102BC000CF911F910F910895262F4F702295207F4E -:102BD000242B64E0422F0E94C4150895662319F047 -:102BE00061E04FE302C061E040E00E94C415089537 -:102BF0000F931F938C010E942415C80167E040E7E2 -:102C00000E94C4151F910F910895CF93DF93EC019B -:102C10000E94AE15CE010E94F6148073D9F3CE0146 -:102C200067E040E70E94C41584FD02C081E004C053 -:102C3000CE010E94FA1480E0DF91CF910895462FD3 -:102C4000603808F04FE765E00E94C4150895EF92E0 -:102C5000FF920F931F93CF93DF937C01162FEA010E -:102C6000022F60E00E947D141F7110621EBD0DB422 -:102C700007FEFDCF1EB508C088818EBD0DB407FECE -:102C8000FDCF21968EB501500023B1F7C70161E059 -:102C90000E947D14812FDF91CF911F910F91FF90A2 -:102CA000EF900895EF92FF920F931F93DF93CF93CE -:102CB000CDB7DEB728970FB6F894DEBF0FBECDBFF5 -:102CC0007C0109831A832B833C834D835E836F834E -:102CD00078878E010F5F1F4F6AE0A80125E00E94F0 -:102CE0002716C70160E1A80125E00E942716C70149 -:102CF00061E1F70144810E94C41528960FB6F8944B -:102D0000DEBF0FBECDBFCF91DF911F910F91FF901E -:102D1000EF9008951F93CF93DF93EC01162F60E09F -:102D20000E947D141F711EBD0DB407FEFDCF8EB530 -:102D30008FEF8EBD0DB407FEFDCF1EB5CE0161E055 -:102D40000E947D14812FDF91CF911F9108950F93E1 -:102D50001F93CF93DF938C01EB0160E00E948A16F2 -:102D6000482F437F209729F0219711F4486001C034 -:102D70004C60C80160E00E94C415DF91CF911F91A3 -:102D80000F910895FF920F931F93CF93DF93EC0160 -:102D90008B0166E00E948A161A82F7EDFF2EF82258 -:102DA0000230110511F480E206C00130110529F44A -:102DB00081E08A8388E0F82A01C01A82CE0166E0A9 -:102DC0004F2D0E94C415CE0166E00E948A168F1511 -:102DD00011F481E002C01A8280E0DF91CF911F914F -:102DE0000F91FF9008951F93CF93DF93EC01162F5F -:102DF00066E00E948A16143010F04CE003C0412FA8 -:102E0000440F4F5F887F482BCE0166E00E94C415B7 -:102E1000DF91CF911F9108950F931F93CF93DF936D -:102E2000EC01162F042F6730F0F461E00E948A163F -:102E3000282F002351F081E090E002C0880F991FF5 -:102E40001A95E2F7422F482B0AC081E090E002C0B9 -:102E5000880F991F1A95E2F7482F40954223CE011B -:102E600061E00E94C415DF91CF911F910F910895E9 -:102E70000F931F938C010E94C714C8016DE10E943B -:102E80008A16482F4660C8016DE10E94C415C8012A -:102E90006CE10E948A16482F4360C8016CE10E94D1 -:102EA000C4151F910F9108950F931F938C010E94D9 -:102EB000C714C8016DE10E948A16482F4460C801FA -:102EC0006DE10E94C415C8016CE10E948A16482F6A -:102ED0004F63C8016CE10E94C41581E0F80185834D -:102EE0001F910F910895BF92CF92DF92EF92FF92C0 -:102EF0000F931F93DF93CF93CDB7DEB728970FB60D -:102F0000F894DEBF0FBECDBF6C01B62EE982FA8207 -:102F10000B831C832D833E834F835887662389F45C -:102F2000F601E6828A8187838B8180878C81818705 -:102F30008D8182878E8183878F818487888585872D -:102F400007C0F6E0F61708F43DC081E0681761F4A9 -:102F5000EB2DF0E0EA5BFE4FE491C6016E2FAE016F -:102F60004F5F5F4F25E00BC0E62FF0E0EA5BFE4FBE -:102F7000E491C6016E2FAE014F5F5F4F21E00E94CA -:102F800027160B2D10E0F801E45BFE4FE491C6011B -:102F90006E2FF60144810E94C415C60162E00E94B2 -:102FA0008A16005C1E4FF801649121E030E002C0F7 -:102FB000220F331F6A95E2F7482F422BC60162E0C9 -:102FC0000E94C41528960FB6F894DEBF0FBECDBF81 -:102FD000CF91DF911F910F91FF90EF90DF90CF90F5 -:102FE000BF9008950F931F93CF93DF93EC018B0154 -:102FF00067E10E948A1680FF02C080E00DC00115C3 -:10300000110549F0CE010E94F61490E09595879540 -:103010008770F801808381E0DF91CF911F910F913C -:103020000895CF93DF93EC0160E00E948A1681FD42 -:1030300010C0CE0160E00E948A16482F4260CE0187 -:1030400060E00E94C41565E070E080E090E00E94BE -:103050002620DF91CF9108950F931F938C01FC01DF -:10306000808160E00E94CD20C80160E00E948A1645 -:10307000482F4D7FC80160E00E94C4151F910F9139 -:1030800008950F931F938C01FC01808160E00E94E2 -:10309000CD20C8010E94FA14C8010E94FE14C80184 -:1030A00060E00E948A16482F4E7FC80160E00E94AF -:1030B000C4151F910F910895CF93DF93EC010E94E7 -:1030C0001118CE0160E00E948A16482F4160CE019F -:1030D00060E00E94C415CE0167E040E70E94C4157D -:1030E0008E819F81892B9885892B9985892B9A853B -:1030F000892B9B85892B9C85892B9D85892B41F06C -:10310000AE014A5F5F4FCE016AE025E00E942716BC -:10311000CE010E94FE14CE010E94FA14888161E063 -:103120000E94CD20DF91CF910895CF93DF93EC01E2 -:10313000888161E00E948E20898161E00E948E205A -:103140000E940619888160E00E94CD20CE0161E0D6 -:103150000E947D1465E070E080E090E00E942620EF -:10316000CE0165E04FE00E94E415CE0162E070E020 -:103170000E94C216882311F081E08B83CE0160E0AB -:1031800070E00E94C216CE0162E070E00E94A716B5 -:10319000CE0167E040E70E94C415CE016CE40E94B6 -:1031A0001F16CE010E94FE14CE010E94FA14CE0119 -:1031B0000E941118CE0160E00E948A16482F4E7FAF -:1031C000CE0160E00E94C415DF91CF91089588235D -:1031D00019F48CB5806202C08CB58F7D8CBD0895CA -:1031E0009CB5937F982B9CBD08952CB5382F3370D8 -:1031F0002C7F322B3CBD2DB590E09595879595950C -:10320000879581702E7F822B8DBD08958AE061E0C5 -:103210000E94CD208AE061E00E948E208CB5806102 -:103220008CBD8CB580648CBD8DE061E00E948E20E9 -:103230008BE061E00E948E200895FC0185EE99E10B -:10324000918B808B75836483138210828FE190E071 -:10325000928381830895FC01838108956F927F9208 -:103260008F929F92AF92BF92CF92DF92EF92FF9296 -:103270000F931F93CF93DF93FB01EA01998180E0C5 -:10328000288130E0282B392BE081E23231F0E8321E -:1032900021F0E03109F084C04BC04C814F3329F15B -:1032A000403420F44F3109F07BC02FC04F3579F006 -:1032B0004F3709F075C0B901882777FD8095982FA1 -:1032C0000E946A2420E030E040E85DE32EC035959E -:1032D0002795B901882777FD8095982F0E946A2449 -:1032E00020E030E040E05EE320C03595279535953D -:1032F0002795B901882777FD8095982F0E946A2429 -:1033000020E030E040E85EE310C093E0359527957B -:103310009A95E1F7B901882777FD8095982F0E944B -:103320006A2420E030E040E05FE30E941A2532C0CA -:10333000EF8035952795B901882777FD8095982FDF -:103340000E946A2420E030E040E85EE30E946623A9 -:103350003B014C016E2D70E02E81621B71098827A4 -:1033600077FD8095982F0E946A245B016C01FF24F1 -:1033700000E010E0C801B7010E9468249B01AC0185 -:10338000C601B5010E94CF239B01AC01C401B3016A -:103390000E9467239B01AC01832F942F752F00C0DF -:1033A000262F382F492F572FB901CA01DF91CF910E -:1033B0001F910F91FF90EF90DF90CF90BF90AF9053 -:1033C0009F908F907F906F9008950895EF92FF9255 -:1033D0000F931F938C017B01FC01848195810E94D6 -:1033E000E51CF80184819581B7010E94C41CF80195 -:1033F0008481958164EB40E00E947F1CF801848108 -:1034000095810E94FA1BF82EF801848195810E9413 -:10341000E51C80E0FF2009F481E01F910F91FF90EF -:10342000EF9008950F931F938C01FC018481958187 -:103430000E94E51CF801848195810E94BF1CF8015F -:103440008481958164E440810E947F1CF801818120 -:1034500092818F33910551F08F35910561F04F972F -:1034600079F46EE570E080E090E00EC06CEB70E007 -:1034700080E090E009C067E771E080E090E004C080 -:103480006EEE72E080E090E00E9426201F910F9186 -:103490000895CF92DF92EF92FF920F931F938C01CA -:1034A0006B017A01FC01848195810E94E51CF80181 -:1034B00084819581B6010E94C41CF80184819581A4 -:1034C0006EEB40E00E947F1CF801848195810E9490 -:1034D0002E1CF7018083F801848195810E942E1CA7 -:1034E000F7018183F801848195810E942E1CF701E8 -:1034F0008283F801848195810E942E1CF7018383C9 -:10350000F801848195810E942E1CF7018483F801C3 -:10351000848195810E942E1CF7018583F8018481A6 -:1035200095810E942E1CF7018683F8018481958184 -:103530000E942E1CF7018783F801848195810E94E7 -:103540002E1CF7018087F801848195810E94E51C7B -:103550001F910F91FF90EF90DF90CF9008950F9300 -:103560001F938A010E94491AC80168E00E94E91B62 -:1035700020E0F8019085891709F421E0822F1F913E -:103580000F910895CF92DF92EF92FF920F931F93C6 -:10359000DF93CF93CDB7DEB729970FB6F894DEBF90 -:1035A0000FBECDBF8C017B016E010894C11CD11CE4 -:1035B000A6010E94AF1A882329F460E070E08EEF24 -:1035C00092EC05C0C801B701A6010E942E192996E8 -:1035D0000FB6F894DEBF0FBECDBFCF91DF911F9124 -:1035E0000F91FF90EF90DF90CF9008950F931F936E -:1035F0008B01CB0167E00E94E91B20E0F801978175 -:10360000891709F421E0822F1F910F910895EF92FD -:10361000FF920F931F93CF93DF93EC017B01042F55 -:103620008C819D810E94DC1B10E007C0CE01B70198 -:103630000E94F61A8823A9F00AC08C819D81B701E7 -:103640000E94301D882329F0101759F4EFCF81E034 -:1036500001C080E0DF91CF911F910F91FF90EF901B -:1036600008951F5F0117A8F3E8CFEF92FF920F9321 -:103670001F93DF93CF93CDB7DEB728970FB6F8949B -:10368000DEBF0FBECDBF7C01462F8E010F5F1F4FE7 -:10369000B8010E94071BC701B8010E94C21A2896F0 -:1036A0000FB6F894DEBF0FBECDBFCF91DF911F9153 -:1036B0000F91FF90EF9008950E94351B26E636E6A5 -:1036C00046EE5FE30E941A2520E030E040E052E43D -:1036D0000E94672308959F92AF92BF92CF92DF928C -:1036E000EF92FF920F931F93DF93CF93CDB7DEB787 -:1036F00061970FB6F894DEBF0FBECDBF8C01FC0101 -:10370000848195810E94DC1BF80113827E0108945C -:10371000E11CF11CE9E0AE2EB12CAC0EBD1E7FE722 -:10372000C72ED12C992493942DC0C801B7010E94B3 -:10373000F61A882339F1F8018081882341F4C80101 -:10374000B7010E94E619882311F0F8019082C801A0 -:10375000B701A5010E94491A8981803121F4F8013D -:10376000D282C1820BC08D85282F30E0F801818183 -:1037700092818217930714F432832183F8018381A5 -:103780008F5F8383F80184819581B7010E94301D8A -:10379000882359F661960FB6F894DEBF0FBECDBFF1 -:1037A000CF91DF911F910F91FF90EF90DF90CF901D -:1037B000BF90AF909F900895FC01138615861486E4 -:1037C00087E090E012863197009711F00197FACFC9 -:1037D0000895DC0180E00BC0E82FF0E08D9190E0CF -:1037E000E827F927ED5FFC4FE49161508E2F6623A7 -:1037F00099F70895DF92EF92FF920F931F93FC01C8 -:10380000E08001811281F894F80181818E29818301 -:103810008281DE2CD0948D21828383E090E00E940F -:10382000E11FF80181818D2181838AE090E00E946F -:10383000E11FF8010081789485E390E00E94E11F88 -:1038400080E010E0FF240E211F21012B09F081E010 -:103850001F910F91FF90EF90DF900895EF92FF92EC -:103860000F931F93CF93DF937C0101E010E0C0E042 -:10387000D0E0C7010E94FA1B8111102B000F219686 -:10388000C830D105B1F7812FDF91CF911F910F91F2 -:10389000FF90EF9008951F93CF93DF93FC01108169 -:1038A000C181D281912F909560FF12C0F8948A81D6 -:1038B00089238A838981812B89838AE090E00E9411 -:1038C000E11F8A81812B8A83789487E390E011C07D -:1038D000F8948A8189238A838981812B898381E471 -:1038E00090E00E94E11F8A81812B8A83789485E091 -:1038F00090E00E94E11FDF91CF911F910895CF9238 -:10390000DF92EF92FF920F931F93CF93DF938C017F -:10391000E42EFF24F394C0E0D0E0C62EDD2460E066 -:103920008F2D90E08C219D21892B09F061E0C80149 -:103930000E944B1CFF0C2196C830D10581F7EE2068 -:10394000A9F4F894D8011196ED91FC911297918108 -:103950008C918095982391831196ED91FC9112970B -:1039600092818C918095982392837894DF91CF9166 -:103970001F910F91FF90EF90DF90CF9008956CEC26 -:1039800040E00E947F1C0895EF92FF920F931F93D7 -:10399000CF93DF938C017B0165E540E00E947F1CA3 -:1039A000C0E0D0E0F701EC0FFD1FC801608140E0EE -:1039B0000E947F1C2196C830D105A1F7DF91CF91DD -:1039C0001F910F91FF90EF900895DF92EF92FF9279 -:1039D0000F931F93CF93DF93FC010081C181D281AC -:1039E000F8948981D02ED0948D21898378941DE715 -:1039F000E02EFF24115059F182E090E00E94E11F77 -:103A0000888190E08E219F21892BA1F3F8948A81EF -:103A10008D218A838981802B8983789484EF91E03A -:103A20000E94E11FF89489818D21898380E590E0CF -:103A30000E94E11F888110E090E0E822F922EF283F -:103A400009F411E0789484EA91E00E94E11F812F4B -:103A5000DF91CF911F910F91FF90EF90DF9008952C -:103A6000AF92BF92DF92EF92FF920F931F93CF938B -:103A7000DF93EC015B018D85882309F061C0CE01E5 -:103A80000E94E51C882329F41B861D861C8690E075 -:103A90006BC0CE0160EF40E00E947F1C01E0DD249E -:103AA000EE24FF24F394CE010E94FA1B182FCE01BE -:103AB0000E94FA1B113019F48130E1F439C0181753 -:103AC00009F58B85081770F460E0FE01EE0DF11D1D -:103AD000838190E02F2D30E082239323181619065E -:103AE0004CF003C060E0081729F0093008F04CC022 -:103AF0000C874AC0FE01EE0DF11D83818F2983835F -:103B000061E009C0612FFE01EE0DF11D9F2D909522 -:103B1000838189238383CE010E944B1C0F5FFF0C9E -:103B200019F4E394FF24F39487E08E1508F0BBCFDB -:103B3000013430F0DB86DD2011F581E08D871FC078 -:103B40001B861D861C8690E0DE0120E030E0F5013A -:103B5000E20FF31F13968C91139780832F5F3F4FD3 -:103B600011962830310599F7892FDF91CF911F9158 -:103B70000F91FF90EF90DF90BF90AF9008958B81F1 -:103B80008823F1F291E0E0CFD02EBDCFFF920F93CA -:103B90001F938C01F62E862F60E00E948E208F2DC1 -:103BA00090E0FC01EB5CFB4FE491D801EC938F5D5E -:103BB0009B4FFC016491E62FF0E0EE0FFF1FE95EE2 -:103BC000FB4F8591949112969C938E9311971B961F -:103BD0001C921B971D961C921D971C961C92F80117 -:103BE00087E090E012863197009711F00197FACFA5 -:103BF0001F910F91FF9008950F931F93CF93DF9321 -:103C0000BC018230910510F462E070E0E09107039E -:103C1000F091080340E050E0A0E0B0E024C08081D3 -:103C2000918186179707D0F08617970771F48281E4 -:103C30009381109729F013969C938E9312972CC022 -:103C4000909308038093070327C04115510519F08D -:103C50008417950718F48D01AC01EF01DF01828113 -:103C600093819C01F9013097D1F641155105F9F086 -:103C7000CA01861B970B8430910580F48A819B8151 -:103C80000115110521F0F8019383828304C09093FC -:103C9000080380930703FE01329645C0FE01E80F3A -:103CA000F91F619371930297998388833CC0809137 -:103CB000050390910603892B41F480914C0190916A -:103CC0004D01909306038093050340914E0150915E -:103CD0004F014115510541F44DB75EB780914A013E -:103CE00090914B01481B590B20910503309106031D -:103CF00024173507B0F4CA01821B930B8617970768 -:103D000080F0AB014E5F5F4F8417950750F0420F74 -:103D1000531F5093060340930503F9016193719378 -:103D200002C0E0E0F0E0CF01DF91CF911F910F9151 -:103D30000895CF93DF939C01009709F48FC0EC01A5 -:103D400022971B821A826091070370910803611504 -:103D5000710581F488819981820F931F2091050359 -:103D6000309106032817390739F5D0930603C0931D -:103D7000050374C0DB0140E050E0AC17BD0708F15B -:103D8000BB83AA83FE0121913191E20FF31FAE178D -:103D9000BF0779F48D919C911197280F391F2E5FE1 -:103DA0003F4F3983288312968D919C9113979B8363 -:103DB0008A834115510571F4D0930803C09307031A -:103DC0004DC012968D919C911397AD01009711F003 -:103DD000DC01D3CFDA011396DC93CE931297FA016C -:103DE00021913191E20FF31FCE17DF0769F488812B -:103DF0009981280F391F2E5F3F4FFA0131832083AD -:103E00008A819B8193838283E0E0F0E0DB0112965C -:103E10008D919C911397009719F0BC01FD01F6CF8D -:103E2000AB014E5F5F4FDB018D919C91840F951F1D -:103E300020910503309106032817390779F430974C -:103E400029F4109208031092070302C01382128211 -:103E5000425050405093060340930503DF91CF91A9 -:103E600008951F920F920FB60F9211242F933F9334 -:103E70004F935F936F937F938F939F93AF93BF9372 -:103E8000EF93FF9380915B0290915C02892B29F064 -:103E9000E0915B02F0915C020995FF91EF91BF9177 -:103EA000AF919F918F917F916F915F914F913F91D2 -:103EB0002F910F900FBE0F901F9018951F920F9289 -:103EC0000FB60F9211242F933F934F935F936F93ED -:103ED0007F938F939F93AF93BF93EF93FF938091C3 -:103EE0005D0290915E02892B29F0E0915D02F091D4 -:103EF0005E020995FF91EF91BF91AF919F918F91D4 -:103F00007F916F915F914F913F912F910F900FBED5 -:103F10000F901F9018951F920F920FB60F921124B9 -:103F20002F933F938F939F93AF93BF93809163029F -:103F300090916402A0916502B0916602309167028F -:103F40000196A11DB11D232F2D5F2D3720F02D5778 -:103F50000196A11DB11D2093670280936302909387 -:103F60006402A0936502B093660280915F02909113 -:103F70006002A0916102B09162020196A11DB11D83 -:103F800080935F0290936002A0936102B0936202FB -:103F9000BF91AF919F918F913F912F910F900FBE45 -:103FA0000F901F9018958FB7F8942091630230916D -:103FB000640240916502509166028FBFB901CA0147 -:103FC0000895019739F0880F991F880F991F02975C -:103FD0000197F1F70895789484B5826084BD84B523 -:103FE000816084BD85B5826085BD85B5816085BDF4 -:103FF000EEE6F0E0808181608083E1E8F0E010820D -:10400000808182608083808181608083E0E8F0E04D -:10401000808181608083E1EBF0E080818460808337 -:10402000E0EBF0E0808181608083EAE7F0E080816E -:1040300084608083808182608083808181608083CE -:104040008081806880831092C1000895EF92FF9272 -:104050000F931F93CF93DF937B018C013FB7F894AD -:1040600080915F0290916002A0916102B091620222 -:1040700026B5A89B05C02F3F19F00196A11DB11DC3 -:104080003FBFBA2FA92F982F8827820F911DA11DFE -:10409000B11D52E0880F991FAA1FBB1F5A95D1F777 -:1040A000EC0130C00E9465233FB7F89480915F0215 -:1040B00090916002A0916102B091620226B5A89B26 -:1040C00005C02F3F19F00196A11DB11D3FBFBA2FAA -:1040D000A92F982F8827820F911DA11DB11D32E0B5 -:1040E000880F991FAA1FBB1F3A95D1F78C1B9D0BF8 -:1040F000885E9340B8F20894E108F10801091109BB -:10410000C851DC4FE114F1040105110559F6DF91A6 -:10411000CF911F910F91FF90EF900895CF93DF9370 -:10412000482F50E0CA018B5C9B4FFC0134914F5DDE -:104130005B4FFA018491882369F190E0880F991F01 -:10414000FC01ED5FFB4FA591B491FC01E35FFB4FD8 -:10415000C591D491662351F42FB7F8948C91932F85 -:10416000909589238C93888189230BC0623061F4F8 -:104170002FB7F8948C91932F909589238C938881F5 -:10418000832B88832FBF06C09FB7F8948C91832B15 -:104190008C939FBFDF91CF910895482F50E0CA01C3 -:1041A000875B9B4FFC012491CA018B5C9B4FFC01F8 -:1041B00094914F5D5B4FFA013491332309F440C071 -:1041C000222351F1233071F0243028F42130A1F062 -:1041D000223011F514C02630B1F02730C1F0243060 -:1041E000D9F404C0809180008F7703C08091800053 -:1041F0008F7D8093800010C084B58F7702C084B516 -:104200008F7D84BD09C08091B0008F7703C08091FD -:10421000B0008F7D8093B000E32FF0E0EE0FFF1F22 -:10422000E35FFB4FA591B4912FB7F894662321F477 -:104230008C919095892302C08C91892B8C932FBFF0 -:104240000895DC015C968C915C97FD01E80FF11DEF -:10425000E35AFF4F20815C968C915C9790E0019629 -:104260008F7390705C968C935C975696ED91FC9151 -:10427000579720835096ED91FC91519780818064EF -:1042800080835B969C915B975C968C915C9798176A -:1042900039F45296ED91FC91539780818F7D808304 -:1042A0000895DF92EF92FF920F931F93CF93DF93C6 -:1042B000EC017A018B01D22EE889F98982E08083B2 -:1042C000403081EE580780E0680780E07807A1F071 -:1042D00060E079E08DE390E0A80197010E947D25E0 -:1042E000215030404040504056954795379527958E -:1042F00080E12030380798F0E889F989108260E879 -:1043000074E88EE190E0A80197010E947D2521507C -:104310003040404050405695479537952795EC855D -:10432000FD853083EE85FF852083188EEC89FD891D -:10433000D082EA89FB89808180618083EA89FB8958 -:10434000808188608083EA89FB898081806880839E -:10435000EA89FB8980818F7D8083DF91CF911F91D6 -:104360000F91FF90EF90DF900895FC01218D828DD9 -:1043700030E0205C3F4F281B31092F733070C9019A -:104380000895FC01918D828D981719F42FEF3FEF5E -:1043900006C0828DE80FF11D858D282F30E0C90100 -:1043A0000895DC0159969C9159975A968C915A9789 -:1043B000981719F42FEF3FEF10C05A968C915A9727 -:1043C000FD01E80FF11D958D5A968C915A978F5FDC -:1043D0008F735A968C93292F30E0C9010895CF939B -:1043E000DF93EC01888D882361F419C08C9185FFDF -:1043F0000AC0E889F989808185FF05C0CE010E9445 -:104400002121AA89BB898C9185FD05C0E889F9899C -:10441000808186FD04C00FB607FEE8CFF4CFDF91A0 -:10442000CF9108950F931F93CF93DF93EC01062F45 -:104430009B8D8C8D981791F5E889F989808185FF8E -:104440002DC0EE89FF896083E889F98980818064C5 -:1044500080831DC00FB607FC08C0E889F9898081F8 -:1044600085FF03C0CE010E9421218C8D181791F386 -:104470008B8DFE01E80FF11DE35AFF4F00831B8F68 -:10448000EA89FB8980818062808381E0888F81E076 -:1044900090E0DF91CF911F910F9108951B8D1F5FC9 -:1044A0001F73E3CF8AED92E2892B51F080E090E018 -:1044B000892B31F00E94DA22882311F00E9400003B -:1044C00008951F920F920FB60F9211242F938F937E -:1044D0009F93EF93FF93E0917802F09179028081AE -:1044E00082FD16C0E0917E02F0917F0220819091C2 -:1044F00081029F5F9F7380918202981771F0E09113 -:104500008102F0E0E859FD4F258F9093810205C0AC -:10451000E0917E02F0917F02E081FF91EF919F9107 -:104520008F912F910F900FBE0F901F9018951092A2 -:104530006B0210926A0288EE93E0A0E0B0E08093F4 -:104540006C0290936D02A0936E02B0936F0284E5AB -:1045500091E0909369028093680285EC90E09093DB -:1045600075028093740284EC90E0909377028093BC -:10457000760280EC90E0909379028093780281EC4F -:1045800090E090937B0280937A0282EC90E090938B -:104590007D0280937C0286EC90E090937F02809372 -:1045A0007E02109281021092820210928302109277 -:1045B0008402089588E692E00E94B52120E0892BCC -:1045C00009F021E0822F08951F920F920FB60F92EB -:1045D00011242F933F934F935F936F937F938F9308 -:1045E0009F93AF93BF93EF93FF9388E692E00E946F -:1045F0002121FF91EF91BF91AF919F918F917F9179 -:104600006F915F914F913F912F910F900FBE0F903F -:104610001F901895CF93DF930E94EB1F0E94F20921 -:10462000C2E5D2E20E945B092097E1F30E94522288 -:10463000F9CF0E94FC1D0895CF92DF92EF92FF9276 -:104640000F931F93CF93DF937C016B018A01C0E02E -:10465000D0E00FC0D6016D916D01D701ED91FC91B5 -:104660000190F081E02DC7010995C80FD91F0150B5 -:1046700010400115110571F7CE01DF91CF911F9107 -:104680000F91FF90EF90DF90CF900895CF93DF933D -:10469000EC016115710519F420E030E00FC0DB0179 -:1046A0000D900020E9F71197A61BB70BE881F9815F -:1046B0000280F381E02DAD0109959C01C901DF91D4 -:1046C000CF9108950E944623089508955058BB271E -:1046D000AA270ED075C166D130F06BD120F031F42D -:1046E0009F3F11F41EF45BC10EF4E095E7FB51C14E -:1046F000E92F77D180F3BA1762077307840795070C -:1047000018F071F49EF58FC10EF4E0950B2EBA2FC0 -:10471000A02D0B01B90190010C01CA01A0011124C7 -:10472000FF27591B99F0593F50F4503E68F11A1673 -:10473000F040A22F232F342F4427585FF3CF469504 -:1047400037952795A795F0405395C9F77EF41F1626 -:10475000BA0B620B730B840BBAF09150A1F0FF0FF0 -:10476000BB1F661F771F881FC2F70EC0BA0F621FDC -:10477000731F841F48F4879577956795B795F795CC -:104780009E3F08F0B3CF9395880F08F09927EE0F5E -:10479000979587950895D9D008F481E008950CD0B5 -:1047A0000FC107D140F0FED030F021F45F3F19F087 -:1047B000F0C0511139C1F3C014D198F39923C9F352 -:1047C0005523B1F3951B550BBB27AA276217730717 -:1047D000840738F09F5F5F4F220F331F441FAA1FCB -:1047E000A9F333D00E2E3AF0E0E830D0915050408B -:1047F000E695001CCAF729D0FE2F27D0660F771F39 -:10480000881FBB1F261737074807AB07B0E809F01A -:10481000BB0B802DBF01FF2793585F4F2AF09E3FAF -:10482000510568F0B6C000C15F3FECF3983EDCF381 -:10483000869577956795B795F7959F5FC9F7880F28 -:10484000911D9695879597F90895E1E0660F771F7A -:10485000881FBB1F621773078407BA0720F0621B0B -:10486000730B840BBA0BEE1F88F7E095089504D004 -:104870006894B111D9C00895BCD088F09F5790F0CA -:10488000B92F9927B751A0F0D1F0660F771F881F75 -:10489000991F1AF0BA95C9F712C0B13081F0C3D090 -:1048A000B1E00895C0C0672F782F8827B85F39F02E -:1048B000B93FCCF3869577956795B395D9F73EF4D4 -:1048C00090958095709561957F4F8F4F9F4F08957C -:1048D000E89409C097FB3EF490958095709561959A -:1048E0007F4F8F4F9F4F9923A9F0F92F96E9BB2750 -:1048F0009395F695879577956795B795F111F8CFCC -:10490000FAF4BB0F11F460FF1BC06F5F7F4F8F4F36 -:104910009F4F16C0882311F096E911C0772321F02C -:104920009EE8872F762F05C0662371F096E8862FC4 -:1049300070E060E02AF09A95660F771F881FDAF71B -:10494000880F9695879597F90895990F0008550F48 -:10495000AA0BE0E8FEEF16161706E807F907C0F005 -:1049600012161306E407F50798F0621B730B840B0D -:10497000950B39F40A2661F0232B242B252B21F4E7 -:1049800008950A2609F4A140A6958FEF811D811D87 -:10499000089597F99F6780E870E060E008959FEFC1 -:1049A00080EC089500240A941616170618060906C6 -:1049B000089500240A941216130614060506089595 -:1049C000092E0394000C11F4882352F0BB0F40F41D -:1049D000BF2B11F460FF04C06F5F7F4F8F4F9F4F5D -:1049E000089557FD9058440F551F59F05F3F71F0DF -:1049F0004795880F97FB991F61F09F3F79F0879546 -:104A00000895121613061406551FF2CF4695F1DFCE -:104A100008C0161617061806991FF1CF869571055E -:104A2000610508940895E894BB2766277727CB0192 -:104A300097F908950BD0C4CFB5DF28F0BADF18F08E -:104A4000952309F0A6CFABCF1124EECFCADFA0F398 -:104A5000959FD1F3950F50E0551F629FF001729F13 -:104A6000BB27F00DB11D639FAA27F00DB11DAA1F32 -:104A7000649F6627B00DA11D661F829F2227B00D7F -:104A8000A11D621F739FB00DA11D621F839FA00D0A -:104A9000611D221F749F3327A00D611D231F849F5A -:104AA000600D211D822F762F6A2F11249F575040B1 -:104AB0008AF0E1F088234AF0EE0FFF1FBB1F661F4C -:104AC000771F881F91505040A9F79E3F510570F005 -:104AD00060CFAACF5F3FECF3983EDCF386957795E5 -:104AE0006795B795F795E7959F5FC1F7FE2B880F00 -:104AF000911D9695879597F90895A1E21A2EAA1B04 -:104B0000BB1BFD010DC0AA1FBB1FEE1FFF1FA2177D -:104B1000B307E407F50720F0A21BB30BE40BF50B7A -:104B2000661F771F881F991F1A9469F76095709503 -:104B3000809590959B01AC01BD01CF010895EE0FCA -:104B4000FF1F0590F491E02D0994AA1BBB1B51E1B6 -:104B500007C0AA1FBB1FA617B70710F0A61BB70BED -:104B6000881F991F5A95A9F780959095BC01CD0192 -:104B700008952F923F924F925F926F927F928F9201 -:104B80009F92AF92BF92CF92DF92EF92FF920F93DC -:104B90001F93CF93DF93CDB7DEB7CA1BDB0B0FB6E6 -:104BA000F894DEBF0FBECDBF09942A8839884888A3 -:104BB0005F846E847D848C849B84AA84B984C88439 -:104BC000DF80EE80FD800C811B81AA81B981CE0F30 -:104BD000D11D0FB6F894DEBF0FBECDBFED01089515 -:044BE000F894FFCF77 -:104BE40054656D70657261747572652053656E737A -:104BF4006F7200312E30006661696C006F6B0000CB -:104C0400312E346231202831383834386132290069 -:104C140073656E736F72007265706561746572009E -:104C240030750000307500000100800009030000A9 -:104C34000000000012221C23B521D121C121EF2143 -:00000001FF diff --git a/NodeJsController/DallasTemperatureSensor/DallasTemperatureSensor.ino b/NodeJsController/DallasTemperatureSensor/DallasTemperatureSensor.ino deleted file mode 100644 index 3ac3888..0000000 --- a/NodeJsController/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ /dev/null @@ -1,69 +0,0 @@ -// Example sketch showing how to send in OneWire temperature readings -#include -#include -#include -#include - -#define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected -#define MAX_ATTACHED_DS18B20 16 -unsigned long WAIT_TIME = 30000; // Wait for feedback from controller after sending and before going to sleep (in milliseconds) -unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) -OneWire oneWire(ONE_WIRE_BUS); -DallasTemperature sensors(&oneWire); -MySensor gw; -float lastTemperature[MAX_ATTACHED_DS18B20]; -int numSensors=0; -boolean receivedConfig = false; -boolean metric = true; -// Initialize temperature message -MyMessage msg(0,V_TEMP); - -void setup() -{ - // Startup OneWire - sensors.begin(); - - // Startup and initialize MySensors library. Set callback for incoming messages. - gw.begin(); - - // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Temperature Sensor", "1.0"); - - // Fetch the number of attached temperature sensors - numSensors = sensors.getDeviceCount(); - - // Present all sensors to controller - for (int i=0; i(static_cast((gw.getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.; - - // Only send data if temperature has changed and no error - if (lastTemperature[i] != temperature && temperature != -127.00) { - - // Send in the new temperature - gw.send(msg.setSensor(i).set(temperature,1)); - lastTemperature[i]=temperature; - } - } - delay(WAIT_TIME); - gw.process(); - gw.sleep(SLEEP_TIME); -} - - diff --git a/NodeJsController/NodeJsController.js b/NodeJsController/NodeJsController.js index 6c52630..53639a2 100644 --- a/NodeJsController/NodeJsController.js +++ b/NodeJsController/NodeJsController.js @@ -11,8 +11,8 @@ const dbAddress = '127.0.0.1'; const dbPort = 27017; const dbName = 'MySensorsDb'; -const fwHexFiles = [ 'BlinkRed.hex', 'BlinkGreen.hex', 'DallasTemperatureSensor.cpp.hex' ]; -const fwDefaultType = 2; // index of hex file from array above +const fwHexFiles = [ ]; +const fwDefaultType = 0xFFFF; // index of hex file from array above (0xFFFF == none defined) const FIRMWARE_BLOCK_SIZE = 16; const BROADCAST_ADDRESS = 255; diff --git a/NodeJsController/Readme.html b/NodeJsController/Readme.md similarity index 91% rename from NodeJsController/Readme.html rename to NodeJsController/Readme.md index 6766851..98dee49 100644 --- a/NodeJsController/Readme.html +++ b/NodeJsController/Readme.md @@ -1,5 +1,4 @@

MySensors with NodeJS Controller and OTA bootloader on RPi

-

My RPi runs Arduino to compile and flash sketches and the bootloader. With this setup no separate PC/Mac is needed. Exactly the same could be achieved (faster) using a PC/Mac for all the Arduino compilation and flashing activities – just skip the steps and execute on PC/Mac instead.

Hardware

Headless Raspberry Pi model B with wired Ethernet

I'm connecting a monitor only for first time boot to get the IP address and then connect via Putty/xRDP

@@ -140,8 +139,6 @@ export PATH

  • git checkout development
  • cd NodeJsController
  • npm install -
  • nano NodeJsController.js (optional : removing sample firmwares) -

    const fwHexFiles = [ ];

  • to confirm that the NodeJsController is working as expected and connects to the local mongo DB: "node NodeJsController.js" which should start the controller, connect to the database and run into an error connecting to the gateway. Stop node again via Ctrl-c

    Start NodeJsController on boot

    @@ -215,7 +212,7 @@ Arduino RESET <-> Raspberry Pi GPIO22 (pin 15)

    //const gwType = 'Serial';
    //const gwPort = '/dev/ttyAMA0';
    //const gwBaud = 115200;

    -
  • sudo service mysensors restart +
  • sudo service mysensors restart (at this point stop/restart doesn't work. use "sudo killall node" followed by "sudo service mysensors start" instead)

    Ethernet Gateway

    @@ -262,7 +259,7 @@ IPAddress myIp (10, 0, 1, 99);

    • nano ~/Arduino/NodeJsController/NodeJsController.js

      const gwAddress = '10.0.1.99';

      -
    • sudo service mysensors restart +
    • sudo service mysensors restart (at this point stop/restart doesn't work. use "sudo killall node" followed by "sudo service mysensors start" instead)

    Sensor Node Bootloader

    @@ -291,12 +288,14 @@ ISP_MCU = m328p

    End-to-End Test

    -

    Add Firmware to Controller

    +

    Add Firmware to Controller (here: DallasTemperatureSensor)

      +
    • use Arduino IDE or codebender or whatever other way to compile your sketch +
    • copy the compiled DallasTemperatureSensor.cpp.hex file to the NodeJsController directory (if using the Arduino IDE, enable verbose logging in preferences and then watch the compilation process to find the temp directory where the output is stored)
    • nano ~/Arduino/NodeJsController/NodeJsController.js -

      const fwHexFiles = [ 'DallasTemperatureSensor.cpp.hex' ];
      -const fwDefaultType = 0;

      -
    • sudo service mysensors restart +

      const fwHexFiles = [ 'DallasTemperatureSensor.cpp.hex' ];
      +const fwDefaultType = 0;

      +
    • sudo service mysensors restart (at this point stop/restart doesn't work. use "sudo killall node" followed by "sudo service mysensors start" instead)

    Flash Firmware OTA

      @@ -305,5 +304,5 @@ const fwDefaultType = 0;

    Check functionality

      -
    • in addition to watching the log file (tail command above) you can connect to the mongo db using a client (e.g. Robomongo) and check if new values are written to the database as a real end-to-end test +
    • in addition to watching the log file (tail command above) you can connect to the mongo db using a client (e.g. Robomongo) and check if new values are written to the database as a real end-to-end test once the bootloader finished uploading the firmware
    From cd84e410fa2dd38acd4334840d38748cb695aeb2 Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Mon, 25 Aug 2014 17:38:25 +0200 Subject: [PATCH 002/660] use codebender to compile sketches I had codebender username/password included originally but compiling works without. Codebender usage guidelines allow "usage via API". --- NodeJsController/NodeJsController.js | 179 +++++++++++++++------------ NodeJsController/package.json | 1 + 2 files changed, 103 insertions(+), 77 deletions(-) diff --git a/NodeJsController/NodeJsController.js b/NodeJsController/NodeJsController.js index 53639a2..fbe1470 100644 --- a/NodeJsController/NodeJsController.js +++ b/NodeJsController/NodeJsController.js @@ -1,18 +1,18 @@ -const gwType = 'Ethernet'; -const gwAddress = '10.0.1.99'; -const gwPort = 9999; +//const gwType = 'Ethernet'; +//const gwAddress = '10.0.1.99'; +//const gwPort = 9999; -//const gwType = 'Serial'; +const gwType = 'Serial'; //const gwPort = 'COM4'; -//const gwPort = '/dev/ttyUSB0'; -//const gwBaud = 115200; +const gwPort = '/dev/ttyAMA0'; +const gwBaud = 115200; const dbAddress = '127.0.0.1'; const dbPort = 27017; const dbName = 'MySensorsDb'; -const fwHexFiles = [ ]; -const fwDefaultType = 0xFFFF; // index of hex file from array above (0xFFFF == none defined) +const fwSketches = [ '../libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino' ]; +const fwDefaultType = 0; // index of hex file from array above const FIRMWARE_BLOCK_SIZE = 16; const BROADCAST_ADDRESS = 255; @@ -117,6 +117,8 @@ const P_ULONG32 = 5; const P_CUSTOM = 6; var fs = require('fs'); +var path = require('path'); +var requestify = require('requestify'); var appendedString=""; function crcUpdate(old, value) { @@ -146,76 +148,99 @@ function pushDWord(arr, val) { arr.push((val >> 24) & 0x000000FF); } -function loadFirmware(fwtype, fwversion, filename, db) { - console.log("loading firmware: " + filename); - fwdata = []; - var start = 0; - var end = 0; - var pos = 0; - var hex = fs.readFileSync(filename).toString().split("\n"); - for(l in hex) { - line = hex[l].trim(); - if (line.length > 0) { - while (line.substring(0, 1) != ":") - line = line.substring(1); - var reclen = parseInt(line.substring(1, 3), 16); - var offset = parseInt(line.substring(3, 7), 16); - var rectype = parseInt(line.substring(7, 9), 16); - var data = line.substring(9, 9 + 2 * reclen); - var chksum = parseInt(line.substring(9 + (2 * reclen), 9 + (2 * reclen) + 2), 16); - if (rectype == 0) { - if ((start == 0) && (end == 0)) { - if (offset % 128 > 0) - throw new Error("error loading hex file - offset can't be devided by 128"); - start = offset; - end = offset; +function loadFirmware(fwtype, fwversion, sketch, db) { + var filename = path.basename(sketch); + console.log("compiling firmware: " + filename); + var req = { + files: [{ + filename: filename, + content: fs.readFileSync(sketch).toString() + }], + format: "hex", + version: "105", + build: { + mcu: "atmega328p", + f_cpu: "16000000L", + core: "arduino", + variant: "standard" + } + }; + requestify.post('https://codebender.cc/utilities/compile/', req).then(function(res) { + var body = JSON.parse(res.getBody()); + if (body.success) { + console.log("loading firmware: " + filename); + fwdata = []; + var start = 0; + var end = 0; + var pos = 0; + var hex = body.output.split("\n"); + for(l in hex) { + line = hex[l].trim(); + if (line.length > 0) { + while (line.substring(0, 1) != ":") + line = line.substring(1); + var reclen = parseInt(line.substring(1, 3), 16); + var offset = parseInt(line.substring(3, 7), 16); + var rectype = parseInt(line.substring(7, 9), 16); + var data = line.substring(9, 9 + 2 * reclen); + var chksum = parseInt(line.substring(9 + (2 * reclen), 9 + (2 * reclen) + 2), 16); + if (rectype == 0) { + if ((start == 0) && (end == 0)) { + if (offset % 128 > 0) + throw new Error("error loading hex file - offset can't be devided by 128"); + start = offset; + end = offset; + } + if (offset < end) + throw new Error("error loading hex file - offset lower than end"); + while (offset > end) { + fwdata.push(255); + pos++; + end++; + } + for (var i = 0; i < reclen; i++) { + fwdata.push(parseInt(data.substring(i * 2, (i * 2) + 2), 16)); + pos++; + } + end += reclen; + } } - if (offset < end) - throw new Error("error loading hex file - offset lower than end"); - while (offset > end) { - fwdata.push(255); - pos++; - end++; - } - for (var i = 0; i < reclen; i++) { - fwdata.push(parseInt(data.substring(i * 2, (i * 2) + 2), 16)); - pos++; - } - end += reclen; + } + var pad = end % 128; // ATMega328 has 64 words per page / 128 bytes per page + for (var i = 0; i < 128 - pad; i++) { + fwdata.push(255); + pos++; + end++; } - } - } - var pad = end % 128; // ATMega328 has 64 words per page / 128 bytes per page - for (var i = 0; i < 128 - pad; i++) { - fwdata.push(255); - pos++; - end++; - } - var blocks = (end - start) / FIRMWARE_BLOCK_SIZE; - var crc = 0xFFFF; - for (var i = 0; i < blocks * FIRMWARE_BLOCK_SIZE; ++i) { - var v = crc; - crc = crcUpdate(crc, fwdata[i]); - } - db.collection('firmware', function(err, c) { - c.update({ - 'type': fwtype, - 'version': fwversion - }, { - $set: { - 'filename': filename, - 'blocks': blocks, - 'crc': crc, - 'data': fwdata + var blocks = (end - start) / FIRMWARE_BLOCK_SIZE; + var crc = 0xFFFF; + for (var i = 0; i < blocks * FIRMWARE_BLOCK_SIZE; ++i) { + var v = crc; + crc = crcUpdate(crc, fwdata[i]); } - }, { - upsert: true - }, function(err, result) { - if (err) - console.log('Error writing firmware to database'); - }); - }); - console.log("loading firmware done. blocks: " + blocks + " / crc: " + crc); + db.collection('firmware', function(err, c) { + c.update({ + 'type': fwtype, + 'version': fwversion + }, { + $set: { + 'filename': filename, + 'blocks': blocks, + 'crc': crc, + 'data': fwdata + } + }, { + upsert: true + }, function(err, result) { + if (err) + console.log('Error writing firmware to database'); + }); + }); + console.log("loading firmware done. blocks: " + blocks + " / crc: " + crc); + } else { + console.log("error: %j", res.body); + } + }); } /* @@ -645,8 +670,8 @@ dbc.connect('mongodb://' + dbAddress + ':' + dbPort + '/' + dbName, function(err db.createCollection('firmware', function(err, collection) { }); // ToDo : check for new hex files / only load if new / get type and version from filename - for (var i = 0; i < fwHexFiles.length; i++) - loadFirmware(i, 1, fwHexFiles[i], db); + for (var i = 0; i < fwSketches.length; i++) + loadFirmware(i, 1, fwSketches[i], db); var gw; if (gwType == 'Ethernet') { diff --git a/NodeJsController/package.json b/NodeJsController/package.json index a4866a6..eaffa4a 100644 --- a/NodeJsController/package.json +++ b/NodeJsController/package.json @@ -5,6 +5,7 @@ "dependencies": { "mongodb": "~1.4.7", "net": "~1.0.2", + "requestify": "^0.1.16", "serialport": "^1.4.5" } } From 1dbe7497bdfb47e043402ae77036f9df26de5732 Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Mon, 25 Aug 2014 18:34:51 +0200 Subject: [PATCH 003/660] Added technical details for controller developers regarding OTA bootloader --- Bootloader/Readme.md | 48 +++++++++++++++++++++++++++- NodeJsController/NodeJsController.js | 4 +-- NodeJsController/Readme.md | 4 +-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Bootloader/Readme.md b/Bootloader/Readme.md index 810b16a..b6d7e33 100644 --- a/Bootloader/Readme.md +++ b/Bootloader/Readme.md @@ -1 +1,47 @@ -See NodeJsController/Readme.md for usage instructions... \ No newline at end of file +See NodeJsController/Readme.md for usage instructions... + +

    Technical details to write your own controller

    +All initialization the bootloader does (finding parent / requesting nodeId on first start) uses the same packets as a normal MySensors sketch. There is no need for the controller to distinguish between packets from the bootloader and packets from normal sketch execution. The controller only needs to care about two additional request/response communications. All communication is binary. +

    FirmwareConfig

    +
      +
    • the bootloader sends a FirmwareConfigRequest packet to the gateway to request information about the firmware it should execute: +

      +typedef struct
      +{
      + uint16_t type;
      + uint16_t version;
      +} FirmwareConfigRequest; +

      +
    • the gateway (the controller) responds with a FirmwareConfigResponse including details about the firmware the sensor should execute: +

      +typedef struct
      +{
      + uint16_t type;
      + uint16_t version;
      + uint16_t blocks;
      + uint16_t crc;
      +} FirmwareConfigResponse; +

      +
    +

    Firmware

    +
      +
    • the bootloader sends a FirmwareRequest packet to the gateway to request a specific subset (block) of the compiled firmware: +

      +typedef struct
      +{
      + uint16_t type;
      + uint16_t version;
      + uint16_t block;
      +} FirmwareRequest; +

      +
    • the gateway (the controller) responds with a FirmwareResponse including the specific block of the compiled firmware: +
    +

    +typedef struct
    +{
    + uint16_t type;
    + uint16_t version;
    + uint16_t block;
    + uint8_t data[FIRMWARE_BLOCK_SIZE];
    +} FirmwareResponse; +

    diff --git a/NodeJsController/NodeJsController.js b/NodeJsController/NodeJsController.js index fbe1470..8bb67da 100644 --- a/NodeJsController/NodeJsController.js +++ b/NodeJsController/NodeJsController.js @@ -11,8 +11,8 @@ const dbAddress = '127.0.0.1'; const dbPort = 27017; const dbName = 'MySensorsDb'; -const fwSketches = [ '../libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino' ]; -const fwDefaultType = 0; // index of hex file from array above +const fwSketches = [ ]; +const fwDefaultType = 0xFFFF; // index of hex file from array above (0xFFFF const FIRMWARE_BLOCK_SIZE = 16; const BROADCAST_ADDRESS = 255; diff --git a/NodeJsController/Readme.md b/NodeJsController/Readme.md index 98dee49..d8b364b 100644 --- a/NodeJsController/Readme.md +++ b/NodeJsController/Readme.md @@ -290,10 +290,8 @@ ISP_MCU = m328p

    End-to-End Test

    Add Firmware to Controller (here: DallasTemperatureSensor)

      -
    • use Arduino IDE or codebender or whatever other way to compile your sketch -
    • copy the compiled DallasTemperatureSensor.cpp.hex file to the NodeJsController directory (if using the Arduino IDE, enable verbose logging in preferences and then watch the compilation process to find the temp directory where the output is stored)
    • nano ~/Arduino/NodeJsController/NodeJsController.js -

      const fwHexFiles = [ 'DallasTemperatureSensor.cpp.hex' ];
      +

      const fwHexFiles = [ '../libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino' ];
      const fwDefaultType = 0;

    • sudo service mysensors restart (at this point stop/restart doesn't work. use "sudo killall node" followed by "sudo service mysensors start" instead)
    From 724567e295236436fb84e55f6adfc486c6360072 Mon Sep 17 00:00:00 2001 From: Daniel Wiegert Date: Wed, 27 Aug 2014 15:24:04 +0200 Subject: [PATCH 004/660] Bugfixes and rewrite parts of code --- libraries/MySensors/MyMQTT.cpp | 364 +++++++++--------- libraries/MySensors/MyMQTT.h | 29 +- .../examples/MQTTGateway/MQTTGateway.ino | 79 ++-- 3 files changed, 215 insertions(+), 257 deletions(-) mode change 100644 => 100755 libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino diff --git a/libraries/MySensors/MyMQTT.cpp b/libraries/MySensors/MyMQTT.cpp index 0884906..2ab42b5 100755 --- a/libraries/MySensors/MyMQTT.cpp +++ b/libraries/MySensors/MyMQTT.cpp @@ -12,71 +12,89 @@ version 2 as published by the Free Software Foundation. #include "MyMQTT.h" #include "utility/MsTimer2.h" +char V_0[] PROGMEM = "TEMP"; //V_TEMP +char V_1[] PROGMEM = "HUM"; //V_HUM +char V_2[] PROGMEM = "LIGHT"; //V_LIGHT +char V_3[] PROGMEM = "DIMMER"; //V_DIMMER +char V_4[] PROGMEM = "PRESSURE"; //V_PRESSURE +char V_5[] PROGMEM = "FORECAST"; //V_FORECAST +char V_6[] PROGMEM = "RAIN"; //V_RAIN +char V_7[] PROGMEM = "RAINRATE"; //V_RAINRATE +char V_8[] PROGMEM = "WIND"; //V_WIND +char V_9[] PROGMEM = "GUST"; //V_GUST +char V_10[] PROGMEM = "DIRECTON"; //V_DIRECTON +char V_11[] PROGMEM = "UV"; //V_UV +char V_12[] PROGMEM = "WEIGHT"; //V_WEIGHT +char V_13[] PROGMEM = "DISTANCE"; //V_DISTANCE +char V_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE +char V_15[] PROGMEM = "ARMED"; //V_ARMED +char V_16[] PROGMEM = "TRIPPED"; //V_TRIPPED +char V_17[] PROGMEM = "WATT"; //V_WATT +char V_18[] PROGMEM = "KWH"; //V_KWH +char V_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON +char V_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF +char V_21[] PROGMEM = "HEATER"; //V_HEATER +char V_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW +char V_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL +char V_24[] PROGMEM = "VAR1"; //V_VAR1 +char V_25[] PROGMEM = "VAR2"; //V_VAR2 +char V_26[] PROGMEM = "VAR3"; //V_VAR3 +char V_27[] PROGMEM = "VAR4"; //V_VAR4 +char V_28[] PROGMEM = "VAR5"; //V_VAR5 +char V_29[] PROGMEM = "UP"; //V_UP +char V_30[] PROGMEM = "DOWN"; //V_DOWN +char V_31[] PROGMEM = "STOP"; //V_STOP +char V_32[] PROGMEM = "IR_SEND"; //V_IR_SEND +char V_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE +char V_34[] PROGMEM = "FLOW"; //V_FLOW +char V_35[] PROGMEM = "VOLUME"; //V_VOLUME +char V_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS +char V_37[] PROGMEM = "DUST_LEVEL"; //V_DUST_LEVEL +char V_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE +char V_39[] PROGMEM = "CURRENT"; //V_CURRENT +char V_40[] PROGMEM = ""; // +char V_41[] PROGMEM = ""; // +char V_42[] PROGMEM = ""; // +char V_43[] PROGMEM = ""; // +char V_44[] PROGMEM = ""; // +char V_45[] PROGMEM = ""; // +char V_46[] PROGMEM = ""; // +char V_47[] PROGMEM = ""; // +char V_48[] PROGMEM = ""; // +char V_49[] PROGMEM = ""; // +char V_50[] PROGMEM = ""; // +char V_51[] PROGMEM = ""; // +char V_52[] PROGMEM = ""; // +char V_53[] PROGMEM = ""; // +char V_54[] PROGMEM = ""; // +char V_55[] PROGMEM = ""; // +char V_56[] PROGMEM = ""; // +char V_57[] PROGMEM = ""; // +char V_58[] PROGMEM = ""; // +char V_59[] PROGMEM = ""; // +char V_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway +char V_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway +char V_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway +char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway + +////////////////////////////////////////////////////////////////// + +PROGMEM const char *vType[] = { + V_0, V_1, V_2, V_3, V_4, V_5, V_6, V_7, V_8, V_9, V_10, + V_11, V_12, V_13, V_14, V_15, V_16, V_17, V_18, V_19, V_20, + V_21, V_22, V_23, V_24, V_25, V_26, V_27, V_28, V_29, V_30, + V_31, V_32, V_33, V_34, V_35, V_36, V_37, V_38, V_39, V_40, + V_41, V_42, V_43, V_44, V_45, V_46, V_47, V_48, V_49, V_50, + V_51, V_52, V_53, V_54, V_55, V_56, V_57, V_58, V_59, V_60, + V_61, V_62, V_63 +}; char broker[] PROGMEM = MQTT_BROKER_PREFIX; -char S_0[] PROGMEM = "Temperature"; //V_TEMP -char S_1[] PROGMEM = "Humidity"; //V_HUM -char S_2[] PROGMEM = "Light"; //V_LIGHT -char S_3[] PROGMEM = "Dimmer"; //V_DIMMER -char S_4[] PROGMEM = "Pressure"; //V_PRESSURE -char S_5[] PROGMEM = "Forecast"; //V_FORECAST -char S_6[] PROGMEM = "Rain"; //V_RAIN -char S_7[] PROGMEM = "Rainrate"; //V_RAINRATE -char S_8[] PROGMEM = "Wind"; //V_WIND -char S_9[] PROGMEM = "Gust"; //V_GUST -char S_10[] PROGMEM = "Direction"; //V_DIRECTION -char S_11[] PROGMEM = "UV"; //V_UV -char S_12[] PROGMEM = "Weight"; //V_WEIGHT -char S_13[] PROGMEM = "Distance"; //V_DISTANCE -char S_14[] PROGMEM = "Impedance"; //V_IMPEDANCE -char S_15[] PROGMEM = "Armed"; //V_ARMED -char S_16[] PROGMEM = "Tripped"; //V_TRIPPED -char S_17[] PROGMEM = "Watt"; //V_WATT -char S_18[] PROGMEM = "KWH"; //V_KWH -char S_19[] PROGMEM = "Scene_ON"; //V_SCENE_ON -char S_20[] PROGMEM = "Scene_OFF"; //V_SCENE_OFF -char S_21[] PROGMEM = "Heater"; //V_HEATER -char S_22[] PROGMEM = "Heater_SW"; //V_HEATER_SW -char S_23[] PROGMEM = "LightLevel"; //V_LIGHT_LEVEL -char S_24[] PROGMEM = "Var1"; //V_VAR1 -char S_25[] PROGMEM = "Var2"; //V_VAR2 -char S_26[] PROGMEM = "Var3"; //V_VAR3 -char S_27[] PROGMEM = "Var4"; //V_VAR4 -char S_28[] PROGMEM = "Var5,"; //V_VAR5 -char S_29[] PROGMEM = "Up"; //V_UP -char S_30[] PROGMEM = "Down"; //V_DOWN -char S_31[] PROGMEM = "Stop"; //V_STOP -char S_32[] PROGMEM = "IR_Send"; //V_IR_SEND -char S_33[] PROGMEM = "IR_Receive"; //V_IR_RECEIVE -char S_34[] PROGMEM = "Flow"; //V_FLOW -char S_35[] PROGMEM = "Volume"; //V_VOLUME -char S_36[] PROGMEM = "Lock_Status";//V_LOCK_STATUS -char S_37[] PROGMEM = "DustLevel"; //V_DUST_LEVEL -char S_38[] PROGMEM = ""; -char S_39[] PROGMEM = ""; -char S_40[] PROGMEM = ""; -char S_41[] PROGMEM = ""; -char S_42[] PROGMEM = ""; -char S_43[] PROGMEM = ""; -char S_44[] PROGMEM = ""; -char S_45[] PROGMEM = "Volt_Batt"; // Does not exist in MyMessage.h! -char S_46[] PROGMEM = ""; -char S_47[] PROGMEM = ""; -char S_48[] PROGMEM = ""; -char S_49[] PROGMEM = "Sketch_name"; // Does not exist in MyMessage.h! -char S_50[] PROGMEM = "Sketch_version"; // Does not exist in MyMessage.h! - - -PROGMEM const char *sType[] = { - S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, S_8, S_9, S_10, - S_11, S_12, S_13, S_14, S_15, S_16, S_17, S_18, S_19, S_20, - S_21, S_22, S_23, S_24, S_25, S_26, S_27, S_28, S_29, S_30, - S_31, S_32, S_33, S_34, S_35, S_36, S_37, S_38, S_39, S_40, - S_41, S_42, S_43, S_44, S_45, S_46, S_47, S_48, S_49, S_50 -}; - +#define S_FIRSTCUSTOM 60 +#define TYPEMAXLEN 20 +#define V_TOTAL (sizeof(vType)/sizeof(char *))-1 extern volatile uint8_t countRx; extern volatile uint8_t countTx; @@ -90,11 +108,32 @@ MySensor(_cepin, _cspin) { } -void MyMQTT::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate, void (*inDataCallback)(const char *, int *), uint8_t _rx, uint8_t _tx, uint8_t _er) { +inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { + msg.destination = destination; + msg.sender = sender; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,enableAck); + mSetAck(msg,false); + return msg; +} + +char *getType(char *b, const char **index) { + char *q = b; + char *p = (char *)pgm_read_ptr(index); + while (*q++ = pgm_read_byte(p++)); + *q=0; + return b; +} + +void MyMQTT::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate, void (*inDataCallback) + (const char *, uint8_t *), uint8_t _rx, uint8_t _tx, uint8_t _er) { Serial.begin(BAUD_RATE); repeaterMode = true; isGateway = true; MQTTClientConnected = false; + setupRepeaterMode(); dataCallback = inDataCallback; @@ -117,10 +156,7 @@ void MyMQTT::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataR MsTimer2::set(200, ledTimersInterrupt); MsTimer2::start(); - - // Send startup log message on serial - //Serial.print(PSTR("Started\n"));//TODO: progmem gives error..? error: sType causes a section type conflict with __c - Serial.print("Started\n");//TODO: fix this... + Serial.print(getType(convBuf, &vType[S_FIRSTCUSTOM])); } void MyMQTT::processRadioMessage() { @@ -134,104 +170,97 @@ void MyMQTT::processRadioMessage() { } -void MyMQTT::processMQTTMessage(char *inputString, int inputPos) { +void MyMQTT::processMQTTMessage(char *inputString, uint8_t inputPos) { char *str, *p; - char i = 0; + uint8_t i = 0; buffer[0]= 0; buffsize = 0; -#ifdef TCPDUMP - Serial.print("<<"); - char buf[4]; - for (int a=0; a> 4 == MQTTCONNECT) { + + if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) { buffer[buffsize++] = MQTTCONNACK << 4; - buffer[buffsize++] = 0x02; // Remaining length - buffer[buffsize++] = 0x00; // Connection accepted - buffer[buffsize++] = 0x00; // Reserved - MQTTClientConnected=true; + buffer[buffsize++] = 0x02; // Remaining length + buffer[buffsize++] = 0x00; // Connection accepted + buffer[buffsize++] = 0x00; // Reserved + MQTTClientConnected=true; // We have connection! } - if ((byte)inputString[0] >> 4 == MQTTPINGREQ) { + if ((uint8_t)inputString[0] >> 4 == MQTTPINGREQ) { buffer[buffsize++] = MQTTPINGRESP << 4; buffer[buffsize++] = 0x00; } - if ((byte)inputString[0] >> 4 == MQTTSUBSCRIBE) { - buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! - buffer[buffsize++] = 0x03; // Remaining length - buffer[buffsize++] = (byte)inputString[2]; // Message ID MSB - buffer[buffsize++] = (byte)inputString[3]; // Message ID LSB - buffer[buffsize++] = MQTTQOS0; // QOS level + if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { + buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! + buffer[buffsize++] = 0x03; // Remaining length + buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB + buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB + buffer[buffsize++] = MQTTQOS0; // QOS level } - if ((byte)inputString[0] >> 4 == MQTTUNSUBSCRIBE) { + if ((uint8_t)inputString[0] >> 4 == MQTTUNSUBSCRIBE) { buffer[buffsize++] = MQTTUNSUBACK << 4; - buffer[buffsize++] = 0x02; // Remaining length - buffer[buffsize++] = (byte)inputString[2]; // Message ID MSB - buffer[buffsize++] = (byte)inputString[3]; // Message ID LSB + buffer[buffsize++] = 0x02; // Remaining length + buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB + buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB } - if ((byte)inputString[0] >> 4 == MQTTDISCONNECT) { - MQTTClientConnected=false; + if ((uint8_t)inputString[0] >> 4 == MQTTDISCONNECT) { + MQTTClientConnected=false; // We lost connection! } if (buffsize > 0) { -#ifdef TCPDUMP - Serial.print(">>"); - char buf[4]; - for (int a=0; a> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (byte)inputString[0] >> 4 == MQTTSUBSCRIBE)) { + if ((uint8_t)inputString[0] >> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { buffer[0]= 0; buffsize = 0; - if ((byte)inputString[0] >> 4 == MQTTSUBSCRIBE) { + // Cut out address and payload depending on message type. + if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { strncat(buffer,inputString+6,inputString[5]); } else { strncat(buffer,inputString+4,inputString[3]); } - msg.sender = GATEWAY_ADDRESS; - for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) { //split using semicolon - // TODO: Check if we should send ack or not. + + // TODO: Check if we should send ack or not. + for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) { if (i == 0) { - if (strcmp_P(str,broker)!=0) { - return; //Message not for us or malformatted! + if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX + return; //Message not for us or malformatted! } } else if (i==1) { - msg.destination = atoi(str); + msg.destination = atoi(str); //NodeID } else if (i==2) { - msg.sensor = atoi(str); + msg.sensor = atoi(str); //SensorID } else if (i==3) { - char match=0; - for (int j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(sType[j]))) ; j++) { - if (strcmp(str,convBuf)==0) { + char match=0; //SensorType + //strcpy(str,(char*)&str[2]); //Strip V_ + + for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) { + if (strcmp((char*)&str[2],convBuf)==0) { //Strip V_ and compare match=j; break; } + if (j >= V_TOTAL) { // No match found! + match=V_TOTAL; // last item. + break; + } } msg.type = match; } i++; - } - if ((char)inputString[1] > (char)(inputString[3]+2) && !((byte)inputString[0] >> 4 == MQTTSUBSCRIBE)) { + } //Check if packge has payload + if ((uint8_t)inputString[1] > (uint8_t)(inputString[3]+2) && !((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { strcpy(convBuf,inputString+(inputString[3]+4)); - msg.set(convBuf); + msg.set(convBuf); //Payload } else { - msg.set(""); + msg.set(""); //No payload } - msg.sender = GATEWAY_ADDRESS; - mSetCommand(msg,C_SET); - mSetRequestAck(msg,false); - mSetAck(msg,false); - mSetVersion(msg, PROTOCOL_VERSION); txBlink(1); - if (!sendRoute(msg)) errBlink(1); + if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type, 0))) errBlink(1); + } } - void MyMQTT::SendMQTT(MyMessage &msg) { - //serial(PSTR("%d;%d;%d;%d;%s\n"),msg.sender, msg.sensor, mGetCommand(msg), msg.type, msg.getString(convBuf)); buffsize = 0; - if (!MQTTClientConnected) return; + if (!MQTTClientConnected) return; //We have no connections - return if (msg.isAck()) { Serial.println("msg is ack!"); if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) { @@ -246,95 +275,52 @@ void MyMQTT::SendMQTT(MyMessage &msg) { if (msg.sender==newNodeID) { saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); } - if (mGetCommand(msg)==C_INTERNAL && msg.type==I_CONFIG) { // CONFIG - // As for now there is only one 'config' request. - // We force SI! Resistance is futile! - // - // Todo : Support for more config types, Maybe just read from own EEPROM? - // Use internal EEPROM_CONTROLLER_CONFIG_ADDRESS and special MQTT address to write to - // EEPROM_CONTROLLER_CONFIG_ADDRESS & EEPROM_LOCAL_CONFIG_ADDRESS - msg.destination = msg.sender; //NodeID - msg.sender = GATEWAY_ADDRESS; - msg.sensor = 255; //SensorID - msg.type = I_CONFIG; //msgType - mSetCommand(msg,C_INTERNAL);//Subtype - mSetRequestAck(msg,false); - mSetAck(msg,false); - msg.set("M"); - mSetVersion(msg, PROTOCOL_VERSION); - txBlink(1); - if (!sendRoute(msg)) errBlink(1); - } else if (mGetCommand(msg)==C_PRESENTATION && (msg.type==S_ARDUINO_NODE || msg.type==S_ARDUINO_REPEATER_NODE)) { - //Doesnt work to check new sensorID here, this message does not always arrive.. See above. - } else if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) { - unsigned char newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; - if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; - if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :( - msg.destination = msg.sender; //NodeID - msg.sender = GATEWAY_ADDRESS; - msg.sensor = 255; //SensorID - msg.type = I_ID_RESPONSE; //MsgType - mSetCommand(msg,C_INTERNAL); //Subtype - mSetRequestAck(msg,false); //Request ack doesn't work, node/gateway gets stuck in enless loop. - mSetAck(msg,false); - msg.set((uint8_t)newNodeID); //Payload - mSetVersion(msg, PROTOCOL_VERSION); - txBlink(1); - if (!sendRoute(msg)) errBlink(1); - // if (sendRoute(msg)) saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); // If send OK save to eeprom. DOES NOT ALWAYS RETURN 'OK'!? + if (mGetCommand(msg)==C_INTERNAL) { + if (msg.type==I_CONFIG) { + txBlink(1); + if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set("M"))) errBlink(1); + } else if (msg.type==I_ID_REQUEST && msg.sender==255) { + uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; + if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; + if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :( + txBlink(1); + if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) errBlink(1); + } } else if (mGetCommand(msg)!=0) { - if (mGetCommand(msg)==3) msg.type=msg.type+38; - buffer[buffsize++] = MQTTPUBLISH << 4; // 0: - buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2 - buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!) - buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later + if (mGetCommand(msg)==3) msg.type=msg.type+(S_FIRSTCUSTOM-10); //Special message + + buffer[buffsize++] = MQTTPUBLISH << 4; // 0: + buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2 + buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!) + buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later + if (msg.type > V_TOTAL) msg.type=V_TOTAL;// If type > defined types set to unknown. strcpy_P(buffer+4, broker); buffsize+=strlen_P(broker); - buffsize+=sprintf(&buffer[buffsize],"/%i/%i/",msg.sender,msg.sensor); - buffsize+=strncpysType_retL(buffer,msg.type,buffsize); - buffer[3]=buffsize-4; // Set correct address length on byte 4. + buffsize+=sprintf(&buffer[buffsize],"/%i/%i/V_%s",msg.sender,msg.sensor,getType(convBuf, &vType[msg.type])); + buffer[3]=buffsize-4; // Set correct address length on byte 4. #ifdef DEBUG Serial.println((char*)&buffer[4]); #endif msg.getString(convBuf); - for (unsigned int a=0; a>"); - char buf[4]; - for (int a=0; a0) otherwise the code might do strange things. -/////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// #define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS) #define MQTT_MAX_PACKET_SIZE 100 @@ -56,29 +55,27 @@ version 2 as published by the Free Software Foundation. class MyMQTT : public MySensor { + public: MyMQTT(uint8_t _cepin=5, uint8_t _cspin=6); - void begin(rf24_pa_dbm_e paLevel=RF24_PA_LEVEL_GW, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE, void (*dataCallback)(const char *, int *)=NULL, uint8_t _rx=6, uint8_t _tx=5, uint8_t _er=4 ); + void begin(rf24_pa_dbm_e paLevel=RF24_PA_LEVEL_GW, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE, void (*dataCallback) + (const char *, uint8_t *)=NULL, uint8_t _rx=6, uint8_t _tx=5, uint8_t _er=4 ); void processRadioMessage(); - void processMQTTMessage(char *inputString, int inputPos); + void processMQTTMessage(char *inputString, uint8_t inputPos); private: - bool MQTTClientConnected; - char buffer[MQTT_MAX_PACKET_SIZE]; - int buffsize; - char convBuf[MAX_PAYLOAD*2+1]; - boolean useWriteCallback; - void (*dataCallback)(const char *, int *); + void (*dataCallback)(const char *, uint8_t *); void SendMQTT(MyMessage &msg); - char strncpysType_retL(char *str, unsigned char index, char start); - - void ledTimers(); void rxBlink(uint8_t cnt); void txBlink(uint8_t cnt); void errBlink(uint8_t cnt); + + bool MQTTClientConnected; + char buffer[MQTT_MAX_PACKET_SIZE]; + char convBuf[MAX_PAYLOAD*2+1]; + uint8_t buffsize; }; extern void ledTimersInterrupt(); - #endif diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino old mode 100644 new mode 100755 index 3cb651a..29f6551 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -31,18 +31,19 @@ This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC y message has any length or not. Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. -* Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/[SensorType] +* Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType] NodeID and SensorID is uint8 (0-255) number. Last segment is translation of the sensor type, look inside MyMQTT.cpp for the definitions. User can change this to their needs. We have also left some space for custom types. Special: (sensor 255 reserved for special commands) -You can receive a node sketch name with MyMQTT/20/255/Sketch_name (or version with _version) +You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version) To-do: Special commands : clear or set EEPROM Values, Send REBOOT and Receive reboot for MyMQTT itself. Be able to send ACK so client returns the data being sent. ... Please come with ideas! +What to do with publish messages. Test in more MQTT clients, So far tested in openhab and MyMQTT for Android (Not my creation) - http://www.openhab.org/ @@ -50,51 +51,16 @@ Test in more MQTT clients, So far tested in openhab and MyMQTT for Android (Not ... Please notify me if you use this broker with other software. -* Example Openhab configuration: -openhab.cfg ---- -mqtt:mysensor.url=tcp://192.168.0.234:1883 -mqtt:mysensor.clientId=MQTT ---- - -items/test.items ---- -Group test -Number Temp_test "Temp [%.1f °C]" (test) {mqtt="<[mysensor:MyMQTT/20/#/Temperature:state:default]"} -Number Hum_test "Hum [%.1f %%]" (test) {mqtt="<[mysensor:MyMQTT/20/#/Humidity:state:default]"} -Number test_test "test [%s]" (test) {mqtt="<[mysensor:MyMQTT/20/3/#:state:default]"} -Switch sw1 "sw 1" (test) {mqtt="<[mysensor:MyMQTT/21/1/Light:command:MAP(1on0off.map)]"} -Switch sw2 "sw2 recieve example" (test) {mqtt=">[mysensor:MyMQTT/21/2/Light:command:ON:1], - >[mysensor:MyMQTT/21/2/Light:command:OFF:0]"} -Switch sw3 "sw2 send + recieve example" (test) {mqtt=">[mysensor:MyMQTT/21/2/Light:command:ON:1], - >[mysensor:MyMQTT/21/2/Light:command:OFF:0],<[mysensor:MyMQTT/21/2/Light:command:MAP(1on0off.map)]"} -String sketch20 "Node 20 Sketch name [%s]" (test) {mqtt="<[mysensor:MyMQTT/20/255/Sketch_name:state:default]"} -String sketch21 "Node 21 Sketch name [%s]" (test) {mqtt="<[mysensor:MyMQTT/21/255/Sketch_name:state:default]"} ---- (Note; # = Wildcard character) - -sitemap/test.site ---- -sitemap demo label="Menu" -Frame label="Openhab" { - Group item=test label="Test group" -} ---- - -transform/1on0off.map ---- -1=ON -0=OFF ---- +* How to set-up Openhab and MQTTGateway: +http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ - #include #include #include - -// Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! +// * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! /* #define RADIO_CE_PIN 3 // radio chip enable #define RADIO_SPI_SS_PIN 8 // radio SPI serial select @@ -102,7 +68,7 @@ transform/1on0off.map #define RADIO_RX_LED_PIN A1 // Receive led pin #define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/ -//Use this for default configured pro mini / nano etc : +// * Use this for default configured pro mini / nano etc : ///* #define RADIO_CE_PIN 5 // radio chip enable #define RADIO_SPI_SS_PIN 6 // radio SPI serial select @@ -110,19 +76,18 @@ transform/1on0off.map #define RADIO_RX_LED_PIN 8 // Receive led pin #define RADIO_TX_LED_PIN 9 // the PCB, on board LED*/ -#define TCP_PORT 1883 // Set your MQTT Broker Listening port. -IPAddress TCP_IP ( 192, 168, 0, 234 ); // Configure your static ip-address here -byte TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above! +#define TCP_PORT 1883 // Set your MQTT Broker Listening port. +IPAddress TCP_IP ( 192, 168, 0, 234 ); // Configure your static ip-address here +uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above! + +////////////////////////////////////////////////////////////////// EthernetServer server = EthernetServer(TCP_PORT); MyMQTT gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); -// -- Uncomment this constructor if you have leds and include button attached to your gateway -//MyMQTT gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); - void processEthernetMessages() { char inputString[MQTT_MAX_PACKET_SIZE] = ""; - int inputSize = 0; + uint8_t inputSize = 0; EthernetClient client = server.available(); if (client) { while (client.available()) { @@ -130,23 +95,33 @@ void processEthernetMessages() { inputString[inputSize] = inChar; inputSize++; } +#ifdef TCPDUMP + Serial.print("<<"); + char buf[4]; + for (uint8_t a=0; a>"); + char buf[4]; + for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(""); +#endif + server.write((const uint8_t *)writeBuffer, *writeSize); } + int main(void) { init(); Ethernet.begin(TCP_MAC, TCP_IP); delay(1000); // Wait for Ethernet to get configured. - gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet); + gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); server.begin(); while (1) { processEthernetMessages(); gw.processRadioMessage(); } } - From 6dde2e428a35e8930214d816df3144fdf09e5985 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 27 Aug 2014 21:24:00 +0200 Subject: [PATCH 005/660] Need to include MySensor.h for gateway examples to work in codebender. --- README.md | 2 +- libraries/MySensors/Version.h | 2 +- .../MySensors/examples/EthernetGateway/EthernetGateway.ino | 5 +++-- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 1 + libraries/MySensors/examples/SerialGateway/SerialGateway.ino | 1 + 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4df7c40..ebb4f31 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Arduino ======= -MySensors Arduino Library +MySensors Arduino Library v1.4 Please visit www.mysensors.org for more information diff --git a/libraries/MySensors/Version.h b/libraries/MySensors/Version.h index bc5edc4..026d736 100644 --- a/libraries/MySensors/Version.h +++ b/libraries/MySensors/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.4b1 (18848a2)" +#define LIBRARY_VERSION "1.4" #endif diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 5932de6..df3b935 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -45,14 +45,15 @@ */ #include +#include #include #include // Use this if you have attached a Ethernet ENC28J60 shields -#include +//#include // Use this fo WizNET module and Arduino Ethernet Shield -//#include +#include #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 29f6551..5050b59 100755 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -57,6 +57,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ #include +#include #include #include diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index a59de08..8c3a7dd 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -22,6 +22,7 @@ */ #include +#include #include #include From cc00bedaa1bb926da1f2a803cabd17e8a47130e7 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 27 Aug 2014 21:53:57 +0200 Subject: [PATCH 006/660] Classify method. --- libraries/MySensors/MyMQTT.cpp | 2 +- libraries/MySensors/MyMQTT.h | 2 ++ libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) mode change 100755 => 100644 libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino diff --git a/libraries/MySensors/MyMQTT.cpp b/libraries/MySensors/MyMQTT.cpp index 2ab42b5..f080790 100755 --- a/libraries/MySensors/MyMQTT.cpp +++ b/libraries/MySensors/MyMQTT.cpp @@ -119,7 +119,7 @@ inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, ui return msg; } -char *getType(char *b, const char **index) { +char *MyMQTT::getType(char *b, const char **index) { char *q = b; char *p = (char *)pgm_read_ptr(index); while (*q++ = pgm_read_byte(p++)); diff --git a/libraries/MySensors/MyMQTT.h b/libraries/MySensors/MyMQTT.h index 76d0830..e5d5447 100755 --- a/libraries/MySensors/MyMQTT.h +++ b/libraries/MySensors/MyMQTT.h @@ -14,6 +14,7 @@ version 2 as published by the Free Software Foundation. #include "MySensor.h" + ////////////////////////////////////////////////////////////////// #ifdef DEBUG @@ -74,6 +75,7 @@ private: char buffer[MQTT_MAX_PACKET_SIZE]; char convBuf[MAX_PAYLOAD*2+1]; uint8_t buffsize; + char *getType(char *b, const char **index); }; extern void ledTimersInterrupt(); diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino old mode 100755 new mode 100644 index 5050b59..bbd44dd --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -61,6 +61,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include + // * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! /* #define RADIO_CE_PIN 3 // radio chip enable From ba098a95e20c55dc00f847f36c3746efa840bb87 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 27 Aug 2014 22:55:52 +0200 Subject: [PATCH 007/660] Fix compiler error. --- libraries/MySensors/MyMQTT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMQTT.cpp b/libraries/MySensors/MyMQTT.cpp index f080790..610414e 100755 --- a/libraries/MySensors/MyMQTT.cpp +++ b/libraries/MySensors/MyMQTT.cpp @@ -121,7 +121,7 @@ inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, ui char *MyMQTT::getType(char *b, const char **index) { char *q = b; - char *p = (char *)pgm_read_ptr(index); + char *p = (char *)pgm_read_word(index); while (*q++ = pgm_read_byte(p++)); *q=0; return b; From 159c22388245bb0f6686efacc3c7ad2204b85e0d Mon Sep 17 00:00:00 2001 From: Daniel Wiegert Date: Thu, 28 Aug 2014 14:30:42 +0200 Subject: [PATCH 008/660] Include more debug text in MINIMAL definition, and enable MINIMAL as default, saves 432bytes --- libraries/MySensors/utility/RF24.cpp | 3 ++- libraries/MySensors/utility/RF24.h | 4 ++-- libraries/MySensors/utility/RF24_config.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) mode change 100644 => 100755 libraries/MySensors/utility/RF24.cpp mode change 100644 => 100755 libraries/MySensors/utility/RF24.h mode change 100644 => 100755 libraries/MySensors/utility/RF24_config.h diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp old mode 100644 new mode 100755 index 2efb7bb..38053ab --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -270,6 +270,7 @@ uint8_t RF24::get_status(void) } /****************************************************************************/ +#if !defined (MINIMAL) void RF24::print_status(uint8_t status) { @@ -325,7 +326,7 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) printf_P(PSTR("\r\n")); } - +#endif /****************************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin): diff --git a/libraries/MySensors/utility/RF24.h b/libraries/MySensors/utility/RF24.h old mode 100644 new mode 100755 index 55253bb..89ed231 --- a/libraries/MySensors/utility/RF24.h +++ b/libraries/MySensors/utility/RF24.h @@ -863,7 +863,7 @@ private: * @return Current value of status register */ uint8_t get_status(void); - +#if !defined (MINIMAL) /** * Decode and print the given status to stdout * @@ -907,7 +907,7 @@ private: * @param qty How many successive registers to print */ void print_address_register(const char* name, uint8_t reg, uint8_t qty = 1); - +#endif /** * Turn on or off the special features of the chip * diff --git a/libraries/MySensors/utility/RF24_config.h b/libraries/MySensors/utility/RF24_config.h old mode 100644 new mode 100755 index b7154a5..55962f1 --- a/libraries/MySensors/utility/RF24_config.h +++ b/libraries/MySensors/utility/RF24_config.h @@ -21,7 +21,7 @@ #include //TMRh20: - //#define MINIMAL + #define MINIMAL // saves 432 bytes! // Define _BV for non-Arduino platforms and for Arduino DUE #if defined (ARDUINO) From 7fa54a6e5a2c6d1d58a2705d32d6fe88c151eeec Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Sep 2014 16:57:56 +0200 Subject: [PATCH 009/660] Proposal to keep gateways separated. --- .../utility => MsTimer2}/MsTimer2.cpp | 0 .../utility => MsTimer2}/MsTimer2.h | 0 .../MsTimer2/examples/FlashLed/FlashLed.pde | 42 ++ libraries/MsTimer2/keywords.txt | 4 + libraries/MySensors/MyGateway.cpp | 297 -------- libraries/MySensors/MyGateway.h | 72 -- libraries/MySensors/MyMQTT.cpp | 326 --------- libraries/MySensors/MySensor.cpp | 9 +- libraries/MySensors/MySensor.h | 2 +- .../EthernetGateway/EthernetGateway.ino | 58 +- .../examples/EthernetGateway/GatewayUtil.h | 262 +++++++ .../examples/MQTTGateway/GatewayUtil.h | 120 ++++ .../examples/MQTTGateway/MQTTGateway.ino | 319 ++++++++- .../MySensors/examples/MQTTGateway/MyMQTT.h | 138 ++++ .../MQTTGateway/MyMQTT.hx} | 0 .../examples/SerialGateway/GatewayUtil.h | 262 +++++++ .../examples/SerialGateway/SerialGateway.ino | 59 +- .../Examples/ByteBuffer/ByteBuffer.cpp | 272 +++++++ .../Examples/ByteBuffer/ByteBuffer.h | 104 +++ .../PinChangeInt/Examples/GetPSTR/GetPSTR.h | 21 + .../PinChangeIntExample.pde | 77 ++ .../PinChangeIntSpeedTest.pde | 265 +++++++ .../PinChangeIntTest/PinChangeIntTest.pde | 344 +++++++++ .../PinChangeIntTest2/PinChangeIntTest2.ino | 275 +++++++ .../utility => PinChangeInt}/PinChangeInt.h | 0 libraries/PinChangeInt/RELEASE_NOTES | 332 +++++++++ libraries/PinChangeInt/gpl.txt | 674 ++++++++++++++++++ libraries/PinChangeInt/keywords.txt | 10 + 28 files changed, 3604 insertions(+), 740 deletions(-) rename libraries/{MySensors/utility => MsTimer2}/MsTimer2.cpp (100%) rename libraries/{MySensors/utility => MsTimer2}/MsTimer2.h (100%) create mode 100644 libraries/MsTimer2/examples/FlashLed/FlashLed.pde create mode 100644 libraries/MsTimer2/keywords.txt delete mode 100644 libraries/MySensors/MyGateway.cpp delete mode 100644 libraries/MySensors/MyGateway.h delete mode 100755 libraries/MySensors/MyMQTT.cpp create mode 100644 libraries/MySensors/examples/EthernetGateway/GatewayUtil.h create mode 100644 libraries/MySensors/examples/MQTTGateway/GatewayUtil.h create mode 100644 libraries/MySensors/examples/MQTTGateway/MyMQTT.h rename libraries/MySensors/{MyMQTT.h => examples/MQTTGateway/MyMQTT.hx} (100%) create mode 100644 libraries/MySensors/examples/SerialGateway/GatewayUtil.h create mode 100644 libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp create mode 100644 libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h create mode 100644 libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h create mode 100644 libraries/PinChangeInt/Examples/PinChangeIntExample/PinChangeIntExample.pde create mode 100644 libraries/PinChangeInt/Examples/PinChangeIntSpeedTest/PinChangeIntSpeedTest.pde create mode 100644 libraries/PinChangeInt/Examples/PinChangeIntTest/PinChangeIntTest.pde create mode 100644 libraries/PinChangeInt/Examples/PinChangeIntTest2/PinChangeIntTest2.ino rename libraries/{MySensors/utility => PinChangeInt}/PinChangeInt.h (100%) create mode 100644 libraries/PinChangeInt/RELEASE_NOTES create mode 100644 libraries/PinChangeInt/gpl.txt create mode 100644 libraries/PinChangeInt/keywords.txt diff --git a/libraries/MySensors/utility/MsTimer2.cpp b/libraries/MsTimer2/MsTimer2.cpp similarity index 100% rename from libraries/MySensors/utility/MsTimer2.cpp rename to libraries/MsTimer2/MsTimer2.cpp diff --git a/libraries/MySensors/utility/MsTimer2.h b/libraries/MsTimer2/MsTimer2.h similarity index 100% rename from libraries/MySensors/utility/MsTimer2.h rename to libraries/MsTimer2/MsTimer2.h diff --git a/libraries/MsTimer2/examples/FlashLed/FlashLed.pde b/libraries/MsTimer2/examples/FlashLed/FlashLed.pde new file mode 100644 index 0000000..4d04496 --- /dev/null +++ b/libraries/MsTimer2/examples/FlashLed/FlashLed.pde @@ -0,0 +1,42 @@ +char dummyvar; // to get Arduinoi IDE to include core headers properly + +/* + MsTimer2 is a small and very easy to use library to interface Timer2 with + humans. It's called MsTimer2 because it "hardcodes" a resolution of 1 + millisecond on timer2 + For Details see: http://www.arduino.cc/playground/Main/MsTimer2 +*/ +#include + +// Switch on LED on and off each half second + +#if defined(ARDUINO) && ARDUINO >= 100 +const int led_pin = LED_BUILTIN; // 1.0 built in LED pin var +#else +#if defined(CORE_LED0_PIN) +const int led_pin = CORE_LED0_PIN; // 3rd party LED pin define +#else +const int led_pin = 13; // default to pin 13 +#endif +#endif + + +void flash() +{ + static boolean output = HIGH; + + digitalWrite(led_pin, output); + output = !output; +} + +void setup() +{ + pinMode(led_pin, OUTPUT); + + MsTimer2::set(500, flash); // 500ms period + MsTimer2::start(); +} + +void loop() +{ +} diff --git a/libraries/MsTimer2/keywords.txt b/libraries/MsTimer2/keywords.txt new file mode 100644 index 0000000..8b4fff7 --- /dev/null +++ b/libraries/MsTimer2/keywords.txt @@ -0,0 +1,4 @@ +MsTimer2 KEYWORD1 +set KEYWORD2 +start KEYWORD2 +stop KEYWORD2 diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp deleted file mode 100644 index 2785ec9..0000000 --- a/libraries/MySensors/MyGateway.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - The MySensors library adds a new layer on top of the RF24 library. - It handles radio network routing, relaying and ids. - - Created by Henrik Ekblad - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. -*/ - -#include "MyGateway.h" -#include "utility/MsTimer2.h" -#include "utility/PinChangeInt.h" - - -uint8_t pinRx; -uint8_t pinTx; -uint8_t pinEr; -boolean buttonTriggeredInclusion; -volatile uint8_t countRx; -volatile uint8_t countTx; -volatile uint8_t countErr; -boolean inclusionMode; // Keeps track on inclusion mode - - -MyGateway::MyGateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time, uint8_t _inclusion_pin, uint8_t _rx, uint8_t _tx, uint8_t _er) : MySensor(_cepin, _cspin) { - pinInclusion = _inclusion_pin; - inclusionTime = _inclusion_time; - pinRx = _rx; - pinTx = _tx; - pinEr = _er; -} - - -void MyGateway::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate, void (*inDataCallback)(char *)) { - Serial.begin(BAUD_RATE); - repeaterMode = true; - isGateway = true; - setupRepeaterMode(); - - if (inDataCallback != NULL) { - useWriteCallback = true; - dataCallback = inDataCallback; - } else { - useWriteCallback = false; - } - - nc.nodeId = 0; - nc.distance = 0; - inclusionMode = 0; - buttonTriggeredInclusion = false; - countRx = 0; - countTx = 0; - countErr = 0; - - // Setup led pins - pinMode(pinRx, OUTPUT); - pinMode(pinTx, OUTPUT); - pinMode(pinEr, OUTPUT); - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); - - // Setup digital in that triggers inclusion mode - pinMode(pinInclusion, INPUT); - digitalWrite(pinInclusion, HIGH); - - // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); - - - // Start up the radio library - setupRadio(paLevel, channel, dataRate); - RF24::openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); - RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); - RF24::startListening(); - - // Add led timer interrupt - MsTimer2::set(300, ledTimersInterrupt); - MsTimer2::start(); - - // Add interrupt for inclusion button to pin - PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); - - // Send startup log message on serial - serial(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); -} - - -void startInclusionInterrupt() { - buttonTriggeredInclusion = true; -} - - - -void MyGateway::checkButtonTriggeredInclusion() { - if (buttonTriggeredInclusion) { - // Ok, someone pressed the inclusion button on the gateway - // start inclusion mode for 1 munute. - serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); - buttonTriggeredInclusion = false; - setInclusionMode(true); - } -} - -void MyGateway::checkInclusionFinished() { - if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { - // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode - setInclusionMode(false); - } -} - -uint8_t MyGateway::h2i(char c) { - uint8_t i = 0; - if (c <= '9') - i += c - '0'; - else if (c >= 'a') - i += c - 'a' + 10; - else - i += c - 'A' + 10; - return i; -} - -void MyGateway::parseAndSend(char *commandBuffer) { - boolean ok = false; - char *str, *p, *value=NULL; - uint8_t bvalue[MAX_PAYLOAD]; - uint8_t blen = 0; - int i = 0; - uint16_t destination = 0; - uint8_t sensor = 0; - uint8_t command = 0; - uint8_t type = 0; - uint8_t ack = 0; - - // Extract command data coming on serial line - for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon - str && i < 6; // loop while str is not null an max 5 times - str = strtok_r(NULL, ";", &p) // get subsequent tokens - ) { - switch (i) { - case 0: // Radioid (destination) - destination = atoi(str); - break; - case 1: // Childid - sensor = atoi(str); - break; - case 2: // Message type - command = atoi(str); - break; - case 3: // Should we request ack from destination? - ack = atoi(str); - break; - case 4: // Data type - type = atoi(str); - break; - case 5: // Variable value - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*str) { - val = h2i(*str++) << 4; - val += h2i(*str++); - bvalue[blen] = val; - blen++; - } - } else { - value = str; - // Remove ending carriage return character (if it exists) - uint8_t lastCharacter = strlen(value)-1; - if (value[lastCharacter] == '\r') - value[lastCharacter] = 0; - } - break; - } - i++; - } - - if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { - // Handle messages directed to gateway - if (type == I_VERSION) { - // Request for version - serial(PSTR("0;0;%d;0;%d;%s\n"),C_INTERNAL, I_VERSION, LIBRARY_VERSION); - } else if (type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(value) == 1); - } - } else { - txBlink(1); - msg.sender = GATEWAY_ADDRESS; - msg.destination = destination; - msg.sensor = sensor; - msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,ack?1:0); - mSetAck(msg,false); - if (command == C_STREAM) - msg.set(bvalue, blen); - else - msg.set(value); - ok = sendRoute(msg); - if (!ok) { - errBlink(1); - } - } -} - - -void MyGateway::setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) - inclusionMode = newMode; - // Send back mode change on serial line to ack command - serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); - - if (inclusionMode) { - inclusionStartTime = millis(); - } -} - -void MyGateway::processRadioMessage() { - if (process()) { - // A new message was received from one of the sensors - MyMessage message = getLastMessage(); - if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { - rxBlink(3); - } else { - rxBlink(1); - } - // Pass along the message from sensors to serial line - serial(message); - } - - checkButtonTriggeredInclusion(); - checkInclusionFinished(); -} - -void MyGateway::serial(const char *fmt, ... ) { - va_list args; - va_start (args, fmt ); - vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); - va_end (args); - Serial.print(serialBuffer); - if (useWriteCallback) { - // We have a registered write callback (probably Ethernet) - dataCallback(serialBuffer); - } -} - -void MyGateway::serial(MyMessage &msg) { - serial(PSTR("%d;%d;%d;%d;%d;%s\n"),msg.sender, msg.sensor, mGetCommand(msg), mGetAck(msg), msg.type, msg.getString(convBuf)); -} - - -void ledTimersInterrupt() { - if(countRx && countRx != 255) { - // switch led on - digitalWrite(pinRx, LOW); - } else if(!countRx) { - // switching off - digitalWrite(pinRx, HIGH); - } - if(countRx != 255) { countRx--; } - - if(countTx && countTx != 255) { - // switch led on - digitalWrite(pinTx, LOW); - } else if(!countTx) { - // switching off - digitalWrite(pinTx, HIGH); - } - if(countTx != 255) { countTx--; } - else if(inclusionMode) { countTx = 8; } - - if(countErr && countErr != 255) { - // switch led on - digitalWrite(pinEr, LOW); - } else if(!countErr) { - // switching off - digitalWrite(pinEr, HIGH); - } - if(countErr != 255) { countErr--; } - -} - -void MyGateway::rxBlink(uint8_t cnt) { - if(countRx == 255) { countRx = cnt; } -} -void MyGateway::txBlink(uint8_t cnt) { - if(countTx == 255 && !inclusionMode) { countTx = cnt; } -} -void MyGateway::errBlink(uint8_t cnt) { - if(countErr == 255) { countErr = cnt; } -} - diff --git a/libraries/MySensors/MyGateway.h b/libraries/MySensors/MyGateway.h deleted file mode 100644 index 21a93d6..0000000 --- a/libraries/MySensors/MyGateway.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - The MySensors library adds a new layer on top of the RF24 library. - It handles radio network routing, relaying and ids. - - Created by Henrik Ekblad - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. -*/ - -#ifndef MyGateway_h -#define MyGateway_h - -#include "MySensor.h" - -#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller -#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller - -class MyGateway : public MySensor -{ - public: - /** - * Constructor - * - * Creates a new instance of MyGateway class. - * If you don't use status leds and/or inclusion mode button on your arduino gateway - * you can disable this functionality by calling the 2 argument constructor. - * - * @param _cepin The pin attached to RF24 Chip Enable on the RF module (default 9) - * @param _cspin The pin attached to RF24 Chip Select (defualt 10) - * @param _inclusion_time Time of inclusion mode (in minutes, default 1) - * @param _inclusion_pin Digital pin that triggers inclusion mode - * @param _rx Digital pin for receive led - * @param _tx Digital pin for transfer led - * @param _er Digital pin for error led - * - */ - MyGateway(uint8_t _cepin=DEFAULT_CE_PIN, uint8_t _cspin=DEFAULT_CS_PIN, uint8_t _inclusion_time = 1, uint8_t _inclusion_pin = 3, uint8_t _rx=6, uint8_t _tx=5, uint8_t _er=4); - - /* Use this and pass a function that should be called when you want to process commands that arrive from radio network */ - void begin(rf24_pa_dbm_e paLevel=RF24_PA_LEVEL_GW, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE, void (*dataCallback)(char *)=NULL); - - void processRadioMessage(); - void parseAndSend(char *inputString); - - private: - char convBuf[MAX_PAYLOAD*2+1]; - char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera - unsigned long inclusionStartTime; - boolean useWriteCallback; - void (*dataCallback)(char *); - uint8_t pinInclusion; - uint8_t inclusionTime; - - uint8_t h2i(char c); - - void serial(const char *fmt, ... ); - void serial(MyMessage &msg); - void checkButtonTriggeredInclusion(); - void setInclusionMode(boolean newMode); - void checkInclusionFinished(); - void ledTimers(); - void rxBlink(uint8_t cnt); - void txBlink(uint8_t cnt); - void errBlink(uint8_t cnt); -}; - -void ledTimersInterrupt(); -void startInclusionInterrupt(); - -#endif diff --git a/libraries/MySensors/MyMQTT.cpp b/libraries/MySensors/MyMQTT.cpp deleted file mode 100755 index 610414e..0000000 --- a/libraries/MySensors/MyMQTT.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* -The MySensors library adds a new layer on top of the RF24 library. -It handles radio network routing, relaying and ids. - -Created by Henrik Ekblad -Modified by Daniel Wiegert -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. -*/ - -#include "MyMQTT.h" -#include "utility/MsTimer2.h" - -char V_0[] PROGMEM = "TEMP"; //V_TEMP -char V_1[] PROGMEM = "HUM"; //V_HUM -char V_2[] PROGMEM = "LIGHT"; //V_LIGHT -char V_3[] PROGMEM = "DIMMER"; //V_DIMMER -char V_4[] PROGMEM = "PRESSURE"; //V_PRESSURE -char V_5[] PROGMEM = "FORECAST"; //V_FORECAST -char V_6[] PROGMEM = "RAIN"; //V_RAIN -char V_7[] PROGMEM = "RAINRATE"; //V_RAINRATE -char V_8[] PROGMEM = "WIND"; //V_WIND -char V_9[] PROGMEM = "GUST"; //V_GUST -char V_10[] PROGMEM = "DIRECTON"; //V_DIRECTON -char V_11[] PROGMEM = "UV"; //V_UV -char V_12[] PROGMEM = "WEIGHT"; //V_WEIGHT -char V_13[] PROGMEM = "DISTANCE"; //V_DISTANCE -char V_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE -char V_15[] PROGMEM = "ARMED"; //V_ARMED -char V_16[] PROGMEM = "TRIPPED"; //V_TRIPPED -char V_17[] PROGMEM = "WATT"; //V_WATT -char V_18[] PROGMEM = "KWH"; //V_KWH -char V_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON -char V_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF -char V_21[] PROGMEM = "HEATER"; //V_HEATER -char V_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW -char V_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL -char V_24[] PROGMEM = "VAR1"; //V_VAR1 -char V_25[] PROGMEM = "VAR2"; //V_VAR2 -char V_26[] PROGMEM = "VAR3"; //V_VAR3 -char V_27[] PROGMEM = "VAR4"; //V_VAR4 -char V_28[] PROGMEM = "VAR5"; //V_VAR5 -char V_29[] PROGMEM = "UP"; //V_UP -char V_30[] PROGMEM = "DOWN"; //V_DOWN -char V_31[] PROGMEM = "STOP"; //V_STOP -char V_32[] PROGMEM = "IR_SEND"; //V_IR_SEND -char V_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE -char V_34[] PROGMEM = "FLOW"; //V_FLOW -char V_35[] PROGMEM = "VOLUME"; //V_VOLUME -char V_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS -char V_37[] PROGMEM = "DUST_LEVEL"; //V_DUST_LEVEL -char V_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE -char V_39[] PROGMEM = "CURRENT"; //V_CURRENT -char V_40[] PROGMEM = ""; // -char V_41[] PROGMEM = ""; // -char V_42[] PROGMEM = ""; // -char V_43[] PROGMEM = ""; // -char V_44[] PROGMEM = ""; // -char V_45[] PROGMEM = ""; // -char V_46[] PROGMEM = ""; // -char V_47[] PROGMEM = ""; // -char V_48[] PROGMEM = ""; // -char V_49[] PROGMEM = ""; // -char V_50[] PROGMEM = ""; // -char V_51[] PROGMEM = ""; // -char V_52[] PROGMEM = ""; // -char V_53[] PROGMEM = ""; // -char V_54[] PROGMEM = ""; // -char V_55[] PROGMEM = ""; // -char V_56[] PROGMEM = ""; // -char V_57[] PROGMEM = ""; // -char V_58[] PROGMEM = ""; // -char V_59[] PROGMEM = ""; // -char V_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway -char V_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway -char V_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway -char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway - -////////////////////////////////////////////////////////////////// - -PROGMEM const char *vType[] = { - V_0, V_1, V_2, V_3, V_4, V_5, V_6, V_7, V_8, V_9, V_10, - V_11, V_12, V_13, V_14, V_15, V_16, V_17, V_18, V_19, V_20, - V_21, V_22, V_23, V_24, V_25, V_26, V_27, V_28, V_29, V_30, - V_31, V_32, V_33, V_34, V_35, V_36, V_37, V_38, V_39, V_40, - V_41, V_42, V_43, V_44, V_45, V_46, V_47, V_48, V_49, V_50, - V_51, V_52, V_53, V_54, V_55, V_56, V_57, V_58, V_59, V_60, - V_61, V_62, V_63 -}; - - -char broker[] PROGMEM = MQTT_BROKER_PREFIX; - -#define S_FIRSTCUSTOM 60 -#define TYPEMAXLEN 20 -#define V_TOTAL (sizeof(vType)/sizeof(char *))-1 - -extern volatile uint8_t countRx; -extern volatile uint8_t countTx; -extern volatile uint8_t countErr; -extern uint8_t pinRx; -extern uint8_t pinTx; -extern uint8_t pinEr; - -MyMQTT::MyMQTT(uint8_t _cepin, uint8_t _cspin) : -MySensor(_cepin, _cspin) { - -} - -inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { - msg.destination = destination; - msg.sender = sender; - msg.sensor = sensor; - msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,enableAck); - mSetAck(msg,false); - return msg; -} - -char *MyMQTT::getType(char *b, const char **index) { - char *q = b; - char *p = (char *)pgm_read_word(index); - while (*q++ = pgm_read_byte(p++)); - *q=0; - return b; -} - -void MyMQTT::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate, void (*inDataCallback) - (const char *, uint8_t *), uint8_t _rx, uint8_t _tx, uint8_t _er) { - Serial.begin(BAUD_RATE); - repeaterMode = true; - isGateway = true; - MQTTClientConnected = false; - - setupRepeaterMode(); - dataCallback = inDataCallback; - - nc.nodeId = 0; - nc.distance = 0; - - // Start up the radio library - setupRadio(paLevel, channel, dataRate); - RF24::openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); - RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); - RF24::startListening(); - - pinRx = _rx; - pinMode(pinRx, OUTPUT); - pinTx = _tx; - pinMode(pinTx, OUTPUT); - pinEr = _er; - pinMode(pinEr, OUTPUT); - - MsTimer2::set(200, ledTimersInterrupt); - MsTimer2::start(); - - Serial.print(getType(convBuf, &vType[S_FIRSTCUSTOM])); -} - -void MyMQTT::processRadioMessage() { - if (process()) { - // A new message was received from one of the sensors - MyMessage message = getLastMessage(); - // Pass along the message from sensors to serial line - rxBlink(1); - SendMQTT(message); - } - -} - -void MyMQTT::processMQTTMessage(char *inputString, uint8_t inputPos) { - char *str, *p; - uint8_t i = 0; - buffer[0]= 0; - buffsize = 0; - - if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) { - buffer[buffsize++] = MQTTCONNACK << 4; - buffer[buffsize++] = 0x02; // Remaining length - buffer[buffsize++] = 0x00; // Connection accepted - buffer[buffsize++] = 0x00; // Reserved - MQTTClientConnected=true; // We have connection! - } - if ((uint8_t)inputString[0] >> 4 == MQTTPINGREQ) { - buffer[buffsize++] = MQTTPINGRESP << 4; - buffer[buffsize++] = 0x00; - } - if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { - buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! - buffer[buffsize++] = 0x03; // Remaining length - buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB - buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB - buffer[buffsize++] = MQTTQOS0; // QOS level - } - if ((uint8_t)inputString[0] >> 4 == MQTTUNSUBSCRIBE) { - buffer[buffsize++] = MQTTUNSUBACK << 4; - buffer[buffsize++] = 0x02; // Remaining length - buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB - buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB - } - if ((uint8_t)inputString[0] >> 4 == MQTTDISCONNECT) { - MQTTClientConnected=false; // We lost connection! - } - if (buffsize > 0) { - dataCallback(buffer,&buffsize); - } - - // We publish everything we get, we dont care if its subscribed or not! - if ((uint8_t)inputString[0] >> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { - buffer[0]= 0; - buffsize = 0; - // Cut out address and payload depending on message type. - if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { - strncat(buffer,inputString+6,inputString[5]); - } else { - strncat(buffer,inputString+4,inputString[3]); - } - - // TODO: Check if we should send ack or not. - for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) { - if (i == 0) { - if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX - return; //Message not for us or malformatted! - } - } else if (i==1) { - msg.destination = atoi(str); //NodeID - } else if (i==2) { - msg.sensor = atoi(str); //SensorID - } else if (i==3) { - char match=0; //SensorType - //strcpy(str,(char*)&str[2]); //Strip V_ - - for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) { - if (strcmp((char*)&str[2],convBuf)==0) { //Strip V_ and compare - match=j; - break; - } - if (j >= V_TOTAL) { // No match found! - match=V_TOTAL; // last item. - break; - } - } - msg.type = match; - } - i++; - } //Check if packge has payload - if ((uint8_t)inputString[1] > (uint8_t)(inputString[3]+2) && !((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { - strcpy(convBuf,inputString+(inputString[3]+4)); - msg.set(convBuf); //Payload - } else { - msg.set(""); //No payload - } - txBlink(1); - if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type, 0))) errBlink(1); - - } -} - -void MyMQTT::SendMQTT(MyMessage &msg) { - buffsize = 0; - if (!MQTTClientConnected) return; //We have no connections - return - if (msg.isAck()) { - Serial.println("msg is ack!"); - if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) { - // TODO: sending ACK request on id_response fucks node up. doesn't work. - // The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS. - } - } else { - // we have to check every message if its a newly assigned id or not. - // Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable. - uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; - if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; - if (msg.sender==newNodeID) { - saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); - } - if (mGetCommand(msg)==C_INTERNAL) { - if (msg.type==I_CONFIG) { - txBlink(1); - if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set("M"))) errBlink(1); - } else if (msg.type==I_ID_REQUEST && msg.sender==255) { - uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; - if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; - if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :( - txBlink(1); - if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) errBlink(1); - } - } else if (mGetCommand(msg)!=0) { - if (mGetCommand(msg)==3) msg.type=msg.type+(S_FIRSTCUSTOM-10); //Special message - - buffer[buffsize++] = MQTTPUBLISH << 4; // 0: - buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2 - buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!) - buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later - if (msg.type > V_TOTAL) msg.type=V_TOTAL;// If type > defined types set to unknown. - strcpy_P(buffer+4, broker); - buffsize+=strlen_P(broker); - buffsize+=sprintf(&buffer[buffsize],"/%i/%i/V_%s",msg.sender,msg.sensor,getType(convBuf, &vType[msg.type])); - buffer[3]=buffsize-4; // Set correct address length on byte 4. -#ifdef DEBUG - Serial.println((char*)&buffer[4]); -#endif - msg.getString(convBuf); - for (uint8_t a=0; a -#include -#include +#include #include +#include +#include +#include "GatewayUtil.h" + // Use this if you have attached a Ethernet ENC28J60 shields //#include @@ -61,10 +65,15 @@ #define RADIO_CE_PIN 5 // radio chip enable #define RADIO_SPI_SS_PIN 6 // radio SPI serial select + #define RADIO_ERROR_LED_PIN 7 // Error led pin #define RADIO_RX_LED_PIN 8 // Receive led pin #define RADIO_TX_LED_PIN 9 // the PCB, on board LED + +MySensor gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); + + #define IP_PORT 5003 // The port you want to open IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here @@ -76,22 +85,37 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // DEAD BEEF FEED // a R/W server on the port EthernetServer server = EthernetServer(IP_PORT); -// No blink or button functionality. Use the vanilla constructor. -MyGateway gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN, INCLUSION_MODE_TIME); - -// Uncomment this constructor if you have leds and include button attached to your gateway -//MyGateway gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN, INCLUSION_MODE_TIME, INCLUSION_MODE_PIN, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); - char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; + +void output(const char *fmt, ... ) { + va_list args; + va_start (args, fmt ); + vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); + va_end (args); + Serial.print(serialBuffer); + server.write(serialBuffer); +} + + void setup() { // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet); + gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); Ethernet.begin(mac, myIp); + setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); + + + // Add led timer interrupt + MsTimer2::set(300, ledTimersInterrupt); + MsTimer2::start(); + + // Add interrupt for inclusion button to pin + PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); + // give the Ethernet interface a second to initialize delay(1000); @@ -100,14 +124,15 @@ void setup() server.begin(); } -// This will be called when data should be written to ethernet -void writeEthernet(char *writeBuffer) { - server.write(writeBuffer); -} - void loop() { + gw.process(); + + + checkButtonTriggeredInclusion(); + checkInclusionFinished(); + // if an incoming client connects, there will be // bytes available to read via the client object EthernetClient client = server.available(); @@ -128,7 +153,7 @@ void loop() // echo the string to the serial port Serial.print(inputString); - gw.parseAndSend(inputString); + parseAndSend(gw, inputString); // clear the string: inputPos = 0; @@ -143,7 +168,8 @@ void loop() } } } - gw.processRadioMessage(); } + + diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h new file mode 100644 index 0000000..ec4d128 --- /dev/null +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -0,0 +1,262 @@ +#ifndef __GATEWAYUTIL_H__ +#define __GATEWAYUTIL_H__ + +#include + +#ifdef ARDUINO + + +uint8_t pinRx = 8; // Rx led pin +uint8_t pinTx = 9; // Tx led pin +uint8_t pinEr = 7; // Err led pin +uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled +uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode + +#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller +#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller + +volatile boolean buttonTriggeredInclusion; +volatile uint8_t countRx; +volatile uint8_t countTx; +volatile uint8_t countErr; +boolean inclusionMode; // Keeps track on inclusion mode +void (*serial)(const char *fmt, ... ); + +MyMessage msg; + +void setInclusionMode(boolean newMode); +void txBlink(uint8_t cnt); +void rxBlink(uint8_t cnt); +void errBlink(uint8_t cnt); + +char convBuf[MAX_PAYLOAD*2+1]; +char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera +unsigned long inclusionStartTime; + +void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { + inclusionMode = 0; + buttonTriggeredInclusion = false; + serial = _serial; + + pinRx = _rx; + pinTx = _tx; + pinEr = _er; + pinInclusion = _inc; + inclusionTime = _incTime; + + countRx = 0; + countTx = 0; + countErr = 0; + + // Setup led pins + pinMode(pinRx, OUTPUT); + pinMode(pinTx, OUTPUT); + pinMode(pinEr, OUTPUT); + digitalWrite(pinRx, LOW); + digitalWrite(pinTx, LOW); + digitalWrite(pinEr, LOW); + + // Setup digital in that triggers inclusion mode + pinMode(pinInclusion, INPUT); + digitalWrite(pinInclusion, HIGH); + + // Set initial state of leds + digitalWrite(pinRx, HIGH); + digitalWrite(pinTx, HIGH); + digitalWrite(pinEr, HIGH); + +} + + + +void startInclusionInterrupt() { + buttonTriggeredInclusion = true; +} + +void incomingMessage(const MyMessage &message) { + if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { + rxBlink(3); + } else { + rxBlink(1); + } + // Pass along the message from sensors to serial line + serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); +} + + + +void checkButtonTriggeredInclusion() { + if (buttonTriggeredInclusion) { + // Ok, someone pressed the inclusion button on the gateway + // start inclusion mode for 1 munute. + serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); + buttonTriggeredInclusion = false; + setInclusionMode(true); + } +} + +void checkInclusionFinished() { + if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { + // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode + setInclusionMode(false); + } +} + +uint8_t h2i(char c) { + uint8_t i = 0; + if (c <= '9') + i += c - '0'; + else if (c >= 'a') + i += c - 'a' + 10; + else + i += c - 'A' + 10; + return i; +} + +void parseAndSend(MySensor gw, char *commandBuffer) { + boolean ok = false; + char *str, *p, *value=NULL; + uint8_t bvalue[MAX_PAYLOAD]; + uint8_t blen = 0; + int i = 0; + uint16_t destination = 0; + uint8_t sensor = 0; + uint8_t command = 0; + uint8_t type = 0; + uint8_t ack = 0; + + // Extract command data coming on serial line + for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon + str && i < 6; // loop while str is not null an max 5 times + str = strtok_r(NULL, ";", &p) // get subsequent tokens + ) { + switch (i) { + case 0: // Radioid (destination) + destination = atoi(str); + break; + case 1: // Childid + sensor = atoi(str); + break; + case 2: // Message type + command = atoi(str); + break; + case 3: // Should we request ack from destination? + ack = atoi(str); + break; + case 4: // Data type + type = atoi(str); + break; + case 5: // Variable value + if (command == C_STREAM) { + blen = 0; + uint8_t val; + while (*str) { + val = h2i(*str++) << 4; + val += h2i(*str++); + bvalue[blen] = val; + blen++; + } + } else { + value = str; + // Remove ending carriage return character (if it exists) + uint8_t lastCharacter = strlen(value)-1; + if (value[lastCharacter] == '\r') + value[lastCharacter] = 0; + } + break; + } + i++; + } + + if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { + // Handle messages directed to gateway + if (type == I_VERSION) { + // Request for version + serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); + } else if (type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(value) == 1); + } + } else { + txBlink(1); + msg.sender = GATEWAY_ADDRESS; + msg.destination = destination; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,ack?1:0); + mSetAck(msg,false); + if (command == C_STREAM) + msg.set(bvalue, blen); + else + msg.set(value); + ok = gw.sendRoute(msg); + if (!ok) { + errBlink(1); + } + } +} + + +void setInclusionMode(boolean newMode) { + if (newMode != inclusionMode) + inclusionMode = newMode; + // Send back mode change on serial line to ack command + serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); + + if (inclusionMode) { + inclusionStartTime = millis(); + } +} + + + + +void ledTimersInterrupt() { + if(countRx && countRx != 255) { + // switch led on + digitalWrite(pinRx, LOW); + } else if(!countRx) { + // switching off + digitalWrite(pinRx, HIGH); + } + if(countRx != 255) { countRx--; } + + if(countTx && countTx != 255) { + // switch led on + digitalWrite(pinTx, LOW); + } else if(!countTx) { + // switching off + digitalWrite(pinTx, HIGH); + } + if(countTx != 255) { countTx--; } + else if(inclusionMode) { countTx = 8; } + + if(countErr && countErr != 255) { + // switch led on + digitalWrite(pinEr, LOW); + } else if(!countErr) { + // switching off + digitalWrite(pinEr, HIGH); + } + if(countErr != 255) { countErr--; } + +} + +void rxBlink(uint8_t cnt) { + if(countRx == 255) { countRx = cnt; } +} +void txBlink(uint8_t cnt) { + if(countTx == 255 && !inclusionMode) { countTx = cnt; } +} +void errBlink(uint8_t cnt) { + if(countErr == 255) { countErr = cnt; } +} + + + +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + +#endif diff --git a/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h b/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h new file mode 100644 index 0000000..58ff64a --- /dev/null +++ b/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h @@ -0,0 +1,120 @@ +#ifndef __GATEWAYUTIL_H__ +#define __GATEWAYUTIL_H__ + +#include + +#ifdef ARDUINO + + +uint8_t pinRx = 8; // Rx led pin +uint8_t pinTx = 9; // Tx led pin +uint8_t pinEr = 7; // Err led pin + +#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller +#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller + +volatile boolean buttonTriggeredInclusion; +volatile uint8_t countRx; +volatile uint8_t countTx; +volatile uint8_t countErr; + +MyMessage msg; + +void setInclusionMode(boolean newMode); +void txBlink(uint8_t cnt); +void rxBlink(uint8_t cnt); +void errBlink(uint8_t cnt); + +char convBuf[MAX_PAYLOAD*2+1]; +char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera +unsigned long inclusionStartTime; + +void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { + inclusionMode = 0; + buttonTriggeredInclusion = false; + serial = _serial; + + pinRx = _rx; + pinTx = _tx; + pinEr = _er; + pinInclusion = _inc; + inclusionTime = _incTime; + + countRx = 0; + countTx = 0; + countErr = 0; + + // Setup led pins + pinMode(pinRx, OUTPUT); + pinMode(pinTx, OUTPUT); + pinMode(pinEr, OUTPUT); + digitalWrite(pinRx, LOW); + digitalWrite(pinTx, LOW); + digitalWrite(pinEr, LOW); + + + // Set initial state of leds + digitalWrite(pinRx, HIGH); + digitalWrite(pinTx, HIGH); + digitalWrite(pinEr, HIGH); + +} + + + +void startInclusionInterrupt() { + buttonTriggeredInclusion = true; +} + + + + + +void ledTimersInterrupt() { + if(countRx && countRx != 255) { + // switch led on + digitalWrite(pinRx, LOW); + } else if(!countRx) { + // switching off + digitalWrite(pinRx, HIGH); + } + if(countRx != 255) { countRx--; } + + if(countTx && countTx != 255) { + // switch led on + digitalWrite(pinTx, LOW); + } else if(!countTx) { + // switching off + digitalWrite(pinTx, HIGH); + } + if(countTx != 255) { countTx--; } + else if(inclusionMode) { countTx = 8; } + + if(countErr && countErr != 255) { + // switch led on + digitalWrite(RADIO_ERROR_LED_PIN, LOW); + } else if(!countErr) { + // switching off + digitalWrite(RADIO_ERROR_LED_PIN, HIGH); + } + if(countErr != 255) { countErr--; } + +} + +void rxBlink(uint8_t cnt) { + if(countRx == 255) { countRx = cnt; } +} +void txBlink(uint8_t cnt) { + if(countTx == 255 && !inclusionMode) { countTx = cnt; } +} +void errBlink(uint8_t cnt) { + if(countErr == 255) { countErr = cnt; } +} + + + +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + +#endif diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index bbd44dd..388fba8 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -58,10 +58,14 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include -#include +#include #include +#include "MyMQTT.h" +#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled +#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button + // * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! /* #define RADIO_CE_PIN 3 // radio chip enable @@ -72,6 +76,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway // * Use this for default configured pro mini / nano etc : ///* + #define RADIO_CE_PIN 5 // radio chip enable #define RADIO_SPI_SS_PIN 6 // radio SPI serial select #define RADIO_ERROR_LED_PIN 7 // Error led pin @@ -84,8 +89,28 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You ////////////////////////////////////////////////////////////////// +MySensor gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); EthernetServer server = EthernetServer(TCP_PORT); -MyMQTT gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); +MyMessage msg; +char convBuf[MAX_PAYLOAD*2+1]; +char broker[] PROGMEM = MQTT_BROKER_PREFIX; +bool MQTTClientConnected = false; +uint8_t buffsize; +char buffer[MQTT_MAX_PACKET_SIZE]; +volatile uint8_t countRx; +volatile uint8_t countTx; +volatile uint8_t countErr; + + +void writeEthernet(const char *writeBuffer, uint8_t *writeSize) { +#ifdef TCPDUMP + Serial.print(">>"); + char buf[4]; + for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(""); +#endif + server.write((const uint8_t *)writeBuffer, *writeSize); +} + void processEthernetMessages() { char inputString[MQTT_MAX_PACKET_SIZE] = ""; @@ -102,28 +127,284 @@ void processEthernetMessages() { char buf[4]; for (uint8_t a=0; a>"); - char buf[4]; - for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(""); + + +void incomingMessage(const MyMessage &message) { + rxBlink(1); + sendMQTT(message); +} + + + +void setup() +{ + // Initialize gateway at maximum PA level, channel 70 and callback for write operations + gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); + + Ethernet.begin(TCP_MAC, TCP_IP); + + + countRx = 0; + countTx = 0; + countErr = 0; + + // Setup led pins + pinMode(RADIO_RX_LED_PIN, OUTPUT); + pinMode(RADIO_TX_LED_PIN, OUTPUT); + pinMode(RADIO_ERROR_LED_PIN, OUTPUT); + digitalWrite(RADIO_RX_LED_PIN, LOW); + digitalWrite(RADIO_TX_LED_PIN, LOW); + digitalWrite(RADIO_ERROR_LED_PIN, LOW); + + + // Set initial state of leds + digitalWrite(RADIO_RX_LED_PIN, HIGH); + digitalWrite(RADIO_TX_LED_PIN, HIGH); + digitalWrite(RADIO_ERROR_LED_PIN, HIGH); + + + // Add led timer interrupt + MsTimer2::set(300, ledTimersInterrupt); + MsTimer2::start(); + + + // give the Ethernet interface a second to initialize + delay(1000); + + // start listening for clients + server.begin(); + + Serial.println("Ok!"); +} + +void loop() +{ + gw.process(); + + processEthernetMessages(); +} + + + + + +inline MyMessage& build (MyMessage &msg, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { + msg.destination = destination; + msg.sender = GATEWAY_ADDRESS; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,enableAck); + mSetAck(msg,false); + return msg; +} + +char *getType(char *b, const char **index) { + char *q = b; + char *p = (char *)pgm_read_word(index); + while (*q++ = pgm_read_byte(p++)); + *q=0; + return b; +} + +void processMQTTMessage(char *inputString, uint8_t inputPos) { + char *str, *p; + uint8_t i = 0; + buffer[0]= 0; + buffsize = 0; + + if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) { + buffer[buffsize++] = MQTTCONNACK << 4; + buffer[buffsize++] = 0x02; // Remaining length + buffer[buffsize++] = 0x00; // Connection accepted + buffer[buffsize++] = 0x00; // Reserved + MQTTClientConnected=true; // We have connection! + } + if ((uint8_t)inputString[0] >> 4 == MQTTPINGREQ) { + buffer[buffsize++] = MQTTPINGRESP << 4; + buffer[buffsize++] = 0x00; + } + if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { + buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! + buffer[buffsize++] = 0x03; // Remaining length + buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB + buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB + buffer[buffsize++] = MQTTQOS0; // QOS level + } + if ((uint8_t)inputString[0] >> 4 == MQTTUNSUBSCRIBE) { + buffer[buffsize++] = MQTTUNSUBACK << 4; + buffer[buffsize++] = 0x02; // Remaining length + buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB + buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB + } + if ((uint8_t)inputString[0] >> 4 == MQTTDISCONNECT) { + MQTTClientConnected=false; // We lost connection! + } + if (buffsize > 0) { + writeEthernet(buffer,&buffsize); + } + + // We publish everything we get, we dont care if its subscribed or not! + if ((uint8_t)inputString[0] >> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { + buffer[0]= 0; + buffsize = 0; + // Cut out address and payload depending on message type. + if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { + strncat(buffer,inputString+6,inputString[5]); + } else { + strncat(buffer,inputString+4,inputString[3]); + } + +#ifdef DEBUG + Serial.println(buffer); #endif - server.write((const uint8_t *)writeBuffer, *writeSize); -} + // TODO: Check if we should send ack or not. + for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) { + if (i == 0) { + if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX + return; //Message not for us or malformatted! + } + } else if (i==1) { + msg.destination = atoi(str); //NodeID + } else if (i==2) { + msg.sensor = atoi(str); //SensorID + } else if (i==3) { + char match=255; //SensorType +#ifdef MQTT_TRANSLATE_TYPES + for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) { + if (strcmp((char*)&str[2],convBuf)==0) { //Strip V_ and compare + match=j; + break; + } + if (j >= V_TOTAL) break; + } + +#endif + if ( atoi(str)!=0 || str=="0" ) { + match=atoi(str); + } + + if (match==255) { + match=V_UNKNOWN; + } + msg.type = match; + } + i++; + } //Check if packge has payload + if ((uint8_t)inputString[1] > (uint8_t)(inputString[3]+2) && !((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { + strcpy(convBuf,inputString+(inputString[3]+4)); + msg.set(convBuf); //Payload + } else { + msg.set(""); //No payload + } + txBlink(1); + if (!gw.sendRoute(build(msg, msg.destination, msg.sensor, C_SET, msg.type, 0))) errBlink(1); -int main(void) { - init(); - Ethernet.begin(TCP_MAC, TCP_IP); - delay(1000); // Wait for Ethernet to get configured. - gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); - server.begin(); - while (1) { - processEthernetMessages(); - gw.processRadioMessage(); } } + +void sendMQTT(const MyMessage &inMsg) { + MyMessage msg = inMsg; + buffsize = 0; + if (!MQTTClientConnected) return; //We have no connections - return + if (msg.isAck()) { +// if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) { +// TODO: sending ACK request on id_response fucks node up. doesn't work. +// The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS. +// } + } else { + // we have to check every message if its a newly assigned id or not. + // Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable. + uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS)+1; + if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; + if (msg.sender==newNodeID) { + gw.saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); + } + if (mGetCommand(msg)==C_INTERNAL) { + if (msg.type==I_CONFIG) { + txBlink(1); + if (!gw.sendRoute(build(msg, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set(MQTT_UNIT))) errBlink(1); + return; + } else if (msg.type==I_ID_REQUEST && msg.sender==255) { + uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS)+1; + if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; + if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :( + txBlink(1); + if (!gw.sendRoute(build(msg, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) errBlink(1); + return; + } + } + if (mGetCommand(msg)!=C_PRESENTATION) { + if (mGetCommand(msg)==C_INTERNAL) msg.type=msg.type+(S_FIRSTCUSTOM-10); //Special message + buffer[buffsize++] = MQTTPUBLISH << 4; // 0: + buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2 + buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!) + buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later + strcpy_P(buffer+4, broker); + buffsize+=strlen_P(broker); +#ifdef MQTT_TRANSLATE_TYPES + if (msg.type > V_TOTAL) msg.type=V_UNKNOWN;// If type > defined types set to unknown. + buffsize+=sprintf(&buffer[buffsize],"/%i/%i/V_%s",msg.sender,msg.sensor,getType(convBuf, &vType[msg.type])); +#else + buffsize+=sprintf(&buffer[buffsize],"/%i/%i/%i",msg.sender,msg.sensor,msg.type); +#endif + buffer[3]=buffsize-4; // Set correct address length on byte 4. +#ifdef DEBUG + Serial.println((char*)&buffer[4]); +#endif + msg.getString(convBuf); + for (uint8_t a=0; a +Modified by Daniel Wiegert +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. +*/ + +#ifdef DEBUG +#define TCPDUMP // Dump TCP packages +#endif + +#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable +#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved. +#define MQTT_BROKER_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short! +#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request. +// NOTE above : Beware to check if there is any length on payload in your incommingMessage code: +// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. +#define MQTT_UNIT "M" // Select M for metric or I for imperial. +#define MQTT_TRANSLATE_TYPES // V_TYPE in address, Comment if you want all numbers (MyMQTT/01/01/01) + +////////////////////////////////////////////////////////////////// + +#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS) +#define MQTT_MAX_PACKET_SIZE 100 + +#define MQTTPROTOCOLVERSION 3 +#define MQTTCONNECT 1 // Client request to connect to Server +#define MQTTCONNACK 2 // Connect Acknowledgment +#define MQTTPUBLISH 3 // Publish message +#define MQTTPUBACK 4 // Publish Acknowledgment +#define MQTTPUBREC 5 // Publish Received (assured delivery part 1) +#define MQTTPUBREL 6 // Publish Release (assured delivery part 2) +#define MQTTPUBCOMP 7 // Publish Complete (assured delivery part 3) +#define MQTTSUBSCRIBE 8 // Client Subscribe request +#define MQTTSUBACK 9 // Subscribe Acknowledgment +#define MQTTUNSUBSCRIBE 10 // Client Unsubscribe request +#define MQTTUNSUBACK 11 // Unsubscribe Acknowledgment +#define MQTTPINGREQ 12 // PING Request +#define MQTTPINGRESP 13 // PING Response +#define MQTTDISCONNECT 14 // Client is Disconnecting +#define MQTTReserved 15 // Reserved + +#define MQTTQOS0 (0 << 1) +#define MQTTQOS1 (1 << 1) +#define MQTTQOS2 (2 << 1) + +#ifdef MQTT_TRANSLATE_TYPES + +char V_0[] PROGMEM = "TEMP"; //V_TEMP +char V_1[] PROGMEM = "HUM"; //V_HUM +char V_2[] PROGMEM = "LIGHT"; //V_LIGHT +char V_3[] PROGMEM = "DIMMER"; //V_DIMMER +char V_4[] PROGMEM = "PRESSURE"; //V_PRESSURE +char V_5[] PROGMEM = "FORECAST"; //V_FORECAST +char V_6[] PROGMEM = "RAIN"; //V_RAIN +char V_7[] PROGMEM = "RAINRATE"; //V_RAINRATE +char V_8[] PROGMEM = "WIND"; //V_WIND +char V_9[] PROGMEM = "GUST"; //V_GUST +char V_10[] PROGMEM = "DIRECTON"; //V_DIRECTON +char V_11[] PROGMEM = "UV"; //V_UV +char V_12[] PROGMEM = "WEIGHT"; //V_WEIGHT +char V_13[] PROGMEM = "DISTANCE"; //V_DISTANCE +char V_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE +char V_15[] PROGMEM = "ARMED"; //V_ARMED +char V_16[] PROGMEM = "TRIPPED"; //V_TRIPPED +char V_17[] PROGMEM = "WATT"; //V_WATT +char V_18[] PROGMEM = "KWH"; //V_KWH +char V_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON +char V_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF +char V_21[] PROGMEM = "HEATER"; //V_HEATER +char V_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW +char V_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL +char V_24[] PROGMEM = "VAR1"; //V_VAR1 +char V_25[] PROGMEM = "VAR2"; //V_VAR2 +char V_26[] PROGMEM = "VAR3"; //V_VAR3 +char V_27[] PROGMEM = "VAR4"; //V_VAR4 +char V_28[] PROGMEM = "VAR5"; //V_VAR5 +char V_29[] PROGMEM = "UP"; //V_UP +char V_30[] PROGMEM = "DOWN"; //V_DOWN +char V_31[] PROGMEM = "STOP"; //V_STOP +char V_32[] PROGMEM = "IR_SEND"; //V_IR_SEND +char V_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE +char V_34[] PROGMEM = "FLOW"; //V_FLOW +char V_35[] PROGMEM = "VOLUME"; //V_VOLUME +char V_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS +char V_37[] PROGMEM = "DUST_LEVEL"; //V_DUST_LEVEL +char V_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE +char V_39[] PROGMEM = "CURRENT"; //V_CURRENT +char V_40[] PROGMEM = ""; // +char V_41[] PROGMEM = ""; // +char V_42[] PROGMEM = ""; // +char V_43[] PROGMEM = ""; // +char V_44[] PROGMEM = ""; // +char V_45[] PROGMEM = ""; // +char V_46[] PROGMEM = ""; // +char V_47[] PROGMEM = ""; // +char V_48[] PROGMEM = ""; // +char V_49[] PROGMEM = ""; // +char V_50[] PROGMEM = ""; // +char V_51[] PROGMEM = ""; // +char V_52[] PROGMEM = ""; // +char V_53[] PROGMEM = ""; // +char V_54[] PROGMEM = ""; // +char V_55[] PROGMEM = ""; // +char V_56[] PROGMEM = ""; // +char V_57[] PROGMEM = ""; // +char V_58[] PROGMEM = ""; // +char V_59[] PROGMEM = ""; // +char V_60[] PROGMEM = "DEFAULT"; //Custom for MQTTGateway +char V_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway +char V_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway +char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway + +////////////////////////////////////////////////////////////////// + +PROGMEM const char *vType[] = { + V_0, V_1, V_2, V_3, V_4, V_5, V_6, V_7, V_8, V_9, V_10, + V_11, V_12, V_13, V_14, V_15, V_16, V_17, V_18, V_19, V_20, + V_21, V_22, V_23, V_24, V_25, V_26, V_27, V_28, V_29, V_30, + V_31, V_32, V_33, V_34, V_35, V_36, V_37, V_38, V_39, V_40, + V_41, V_42, V_43, V_44, V_45, V_46, V_47, V_48, V_49, V_50, + V_51, V_52, V_53, V_54, V_55, V_56, V_57, V_58, V_59, V_60, + V_61, V_62, V_63 +}; + + + +#define S_FIRSTCUSTOM 60 +#define V_TOTAL (sizeof(vType)/sizeof(char *))-1 + +#endif + +#define S_FIRSTCUSTOM 60 +#define V_UNKNOWN 63 diff --git a/libraries/MySensors/MyMQTT.h b/libraries/MySensors/examples/MQTTGateway/MyMQTT.hx similarity index 100% rename from libraries/MySensors/MyMQTT.h rename to libraries/MySensors/examples/MQTTGateway/MyMQTT.hx diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h new file mode 100644 index 0000000..ec4d128 --- /dev/null +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -0,0 +1,262 @@ +#ifndef __GATEWAYUTIL_H__ +#define __GATEWAYUTIL_H__ + +#include + +#ifdef ARDUINO + + +uint8_t pinRx = 8; // Rx led pin +uint8_t pinTx = 9; // Tx led pin +uint8_t pinEr = 7; // Err led pin +uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled +uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode + +#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller +#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller + +volatile boolean buttonTriggeredInclusion; +volatile uint8_t countRx; +volatile uint8_t countTx; +volatile uint8_t countErr; +boolean inclusionMode; // Keeps track on inclusion mode +void (*serial)(const char *fmt, ... ); + +MyMessage msg; + +void setInclusionMode(boolean newMode); +void txBlink(uint8_t cnt); +void rxBlink(uint8_t cnt); +void errBlink(uint8_t cnt); + +char convBuf[MAX_PAYLOAD*2+1]; +char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera +unsigned long inclusionStartTime; + +void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { + inclusionMode = 0; + buttonTriggeredInclusion = false; + serial = _serial; + + pinRx = _rx; + pinTx = _tx; + pinEr = _er; + pinInclusion = _inc; + inclusionTime = _incTime; + + countRx = 0; + countTx = 0; + countErr = 0; + + // Setup led pins + pinMode(pinRx, OUTPUT); + pinMode(pinTx, OUTPUT); + pinMode(pinEr, OUTPUT); + digitalWrite(pinRx, LOW); + digitalWrite(pinTx, LOW); + digitalWrite(pinEr, LOW); + + // Setup digital in that triggers inclusion mode + pinMode(pinInclusion, INPUT); + digitalWrite(pinInclusion, HIGH); + + // Set initial state of leds + digitalWrite(pinRx, HIGH); + digitalWrite(pinTx, HIGH); + digitalWrite(pinEr, HIGH); + +} + + + +void startInclusionInterrupt() { + buttonTriggeredInclusion = true; +} + +void incomingMessage(const MyMessage &message) { + if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { + rxBlink(3); + } else { + rxBlink(1); + } + // Pass along the message from sensors to serial line + serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); +} + + + +void checkButtonTriggeredInclusion() { + if (buttonTriggeredInclusion) { + // Ok, someone pressed the inclusion button on the gateway + // start inclusion mode for 1 munute. + serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); + buttonTriggeredInclusion = false; + setInclusionMode(true); + } +} + +void checkInclusionFinished() { + if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { + // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode + setInclusionMode(false); + } +} + +uint8_t h2i(char c) { + uint8_t i = 0; + if (c <= '9') + i += c - '0'; + else if (c >= 'a') + i += c - 'a' + 10; + else + i += c - 'A' + 10; + return i; +} + +void parseAndSend(MySensor gw, char *commandBuffer) { + boolean ok = false; + char *str, *p, *value=NULL; + uint8_t bvalue[MAX_PAYLOAD]; + uint8_t blen = 0; + int i = 0; + uint16_t destination = 0; + uint8_t sensor = 0; + uint8_t command = 0; + uint8_t type = 0; + uint8_t ack = 0; + + // Extract command data coming on serial line + for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon + str && i < 6; // loop while str is not null an max 5 times + str = strtok_r(NULL, ";", &p) // get subsequent tokens + ) { + switch (i) { + case 0: // Radioid (destination) + destination = atoi(str); + break; + case 1: // Childid + sensor = atoi(str); + break; + case 2: // Message type + command = atoi(str); + break; + case 3: // Should we request ack from destination? + ack = atoi(str); + break; + case 4: // Data type + type = atoi(str); + break; + case 5: // Variable value + if (command == C_STREAM) { + blen = 0; + uint8_t val; + while (*str) { + val = h2i(*str++) << 4; + val += h2i(*str++); + bvalue[blen] = val; + blen++; + } + } else { + value = str; + // Remove ending carriage return character (if it exists) + uint8_t lastCharacter = strlen(value)-1; + if (value[lastCharacter] == '\r') + value[lastCharacter] = 0; + } + break; + } + i++; + } + + if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { + // Handle messages directed to gateway + if (type == I_VERSION) { + // Request for version + serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); + } else if (type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(value) == 1); + } + } else { + txBlink(1); + msg.sender = GATEWAY_ADDRESS; + msg.destination = destination; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,ack?1:0); + mSetAck(msg,false); + if (command == C_STREAM) + msg.set(bvalue, blen); + else + msg.set(value); + ok = gw.sendRoute(msg); + if (!ok) { + errBlink(1); + } + } +} + + +void setInclusionMode(boolean newMode) { + if (newMode != inclusionMode) + inclusionMode = newMode; + // Send back mode change on serial line to ack command + serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); + + if (inclusionMode) { + inclusionStartTime = millis(); + } +} + + + + +void ledTimersInterrupt() { + if(countRx && countRx != 255) { + // switch led on + digitalWrite(pinRx, LOW); + } else if(!countRx) { + // switching off + digitalWrite(pinRx, HIGH); + } + if(countRx != 255) { countRx--; } + + if(countTx && countTx != 255) { + // switch led on + digitalWrite(pinTx, LOW); + } else if(!countTx) { + // switching off + digitalWrite(pinTx, HIGH); + } + if(countTx != 255) { countTx--; } + else if(inclusionMode) { countTx = 8; } + + if(countErr && countErr != 255) { + // switch led on + digitalWrite(pinEr, LOW); + } else if(!countErr) { + // switching off + digitalWrite(pinEr, HIGH); + } + if(countErr != 255) { countErr--; } + +} + +void rxBlink(uint8_t cnt) { + if(countRx == 255) { countRx = cnt; } +} +void txBlink(uint8_t cnt) { + if(countTx == 255 && !inclusionMode) { countTx = cnt; } +} +void errBlink(uint8_t cnt) { + if(countErr == 255) { countErr = cnt; } +} + + + +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + +#endif diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 8c3a7dd..1d314d6 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Henrik Ekblad + * Copyright (C) 2013-2014 Henrik Ekblad * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -13,41 +13,83 @@ * * Wire connections (OPTIONAL): * - Inclusion button should be connected between digital pin 3 and GND - * - RX/TX/ERR leds need to be connected between +5V (anode) and digital ping 6/5/4 with resistor 270-330R in a series + * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error */ + +#define NO_PORTB_PINCHANGES #include #include -#include #include +#include +#include +#include "GatewayUtil.h" + #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled -#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button +#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button +#define RADIO_ERROR_LED_PIN 4 // Error led pin +#define RADIO_RX_LED_PIN 6 // Receive led pin +#define RADIO_TX_LED_PIN 5 // the PCB, on board LED -MyGateway gw(DEFAULT_CE_PIN, DEFAULT_CS_PIN, INCLUSION_MODE_TIME, INCLUSION_MODE_PIN, 6, 5, 4); +MySensor gw(DEFAULT_CE_PIN, DEFAULT_CS_PIN); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; boolean commandComplete = false; // whether the string is complete +void parseAndSend(char *commandBuffer); + +void output(const char *fmt, ... ) { + va_list args; + va_start (args, fmt ); + vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); + va_end (args); + Serial.print(serialBuffer); +} + + void setup() { - gw.begin(); + gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); + // Stetup pipes for radio library + gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); + gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); + gw.startListening(); + + Serial.begin(BAUD_RATE); + + setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); + + // Add led timer interrupt + MsTimer2::set(300, ledTimersInterrupt); + MsTimer2::start(); + + // Add interrupt for inclusion button to pin + PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); + + + // Send startup log message on serial + serial(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); } void loop() { - gw.processRadioMessage(); + gw.process(); + + checkButtonTriggeredInclusion(); + checkInclusionFinished(); + if (commandComplete) { // A command wass issued from serial interface // We will now try to send it to the actuator - gw.parseAndSend(inputString); + parseAndSend(gw, inputString); commandComplete = false; inputPos = 0; } @@ -83,3 +125,4 @@ void serialEvent() { } + diff --git a/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp b/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp new file mode 100644 index 0000000..db49dce --- /dev/null +++ b/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp @@ -0,0 +1,272 @@ +/* + ByteBuffer.cpp - A circular buffer implementation for Arduino + Created by Sigurdur Orn, July 19, 2010. + siggi@mit.edu + Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012 + added the putString() method and the fillError variable. + added the checkError() and resetError() methods. The checkError() method resets the fillError variable + to false as a side effect. + added the ByteBuffer(unsigned int buf_size) constructor. + added the init() method, and had the constructor call it automagically. + Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts. + */ + +#include "ByteBuffer.h" + +void ByteBuffer::init(){ + ByteBuffer::init(DEFAULTBUFSIZE); +} + +void ByteBuffer::init(unsigned int buf_length){ + data = (byte*)malloc(sizeof(byte)*buf_length); + capacity = buf_length; + position = 0; + length = 0; + fillError=false; +} + +void ByteBuffer::deAllocate(){ + free(data); +} + +void ByteBuffer::clear(){ + position = 0; + length = 0; +} + +void ByteBuffer::resetError(){ + fillError=false; +} + +boolean ByteBuffer::checkError(){ + /* + if (fillError) { + Serial.print("E: checkError: length "); + Serial.println(length, DEC); + } + */ + + boolean result=fillError; + fillError=false; + return(result); +} + +int ByteBuffer::getSize(){ + return length; +} + +int ByteBuffer::getCapacity(){ + return capacity; +} + +byte ByteBuffer::peek(unsigned int index){ + byte b = data[(position+index)%capacity]; + return b; +} + +uint8_t ByteBuffer::put(byte in){ + if(length < capacity){ + // save data byte at end of buffer + data[(position+length) % capacity] = in; + // increment the length + length++; + return 1; + } + // return failure + //Serial.print("E: put: "); + //Serial.println(length, DEC); + fillError=true; + return 0; +} + + +uint8_t ByteBuffer::putString(char *in){ + uint8_t count=0; + char *inString; + + inString=in; + uint8_t oldSREG = SREG; cli(); + while(length <= capacity){ + if (length == capacity) { + fillError=true; + return count; + } + // save data byte at end of buffer + data[(position+length) % capacity] = *inString; + // increment the length + length++; + inString++; + count++; + if (*inString == 0) { + if (count==0) fillError=true; // Serial.println("E: putString"); }; + SREG = oldSREG; // Restore register; reenables interrupts + return count; + } + } + SREG = oldSREG; // Restore register; reenables interrupts + return count; +} + +uint8_t ByteBuffer::putInFront(byte in){ + uint8_t oldSREG = SREG; cli(); + if(length < capacity){ + // save data byte at end of buffer + if( position == 0 ) + position = capacity-1; + else + position = (position-1)%capacity; + data[position] = in; + // increment the length + length++; + SREG = oldSREG; // Restore register; reenables interrupts + return 1; + } + // return failure + //Serial.println("E: putInFront"); + fillError=true; + SREG = oldSREG; // Restore register; reenables interrupts + return 0; +} + +byte ByteBuffer::get(){ + uint8_t oldSREG = SREG; cli(); + byte b = 0; + + if(length > 0){ + b = data[position]; + // move index down and decrement length + position = (position+1)%capacity; + length--; + } + SREG = oldSREG; // Restore register; reenables interrupts + return b; +} + +byte ByteBuffer::getFromBack(){ + byte b = 0; + if(length > 0){ + uint8_t oldSREG = SREG; cli(); + b = data[(position+length-1)%capacity]; + length--; + SREG = oldSREG; // Restore register; reenables interrupts + } + + return b; +} + +// +// Ints +// + +void ByteBuffer::putIntInFront(int in){ + byte *pointer = (byte *)∈ + putInFront(pointer[0]); + putInFront(pointer[1]); +} + +void ByteBuffer::putInt(int in){ + byte *pointer = (byte *)∈ + put(pointer[1]); + put(pointer[0]); +} + + +int ByteBuffer::getInt(){ + int ret; + byte *pointer = (byte *)&ret; + pointer[1] = get(); + pointer[0] = get(); + return ret; +} + +int ByteBuffer::getIntFromBack(){ + int ret; + byte *pointer = (byte *)&ret; + pointer[0] = getFromBack(); + pointer[1] = getFromBack(); + return ret; +} + +// +// Longs +// + +void ByteBuffer::putLongInFront(long in){ + byte *pointer = (byte *)∈ + putInFront(pointer[0]); + putInFront(pointer[1]); + putInFront(pointer[2]); + putInFront(pointer[3]); +} + +void ByteBuffer::putLong(long in){ + byte *pointer = (byte *)∈ + put(pointer[3]); + put(pointer[2]); + put(pointer[1]); + put(pointer[0]); +} + + +long ByteBuffer::getLong(){ + long ret; + byte *pointer = (byte *)&ret; + pointer[3] = get(); + pointer[2] = get(); + pointer[1] = get(); + pointer[0] = get(); + return ret; +} + +long ByteBuffer::getLongFromBack(){ + long ret; + byte *pointer = (byte *)&ret; + pointer[0] = getFromBack(); + pointer[1] = getFromBack(); + pointer[2] = getFromBack(); + pointer[3] = getFromBack(); + return ret; +} + + +// +// Floats +// + +void ByteBuffer::putFloatInFront(float in){ + byte *pointer = (byte *)∈ + putInFront(pointer[0]); + putInFront(pointer[1]); + putInFront(pointer[2]); + putInFront(pointer[3]); +} + +void ByteBuffer::putFloat(float in){ + byte *pointer = (byte *)∈ + put(pointer[3]); + put(pointer[2]); + put(pointer[1]); + put(pointer[0]); +} + +float ByteBuffer::getFloat(){ + float ret; + byte *pointer = (byte *)&ret; + pointer[3] = get(); + pointer[2] = get(); + pointer[1] = get(); + pointer[0] = get(); + return ret; +} + +float ByteBuffer::getFloatFromBack(){ + float ret; + byte *pointer = (byte *)&ret; + pointer[0] = getFromBack(); + pointer[1] = getFromBack(); + pointer[2] = getFromBack(); + pointer[3] = getFromBack(); + return ret; +} + + diff --git a/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h b/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h new file mode 100644 index 0000000..8916e58 --- /dev/null +++ b/libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h @@ -0,0 +1,104 @@ +/* + ByteBuffer.h - A circular buffer implementation for Arduino + Created by Sigurdur Orn, July 19, 2010. siggi@mit.edu + Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012 + added the putString() method and the fillError variable. + added the checkError() and resetError() methods. The checkError() method resets the fillError variable + to false as a side effect. + added the ByteBuffer(unsigned int buf_size) constructor. + added the init() method, and had the constructor call it automagically. + protected certain sections of the code with cli()/sei() calls, for safe use by interrupts. + Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts. + */ + +#ifndef ByteBuffer_h +#define ByteBuffer_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif +//#include + +#define DEFAULTBUFSIZE 32 +class ByteBuffer +{ +public: + ByteBuffer() { + init(); + }; + ByteBuffer(unsigned int buf_size) { + init(buf_size); + }; + + // This method initializes the datastore of the buffer to a certain size. + void init(unsigned int buf_size); + + // This method initializes the datastore of the buffer to the default size. + void init(); + + // This method resets the buffer into an original state (with no data) + void clear(); + + // This method resets the fillError variable to false. + void resetError(); + + // This method tells you if your buffer overflowed at some time since the last + // check. The error state will be reset to false. + boolean checkError(); + + // This releases resources for this buffer, after this has been called the buffer should NOT be used + void deAllocate(); + + // Returns how much space is used in the buffer + int getSize(); + + // Returns the maximum capacity of the buffer + int getCapacity(); + + // This method returns the byte that is located at index in the buffer but doesn't modify the buffer like the get methods (doesn't remove the retured byte from the buffer) + byte peek(unsigned int index); + + // + // Put methods, either a regular put in back or put in front + // + uint8_t putInFront(byte in); + uint8_t put(byte in); + uint8_t putString(char *in); + + void putIntInFront(int in); + void putInt(int in); + + void putLongInFront(long in); + void putLong(long in); + + void putFloatInFront(float in); + void putFloat(float in); + + // + // Get methods, either a regular get from front or from back + // + byte get(); + byte getFromBack(); + + int getInt(); + int getIntFromBack(); + + long getLong(); + long getLongFromBack(); + + float getFloat(); + float getFloatFromBack(); + +private: + byte* data; + + volatile unsigned int capacity; + volatile unsigned int position; + volatile unsigned int length; + volatile boolean fillError; +}; + +#endif + diff --git a/libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h b/libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h new file mode 100644 index 0000000..aaab06a --- /dev/null +++ b/libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h @@ -0,0 +1,21 @@ +#ifndef INCLUDE_GETPSTR +#define INCLUDE_GETPSTR + +#if defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include "pins_arduino.h" + #include "WProgram.h" + #include "wiring.h" +#endif + +#define getPSTR(s) pgmStrToRAM(PSTR(s)) + +char *_pstr_to_print; +char *pgmStrToRAM(PROGMEM char *theString) { + free(_pstr_to_print); + _pstr_to_print=(char *) malloc(strlen_P(theString)); + strcpy_P(_pstr_to_print, theString); + return (_pstr_to_print); +} +#endif diff --git a/libraries/PinChangeInt/Examples/PinChangeIntExample/PinChangeIntExample.pde b/libraries/PinChangeInt/Examples/PinChangeIntExample/PinChangeIntExample.pde new file mode 100644 index 0000000..2f254d4 --- /dev/null +++ b/libraries/PinChangeInt/Examples/PinChangeIntExample/PinChangeIntExample.pde @@ -0,0 +1,77 @@ +// PinChangeIntExample, version 1.1 Sun Jan 15 06:24:19 CST 2012 +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. +//-------- define these in your sketch, if applicable ---------------------------------------------------------- +// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts +// on any one or two of the three ports. If only a single port remains, the handler will be declared inline +// reducing the size and latency of the handler. +//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts +//#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts +// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts +// if there is only one PCInt vector in use the code can be inlined +// reducing latency and code size +// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. +// #define DISABLE_PCINT_MULTI_SERVICE +//-------- define the above in your sketch, if applicable ------------------------------------------------------ +#include + +// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions. +// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately +// on the Terminal. The other function connected to 2 pins sets an array member that is queried in loop(). +// You can then query the array at your leisure. +// This makes loop timing non-critical. + +// Add more Pins at your leisure. +// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc. +// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's +// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT); +#define PIN1 2 +#define PIN2 3 +#define PIN3 4 + +uint8_t latest_interrupted_pin; +uint8_t interrupt_count[20]={0}; // 20 possible arduino pins +void quicfunc() { + latest_interrupted_pin=PCintPort::arduinoPin; + interrupt_count[latest_interrupted_pin]++; +}; + +// You can assign any number of functions to any number of pins. +// How cool is that? +void pin3func() { + Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!"); +} + +void setup() { + pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH); + PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING); // add more attachInterrupt code as required + pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH); + PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING); + pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH); + PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE); + Serial.begin(115200); + Serial.println("---------------------------------------"); +} + +uint8_t i; +void loop() { + uint8_t count; + Serial.print("."); + delay(1000); + for (i=0; i < 20; i++) { + if (interrupt_count[i] != 0) { + count=interrupt_count[i]; + interrupt_count[i]=0; + Serial.print("Count for pin "); + if (i < 14) { + Serial.print("D"); + Serial.print(i, DEC); + } else { + Serial.print("A"); + Serial.print(i-14, DEC); + } + Serial.print(" is "); + Serial.println(count, DEC); + } + } +} + diff --git a/libraries/PinChangeInt/Examples/PinChangeIntSpeedTest/PinChangeIntSpeedTest.pde b/libraries/PinChangeInt/Examples/PinChangeIntSpeedTest/PinChangeIntSpeedTest.pde new file mode 100644 index 0000000..f0ac0f2 --- /dev/null +++ b/libraries/PinChangeInt/Examples/PinChangeIntSpeedTest/PinChangeIntSpeedTest.pde @@ -0,0 +1,265 @@ +// PinChangeIntSpeedTest by GreyGnome aka Mike Schwager. Version numbers here refer to this sketch. +// Version 1.0 - initial version +// Version 1.1 - added code to test digitalRead() +// Version 1.2 - added new comments for the #define's for the NO_PORTx_PINCHANGES. +// Version 1.3 - includes cbiface.h with ooPinChangeInt, rather than cb.h +// Version 1.4 - testing version 2.10Beta with robtillaart's optimization +// Also added a #define/#undef INLINE_PCINTFUNC for inlining of the function called by the interrupt. +// Default: #undef for using the function as per usual. Changed PCIVERSION so that +// ooPinChangeInt starts at 1000 instead of 200. Modified the "Start" message to show "Start..", pause +// for 1 second, show "*\n" (where \n is a newline), pause for 1 second, then run the test. +// Version 1.4 - made this compatible with version 1.5 of PinChangeInt +// Version 1.5 - modified it to use #define OOPCIVERSION for ooPinChangeInt + +// This version number is for ooPinChangeInt +//#define OOPCIVERSION 1030 +#ifndef OOPCIVERSION +#define PCIVERSION 217 // 110 if using PinChangeInt-1.1, 120 for version 1.2 + // 1000 for ooPinChangeIntversion 1.00, 1001 for ooPinChangeInt version 1.01, etc. +#endif + +//-------- define these in your sketch, if applicable ---------------------------------------------------------- +// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts +// on any one or two of the three ports. If only a single port remains, the handler will be declared inline +// reducing the size and latency of the handler. +#undef NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts +#undef NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts +// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts +// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine +// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or +// PCintPort::arduinoPin are set and made available to your interrupt routine. +// #define NO_PIN_STATE // to indicate that you don't need the pinState +// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin +// if there is only one PCInt vector in use the code can be inlined +// reducing latency and code size +// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. +//#define DISABLE_PCINT_MULTI_SERVICE +//-------- define the above in your sketch, if applicable ------------------------------------------------------ +#if defined(OOPCIVERSION) + #define LIBRARYUNDERTEST "ooPinChangeInt" + #include + #if PCIVERSION == 1001 + #include + #else + #include + #endif +#else + #define LIBRARYUNDERTEST "PinChangeInt" + #include +#endif + +#define SERIALSTUFF // undef to take out all serial statements. Default: #define for measuring time. +#undef MEMTEST // undef to take out memory tests. Default: #undef for measuring time. +#undef INLINE_PCINTFUNC // define to inline the function called from the interrupt. This should have no effect, + // because the compiler will store the registers upon calling the interrupt routine, just + // like calling a function. Still, we test all assumptions. +//----------------------- +// NOTE: BECAUSE OF COLLISIONS in these libraries, you CANNOT have both libraries: PinChangeInt +// and ooPinChangeInt in the libraries directory at the same time. That said, under UNIX-y operating +// systems, it's easy to move the library directory to a name such as "PinChangeInt-1.3", which the +// Arduino will not recognize, and then create a symbolic link when you want to use a library. Such as: +// cd ~/Documents/Arduino/libaries +// mv PinChangeInt PinChangeInt-1.30 +// mv ooPinChangeInt ooPinChangeInt-1.00 +// ln -s PinChangeInt-1.30 PinChangeInt + +#undef FLASH // to flash LED on pin 13 during test + +#ifdef MEMTEST +#include +#endif + +#define TEST 6 + +#if TEST == 1 +#define PTEST 2 // pin to trigger interrupt. pins 0 and 1 are used +#define PLOW 2 // by Serial, so steer clear of them! +#define PHIGH 2 // Interrupts are attached to these pins + +#elif TEST == 2 // see the #if TEST == 2 || TEST == 3 code, below +#define PTEST 2 +#define PLOW 2 +#define PHIGH 2 // need to attachInterrupt to 5 in the code + +#elif TEST == 3 // see the #if TEST == 2 || TEST == 3 code, below +#define PTEST 5 +#define PLOW 2 +#define PHIGH 2 // need to attachInterrupt to 5 in the code + +#elif TEST == 4 +#define PTEST 2 +#define PLOW 2 +#define PHIGH 5 + +#elif TEST == 5 +#define PTEST 3 +#define PLOW 2 +#define PHIGH 5 + +#elif TEST == 6 +#define PTEST 4 +#define PLOW 2 +#define PHIGH 5 + +#elif TEST == 7 +#define PTEST 5 +#define PLOW 2 +#define PHIGH 5 +#endif + +uint8_t qf0; + +#ifdef INLINE_PCINTFUNC +#define INLINE_PCINTFUNC inline +#else +#define INLINE_PCINTFUNC +#endif +INLINE_PCINTFUNC void quicfunc(); +void quicfunc() { + qf0=TCNT0; +} + +#if defined(OOPCIVERSION) +class speedy : public CallBackInterface +{ + public: + uint8_t id; + static uint8_t var0; + speedy () { id=0; }; + speedy (uint8_t _i): id(_i) {}; + + void cbmethod() { + speedy::var0=TCNT0; + //Serial.print("Speedy method "); // debugging + //Serial.println(id, DEC); + }; +}; +uint8_t speedy::var0=0; +#endif + +volatile uint8_t *led_port; +volatile uint8_t *pinT_OP; +volatile uint8_t *pinT_IP; +uint8_t led_mask, not_led_mask; +uint8_t pinT_M, not_pinT_M; +volatile uint8_t pintest, pinIntLow, pinIntHigh; +uint8_t totalpins; +#if defined(OOPCIVERSION) +speedy speedster[8]={speedy(0), speedy(1), speedy(2), speedy(3), speedy(4), speedy(5), speedy(6), speedy(7) }; +#endif +#ifdef MEMTEST +int freemem; +#endif + +int i=0; + +#define PINLED 13 +void setup() +{ +#ifdef SERIALSTUFF + Serial.begin(115200); Serial.println("---------------------------------------"); +#endif // SERIALSTUFF + // set up ports for trigger + pinMode(0, OUTPUT); digitalWrite(0, HIGH); + pinMode(1, OUTPUT); digitalWrite(1, HIGH); + pinMode(2, OUTPUT); digitalWrite(2, HIGH); + pinMode(3, OUTPUT); digitalWrite(3, HIGH); + pinMode(4, OUTPUT); digitalWrite(4, HIGH); + pinMode(5, OUTPUT); digitalWrite(5, HIGH); + pinMode(6, OUTPUT); digitalWrite(6, HIGH); + pinMode(7, OUTPUT); digitalWrite(7, HIGH); +#ifdef FLASH + led_port=portOutputRegister(digitalPinToPort(PINLED)); + led_mask=digitalPinToBitMask(PINLED); + not_led_mask=led_mask^0xFF; + pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW); +#endif + // ***************************************************************************** + // set up ports for output ************ PIN TO TEST IS GIVEN HERE ************** + // ***************************************************************************** + pintest=PTEST; + pinIntLow=PLOW; pinIntHigh=PHIGH; // Interrupts are attached to these pins + // ***************************************************************************** + // ***************************************************************************** + pinT_OP=portOutputRegister(digitalPinToPort(pintest)); // output port + pinT_IP=portInputRegister(digitalPinToPort(pintest)); // input port + pinT_M=digitalPinToBitMask(pintest); // mask + not_pinT_M=pinT_M^0xFF; // not-mask + *pinT_OP|=pinT_M; + for (i=pinIntLow; i <= pinIntHigh; i++) { +#if defined(OOPCIVERSION) + PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better +#endif +#if defined(PCIVERSION) + PCintPort::attachInterrupt((uint8_t) i, &quicfunc, CHANGE); // C technique; v1.2 or earlier +#endif + } +#if TEST == 2 || TEST == 3 + i=5; totalpins=2; +#if defined(OOPCIVERSION) + PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better +#endif +#if defined(PCIVERSION) + PCintPort::attachInterrupt(i, &quicfunc, CHANGE); // C technique; v1.2 or earlier +#endif +#else + totalpins=pinIntHigh - pinIntLow + 1; +#endif + i=0; +} // end setup() + +uint8_t k=0; +unsigned long milliStart, milliEnd, elapsed; +void loop() { + k=0; + *pinT_OP|=pinT_M; // pintest to 1 +#ifdef SERIALSTUFF + Serial.print(LIBRARYUNDERTEST); Serial.print(" "); + Serial.print("TEST: "); Serial.print(TEST, DEC); Serial.print(" "); +#ifndef MEMTEST + Serial.print("test pin mask: "); Serial.print(pinT_M, HEX); + Serial.print(". Total of "); Serial.print(totalpins, DEC); Serial.println(" pins enabled."); +#endif +#ifdef MEMTEST + freemem=freeMemory(); Serial.print("Free memory: "); Serial.println(freemem, DEC); +#endif +#endif + delay(1000); + Serial.print("Start.."); + delay(1000); Serial.print("*"); + #ifdef FLASH + *led_port|=led_mask; + #endif + milliStart=millis(); + while (k < 10) { + i=0; + while (i < 10000) { + *pinT_OP&=not_pinT_M; // pintest to 0 ****************************** 16.8 us + *pinT_OP|=pinT_M; // pintest to 1 ****************************** ...to get here + i++; + } + k++; + } + milliEnd=millis(); + #ifdef FLASH + *led_port&=not_led_mask; + #endif + elapsed=milliEnd-milliStart; + #ifndef MEMTEST + Serial.print(" Elapsed: "); + Serial.println(elapsed, DEC); + #endif + #ifdef SERIALSTUFF + Serial.print("Interrupted pin: "); + #if defined(OOPCIVERSION) + Serial.println(speedster[pintest].id, DEC); + #else + Serial.println(PCintPort::arduinoPin, DEC); + #endif +#ifdef MEMTEST + freemem=freeMemory(); Serial.print("END-Free memory: "); Serial.println(freemem, DEC); +#endif +#endif + delay(500); +} + diff --git a/libraries/PinChangeInt/Examples/PinChangeIntTest/PinChangeIntTest.pde b/libraries/PinChangeInt/Examples/PinChangeIntTest/PinChangeIntTest.pde new file mode 100644 index 0000000..c8df127 --- /dev/null +++ b/libraries/PinChangeInt/Examples/PinChangeIntTest/PinChangeIntTest.pde @@ -0,0 +1,344 @@ +// PinChangeIntTest +// version 1.0 Wed Feb 15 07:25:09 CST 2012 +// Version 1.1 Fri Jun 22 19:10:50 CDT 2012 minor tweaks to eliminate compiler warnings. Also, there were bugfixes in ByteBuffer. +// I had some "cli()" without "sei()" in there. +// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. +// This sketch requires the ByteBuffer library, which is found in the PinChangeInt zipfile. +//-------- define these in your sketch, if applicable ---------------------------------------------------------- +//-------- This must go ahead of the #include statement -------------------------------------------------------- +// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts +// on any one or two of the three ports. If only a single port remains, the handler will be declared inline +// reducing the size and latency of the handler. +// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts +// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts +// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts +// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine +// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or +// PCintPort::arduinoPin are set and made available to your interrupt routine. +// #define NO_PIN_STATE // to indicate that you don't need the pinState +// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin +// if there is only one PCInt vector in use the code can be inlined +// reducing latency and code size +// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. +// #define DISABLE_PCINT_MULTI_SERVICE +// The following is intended for testing purposes. If defined, then a variable PCintPort::pinMode can be read +// in your interrupt subroutine. It is not defined by default: +// #define PINMODE +//-------- define the above in your sketch, if applicable ------------------------------------------------------ +#define PINMODE +#define FLASH +#include +#include + +// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions. +// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino. +// The pins are as follows: +#define tPIN1 2 // port D +#define tPIN2 3 +#define tPIN3 11 // Port B +#define tPIN4 12 +#define tPIN5 A3 // Port C, also can be given as "17" +#define tPIN6 A4 // starts and stops the count +// All pins send interrupts. Arduino pins 2 and A4 (tPIN1,6) interrupt on FALLING. +// Arduino pins 3 and 12 (tPIN2,4) interrupt on RISING. +// Arduino pins 11 and A3 (tPIN5) interrupts on CHANGE. +// quicfunc0 is attached to Arduino pins 2, 3, 11, and 12 (tPIN1-4) +// quicfunc1 is attached to Arduino pin A3 (tPIN5) +// quicfunc2 is attached to Arduino pin A4 (tPIN6). +// NOTE: +// For the Analog Input pins used as digital input pins, you can use numbers such as 14, 15, 16, etc. +// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's for the Analog Input pin +// names and will properly recognize e.g., pinMode(A0, INPUT)); + +// HOW IT WORKS +// The interrupt on Arduino pin A4 (tPIN6) will, when triggered, start the counting of interrupts. +// The array interrupt_count0[20] is updated in the interrupts; each cell keeps track of the number +// of interrupts on one of the 20 available interrupt pins on the Arduino. Every second in the main +// loop the array is scanned and registered interrupts are reported for all pins interrupted since +// the previous second. If no interrupts, the output is quiet. + +// tPIN6 is special. Not only does it start the counting of the interrups, but it turns on and off +// interrupts on pins 2, 11, and A3/17 (tPIN1, tPIN3, tPIN5). All pins start by interrupting, but after +// the count is turned on and then turned off, the 3 pins are detached from interrupts. +// Everytime thereafter when the count is turned off the 3 pins are detached. They are reattached +// when turned on. + +// Output is copied to a buffer, because we can't do a Serial.print() statement in an interrupt +// routine. The main loop checks for entries in the buffer and prints them if found. +// Output looks like this: +// -F- - an interrupt triggered by a falling signal occurred. +// +R+ - an interrupt triggered by a rising signal occurred. +// *C* - an interrupt triggered by a change in signal occurred. +// f#p#-P# - f# shows the interrupt subroutine that was called: 0, 1, or 2 +// - p# shows the pin number that triggered the interrupt +// - P# shows the port that this pin number is attached to. 2 is PORTB, 3 is PORTC, 4 is PORTD + +// HOW TO CONNECT +// Each pin gets a momentary contact switch connected to it. One side of the switch should connect +// to ground. The other side of the switch connects to the Arduino pin. For my purposes, I am using +// two rotary encoders. Each encoder contains 3 switches. But 6 regular pushbuttons would work, too. + +/* WHAT TO LOOK FOR + Output is sent to the serial line, so the Arduino IDE's serial terminal should be opened. + Upon startup, press tPINS1-5. You will see output like this: +-F-f0p2-P4 (counting off) +..*C*f0p11-P2 (counting off) ++R+f0p3-P4 (counting off) + This shows that + 1. an interrupt was triggered on a falling signal (*F*). It called (f0) function 0, which is quicfunc0. + The triggering pin was (p2) Arduuino pin 2, which is on (P4) Port 4 (PORTD). Counting of this interrupt is + off, so you will not see any output from the main loop. + 2. Two dots appeared. Dots came from iterations of loop(), so these 2 dots show that the two interrupts happened 2 seconds apart. + 3. an interrupt was triggered on a change in signal (*C*). It called quicfunc0, from Arduino pin 11, on Port 2 (PORTB). + The interrupt was not counted. + 4. an interrupt was triggered on a rising signal (+R+). It called quicfunc0, from Arduino pin 3, on Purt 4 (PORTD). + The pin should have started out at the high level, so likely the signal fell during onother interrupt, and now + the rise has been caught. + + Now press the button attached to tPIN6 (in our case, A4 or D18). You will see something like this: +-F-START! f2p18-P3 +.Count for pin A4 is 1 + This shows that + 1. The counting machanism (START!) was triggered by a folling signal (-F-) on pin 18 (p18) which is in Port 3 (P3) (which == PORTC) and + function f2 was called (f2). + 2. A dot appeared, which came from loop() because a second passed. + 3. The count for p18 or A4 was displayed. + + Now you will see messages for all the pins that you manipulate, for example: +*C*f0p11-P2 ++R+f0p3-P4 +*C*f0p11-P2 ++R+f0p3-P4 +*C*f0p11-P2 +.Count for pin D3 is 6 +Count for pin D11 is 9 +.+R+f0p3-P4 +-F-f0p2-P4 +.Count for pin D2 is 1 +Count for pin D3 is 1 + These codes reflect the interrupts, as described above. This output will take place until you press tPIN6: +-F-f2: STOP! Counting off. +Interrupt OFF on tPIN1 (2) tPIN3 (11) tPIN5 (17) + Then you will see output like this: +.....................+R+f0p12-P2 (counting off) +.+R+f0p12-P2 (counting off) ++R+f0p12-P2 (counting off) ++R+f0p12-P2 (counting off) + and tPIN1, tPIN3, and tPIN5 will not trigger interrupts. +*/ +// NOTES +// Output overwrites: +// It's possible during moderately fast interrupts to see your print output get garbled; eg, +// +R+f0p12-P2 (+R+f0p12-P2 (counting +R+f0p12-P2 (cou+R+f0p12-P+R+f0p12 +// This is because the print of the buffer takes place inside a while loop, and it can +// be interrupted and new data inserted into the buffer at a midpoint of the buffer's text. +// Just by spinning my rotary encoders I can readily generate over 200 interrupts per second +// on a pin, which is easily fast enough to overrun Serial output at 115,200 bps. +// The lesson here? ...Interrupts are tricky, and interrupt service routines should be fast. +// Just sayin'. + +// Pins: +// We want to use pins from each of ports B, C and D. So choose wisely. Ports are shown in +// this diagram of the ATmega328P chip. PD0 means "Port D, pin 0". PC3 means "Port C, Pin 3", +// PB2 means "Port B, pin 2" and so on. The corresponding Arduino pins are in parentheses. +// So PB2 is Arduino pin D 10, for example. +/* + +-\/-+ + PC6 1| |28 PC5 (AI 5) + (D 0) PD0 2| |27 PC4 (AI 4) + (D 1) PD1 3| |26 PC3 (AI 3) + (D 2) PD2 4| |25 PC2 (AI 2) + PWM+ (D 3) PD3 5| |24 PC1 (AI 1) + (D 4) PD4 6| |23 PC0 (AI 0) + VCC 7| |22 GND + GND 8| |21 AREF + PB6 9| |20 AVCC + PB7 10| |19 PB5 (D 13) + PWM+ (D 5) PD5 11| |18 PB4 (D 12) + PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM + (D 7) PD7 13| |16 PB2 (D 10) PWM + (D 8) PB0 14| |15 PB1 (D 9) PWM + +----+ +*/ + +uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 }; +uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 }; + +uint8_t latest_interrupted_pin; +uint8_t interrupt_count[20]={0}; // 20 possible arduino pins +uint8_t port; +uint8_t mode; + +ByteBuffer printBuffer(80); +char charArray[16]; +char numBuffer[4] = { 0, 0, 0, 0 }; +uint8_t printFull=0; + +volatile boolean start=0; +volatile boolean initial=true; +long begintime=0; +long now=0; + +void uint8ToString(char *outString, uint8_t number) { + uint8_t hundreds=0; + uint8_t tens=0; + uint8_t ones=0; + + while (number >= 100 ) { + hundreds++; + number-=100; + } + while (number >= 10 ) { + tens++; + number-=10; + } + ones=number; + ones+=48; + if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; } + else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; } + else { outString[0]=ones; outString[1]=0; }; +} + +void showMode() { + switch (mode) { + case FALLING: + printBuffer.putString((char *) "-F-"); + break; + case RISING: + printBuffer.putString((char *) "+R+"); + break; + case CHANGE: + printBuffer.putString((char *) "*C*"); + break; + } +} + +void quicfunc0() { + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + if (start==1) { + interrupt_count[latest_interrupted_pin]++; + } + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); + if (start !=1) printBuffer.putString((char *) " (counting off)"); + printBuffer.putString((char *) "\n"); +}; + +void quicfunc1() { + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + if (start==1) { + interrupt_count[latest_interrupted_pin]++; + } + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString((char *) "f1p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); + if (start !=1) printBuffer.putString((char *) " (counting off)"); + printBuffer.putString((char *) "\n"); +}; + +void quicfunc2() { + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + if (start == 1) { + printBuffer.putString((char *) "f2: STOP! Counting off.\n"); + printBuffer.putString((char *) "Interrupt OFF on tPIN1 ("); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer); + printBuffer.putString((char *) ") tPIN3 (");uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer); + printBuffer.putString((char *) ") tPIN5 (");uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer); + printBuffer.putString((char *) ")\n"); + PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5); + start=0; + } else { + start=1; + interrupt_count[latest_interrupted_pin]++; + printBuffer.putString((char *) "START! f2p"); + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); printBuffer.putString((char *) "\n"); + if (! initial) { + PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING); + PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE); + PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE); + } else { + initial=false; + } + } +}; + +uint8_t i; +void setup() { + Serial.begin(115200); + delay(250); + Serial.println("Test"); + delay(500); + for (i=0; i < 7; i++) { + pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH); + ports[i]=digitalPinToPort(pins[i]); + switch (pins[i]) { + case tPIN1: + PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING); + break; + case tPIN3: + PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE); + break; + case tPIN2: + case tPIN4: + PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING); + break; + case tPIN5: + PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE); + break; + case tPIN6: + PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING); + break; + } + } + //Serial.println(printBuffer.getCapacity(), DEC); + //Serial.println("*---------------------------------------*"); + Serial.print("*---*"); + delay(250); + begintime=millis(); +} + +void loop() { + now=millis(); + uint8_t count; + char outChar; + // uint8_t bufsize; + //if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); }; + //bufsize=printBuffer.getSize(); + //if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); } + while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar); + if ((now - begintime) > 1000) { + Serial.print("."); + if (printBuffer.checkError()) { + Serial.println("NOTICE: Some output lost due to filled buffer."); + } + for (i=0; i < 20; i++) { + if (interrupt_count[i] != 0) { + count=interrupt_count[i]; + interrupt_count[i]=0; + Serial.print("Count for pin "); + if (i < 14) { + Serial.print("D"); + Serial.print(i, DEC); + } else { + Serial.print("A"); + Serial.print(i-14, DEC); + } + Serial.print(" is "); + Serial.println(count, DEC); + } + } + begintime=millis(); + } +} + diff --git a/libraries/PinChangeInt/Examples/PinChangeIntTest2/PinChangeIntTest2.ino b/libraries/PinChangeInt/Examples/PinChangeIntTest2/PinChangeIntTest2.ino new file mode 100644 index 0000000..aec34c4 --- /dev/null +++ b/libraries/PinChangeInt/Examples/PinChangeIntTest2/PinChangeIntTest2.ino @@ -0,0 +1,275 @@ +//#define DISABLE_PCINT_MULTI_SERVICE +#define PINMODE +#define FLASH +#include +#include +#include + +// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions. +// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino. +// The pins are as follows: +#define tPIN1 2 // port D +#define tPIN2 3 +#define tPIN3 11 // Port B +#define tPIN4 12 +#define tPIN5 A3 // Port C, also can be given as "17" +#define tPIN6 A4 // starts and stops the count + +uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 }; +uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 }; + +uint8_t latest_interrupted_pin; +uint8_t interrupt_count[20]={0}; // 20 possible arduino pins +uint8_t port; +uint8_t mode; + +ByteBuffer printBuffer(200); +char charArray[16]; +char numBuffer[5] = { 0, 0, 0, 0, 0 }; +uint8_t printFull=0; + +volatile boolean start=0; +volatile boolean initial=true; +long begintime=0; +long now=0; + +void uint8ToHexString(char *outString, uint8_t theByte) { + outString[0]='0'; outString[1]='x'; + uint8_t hinybble=theByte>>4; + uint8_t lonybble=theByte & 0x0F; + if (hinybble < 0x0a) outString[2]=hinybble+48; + else outString[2]=hinybble+55; + if (lonybble < 0x0a) outString[3]=lonybble+48; + else outString[3]=lonybble+55; + outString[4]=0; +} + +void uint8ToString(char *outString, uint8_t number) { + uint8_t hundreds=0; + uint8_t tens=0; + uint8_t ones=0; + + while (number >= 100 ) { + hundreds++; + number-=100; + } + while (number >= 10 ) { + tens++; + number-=10; + } + ones=number; + ones+=48; + if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; } + else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; } + else { outString[0]=ones; outString[1]=0; }; +} + +void showMode() { + switch (mode) { + case FALLING: + printBuffer.putString(getPSTR("-F-")); + break; + case RISING: + printBuffer.putString(getPSTR("+R+")); + break; + case CHANGE: + printBuffer.putString(getPSTR("*C*")); + break; + } +} + +/* +void quicfunc0() { + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + if (start==1) { + interrupt_count[latest_interrupted_pin]++; + } + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); + if (start !=1) printBuffer.putString(getPSTR(" no count")); + printBuffer.putString((char *) "\n"); +}; + +void quicfunc1() { + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + if (start==1) { + interrupt_count[latest_interrupted_pin]++; + } + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString(getPSTR("f1p")); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); + if (start !=1) printBuffer.putString(getPSTR(" (counting off)")); + printBuffer.putString((char *) "\n"); +}; +*/ + +void quicfunc2() { + //*led_port|=led_mask; + //*led_port&=not_led_mask; // 2 micros to here (ie, 2 micros used to push registers and call subroutine) + latest_interrupted_pin=PCintPort::arduinoPin; + mode=PCintPort::pinmode; + showMode(); + *led_port|=led_mask; // 73 micros to get here from above. Used in "Rigol Timing Example" + *led_port&=not_led_mask; + //uint8ToString(numBuffer, PCintPort::s_count); printBuffer.putString(numBuffer); + *led_port|=led_mask; // 73 micros to get here from above. Second pulse in "Rigol Timing Example" + *led_port&=not_led_mask; + printBuffer.putString(getPSTR(" f2: P"));/* + uint8ToHexString(numBuffer, *portInputRegister(3)); printBuffer.putString(numBuffer);// C port + printBuffer.putString(getPSTR(" pin:")); uint8ToString(numBuffer, latest_interrupted_pin); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" c")); uint8ToHexString(numBuffer, PCintPort::curr); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" l")); uint8ToHexString(numBuffer, PCintPort::s_lastPinView); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" r")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" f")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" m")); uint8ToHexString(numBuffer, PCintPort::s_pmask); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" P")); printBuffer.put(PCintPort::s_PORT); printBuffer.putString("\r\n"); + printBuffer.putString(getPSTR("cp")); uint8ToHexString(numBuffer, PCintPort::s_changedPins); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" cXORlpv")); uint8ToHexString(numBuffer, PCintPort::s_currXORlastPinView); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" rp_nCurr")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins_nCurr); printBuffer.putString(numBuffer); + printBuffer.putString(getPSTR(" fp_nNCurr")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins_nNCurr); printBuffer.putString(numBuffer); + */printBuffer.putString("\r\n"); + if (PCintPort::pcint_multi > 0) { + printBuffer.putString("MULTI!\n"); PCintPort::pcint_multi=0; + } + if (PCintPort::PCIFRbug > 0) { printBuffer.putString("ERROR: BUG- PCIFR should be reset!"); PCintPort::PCIFRbug=0; } + //s_registers, if it existed, could be used to keep a running queue of the latest interrupts that have + //been serviced by the PCint(). But generally I don't think it's necessary for debugging at this point (famous last words?) + /*if (PCintPort::s_count > 2) { + for (uint8_t i=0; i < PCintPort::s_count; i++) { + uint8ToHexString(numBuffer, PCintPort::s_registers[i]); printBuffer.putString(numBuffer); printBuffer.putString(" "); + } + } + PCintPort::s_count=0;*/ + /* + if (start == 1) { + printBuffer.putString(getPSTR("STOP Count off\n")); + printBuffer.putString(getPSTR("Intr OFF: (")); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer); + printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer); + printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer); + printBuffer.putString((char *) ")\n"); + PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5); + start=0; + } else { + start=1; + interrupt_count[latest_interrupted_pin]++; + printBuffer.putString(getPSTR("START! p")); + uint8ToString(numBuffer, latest_interrupted_pin); + printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P"); + // MIKE put the REAL PORT HERE + uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin)); + printBuffer.putString(numBuffer); printBuffer.putString((char *) "\n"); + if (! initial) { + PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING); + PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE); + PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE); + } else { + initial=false; + } + }*/ +}; + +uint8_t i; +char hexBuffer[5]; +void setup() { + int8_t returncode=1; + Serial.begin(115200); + Serial.println("Test"); + delay(500); + for (i=5; i < 6; i++) { + pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH); + ports[i]=digitalPinToPort(pins[i]); + switch (pins[i]) { + /*case tPIN1: + #if PCINT_VERSION > 2100 + returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING); + #else + PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING); + #endif + Serial.println(getPSTR("FIRST FAILURE OK.")); + break; + case tPIN3: + #if PCINT_VERSION > 2100 + returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE); + #else + PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE); + #endif + break; + case tPIN2: + case tPIN4: + #if PCINT_VERSION > 2100 + returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING); + #else + PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING); + #endif + break; + case tPIN5: + #if PCINT_VERSION > 2100 + returncode=PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE); + #else + PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE); + #endif + break;*/ + case tPIN6: + #if PCINT_VERSION > 2100 + returncode=PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING); + #else + PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING); + #endif + break; + } + #if PCINT_VERSION > 2100 + Serial.print(getPSTR("setup(): Interrupt attach ")); + if (returncode != 1) Serial.print(getPSTR("unsuccessful ")); + else Serial.print(getPSTR("GOOD ")); + Serial.print(pins[i], DEC); + Serial.print(getPSTR(":pin, code: ")); Serial.println(returncode, DEC); + #endif + } + //Serial.println(printBuffer.getCapacity(), DEC); + //Serial.println("*---------------------------------------*"); + Serial.print("*---*"); + delay(250); + begintime=millis(); +} + +void loop() { + now=millis(); + uint8_t count; + char outChar; + // uint8_t bufsize; + //if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); }; + //bufsize=printBuffer.getSize(); + //if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); } + while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar); + if ((now - begintime) > 1000) { + Serial.print("."); + if (printBuffer.checkError()) { + Serial.println(getPSTR("!Some output lost due to full buffer!")); + } + for (i=0; i < 20; i++) { + if (interrupt_count[i] != 0) { + count=interrupt_count[i]; + interrupt_count[i]=0; + Serial.print(getPSTR("Count for pin ")); + if (i < 14) { + Serial.print("D"); + Serial.print(i, DEC); + } else { + Serial.print("A"); + Serial.print(i-14, DEC); + } + Serial.print(" is "); + Serial.println(count, DEC); + } + } + begintime=millis(); + } +} + diff --git a/libraries/MySensors/utility/PinChangeInt.h b/libraries/PinChangeInt/PinChangeInt.h similarity index 100% rename from libraries/MySensors/utility/PinChangeInt.h rename to libraries/PinChangeInt/PinChangeInt.h diff --git a/libraries/PinChangeInt/RELEASE_NOTES b/libraries/PinChangeInt/RELEASE_NOTES new file mode 100644 index 0000000..635e4f8 --- /dev/null +++ b/libraries/PinChangeInt/RELEASE_NOTES @@ -0,0 +1,332 @@ +****************************************************************************** + + PinChangeInt + ---- RELEASE NOTES --- + +Version 2.19 (beta) Tue Nov 20 07:33:37 CST 2012 +SANGUINO SUPPORT! ...And Mioduino! +...The ATmega644 chip is so cool, how can I not? 4 full ports of Pin Change Interrupt bliss! 32 i/o pins! 64k Flash! 4k RAM! Well I wish I had one. That said, Sanguino users, PLEASE send in your bug or bliss reports! Your interrupt-loving brethren and sistren are depending on you, so I can assure everyone that my changes work on that platform. Thanks. + +Modified the addPin() method to save 12 bytes; thanks again robtilllart! + if (firstPin != NULL) { + tmp=firstPin; + do { + if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); } + if (tmp->next == NULL) break; + tmp=tmp->next; + } while (true); + } +Also changed the goto in the PCint() loop to be a while/break combination. No change to +code speed, but it looks better and passes the cleanliness "gut check". + +Includes PinChangeIntTest 1.5 sketch. + +...Ooops! Forgot the GetPSTR library, needed for the PinChangeIntTest code! Now it's included. +****************************************************************************** +Version 2.17 (beta) Sat Nov 17 09:46:50 CST 2012 +Another bugfix in the PCINT_MULTI_SERVICE section. I was using sbi(PCIFR, PCICRbit); +I didn't realize that was for I/O ports, and not ATmega registers. +But according to "deprecated.h", +"These macros became obsolete, as reading and writing IO ports can + be done by simply using the IO port name in an expression, and all + bit manipulation (including those on IO ports) can be done using + generic C bit manipulation operators." +So now I do: + PCIFR |= PCICRbit; +****************************************************************************** +Version 2.15 (beta) Sat Nov 17 01:17:44 CST 2012 +Fixed it so that attachInterrupt() will now follow your changes to the user function, +as well as the mode. detachInterrupt() still does not delete the PCintPin object but +at least you can detach and reattach at will, using different modes (RISING, FALLING, +CHANGE) and different functions as you wish. + +****************************************************************************** +Version 2.13 (beta) Mon Nov 12 09:33:06 CST 2012 +SIGNIFICANT BUGFIX release! Significant changes: +1. PCintPort::curr bug. Interrupts that occur rapidly will likely not get serviced properly by PCint(). +2. PCint() interrupt handler optimization. +3. PCIFR port bit set bug fix. +4. Many static variables added for debugging; used only when #define PINMODE is on. +5. detachInterrupt() no longer does a delete(), since that wasn't working anyway. When you detachInterrupt(), the PORT just disables interrupts for that pin; the PCintPin object remains in memory and in the linked list of pins (possibly slowing down your interrupts a couple of micros). You can reenable a detached interrupt- but you must do it within the PinChangeInt library (would anyone ever enable an interrupt on a pin, then disable it, then have need to reenable it but not using the library?). +6. attachInterrupt() now returns a uint8_t value: 1 on successful attach, 0 on successful attach but using an already-enabled pin, and -1 if the new() operator failed to create a PCintPin object. +Also, modified these release notes. + +Details: + +Uncovered a nasty bug, thanks to robtillaart on the Arduino Forums and Andre' Franken who posted to the PinChangeInt groups. This bug was introduced by me when I assigned PCintPort::curr early in the interrupt handler: +ISR(PCINT0_vect) { + PCintPort::curr = portB.portInputReg; + portB.PCint(); +} +Later, in the interrupt handler PCint(), we loop as long as PCIFR indicates a new interrupt wants to be triggered, provided DISABLE_PCINT_MULTI_SERVICE is not defined (it is not by default): +#ifndef DISABLE_PCINT_MULTI_SERVICE + pcifr = PCIFR & PCICRbit; + PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero) +} while(pcifr); +#endif +...Well. Problem is, if a pin pops up and causes the PCIFR to change, we have to reread the port and look at how it is now! I wasn't doing that before, so if a new interrupt appeared while I was still servicing the old one, odd behavior would take place. For example, an interrupt would register but then the userFunc would not be called upon to service it. The code needs to be: + pcifr = PCIFR & PCICRbit; + PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero) + PCintPort::curr=portInputReg; // ...Fixed in 2.11beta. +} while(pcifr); + +Also, made the interrupt handler even faster with an optimization from robtillaart to take out the checks for changed pins from the while() loop that steps through the pins: +uint8_t changedPins = (PCintPort::curr ^ lastPinView) & + ((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr )); + +...This speedup is offset by more changes in the PCint() handler, which now looks like the following; there are two bug fixes: +---------------------------- +FIX 1: sbi(PCIFR, PCICRbit); +FIX 2: ...the aforementioned PCintPort::curr=portInputReg; +Here's the new code: +---------------------------- + #ifndef DISABLE_PCINT_MULTI_SERVICE + pcifr = PCIFR & PCICRbit; + if (pcifr) { + //if (PCIFR & PCICRbit) { // believe it or not, this adds .6 micros + sbi(PCIFR, PCICRbit); // This was a BUG: PCIFR = pcifr ...And here is the fix. + #ifdef PINMODE + PCintPort::pcint_multi++; + if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here! + #endif + PCintPort::curr=portInputReg; // ...Fixed in 2.11beta. + goto loop; // A goto!!! Don't want to look at the portInputReg gratuitously, so the while() will not do. + } + #endif + +Also I added a lot of variables for debugging when PINMODE is defined, for routing out nasty bugs. I may need them in the future... :-( + +Finally, I am not putting newlines in this commentary so I can make it easier to paste online. + +****************************************************************************** +Version 2.11 (beta) Mon Nov 12 09:33:06 CST 2012 +See version 2.13 (beta) above. No change other than tidying up the release notes. +****************************************************************************** + Version 2.01 (beta) Thu Jun 28 12:35:48 CDT 2012 + ...Wow, Version 2! What? Why? + Modified the way that the pin is tested inside the interrupt subroutine (ISR) PCintPort::PCint(), + to make the interrupt quicker and slightly reduce the memory footprint. The interrupt's time is + reduced by 2 microseconds or about 7%. Instead of using the mode variable, two bitmasks are maintained + for each port. One bitmask contains all the pins that are configured to work on RISING signals, the other + on FALLING signals. A pin configured to work on CHANGE signals will appear in both bitmasks of the port. + Then, the test for a change goes like this: + if (thisChangedPin) { + if ((thisChangedPin & portRisingPins & PCintPort::curr ) || + (thisChangedPin & portFallingPins & ~PCintPort::curr )) { + where portRisingPins is the bitmask for the pins configured to interrupt on RISING signals, and + portFallingPins is the bitmask for the pins configured to interrupt on FALLING signals. Each port includes + these two bitmask variables. + + This is a significant change to some core functionality to the library, and it saves an appreciable amount + of time (2 out of 36 or so micros). Hence, the 2.00 designation. + + Tue Jun 26 12:42:20 CDT 2012 + I was officially given permission to use the PCint library: + + Re: PCint library + « Sent to: GreyGnome on: Today at 08:10:33 AM » + « You have forwarded or responded to this message. » + Quote Reply Remove + HI, + Yeah, I wrote the original PCint library. It was a bit of a hack and the new one has better features. + I intended the code to be freely usable. Didn't really think about a license. Feel free to use it in + your code: I hereby grant you permission. + + I'll investigate the MIT license, and see if it is appropriate. + Chris J. Kiick + Robot builder and all around geek. + + Version 1.81 (beta) Tue Jun 19 07:29:08 CDT 2012 + Created the getPCIntVersion function, and its associated GET_PCINT_VERSION preprocessor macro. The version + is a 16-bit int, therefore versions are represented as a 4-digit integer. 1810, then, is the first beta + release of 1.81x series. 1811 would be a bugfix of 1.810. 1820 would be the production release. + + Reversed the order of this list, so the most recent notes come first. + + Made some variables "volatile", because they are changed in the interrupt code. Thanks, Tony Cappellini! + + Added support for the Arduino Mega! Thanks to cserveny...@gmail.com! + NOTE: I don't have a Mega, so I rely on you to give me error (or working) reports! + To sum it up for the Mega: No Port C, no Port D. Instead, you get Port J and Port K. Port B remains. + Port J, however, is practically useless because there is only 1 pin available for interrupts. + Most of the Port J pins are not even connected to a header connector. Caveat Programmer. + + Created a function to report the version of this code. Put this #define ahead of the #include of this file, + in your sketch: + #define GET_PCINT_VERSION + Then you can call + uint16_t getPCIntVersion (); + and it will return a 16-bit integer representation of the version of this library. That is, version 1.73beta + will be reported as "1730". 1.74, then, will return "1740". And so on, for whatever version of the library + this happens to be. The odd number in the 10's position will indicate a beta version, as per usual, and the + number in the 1s place will indicate the beta revision (bugs may necessitate a 1.731, 1.732, etc.). + + Here are some of his notes based on his changes: + Mega and friends are using port B, J and K for interrupts. B is working without any modifications. + + J is mostly useless, because of the hardware UART. I was not able to get pin change notifications from + the TX pin (14), so only 15 left. All other (PORT J) pins are not connected on the Arduino boards. + + K controls Arduino pin A8-A15, working fine. + + 328/168 boards use C and D. So in case the lib is compiled with Mega target, the C and D will be + disabled. Also you cannot see port J/K with other targets. For J and K new flags introduced: + NO_PORTJ_PINCHANGES and NO_PORTK_PINCHANGES. + Maybe we should have PORTJ_PINCHANGES to enable PJ, because they will be most likely unused. + + Enjoy! + + Note: To remain consistent, I have not included PORTJ_PINCHANGES. All ports behave the same, + no matter how trivial those ports may seem... no surprises... + + Version 1.72 Wed Mar 14 18:57:55 CDT 2012 + Release. + + Version 1.71beta Sat Mar 10 12:57:05 CST 2012 + Code reordering: Starting in version 1.3 of this library, I put the code that enables + interrupts for the given pin, and the code that enables Pin Change Interrupts, ahead of actually + setting the user's function for the pin. Thus in the small interval between turning on the + interrupts and actually creating a valid link to an interrupt handler, it is possible to get an + interrupt. At that point the value of the pointer is 0, so this means that the Arduino + will start over again from memory location 0- just as if you'd pressed the reset button. Oops! + + I corrected it so the code now operates in the proper order. + (EDITORIAL NOTE: If you want to really learn something, teach it!) + + Minor code clean-up: All references to PCintPort::curr are now explicit. This changes the compiled + hex code not one whit. I just sleep better at night. + + Numbering: Changed the numbering scheme. Beta versions will end with an odd number in the hundredths + place- because they may be odd- and continue to be marked "beta". I'll just sleep better at night. :-) + + Version 1.70beta Mon Feb 27 07:20:42 CST 2012 + Happy Birthday to me! Happy Birthday tooooo meee! Happy Birthday, Dear Meeeeee-eeeee! + Happy Birthday to me! + + Yes, it is on this auspicious occasion of mine (and Elizabeth Taylor's [R.I.P.]) birthday that I + humbly submit to you, gracious Arduino PinChangeInt user, version 1.70beta of the PinChangeInt + library. I hope you enjoy it. + + New in this release: + The PinChangeIntTest sketch was created, which can be found in the Examples directory. It exercises: + * Two interrupting pins, one on each of the Arduino's PORTs. + * detachInterrupt() (and subsequent attachInterrupt()s). + Hopefully this will help avoid the embarrassing bugs that I have heretofore missed. + + As well, it has come to this author's (GreyGnome) attention that the Serial class in Arduino 1.0 + uses an interrupt that, if you attempt to print from an interrupt (which is what I was doing in my + tests) can easily lock up the Arduino. So I have taken SigurðurOrn's excellent ByteBuffer library + and modified it for my own nefarious purposes. (see http://siggiorn.com/?p=460). The zipfile + comes complete with the ByteBuffer library; see the ByteBuffer/ByteBuffer.h file for a list of + changes, and see the PinChangeIntTest sketch for a usage scenario. Now the (interrupt-less and) + relatively fast operation of filling a circular buffer is used in the interrupt routines. The buffer + is then printed from loop(). + + The library has been modified so it can be used in other libraries, such as my AdaEncoder library + (http://code.google.com/p/adaencoder/). When #include'd by another library you should #define + the LIBCALL_PINCHANGEINT macro. For example: + #ifndef PinChangeInt_h + #define LIBCALL_PINCHANGEINT + #include "../PinChangeInt/PinChangeInt.h" + #endif + This is necessary because the IDE compiles both your sketch and the .cpp file of your library, and + the .h file is included in both places. But since the .h file actually contains the code, any variable + or function definitions would occur twice and cause compilation errors- unless #ifdef'ed out. + + Version 1.6beta Fri Feb 10 08:48:35 CST 2012 + Set the value of the current register settings, first thing in each ISR; e.g., + ISR(PCINT0_vect) { + PCintPort::curr = portB.portInputReg; // version 1.6 + ... + ...instead of at the beginning of the PCintPort::PCint() static method. This means that the port is read + closer to the beginning of the interrupt, and may be slightly more accurate- only by a couple of microseconds, + really, but it's a cheap win. + + Fixed a bug- a BUG!- in the attachInterrupt() and detachInterrupt() methods. I didn't have breaks in my + switch statements! Augh! What am I, a (UNIX) shell programmer? ...Uh, generally, yes... + + Added the PINMODE define and the PCintPort::pinmode variable. + + Version 1.51 Sun Feb 5 23:28:02 CST 2012 + Crap, a bug! Changed line 392 from this: + PCintPort::pinState=curr & changedPins ? HIGH : LOW; + to this: + PCintPort::pinState=curr & p->mask ? HIGH : LOW; + Also added a few lines of (commented-out) debug code. + + Version 1.5 Thu Feb 2 18:09:49 CST 2012 + Added the PCintPort::pinState static variable to allow the programmer to query the state of the pin + at the time of interrupt. + Added two new #defines, NO_PIN_STATE and NO_PIN_NUMBER so as to reduce the code size by 20-50 bytes, + and to speed up the interrupt routine slightly by declaring that you don't care if the static variables + PCintPort::pinState and/or PCintPort::arduinoPin are set and made available to your interrupt routine. + // #define NO_PIN_STATE // to indicate that you don't need the pinState + // #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin + + Version 1.4 Tue Jan 10 09:41:14 CST 2012 + All the code has been moved into this .h file, so as to allow #define's to work from the user's + sketch. Thanks to Paul Stoffregen from pjrc.com for the inspiration! (Check out his website for + some nice [lots more memory] Arduino-like boards at really good prices. ...This has been an unsolicited + plug. Now back to our regular programming. ...Hehe, "programming", get it?) + + As a result, we no longer use the PinChangeIntConfig.h file. The user must #define things in his/her + sketch. Which is better anyway. + + Removed the pcIntPorts[] array, which created all the ports by default no matter what. Now, only + those ports (PCintPort objects) that you need will get created if you use the NO_PORTx_PINCHANGES #defines. + This saves flash memory, and actually we get a bit of a memory savings anyway even if all the ports are + left enabled. + + The attachInterrupt and detachInterrupt routines were modified to handle the new PCintPort objects. + + Version 1.3 Sat Dec 3 22:56:20 CST 2011 + Significant internal changes: + Tested and modified to work with Arduino 1.0. + + Modified to use the new() operator and symbolic links instead of creating a pre-populated + PCintPins[]. Renamed some variables to simplify or make their meaning more obvious (IMHO anyway). + Modified the PCintPort::PCint() code (ie, the interrupt code) to loop over a linked-list. For + those who love arrays, I have left some code in there that should work to loop over an array + instead. But it is commented out in the release version. + + For Arduino versions prior to 1.0: The new() operator requires the cppfix.h library, which is + included with this package. For Arduino 1.0 and above: new.h comes with the distribution, and + that is #included. + + Version 1.2 Sat Dec 3 Sat Dec 3 09:15:52 CST 2011 + Modified Thu Sep 8 07:33:17 CDT 2011 by GreyGnome. Fixes a bug with the initial port + value. Now it sets the initial value to be the state of the port at the time of + attachInterrupt(). The line is port.PCintLast=port.portInputReg; in attachInterrupt(). + See GreyGnome comment, below. + + Added the "arduinoPin" variable, so the user's function will know exactly which pin on + the Arduino was triggered. + + Version 1.1 Sat Dec 3 00:06:03 CST 2011 + ...updated to fix the "delPin" function as per "pekka"'s bug report. Thanks! + + ---- ^^^ VERSIONS ^^^ (NOTE TO SELF: Update the PCINT_VERSION define, below) ------------- + + See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/ + For more information Refer to avr-gcc header files, arduino source and atmega datasheet. + + This library was inspired by and derived from "johnboiles" (it seems) + PCInt Arduino Playground example here: http://www.arduino.cc/playground/Main/PcInt + If you are the original author, please let us know at the google code page + + It provides an extension to the interrupt support for arduino by + adding pin change interrupts, giving a way for users to have + interrupts drive off of any pin. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . diff --git a/libraries/PinChangeInt/gpl.txt b/libraries/PinChangeInt/gpl.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/libraries/PinChangeInt/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/libraries/PinChangeInt/keywords.txt b/libraries/PinChangeInt/keywords.txt new file mode 100644 index 0000000..24e1cec --- /dev/null +++ b/libraries/PinChangeInt/keywords.txt @@ -0,0 +1,10 @@ +# LITERAL1 specifies constants + +# KEYWORD1 specifies datatypes and C/C++ keywords +pinState KEYWORD1 PinState +arduinoPin KEYWORD1 ArduinoPin +PCintPort KEYWORD1 PCInterruptPort + +# KEYWORD2 specifies methods and functions +attachInterrupt KEYWORD2 AttachInterrupt +detachInterrupt KEYWORD2 DetachInterrupt From 5bb8c9b40c6aeace055e25de698370c930e351fb Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Sep 2014 22:33:49 +0200 Subject: [PATCH 010/660] Bugfixes and cleanup --- libraries/MySensors/MyConfig.h | 2 +- libraries/MySensors/MySensor.cpp | 4 +- .../EthernetGateway/EthernetGateway.ino | 22 ++-- .../examples/EthernetGateway/GatewayUtil.h | 3 +- .../examples/MQTTGateway/GatewayUtil.h | 120 ------------------ .../examples/MQTTGateway/MQTTGateway.ino | 6 +- .../MySensors/examples/MQTTGateway/MyMQTT.hx | 83 ------------ .../examples/SerialGateway/SerialGateway.ino | 2 - 8 files changed, 24 insertions(+), 218 deletions(-) delete mode 100644 libraries/MySensors/examples/MQTTGateway/GatewayUtil.h delete mode 100755 libraries/MySensors/examples/MQTTGateway/MyMQTT.hx diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index adcb219..89f7198 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -18,6 +18,6 @@ /*** * Enable/Disable debug logging */ -#define DEBUG +//#define DEBUG #endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 5a0670c..2c9b780 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -81,7 +81,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b requestNodeId(); } - debug(PSTR("%s started, id %d\n"), repeaterMode?"repeater":"sensor", nc.nodeId); + if (!isGateway) { + debug(PSTR("%s started, id %d\n"), repeaterMode?"repeater":"sensor", nc.nodeId); + } // Open reading pipe for messages directed to this node (set write pipe to same) RF24::openReadingPipe(WRITE_PIPE, TO_ADDR(nc.nodeId)); diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 77f53f8..55c215b 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -104,11 +104,14 @@ void setup() { // Initialize gateway at maximum PA level, channel 70 and callback for write operations gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); - + // Setup pipes for radio library + gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); + gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); + gw.startListening(); + Ethernet.begin(mac, myIp); setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - // Add led timer interrupt MsTimer2::set(300, ledTimersInterrupt); MsTimer2::start(); @@ -116,12 +119,14 @@ void setup() // Add interrupt for inclusion button to pin PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); - // give the Ethernet interface a second to initialize delay(1000); - + // start listening for clients server.begin(); + + //output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); + } @@ -132,20 +137,21 @@ void loop() checkButtonTriggeredInclusion(); checkInclusionFinished(); - + // if an incoming client connects, there will be // bytes available to read via the client object EthernetClient client = server.available(); if (client) { - // if got 1 or more bytes + + // if got 1 or more bytes if (client.available()) { // read the bytes incoming from the client char inChar = client.read(); - if (inputPos #ifdef ARDUINO @@ -48,6 +47,7 @@ void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _ countTx = 0; countErr = 0; + // Setup led pins pinMode(pinRx, OUTPUT); pinMode(pinTx, OUTPUT); @@ -240,7 +240,6 @@ void ledTimersInterrupt() { digitalWrite(pinEr, HIGH); } if(countErr != 255) { countErr--; } - } void rxBlink(uint8_t cnt) { diff --git a/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h b/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h deleted file mode 100644 index 58ff64a..0000000 --- a/libraries/MySensors/examples/MQTTGateway/GatewayUtil.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef __GATEWAYUTIL_H__ -#define __GATEWAYUTIL_H__ - -#include - -#ifdef ARDUINO - - -uint8_t pinRx = 8; // Rx led pin -uint8_t pinTx = 9; // Tx led pin -uint8_t pinEr = 7; // Err led pin - -#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller -#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller - -volatile boolean buttonTriggeredInclusion; -volatile uint8_t countRx; -volatile uint8_t countTx; -volatile uint8_t countErr; - -MyMessage msg; - -void setInclusionMode(boolean newMode); -void txBlink(uint8_t cnt); -void rxBlink(uint8_t cnt); -void errBlink(uint8_t cnt); - -char convBuf[MAX_PAYLOAD*2+1]; -char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera -unsigned long inclusionStartTime; - -void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { - inclusionMode = 0; - buttonTriggeredInclusion = false; - serial = _serial; - - pinRx = _rx; - pinTx = _tx; - pinEr = _er; - pinInclusion = _inc; - inclusionTime = _incTime; - - countRx = 0; - countTx = 0; - countErr = 0; - - // Setup led pins - pinMode(pinRx, OUTPUT); - pinMode(pinTx, OUTPUT); - pinMode(pinEr, OUTPUT); - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); - - - // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); - -} - - - -void startInclusionInterrupt() { - buttonTriggeredInclusion = true; -} - - - - - -void ledTimersInterrupt() { - if(countRx && countRx != 255) { - // switch led on - digitalWrite(pinRx, LOW); - } else if(!countRx) { - // switching off - digitalWrite(pinRx, HIGH); - } - if(countRx != 255) { countRx--; } - - if(countTx && countTx != 255) { - // switch led on - digitalWrite(pinTx, LOW); - } else if(!countTx) { - // switching off - digitalWrite(pinTx, HIGH); - } - if(countTx != 255) { countTx--; } - else if(inclusionMode) { countTx = 8; } - - if(countErr && countErr != 255) { - // switch led on - digitalWrite(RADIO_ERROR_LED_PIN, LOW); - } else if(!countErr) { - // switching off - digitalWrite(RADIO_ERROR_LED_PIN, HIGH); - } - if(countErr != 255) { countErr--; } - -} - -void rxBlink(uint8_t cnt) { - if(countRx == 255) { countRx = cnt; } -} -void txBlink(uint8_t cnt) { - if(countTx == 255 && !inclusionMode) { countTx = cnt; } -} -void errBlink(uint8_t cnt) { - if(countErr == 255) { countErr = cnt; } -} - - - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 388fba8..b7cb4ca 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -144,7 +144,11 @@ void setup() { // Initialize gateway at maximum PA level, channel 70 and callback for write operations gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); - + // Setup pipes for radio library + gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); + gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); + gw.startListening(); + Ethernet.begin(TCP_MAC, TCP_IP); diff --git a/libraries/MySensors/examples/MQTTGateway/MyMQTT.hx b/libraries/MySensors/examples/MQTTGateway/MyMQTT.hx deleted file mode 100755 index e5d5447..0000000 --- a/libraries/MySensors/examples/MQTTGateway/MyMQTT.hx +++ /dev/null @@ -1,83 +0,0 @@ -/* -The MySensors library adds a new layer on top of the RF24 library. -It handles radio network routing, relaying and ids. - -Created by Henrik Ekblad -Modified by Daniel Wiegert -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. -*/ - -#ifndef MyMQTT_h -#define MyMQTT_h - -#include "MySensor.h" - - -////////////////////////////////////////////////////////////////// - -#ifdef DEBUG -#define TCPDUMP // Dump TCP packages. -#endif - -#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable -#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved. -#define MQTT_BROKER_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short! -#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request. -// NOTE above : Beware to check if there is any length on payload in your incommingMessage code: -// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. - -////////////////////////////////////////////////////////////////// - -#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS) -#define MQTT_MAX_PACKET_SIZE 100 - -#define MQTTPROTOCOLVERSION 3 -#define MQTTCONNECT 1 // Client request to connect to Server -#define MQTTCONNACK 2 // Connect Acknowledgment -#define MQTTPUBLISH 3 // Publish message -#define MQTTPUBACK 4 // Publish Acknowledgment -#define MQTTPUBREC 5 // Publish Received (assured delivery part 1) -#define MQTTPUBREL 6 // Publish Release (assured delivery part 2) -#define MQTTPUBCOMP 7 // Publish Complete (assured delivery part 3) -#define MQTTSUBSCRIBE 8 // Client Subscribe request -#define MQTTSUBACK 9 // Subscribe Acknowledgment -#define MQTTUNSUBSCRIBE 10 // Client Unsubscribe request -#define MQTTUNSUBACK 11 // Unsubscribe Acknowledgment -#define MQTTPINGREQ 12 // PING Request -#define MQTTPINGRESP 13 // PING Response -#define MQTTDISCONNECT 14 // Client is Disconnecting -#define MQTTReserved 15 // Reserved - -#define MQTTQOS0 (0 << 1) -#define MQTTQOS1 (1 << 1) -#define MQTTQOS2 (2 << 1) - -class MyMQTT : -public MySensor { - -public: - MyMQTT(uint8_t _cepin=5, uint8_t _cspin=6); - void begin(rf24_pa_dbm_e paLevel=RF24_PA_LEVEL_GW, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE, void (*dataCallback) - (const char *, uint8_t *)=NULL, uint8_t _rx=6, uint8_t _tx=5, uint8_t _er=4 ); - void processRadioMessage(); - void processMQTTMessage(char *inputString, uint8_t inputPos); -private: - void (*dataCallback)(const char *, uint8_t *); - void SendMQTT(MyMessage &msg); - void ledTimers(); - void rxBlink(uint8_t cnt); - void txBlink(uint8_t cnt); - void errBlink(uint8_t cnt); - - bool MQTTClientConnected; - char buffer[MQTT_MAX_PACKET_SIZE]; - char convBuf[MAX_PAYLOAD*2+1]; - uint8_t buffsize; - char *getType(char *b, const char **index); -}; - -extern void ledTimersInterrupt(); - -#endif diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 1d314d6..ed50829 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -63,8 +63,6 @@ void setup() gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); gw.startListening(); - Serial.begin(BAUD_RATE); - setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); // Add led timer interrupt From e5bd891a772bd28ad62ba0c1c155363c29490858 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 11 Sep 2014 09:37:42 +0200 Subject: [PATCH 011/660] Improved parent node search Retry parent node search with each transmit when parent has not been found. Transmit does not block on transmit when no parent has been found as this depletes batteries on battery powered nodes. Fix nRF24 configuration for dynamic ACK's. This bug caused broadcasts to be sent with auto-ACK's. To not break existing functionality parent search can be started when node ID is still unknown. In this case node ID is set to broadcast ID, which can cause funky stuff to happen... --- libraries/MySensors/MySensor.cpp | 141 ++++++++++++++++++------------- libraries/MySensors/MySensor.h | 2 +- 2 files changed, 85 insertions(+), 58 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index e7002d5..907ba43 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -14,9 +14,11 @@ #include "utility/RF24.h" #include "utility/RF24_config.h" +#define DISTANCE_INVALID (0xFF) + // Inline function and macros -inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { +static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { msg.sender = sender; msg.destination = destination; msg.sensor = sensor; @@ -27,6 +29,13 @@ inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, ui return msg; } +static inline bool isValidParent( const uint8_t parent ) { + return parent != AUTO; +} +static inline bool isValidDistance( const uint8_t distance ) { + return distance != DISTANCE_INVALID; +} + MySensor::MySensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) { } @@ -37,6 +46,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b isGateway = false; repeaterMode = _repeaterMode; msgCallback = _msgCallback; + failedTransmissions = 0; if (repeaterMode) { setupRepeaterMode(); @@ -52,11 +62,13 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b cc.isMetric = 0x01; } - if (_parentNodeId != AUTO) { + autoFindParent = _parentNodeId == AUTO; + if (!autoFindParent) { nc.parentNodeId = _parentNodeId; - autoFindParent = false; - } else { - autoFindParent = true; + nc.distance = 0; + } else if (!isValidParent(nc.parentNodeId)) { + // Auto find parent, but parent in eeprom is invalid. Force parent search on first transmit. + nc.distance = DISTANCE_INVALID; } if (_nodeId != AUTO) { @@ -64,17 +76,12 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b nc.nodeId = _nodeId; } - // If no parent was found in eeprom. Try to find one. - if (autoFindParent && nc.parentNodeId == 0xff) { - findParentNode(); - } - // Try to fetch node-id from gateway if (nc.nodeId == AUTO) { requestNodeId(); } - debug(PSTR("%s started, id %d\n"), repeaterMode?"repeater":"sensor", nc.nodeId); + debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), repeaterMode?"repeater":"sensor", nc.nodeId, nc.parentNodeId, nc.distance); // Open reading pipe for messages directed to this node (set write pipe to same) RF24::openReadingPipe(WRITE_PIPE, TO_ADDR(nc.nodeId)); @@ -93,8 +100,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) { - failedTransmissions = 0; - // Start up the radio library RF24::begin(); @@ -104,13 +109,13 @@ void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_ } RF24::setAutoAck(1); RF24::setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast - RF24::enableAckPayload(); RF24::setChannel(channel); RF24::setPALevel(paLevel); RF24::setDataRate(dataRate); RF24::setRetries(5,15); RF24::setCRCLength(RF24_CRC_16); RF24::enableDynamicPayloads(); + RF24::enableDynamicAck(); // Required to disable ack-sending for broadcast messages // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); @@ -139,14 +144,12 @@ void MySensor::requestNodeId() { void MySensor::findParentNode() { - failedTransmissions = 0; - - // Set distance to max - nc.distance = 255; - // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) + debug(PSTR("find parent\n")); + build(msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); - sendWrite(BROADCAST_ADDRESS, msg, true); + // Write msg, but suppress recursive parent search + sendWrite(BROADCAST_ADDRESS, msg, false); // Wait for ping response. waitForReply(); @@ -182,44 +185,64 @@ boolean MySensor::sendRoute(MyMessage &message) { } else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) { // Node has not yet received any id. We need to send it // by doing a broadcast sending, - return sendWrite(BROADCAST_ADDRESS, message, true); + return sendWrite(BROADCAST_ADDRESS, message); } } if (!isGateway) { - // --- debug(PSTR("route parent\n")); // Should be routed back to gateway. - bool ok = sendWrite(nc.parentNodeId, message); - - if (!ok) { - // Failure when sending to parent node. The parent node might be down and we - // need to find another route to gateway. - if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { - findParentNode(); - } - failedTransmissions++; - } else { - failedTransmissions = 0; - } - return ok; + return sendWrite(nc.parentNodeId, message); } return false; } -boolean MySensor::sendWrite(uint8_t next, MyMessage &message, bool broadcast) { - uint8_t length = mGetLength(message); - message.last = nc.nodeId; - mSetVersion(message, PROTOCOL_VERSION); - // Make sure radio has powered up - RF24::powerUp(); - RF24::stopListening(); - RF24::openWritingPipe(TO_ADDR(next)); - bool ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast); - RF24::startListening(); +boolean MySensor::sendWrite(uint8_t next, MyMessage &message, const bool allowFindParent) { + bool ok = true; + const bool broadcast = next == BROADCAST_ADDRESS; + const bool toParent = next == nc.parentNodeId; + // With current implementation parent node Id can equal the broadcast address when + // starting with empty eeprom and AUTO node Id is active. + // This behavior is undesired, as possible parents will report back to broadcast address. +// debug(PSTR("sendWrite next=%d, parent=%d, distance=%d\n"), next, nc.parentNodeId, nc.distance); + // If sending directly to parent node and distance is not set, then try to find parent now. + if ( allowFindParent && toParent && !isValidDistance(nc.distance) ) { + findParentNode(); + // Known distance indicates parent has been found + ok = isValidDistance(nc.distance); + } - debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), - message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, mGetPayloadType(message), mGetLength(message), ok?"ok":"fail", message.getString(convBuf)); + if (ok) { + uint8_t length = mGetLength(message); + message.last = nc.nodeId; + mSetVersion(message, PROTOCOL_VERSION); + // Make sure radio has powered up + RF24::powerUp(); + RF24::stopListening(); + RF24::openWritingPipe(TO_ADDR(next)); + // Send message. Disable auto-ack for broadcasts. + ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast); + RF24::startListening(); + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), + message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, + mGetPayloadType(message), mGetLength(message), broadcast ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); + + // If many successive transmissions to parent failed, the parent node might be down and we + // need to find another route to gateway. + if (toParent) { + if (ok) { + failedTransmissions = 0; + } else { + failedTransmissions++; + if ( autoFindParent && (failedTransmissions >= SEARCH_FAILURES)) { + debug(PSTR("lost parent\n")); + // Set distance invalid to trigger parent search on next write. + nc.distance = DISTANCE_INVALID; + failedTransmissions = 0; + } + } + } + } return ok; } @@ -267,7 +290,6 @@ boolean MySensor::process() { uint8_t len = RF24::getDynamicPayloadSize(); RF24::read(&msg, len); - RF24::writeAckPayload(pipe,&pipe, 1 ); // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; @@ -287,10 +309,10 @@ boolean MySensor::process() { if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) { // Relaying nodes should always answer ping messages - // Wait a random delay of 0-2 seconds to minimize collision + // Wait a random delay of 0-1.023 seconds to minimize collision // between ping ack messages from other relaying nodes delay(millis() & 0x3ff); - sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance), true); + sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); return false; } else if (destination == nc.nodeId) { // Check if sender requests an ack back. @@ -315,13 +337,18 @@ boolean MySensor::process() { // We've received a reply to a FIND_PARENT message. Check if the distance is // shorter than we already have. uint8_t distance = msg.getByte(); - if (distance Date: Sat, 20 Sep 2014 13:04:01 +0200 Subject: [PATCH 012/660] Made Time, LiquidCrystal and RealTimeClockDisplaySensor example work in Arduino IDE 1.5.7. --- libraries/LiquidCrystal/LCD.cpp | 2 +- libraries/LiquidCrystal/LCD.h | 2 +- libraries/MySensors/MyConfig.h | 2 +- .../EthernetGateway/EthernetGateway.ino | 8 ++-- libraries/Time/DateStrings.cpp | 48 +++++++++---------- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/libraries/LiquidCrystal/LCD.cpp b/libraries/LiquidCrystal/LCD.cpp index f0e3068..e7af077 100644 --- a/libraries/LiquidCrystal/LCD.cpp +++ b/libraries/LiquidCrystal/LCD.cpp @@ -304,7 +304,7 @@ void LCD::createChar(uint8_t location, uint8_t charmap[]) } #ifdef __AVR__ -void LCD::createChar(uint8_t location, const prog_uchar charmap[]) +void LCD::createChar(uint8_t location, const unsigned char charmap[]) { location &= 0x7; // we only have 8 memory locations 0-7 diff --git a/libraries/LiquidCrystal/LCD.h b/libraries/LiquidCrystal/LCD.h index 126b935..9b977f4 100644 --- a/libraries/LiquidCrystal/LCD.h +++ b/libraries/LiquidCrystal/LCD.h @@ -418,7 +418,7 @@ public: (0 to 7) @param charmap[in] the bitmap array representing each row of the character. */ - void createChar(uint8_t location, const prog_uchar charmap[]); + void createChar(uint8_t location, const unsigned char charmap[]); #endif // __AVR__ /*! diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 89f7198..adcb219 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -18,6 +18,6 @@ /*** * Enable/Disable debug logging */ -//#define DEBUG +#define DEBUG #endif diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 49a6065..82609c3 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -42,8 +42,8 @@ * 7 Radio error LED (optional) +5V -> LED -> 270-330 Ohm resistor -> pin 7. * 6 Radio SPI Slave Select * 5 Radio Chip Enable - * 3 Inclusion mode button (optional), 10K pull down to GND, button to VCC) - * 2 Radio IRQ pin (optional), W5100 Int, if linked to pin 2) + * 3 Inclusion mode button (optional) GND-> Button -> Pin3 + * 2 Radio IRQ pin (optional) * ----------------------------------------------------------------------------------------------------------- * Powering: both NRF24l01 radio and Ethernet(ENC28J60) uses 3.3V */ @@ -58,10 +58,10 @@ // Use this if you have attached a Ethernet ENC28J60 shields -#include +//#include // Use this fo WizNET module and Arduino Ethernet Shield -//#include +#include #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled diff --git a/libraries/Time/DateStrings.cpp b/libraries/Time/DateStrings.cpp index fc6e15f..a0eef9d 100644 --- a/libraries/Time/DateStrings.cpp +++ b/libraries/Time/DateStrings.cpp @@ -15,38 +15,38 @@ static char buffer[dt_MAX_STRING_LEN+1]; // must be big enough for longest string and the terminating null -char monthStr1[] PROGMEM = "January"; -char monthStr2[] PROGMEM = "February"; -char monthStr3[] PROGMEM = "March"; -char monthStr4[] PROGMEM = "April"; -char monthStr5[] PROGMEM = "May"; -char monthStr6[] PROGMEM = "June"; -char monthStr7[] PROGMEM = "July"; -char monthStr8[] PROGMEM = "August"; -char monthStr9[] PROGMEM = "September"; -char monthStr10[] PROGMEM = "October"; -char monthStr11[] PROGMEM = "November"; -char monthStr12[] PROGMEM = "December"; +const char monthStr1[] PROGMEM = "January"; +const char monthStr2[] PROGMEM = "February"; +const char monthStr3[] PROGMEM = "March"; +const char monthStr4[] PROGMEM = "April"; +const char monthStr5[] PROGMEM = "May"; +const char monthStr6[] PROGMEM = "June"; +const char monthStr7[] PROGMEM = "July"; +const char monthStr8[] PROGMEM = "August"; +const char monthStr9[] PROGMEM = "September"; +const char monthStr10[] PROGMEM = "October"; +const char monthStr11[] PROGMEM = "November"; +const char monthStr12[] PROGMEM = "December"; -PGM_P monthNames_P[] PROGMEM = +PGM_P const monthNames_P[] PROGMEM = { "",monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6, monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12 }; -char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec"; +const char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec"; -char dayStr0[] PROGMEM = "Err"; -char dayStr1[] PROGMEM = "Sunday"; -char dayStr2[] PROGMEM = "Monday"; -char dayStr3[] PROGMEM = "Tuesday"; -char dayStr4[] PROGMEM = "Wednesday"; -char dayStr5[] PROGMEM = "Thursday"; -char dayStr6[] PROGMEM = "Friday"; -char dayStr7[] PROGMEM = "Saturday"; +const char dayStr0[] PROGMEM = "Err"; +const char dayStr1[] PROGMEM = "Sunday"; +const char dayStr2[] PROGMEM = "Monday"; +const char dayStr3[] PROGMEM = "Tuesday"; +const char dayStr4[] PROGMEM = "Wednesday"; +const char dayStr5[] PROGMEM = "Thursday"; +const char dayStr6[] PROGMEM = "Friday"; +const char dayStr7[] PROGMEM = "Saturday"; -PGM_P dayNames_P[] PROGMEM = { dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7}; -char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat"; +PGM_P const dayNames_P[] PROGMEM = { dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7}; +const char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat"; /* functions to return date strings */ From 7a304a0523e3feb712ee088232605287ac09cffb Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Sun, 28 Sep 2014 23:43:28 +0200 Subject: [PATCH 013/660] Reduce Bootloader Size changing few uint16 variables to uint8 --- Bootloader/MyOtaBootloader.c | 4 +- Bootloader/MyOtaBootloader.hex | 404 ++++++++++++++++----------------- Bootloader/MyOtaBootloaderHW.h | 5 +- 3 files changed, 205 insertions(+), 208 deletions(-) diff --git a/Bootloader/MyOtaBootloader.c b/Bootloader/MyOtaBootloader.c index cd58712..fe4f24f 100644 --- a/Bootloader/MyOtaBootloader.c +++ b/Bootloader/MyOtaBootloader.c @@ -56,9 +56,9 @@ static uint8_t sendAndWait(uint8_t reqType, uint8_t resType) { msg.type = reqType; for (uint8_t i = 0; i < 10; i++) { sendWrite(msg); - for (uint16_t j = 0; j < 20; j++) { + for (uint8_t j = 0; j < 20; j++) { wdt_reset(); - for (uint16_t j = 0; j < 100; j++) { + for (uint8_t j = 0; j < 100; j++) { wdt_reset(); uint8_t pipe; boolean avail = available(&pipe); diff --git a/Bootloader/MyOtaBootloader.hex b/Bootloader/MyOtaBootloader.hex index 6fd8c58..538354d 100644 --- a/Bootloader/MyOtaBootloader.hex +++ b/Bootloader/MyOtaBootloader.hex @@ -1,4 +1,4 @@ -:1070000011E0A0E0B1E0E0E4FDE702C005900D92E0 +:1070000011E0A0E0B1E0E8EFFCE702C005900D92CE :10701000A030B107D9F711E0A0E0B1E001C01D92A6 :10702000A83DB107E1F711248091610090E08F70D5 :107030009070909301018093000182E090E020E83D @@ -7,208 +7,204 @@ :107060000FBE20936000A8951092CF011092D0011E :107070001092D1011092D2011092D3011092D4013A :107080001092D5011092D60184B18E6284B92498F1 -:1070900085B1857D85B92A9A8AE090E0B3D184E0F4 -:1070A0006FE520D281E06BE31DD285E06CE41AD25B -:1070B00086E0E5D1682F607D676286E013D280E0CC -:1070C000DED1682F6C6080E00DD287E060E70AD2E5 -:1070D0002A9881E090E096D180E5A6D183E7A4D1FB -:1070E0002A9A81E090E08ED18DE1C9D1682F666047 -:1070F0008DE1F8D18CE1C3D1682F6F638CE1F2D1BF -:1071000082EEADD181EEABD104D280E0B8D1682F50 -:107110006E7F80E0E7D182E00FEF1CEF21EE38EACE -:1071200048EA50E060E070E002D2A89582E091E089 -:1071300060E070E043E050E02DEE39E38AD5A89599 -:107140008091020180930E0180930D014FD22FEFA9 -:10715000209313018091110192E0909310012093EC -:107160000401887083608093110120930F0187E0F0 -:1071700068E04AD3882309F42AD310920F01809142 -:1071800002018F3F09F038C081E00FEF1CEF21EEC4 -:1071900038EA48EA50E060E070E0C9D183E064E09A -:1071A00033D3882309F407D38091320182958695E1 -:1071B0008770813019F48091350105C0882329F446 -:1071C00085E391E028D580930201809102018F3FF1 -:1071D00009F4F1D280910201F999FECF1FBA12BCD5 -:1071E00011BC80BD0FB6F894FA9AF99A0FBE80933D -:1071F0000E0180930D01FAD185E091E06BE171E021 -:1072000048E050E02DEE39E324D5909111019871BA -:10721000809110018770806280931001946C90932C -:1072200011018091050190910601909315018093C1 -:1072300014018091070190910801909317018093A8 -:10724000160180E061E0E0D2882309F4C0D22091E9 -:10725000370130913801809107019091080128177A -:107260003907C9F42091390130913A01809109011F -:1072700090910A012817390771F420913B01309150 -:107280003C0180910B0190910C012817390719F4EA -:107290005DD281119CD240913501509136015093BD -:1072A0000601409305012091370130913801309358 -:1072B0000801209307018091390190913A01909340 -:1072C0000A018093090180913B0190913C019093C8 -:1072D0000C0180930B01F4E1EF2EF1E0FF2E809181 -:1072E00010018770806380931001509315014093C3 -:1072F00014013093170120931601C0E0D0E000E99B -:107300001FEFBB24B394E5E0CE2E71E1D72E4DC024 -:10731000F701D583C48382E063E076D2882309F441 -:107320004AD2902F90599F77E92FF0E0E15BFE4F12 -:10733000ABE3B1E080E10D9001928150E1F790372D -:1073400009F030C03FB7F894F999FECF83E0F80117 -:1073500080935700E89507B600FCFDCFA801AFE485 -:10736000B1E02C9111968C91119790E0982F88277D -:10737000820F911D1296FA010C01B0925700E89508 -:1073800011244E5F5F4FF1E0AF3CBF0751F7F801AA -:10739000C0925700E89507B600FCFDCFD092570089 -:1073A000E8953FBF2196005F1F4F809109019091A2 -:1073B0000A01C817D90708F4ABCFA895C7D188230D -:1073C00049F08BE191E065E071E048E050E024EFA6 -:1073D00039E35BD4F0D180E090E0F999FECF92BD23 -:1073E00081BDF89A80B50895F999FECF1FBA92BD74 -:1073F00081BD60BD0FB6F894FA9AF99A0FBE089550 -:107400000000089540E050E00BC020E030E00000B4 -:107410002F5F3F4F61E0243F3607C9F74F5F5F4F53 -:107420004817590790F308950F931F93182F00E002 -:10743000E7DF17FD02C02B9801C02B9AE1DF2D9AE0 -:1074400083B1110F82958170182BDADF2D98D8DF68 -:107450000F5F083069F7812F1F910F9108951F93D7 -:10746000182F2A9881E090E0CDDF812FDDDF182FE3 -:107470002A9A81E090E0C6DF812F1F9108951F9323 -:10748000182F2A9881E090E0BDDF812F8F71CCDF2B -:107490008FEFCADF182F2A9A81E090E0B3DF812FA7 -:1074A0001F9108950F931F93CF93DF93182FEB0134 -:1074B000042F2A9881E090E0A5DF1F71812F806260 -:1074C000B3DF182F03C08991AFDF01500023D9F734 -:1074D0002A9A81E090E096DF812FDF91CF911F9172 -:1074E0000F9108950F931F93182F062F2A9881E06C -:1074F00090E088DF1F71812F806296DF182F802F28 -:1075000093DF2A9A81E090E07DDF812F1F910F9118 -:10751000089580E0B4DF81FD09C080E0B0DF682F0E -:10752000626080E0DFDF85E090E06CDF08957F92AD -:107530008F929F92AF92BF92CF92DF92EF92FF9283 -:107540000F931F93DF93CF93CDB7DEB728970FB676 -:10755000F894DEBF0FBECDBF782E480159016A01F5 -:107560007B01882381F40093CF019092D001209376 -:10757000D101B092D2014093D301D092D401609353 -:10758000D501F092D60189829A82AB82BC82CD82EB -:10759000DE82EF82F88681E0871538F0872D865FDE -:1075A000BE016F5F7F4F45E07DDF82E068DF21E055 -:1075B00030E002C0220F331F7A94E2F7682F622B6B -:1075C00082E090DF28960FB6F894DEBF0FBECDBFE5 -:1075D000CF91DF911F910F91FF90EF90DF90CF90AF -:1075E000BF90AF909F908F907F9008957F928F92E1 -:1075F0009F92AF92BF92CF92DF92EF92FF920F9342 -:107600001F93DF93CF93CDB7DEB728970FB6F894CB -:10761000DEBF0FBECDBF8F3F09F483C0082F10E03F -:1076200020E030E040E050E060E070E089831A83C1 -:107630002B833C834D835E836F83788788243CEF64 -:10764000932E21EEA22E98EAB92E88EAC82EDD24C8 -:10765000EE24FF24080D81E09981091708F080E0ED -:10766000192D91E0AA819A1608F090E0E82FE10F19 -:1076700081E0E11708F080E0982B1E2F2A2D772457 -:107680007394BB81AB1608F07724920F81E09217B8 -:1076900008F080E0782A292F3B2D91E0EC81BE167E -:1076A00008F090E0E72DE30F81E0E31708F080E0B9 -:1076B000982B3E2F4C2D77247394FD81CF1608F024 -:1076C0007724940F81E0941708F080E0782A492FFE -:1076D0005D2D91E08E81D81608F090E0E72DE50F42 -:1076E00081E0E51708F080E0982B5E2F6E2D77245F -:1076F0007394AF81EA1608F07724960F81E096170D -:1077000008F080E0782A692F7F0C772D59016A01F3 -:10771000E92E80E00CDF81E09501A6016E2D772D2A -:1077200006DF28960FB6F894DEBF0FBECDBFCF910F -:10773000DF911F910F91FF90EF90DF90CF90BF905E -:10774000AF909F908F907F90089518954091090178 -:1077500050910A0164E0440F551F6A95E1F7E0E09B -:10776000F0E02FEF3FEF19C084912827822F8295F8 -:107770008227082E869586958025082E8695802559 -:107780008770022E232F869507948795302D282702 -:1077900006948795302528273196E417F50720F3BE -:1077A00040E080910B0190910C012817390709F4F2 -:1077B00041E0842F089528E088E190E00FB6F89426 -:1077C000A895809360000FBE20936000FFCFBEDFBE -:1077D0008823C1F088E10FB6F8948093600010927E -:1077E00060000FBE809100019091010120E80FB66A -:1077F000F89420936100809361000FBEE0E0F0E018 -:1078000009950895D8DF08952F923F924F925F9285 -:107810006F927F928F929F92AF92BF92CF92DF92A0 -:10782000EF92FF920F931F93DF93CF93CDB7DEB705 -:10783000E3970FB6F894DEBF0FBECDBF6BA7809362 -:1078400012016624B9E02B2E312C2C0E3D1E2E0188 -:107850000894411C511CD101EDE0F1E081E201905E -:107860000D928150E1F7109103017C842B852AA7AA -:1078700050DE299881E090E0C5DD81EEF0DD82EEFA -:10788000EEDD80E0FCDD682F6E7F80E02BDE30E0F7 -:1078900040E050E060E070E080E090E01CA73DA791 -:1078A0004EA75FA768AB79AB8AAB9BAB8824ACEFE4 -:1078B0009A2EF1EEAF2EE8EABE2E78EAC72EDD242E -:1078C000EE24FF24012F080D81E0011708F080E06D -:1078D000192D91E0EDA59E1608F090E0E82FE10F3C -:1078E00081E0E11708F080E0982B1E2F2A2DE1E0BF -:1078F000FEA5AF1608F0E0E0920F81E0921708F0C5 -:1079000080E0E82B292F3B2D91E08FA5B81608F0D9 -:1079100090E0E30F81E0E31708F080E0982B3E2F22 -:107920004C2DE1E0F8A9CF1608F0E0E0940F81E0DB -:10793000941708F080E0E82B492F5D2D91E089A98C -:10794000D81608F090E0E50F81E0E51708F080E038 -:10795000982B5E2F6E2D81E0EAA9EE1608F080E0EC -:10796000E92FE60F91E0E61708F090E0892B8F0DE4 -:1079700009831A832B833C834D835E83EF8388873F -:107980008AE0B20145E08EDD80E1B20145E08ADDAA -:10799000FAA5FF3F11F010EA01C010EB769476943F -:1079A000769427E0720E2A9881E090E02BDD812FFB -:1079B0003BDD81017101E70CF11C04C0F8018191EC -:1079C0008F0132DD0E151F05C9F72A9A81E090E07C -:1079D00019DD299A81E090E015DD299881E090E099 -:1079E00011DD8FEF3CDD8073E1F387E060E77ADD46 -:1079F00084FF02C081EE33DD8CDD80E040DD682F46 -:107A0000616080E06FDD87E060E76CDD0091CF01B1 -:107A10001091D0012091D1013091D2014091D30138 -:107A20005091D4016091D5017091D601802F812BA6 -:107A3000822B832B842B852B862B872B61F009834C -:107A40001A832B833C834D835E836F8378878AE020 -:107A5000B20145E027DD82EE02DD81EE00DD299AEC -:107A600081E090E0CFDCAA24BB24A895CC24DD24BF -:107A7000A89587E104DD80FD9CC08FEFF0DCE82E47 -:107A8000E694F7E0EF22EF1609F493C02A9881E01C -:107A900090E0B8DC80E6C8DC8FEFC6DCF82E2A9ACE -:107AA00081E090E0AFDC20E22F1518F482EED7DC05 -:107AB000FF242A9881E090E0A5DC81E6B5DC0EE2A7 -:107AC00011E006C08FEFB0DCF80181938F01FA94CA -:107AD000FF20C1F72A9A81E090E094DC87E060E71C -:107AE00001DD2A9881E090E08DDC8E2D886A9CDC97 -:107AF0008E2D9ADC2A9A81E090E084DC809131011D -:107B00008770823009F058C0909130018091020155 -:107B1000981709F04EC080913201682F70E0CB01B8 -:107B200087709070039709F034C0809133018830DA -:107B300009F02FC040913501242F332727FD3095C0 -:107B40008091040190E001972817390714F5242F3C -:107B50002F5F2093040140912F0140930301F99975 -:107B6000FECF1FBA81E090E092BD81BD40BD0FB64F -:107B7000F894FA9AF99A0FBEF999FECF1FBA42E02B -:107B800050E052BD41BD20BD0FB6F894FA9AF99A63 -:107B90000FBE8091110190E0862797278770907023 -:107BA000892B39F4809133015BA5851711F481E0AD -:107BB00019C081E090E026DC0894C11CD11C64E669 -:107BC000C616D10409F054CF0894A11CB11C74E16D -:107BD000A716B10409F049CF63948AE0681609F04A -:107BE0003ACE80E0E3960FB6F894DEBF0FBECDBF6D -:107BF000CF91DF911F910F91FF90EF90DF90CF9089 -:107C0000BF90AF909F908F907F906F905F904F90BC -:107C10003F902F900895FC0188279927E89421919F -:107C20002032E9F3293010F02E30C8F32B3241F026 -:107C30002D3239F4689404C00E94613E820F911D78 -:107C4000219120532A30C0F31EF4909581959F4FC7 -:107C50000895A0E0B0E0EFE2FEE30C94733E7C01F7 -:107C6000EB018A01690109C0CE012196F60109954F -:107C7000F70181937F010150104001151105A1F713 -:107C8000CDB7DEB7E8E00C948F3EA0E0B0E0EBE4C7 -:107C9000FEE30C94733EEC017B018A01690109C08B -:107CA000CE012196F70161917F01F60109950150FE -:107CB000104001151105A1F7CDB7DEB7E8E00C942F -:107CC0008F3E7AE0979F902D879F802D910D1124F4 -:107CD00008952F923F924F925F926F927F928F9270 -:107CE0009F92AF92BF92CF92DF92EF92FF920F934B -:107CF0001F93CF93DF93CDB7DEB7CA1BDB0B0FB655 -:107D0000F894DEBF0FBECDBF09942A883988488811 -:107D10005F846E847D848C849B84AA84B984C884A7 -:107D2000DF80EE80FD800C811B81AA81B981CE0F9E -:107D3000D11D0FB6F894DEBF0FBECDBFED01089583 +:1070900085B1857D85B92A9A8AE0B1D184E06FE512 +:1070A00015D281E06BE312D285E06CE40FD286E06A +:1070B000DED1682F607D676286E008D280E0D7D19C +:1070C000682F6C6080E002D287E060E7FFD12A98E9 +:1070D00081E095D180E5A2D183E7A0D12A9A81E011 +:1070E0008ED18DE1C4D1682F66608DE1EFD18CE146 +:1070F000BED1682F6F638CE1E9D182EEAAD181EE17 +:10710000A8D1F9D180E0B3D1682F6E7F80E0DED1C5 +:1071100082E00FEF1CEF21EE38EA48EA50E060E031 +:1071200070E0F6D1A89582E091E060E070E043E085 +:1071300050E02AEE39E369D5A89580910201809349 +:107140000E0180930D0143D22FEF20931301809104 +:10715000110192E0909310012093040188708360E4 +:107160008093110120930F0187E068E03ED38823CC +:1071700009F41ED310920F01809102018F3F09F094 +:1071800038C081E00FEF1CEF21EE38EA48EA50E00A +:1071900060E070E0BDD183E064E027D3882309F488 +:1071A000FBD280913201829586958770813019F4E7 +:1071B0008091350105C0882329F485E391E007D546 +:1071C00080930201809102018F3F09F4E5D2809102 +:1071D0000201F999FECF1FBA12BC11BC80BD0FB6D7 +:1071E000F894FA9AF99A0FBE80930E0180930D01DC +:1071F000EED185E091E06BE171E048E050E02AEEED +:1072000039E303D590911101987180911001877035 +:10721000806280931001946C90931101809105011C +:1072200090910601909315018093140180910701BC +:1072300090910801909317018093160180E061E01E +:10724000D4D2882309F4B4D2209137013091380187 +:10725000809107019091080128173907C9F42091FE +:10726000390130913A018091090190910A01281762 +:10727000390771F420913B0130913C0180910B0161 +:1072800090910C012817390719F451D2811190D22D +:10729000409135015091360150930601409305010C +:1072A0002091370130913801309308012093070174 +:1072B0008091390190913A0190930A0180930901DC +:1072C00080913B0190913C0190930C0180930B01C4 +:1072D000F4E1EF2EF1E0FF2E8091100187708063C2 +:1072E00080931001509315014093140130931701BE +:1072F00020931601C0E0D0E000E91FEFBB24B39457 +:10730000E5E0CE2E71E1D72E4DC0F701D583C483C1 +:1073100082E063E06AD2882309F43ED2902F90592C +:107320009F77E92FF0E0E15BFE4FABE3B1E080E156 +:107330000D9001928150E1F7903709F030C03FB7CE +:10734000F894F999FECF83E0F80180935700E8950F +:1073500007B600FCFDCFA801AFE4B1E02C91119677 +:107360008C91119790E0982F8827820F911D12968B +:10737000FA010C01B0925700E89511244E5F5F4F5F +:10738000F1E0AF3CBF0751F7F801C0925700E89514 +:1073900007B600FCFDCFD0925700E8953FBF21967D +:1073A000005F1F4F8091090190910A01C817D9070A +:1073B00008F4ABCFA895BBD1882349F08BE191E0CD +:1073C00065E071E048E050E021EF39E33AD4E4D1E0 +:1073D00080E090E0F999FECF92BD81BDF89A80B52A +:1073E0000895F999FECF1FBA92BD81BD60BD0FB659 +:1073F000F894FA9AF99A0FBE08950000089590E063 +:107400000AC020E030E000002F5F3F4F41E0243F02 +:107410003407C9F79F5F9817A0F308950F931F9340 +:10742000182F00E0EADF17FD02C02B9801C02B9A4D +:10743000E4DF2D9A83B1110F82958170182BDDDF67 +:107440002D98DBDF0F5F083069F7812F1F910F91B7 +:1074500008951F93182F2A9881E0D1DF812FDEDF56 +:10746000182F2A9A81E0CBDF812F1F9108951F9357 +:10747000182F2A9881E0C3DF812F8F71CFDF8FEF24 +:10748000CDDF182F2A9A81E0BADF812F1F9108954E +:107490000F931F93CF93DF93182FEB01042F2A989C +:1074A00081E0ADDF1F71812F8062B8DF182F03C02C +:1074B0008991B4DF01500023D9F72A9A81E09FDF38 +:1074C000812FDF91CF911F910F9108950F931F93FB +:1074D000182F062F2A9881E092DF1F71812F80627A +:1074E0009DDF182F802F9ADF2A9A81E088DF812F75 +:1074F0001F910F91089580E0BADF81FD08C080E000 +:10750000B6DF682F626080E0E1DF85E078DF089514 +:107510007F928F929F92AF92BF92CF92DF92EF9223 +:10752000FF920F931F93DF93CF93CDB7DEB72897CA +:107530000FB6F894DEBF0FBECDBF782E48015901BB +:107540006A017B01882381F40093CF019092D001DE +:107550002093D101B092D2014093D301D092D401B3 +:107560006093D501F092D60189829A82AB82BC8267 +:10757000CD82DE82EF82F88681E0871538F0872D94 +:10758000865FBE016F5F7F4F45E082DF82E06FDF85 +:1075900021E030E002C0220F331F7A94E2F7682F17 +:1075A000622B82E093DF28960FB6F894DEBF0FBE01 +:1075B000CDBFCF91DF911F910F91FF90EF90DF90A2 +:1075C000CF90BF90AF909F908F907F9008957F92C3 +:1075D0008F929F92AF92BF92CF92DF92EF92FF92E3 +:1075E0000F931F93DF93CF93CDB7DEB728970FB6D6 +:1075F000F894DEBF0FBECDBF8F3F09F483C0082FC4 +:1076000010E020E030E040E050E060E070E089838E +:107610001A832B833C834D835E836F837887882412 +:107620003CEF932E21EEA22E98EAB92E88EAC82EBE +:10763000DD24EE24FF24080D81E09981091708F06C +:1076400080E0192D91E0AA819A1608F090E0E82FC9 +:10765000E10F81E0E11708F080E0982B1E2F2A2D22 +:1076600077247394BB81AB1608F07724920F81E0E6 +:10767000921708F080E0782A292F3B2D91E0EC81C9 +:10768000BE1608F090E0E72DE30F81E0E31708F065 +:1076900080E0982B3E2F4C2D77247394FD81CF16DC +:1076A00008F07724940F81E0941708F080E0782A9E +:1076B000492F5D2D91E08E81D81608F090E0E72DDE +:1076C000E50F81E0E51708F080E0982B5E2F6E2D26 +:1076D00077247394AF81EA1608F07724960F81E03F +:1076E000961708F080E0782A692F7F0C772D5901D2 +:1076F0006A01E92E80E00CDF81E09501A6016E2D84 +:10770000772D06DF28960FB6F894DEBF0FBECDBFEB +:10771000CF91DF911F910F91FF90EF90DF90CF906D +:10772000BF90AF909F908F907F9008951895409153 +:10773000090150910A0164E0440F551F6A95E1F771 +:10774000E0E0F0E02FEF3FEF19C084912827822F6F +:1077500082958227082E869586958025082E869507 +:1077600080258770022E232F869507948795302DCC +:10777000282706948795302528273196E417F507A2 +:1077800020F340E080910B0190910C0128173907FC +:1077900009F441E0842F089528E088E190E00FB6D5 +:1077A000F894A895809360000FBE20936000FFCFEF +:1077B000BEDF8823C1F088E10FB6F89480936000A3 +:1077C000109260000FBE809100019091010120E8AD +:1077D0000FB6F89420936100809361000FBEE0E043 +:1077E000F0E009950895D8DF08952F923F924F92C7 +:1077F0005F926F927F928F929F92AF92BF92CF9241 +:10780000DF92EF92FF920F931F93DF93CF93CDB749 +:10781000DEB7E3970FB6F894DEBF0FBECDBF6BA700 +:10782000809312016624B9E02B2E312C2C0E3D1EC4 +:107830002E010894411C511CD101EDE0F1E081E2E0 +:1078400001900D928150E1F7109103017C842B850A +:107850002AA751DE299881E0D2DD81EEFADD82EEA1 +:10786000F8DD80E004DE682F6E7F80E02FDE30E000 +:1078700040E050E060E070E080E090E01CA73DA7B1 +:107880004EA75FA768AB79AB8AAB9BAB8824ACEF04 +:107890009A2EF1EEAF2EE8EABE2E78EAC72EDD244E +:1078A000EE24FF24012F080D81E0011708F080E08D +:1078B000192D91E0EDA59E1608F090E0E82FE10F5C +:1078C00081E0E11708F080E0982B1E2F2A2DE1E0DF +:1078D000FEA5AF1608F0E0E0920F81E0921708F0E5 +:1078E00080E0E82B292F3B2D91E08FA5B81608F0FA +:1078F00090E0E30F81E0E31708F080E0982B3E2F43 +:107900004C2DE1E0F8A9CF1608F0E0E0940F81E0FB +:10791000941708F080E0E82B492F5D2D91E089A9AC +:10792000D81608F090E0E50F81E0E51708F080E058 +:10793000982B5E2F6E2D81E0EAA9EE1608F080E00C +:10794000E92FE60F91E0E61708F090E0892B8F0D04 +:1079500009831A832B833C834D835E83EF8388875F +:107960008AE0B20145E094DD80E1B20145E090DDBE +:10797000FAA5FF3F11F010EA01C010EB769476945F +:10798000769427E0720E2A9881E039DD812F46DD5A +:1079900081017101E70CF11C04C0F80181918F0194 +:1079A0003DDD0E151F05C9F72A9A81E028DD299AC9 +:1079B00081E025DD299881E022DD8FEF4ADD8073AB +:1079C000E1F387E060E782DD84FF02C081EE41DD04 +:1079D00092DD80E04CDD682F616080E077DD87E03C +:1079E00060E774DD0091CF011091D0012091D101A9 +:1079F0003091D2014091D3015091D4016091D501D1 +:107A00007091D601802F812B822B832B842B852B89 +:107A1000862B872B61F009831A832B833C834D834C +:107A20005E836F8378878AE0B20145E031DD82EEC4 +:107A300010DD81EE0EDD299A81E0E1DCCC24A895F1 +:107A4000DD24A89587E113DD80FD96C08FEF01DD71 +:107A5000E82EE694F7E0EF22EF1609F48DC02A989D +:107A600081E0CDDC80E6DADC8FEFD8DCF82E2A9AD4 +:107A700081E0C5DC20E22F1518F482EEEADCFF2459 +:107A80002A9881E0BCDC81E6C9DC0EE211E006C088 +:107A90008FEFC4DCF80181938F01FA94FF20C1F7C6 +:107AA0002A9A81E0ACDC87E060E710DD2A9881E06B +:107AB000A6DC8E2D886AB2DC8E2DB0DC2A9A81E09D +:107AC0009EDC809131018770823009F057C090911F +:107AD000300180910201981709F04EC08091320167 +:107AE000682F70E0CB0187709070039709F034C065 +:107AF00080913301883009F02FC040913501242F47 +:107B0000332727FD30958091040190E001972817D5 +:107B1000390714F5242F2F5F2093040180912F0142 +:107B200080930301F999FECF1FBA41E050E052BDA6 +:107B300041BD80BD0FB6F894FA9AF99A0FBEF99933 +:107B4000FECF1FBA82E090E092BD81BD20BD0FB68E +:107B5000F894FA9AF99A0FBE8091110190E0862765 +:107B6000972787709070892B39F4809133019BA5FA +:107B7000891711F481E012C081E041DCD394E4E67E +:107B8000DE1609F05ECFC394F4E1CF1609F057CFAB +:107B900063942AE0621609F04FCE80E0E3960FB6B8 +:107BA000F894DEBF0FBECDBFCF91DF911F910F9133 +:107BB000FF90EF90DF90CF90BF90AF909F908F900D +:107BC0007F906F905F904F903F902F900895FC01B1 +:107BD00088279927E89421912032E9F3293010F081 +:107BE0002E30C8F32B3241F02D3239F4689404C0A2 +:107BF0000E943D3E820F911D219120532A30C0F3F7 +:107C00001EF4909581959F4F0895A0E0B0E0EBE0C1 +:107C1000FEE30C944F3E7C01EB018A01690109C02F +:107C2000CE012196F6010995F70181937F0101505C +:107C3000104001151105A1F7CDB7DEB7E8E00C94AF +:107C40006B3EA0E0B0E0E7E2FEE30C944F3EEC01B7 +:107C50007B018A01690109C0CE012196F70161917A +:107C60007F01F60109950150104001151105A1F79A +:107C7000CDB7DEB7E8E00C946B3E7AE0979F902D8D +:107C8000879F802D910D112408952F923F924F923E +:107C90005F926F927F928F929F92AF92BF92CF929C +:107CA000DF92EF92FF920F931F93CF93DF93CDB7A5 +:107CB000DEB7CA1BDB0B0FB6F894DEBF0FBECDBF1D +:107CC00009942A88398848885F846E847D848C84EE +:107CD0009B84AA84B984C884DF80EE80FD800C81F7 +:107CE0001B81AA81B981CE0FD11D0FB6F894DEBFDA +:087CF0000FBECDBFED010895A8 :040000030000700089 :00000001FF diff --git a/Bootloader/MyOtaBootloaderHW.h b/Bootloader/MyOtaBootloaderHW.h index 2eec57b..02740a6 100644 --- a/Bootloader/MyOtaBootloaderHW.h +++ b/Bootloader/MyOtaBootloaderHW.h @@ -32,8 +32,9 @@ static void delayu() { asm("nop"); } -static void delaym(uint16_t t) { - uint16_t d, a; +static void delaym(uint8_t t) { + uint8_t d; + uint16_t a; for (d = 0; d < t; d++) for (a = 0; a < DELAY_M; a++) asm("nop"); From c3dbcd1feadc4d5c32ad1a040b3de69f1bfcac47 Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Sun, 28 Sep 2014 23:47:22 +0200 Subject: [PATCH 014/660] Accept Time Broadcasts NodeJsController sending Time broadcasts every few minutes. Sensor accepting not just Time messages addressed to the specific sensor. --- NodeJsController/NodeJsController.js | 3 +++ libraries/MySensors/MySensor.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/NodeJsController/NodeJsController.js b/NodeJsController/NodeJsController.js index 8bb67da..2c40fb4 100644 --- a/NodeJsController/NodeJsController.js +++ b/NodeJsController/NodeJsController.js @@ -706,5 +706,8 @@ dbc.connect('mongodb://' + dbAddress + ':' + dbPort + '/' + dbName, function(err } else { throw new Error('unknown Gateway type'); } + setInterval(function() { + sendTime(BROADCAST_ADDRESS, NODE_SENSOR_ID, gw); + }, 5*60*1000); }); diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index de02ac0..e71e1e8 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -322,6 +322,11 @@ boolean MySensor::process() { delay(millis() & 0x3ff); sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); return false; + } else if (command == C_INTERNAL && type == I_TIME) { + if (timeCallback != NULL) { + // Deliver time to callback + timeCallback(msg.getULong()); + } } else if (destination == nc.nodeId) { // Check if sender requests an ack back. if (mGetRequestAck(msg)) { @@ -397,11 +402,6 @@ boolean MySensor::process() { } sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } - } else if (type == I_TIME) { - if (timeCallback != NULL) { - // Deliver time to callback - timeCallback(msg.getULong()); - } } return false; } From 39bab3dfba5b3f167e15e91bf3ce97f3f79ac317 Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Mon, 29 Sep 2014 00:24:57 +0200 Subject: [PATCH 015/660] Split Application and Driver Layer --- libraries/MySensors/MyConfig.h | 16 +++-- libraries/MySensors/MyDriver.cpp | 4 ++ libraries/MySensors/MyDriver.h | 52 ++++++++++++++ libraries/MySensors/MyDriverNRF24.cpp | 68 +++++++++++++++++++ libraries/MySensors/MyDriverNRF24.h | 32 +++++++++ libraries/MySensors/MySensor.cpp | 68 ++++++------------- libraries/MySensors/MySensor.h | 35 +++------- .../EthernetGateway/EthernetGateway.ino | 12 ++-- .../examples/MQTTGateway/MQTTGateway.ino | 9 +-- .../examples/SerialGateway/SerialGateway.ino | 8 +-- 10 files changed, 200 insertions(+), 104 deletions(-) create mode 100644 libraries/MySensors/MyDriver.cpp create mode 100644 libraries/MySensors/MyDriver.h create mode 100644 libraries/MySensors/MyDriverNRF24.cpp create mode 100644 libraries/MySensors/MyDriverNRF24.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index adcb219..8991e99 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -4,16 +4,18 @@ /*** * Configure Sensor Network */ +#define COMMDRIVER_NRF24 + +#ifdef COMMDRIVER_NRF24 +#include "MyDriverNRF24.h" +typedef class MyDriverNRF24 MyDriverClass; #define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 #define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps #define RF24_PA_LEVEL RF24_PA_MAX //Sensor PA Level == RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBM, and RF24_PA_MAX=0dBm -#define RF24_PA_LEVEL_GW RF24_PA_LOW //Gateway PA Level, defaults to Sensor net PA Level. Tune here if using an amplified nRF2401+ in your gateway. -#define BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. - -// MySensors online examples defaults -#define DEFAULT_CE_PIN 9 -#define DEFAULT_CS_PIN 10 - +#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. +#define RF24_CE_PIN 9 +#define RF24_CS_PIN 10 +#endif /*** * Enable/Disable debug logging diff --git a/libraries/MySensors/MyDriver.cpp b/libraries/MySensors/MyDriver.cpp new file mode 100644 index 0000000..e592552 --- /dev/null +++ b/libraries/MySensors/MyDriver.cpp @@ -0,0 +1,4 @@ +#include "MyDriver.h" + +MyDriver::MyDriver() { +} diff --git a/libraries/MySensors/MyDriver.h b/libraries/MySensors/MyDriver.h new file mode 100644 index 0000000..fe35f5f --- /dev/null +++ b/libraries/MySensors/MyDriver.h @@ -0,0 +1,52 @@ +#ifndef MyDriver_h +#define MyDriver_h + +#include + +#ifdef DEBUG +#define debug(x,...) debugPrint(x, ##__VA_ARGS__) +#else +#define debug(x,...) +#endif + +#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. +#define NODE_SENSOR_ID 0xFF // Node child id is always created for when a node + +// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). +#define GATEWAY_ADDRESS ((uint8_t)0) +#define BROADCAST_ADDRESS ((uint8_t)0xFF) + +class MyDriver +{ +public: + // MyDriver constructor + // different parameters would be needed depending on radio module (e.g. pins connected etc.) + // keeping these parameters as #define's in MyConfig to streamline the driver interface + MyDriver(); + // init() + // different parameters would be needed depending on radio module (e.g. channel, power, crc, etc.) + // keeping these parameters as #define's in MyConfig to streamline the driver interface + virtual void init() = 0; + // setAddress(address) + // set the node address and start listening to that address (and the broadcast address) + virtual void setAddress(uint8_t address) = 0; + // getAddress() + // returns the current address from the radio driver + virtual uint8_t getAddress() = 0; + // send(to, data, len) + // reliable transmission of the data with given length (in bytes) to the destination address + // returns true if successfully submitted + virtual bool send(uint8_t to, const void* data, uint8_t len) = 0; + // available(to) + // returns true if a new packet arrived in the rx buffer + // populates "to" parameter with the address the packet was sent to (either own address or broadcast) + virtual bool available(uint8_t *to) = 0; + // receive(data) + // returns length of received packet + // populates "data" parameter with received data + virtual uint8_t receive(void* data) = 0; + // powers down the radio + virtual void powerDown() = 0; +}; + +#endif diff --git a/libraries/MySensors/MyDriverNRF24.cpp b/libraries/MySensors/MyDriverNRF24.cpp new file mode 100644 index 0000000..f59f2d5 --- /dev/null +++ b/libraries/MySensors/MyDriverNRF24.cpp @@ -0,0 +1,68 @@ +#include "MyDriver.h" +#include "MyDriverNRF24.h" + +MyDriverNRF24::MyDriverNRF24() : MyDriver() { + rf24 = new RF24(RF24_CE_PIN, RF24_CS_PIN); +} + +void MyDriverNRF24::init() { + // Start up the radio library + rf24->begin(); + + if (!rf24->isPVariant()) { + debug(PSTR("check wires\n")); + while(1); + } + rf24->setAutoAck(1); + rf24->setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast + rf24->enableAckPayload(); + rf24->setChannel(RF24_CHANNEL); + rf24->setPALevel(RF24_PA_LEVEL); + rf24->setDataRate(RF24_DATARATE); + rf24->setRetries(5,15); + rf24->setCRCLength(RF24_CRC_16); + rf24->enableDynamicPayloads(); + + // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) + rf24->openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); +} + +void MyDriverNRF24::setAddress(uint8_t address) { + _address = address; + rf24->openReadingPipe(WRITE_PIPE, TO_ADDR(address)); + rf24->openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); + rf24->startListening(); +} + +uint8_t MyDriverNRF24::getAddress() { + return _address; +} + +bool MyDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { + // Make sure radio has powered up + rf24->powerUp(); + rf24->stopListening(); + rf24->openWritingPipe(TO_ADDR(to)); + bool ok = rf24->write(data, len, to == BROADCAST_ADDRESS); + rf24->startListening(); + return ok; +} + +bool MyDriverNRF24::available(uint8_t *to) { + uint8_t pipe = 255; + boolean avail = rf24->available(&pipe); + if (pipe == CURRENT_NODE_PIPE) + *to = _address; + else if (pipe == BROADCAST_PIPE) + *to = BROADCAST_ADDRESS; + return (rf24->available() && pipe < 6); +} + +uint8_t MyDriverNRF24::receive(void* data) { + uint8_t len = rf24->getDynamicPayloadSize(); + rf24->read(data, len); +} + +void MyDriverNRF24::powerDown() { + rf24->powerDown(); +} diff --git a/libraries/MySensors/MyDriverNRF24.h b/libraries/MySensors/MyDriverNRF24.h new file mode 100644 index 0000000..f329ff3 --- /dev/null +++ b/libraries/MySensors/MyDriverNRF24.h @@ -0,0 +1,32 @@ +#ifndef MyCommDriver_h +#define MyCommDriver_h + +#include "MyConfig.h" +#include "MyDriver.h" +#include +#include "utility/RF24.h" +#include "utility/RF24_config.h" + +#define TO_ADDR(x) (RF24_BASE_RADIO_ID + x) + +#define WRITE_PIPE ((uint8_t)0) +#define CURRENT_NODE_PIPE ((uint8_t)1) +#define BROADCAST_PIPE ((uint8_t)2) + +class MyDriverNRF24 : public MyDriver +{ +public: + MyDriverNRF24(); + void init(); + void setAddress(uint8_t address); + uint8_t getAddress(); + bool send(uint8_t to, const void* data, uint8_t len); + bool available(uint8_t *to); + uint8_t receive(void* data); + void powerDown(); +private: + RF24 *rf24; + uint8_t _address; +}; + +#endif \ No newline at end of file diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index e71e1e8..bf8205f 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -10,9 +10,6 @@ */ #include "MySensor.h" -#include "utility/LowPower.h" -#include "utility/RF24.h" -#include "utility/RF24_config.h" #define DISTANCE_INVALID (0xFF) @@ -36,12 +33,12 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } - -MySensor::MySensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) { -} + MySensor::MySensor() { + driver = (MyDriver*) new MyDriverClass(); + } -void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId, rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) { +void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { Serial.begin(BAUD_RATE); repeaterMode = _repeaterMode; msgCallback = _msgCallback; @@ -52,7 +49,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b if (repeaterMode) { setupRepeaterMode(); } - setupRadio(paLevel, channel, dataRate); + setupRadio(); // Read settings from EEPROM eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); @@ -92,8 +89,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } // Open reading pipe for messages directed to this node (set write pipe to same) - RF24::openReadingPipe(WRITE_PIPE, TO_ADDR(nc.nodeId)); - RF24::openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId)); + driver->setAddress(nc.nodeId); // Send presentation for this radio node (attach present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); @@ -107,26 +103,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b waitForReply(); } -void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) { - // Start up the radio library - RF24::begin(); - - if (!RF24::isPVariant()) { - debug(PSTR("check wires\n")); - while(1); - } - RF24::setAutoAck(1); - RF24::setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast - RF24::setChannel(channel); - RF24::setPALevel(paLevel); - RF24::setDataRate(dataRate); - RF24::setRetries(5,15); - RF24::setCRCLength(RF24_CRC_16); - RF24::enableDynamicPayloads(); - RF24::enableDynamicAck(); // Required to disable ack-sending for broadcast messages - - // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) - RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); +void MySensor::setupRadio() { + failedTransmissions = 0; + driver->init(); } void MySensor::setupRepeaterMode(){ @@ -145,7 +124,7 @@ ControllerConfig MySensor::getConfig() { void MySensor::requestNodeId() { debug(PSTR("req node id\n")); - RF24::openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId)); + driver->setAddress(nc.nodeId); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); waitForReply(); } @@ -223,13 +202,7 @@ boolean MySensor::sendWrite(uint8_t next, MyMessage &message, const bool allowFi uint8_t length = mGetLength(message); message.last = nc.nodeId; mSetVersion(message, PROTOCOL_VERSION); - // Make sure radio has powered up - RF24::powerUp(); - RF24::stopListening(); - RF24::openWritingPipe(TO_ADDR(next)); - // Send message. Disable auto-ack for broadcasts. - ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast); - RF24::startListening(); + bool ok = driver->send(next, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, @@ -290,14 +263,11 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { boolean MySensor::process() { - uint8_t pipe; - boolean available = RF24::available(&pipe); - - if (!available || pipe>6) + uint8_t to = 0; + if (!driver->available(&to)) return false; - uint8_t len = RF24::getDynamicPayloadSize(); - RF24::read(&msg, len); + uint8_t len = driver->receive((uint8_t *)&msg); // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; @@ -380,7 +350,7 @@ boolean MySensor::process() { debug(PSTR("full\n")); while (1); // Wait here. Nothing else we can do... } else { - RF24::openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId)); + driver->setAddress(nc.nodeId); eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId); } debug(PSTR("id=%d\n"), nc.nodeId); @@ -412,7 +382,7 @@ boolean MySensor::process() { } // Return true if message was addressed for this node... return true; - } else if (repeaterMode && pipe == CURRENT_NODE_PIPE) { + } else if (repeaterMode && to == nc.nodeId) { // We should try to relay this message to another node uint8_t route = getChildRoute(msg.destination); @@ -511,7 +481,7 @@ void MySensor::internalSleep(unsigned long ms) { void MySensor::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); - RF24::powerDown(); + driver->powerDown(); pinIntTrigger = 0; internalSleep(ms); } @@ -520,7 +490,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; Serial.flush(); - RF24::powerDown(); + driver->powerDown(); attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; @@ -539,7 +509,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; Serial.flush(); // Let serial prints finish (debug, log etc) - RF24::powerDown(); + driver->powerDown(); attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 3a4090e..25ff8fa 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -25,8 +25,6 @@ #include #include #include "utility/LowPower.h" -#include "utility/RF24.h" -#include "utility/RF24_config.h" #endif #ifdef DEBUG @@ -37,9 +35,6 @@ #define BAUD_RATE 115200 -#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. -#define NODE_SENSOR_ID 0xFF // Node child id is always created for when a node - // EEPROM start address for mysensors library data #define EEPROM_START 0 // EEPROM location of node id @@ -56,15 +51,6 @@ #define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) #define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) // First free address for sketch static configuration -// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). -#define GATEWAY_ADDRESS ((uint8_t)0) -#define BROADCAST_ADDRESS ((uint8_t)0xFF) -#define TO_ADDR(x) (BASE_RADIO_ID + x) - -#define WRITE_PIPE ((uint8_t)0) -#define CURRENT_NODE_PIPE ((uint8_t)1) -#define BROADCAST_PIPE ((uint8_t)2) - // Search for a new parent node after this many transmission failures #define SEARCH_FAILURES 5 @@ -80,7 +66,7 @@ struct ControllerConfig { }; #ifdef __cplusplus -class MySensor : public RF24 +class MySensor { public: /** @@ -88,10 +74,8 @@ class MySensor : public RF24 * * Creates a new instance of Sensor class. * - * @param _cepin The pin attached to RF24 Chip Enable on the RF module (default 9) - * @param _cspin The pin attached to RF24 Chip Select (default 10) */ - MySensor(uint8_t _cepin=DEFAULT_CE_PIN, uint8_t _cspin=DEFAULT_CS_PIN); + MySensor(); /** * Begin operation of the MySensors library @@ -101,12 +85,9 @@ class MySensor : public RF24 * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. - * @param paLevel Radio PA Level for this sensor. Default RF24_PA_MAX - * @param channel Radio channel. Default is channel 76 - * @param dataRate Radio transmission speed. Default RF24_1MBPS */ - void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO, rf24_pa_dbm_e paLevel=RF24_PA_LEVEL, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE); + void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); /** * Return the nodes nodeId. @@ -141,6 +122,8 @@ class MySensor : public RF24 */ bool send(MyMessage &msg, bool ack=false); + boolean sendRoute(MyMessage &message); + /** * Send this nodes battery level to gateway. * @param level Level between 0-100(%) @@ -234,10 +217,6 @@ class MySensor : public RF24 */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); - - - boolean sendRoute(MyMessage &message); - #ifdef DEBUG void debugPrint(const char *fmt, ... ); int freeRam(); @@ -252,8 +231,10 @@ class MySensor : public RF24 MyMessage msg; // Buffer for incoming messages. MyMessage ack; // Buffer for ack messages. + MyDriver *driver; + void setupRepeaterMode(); - void setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate); + void setupRadio(); boolean sendWrite(uint8_t dest, MyMessage &message, const bool allowFindParent = true ); private: diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 82609c3..da25fb7 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -58,10 +58,10 @@ // Use this if you have attached a Ethernet ENC28J60 shields -//#include +#include // Use this fo WizNET module and Arduino Ethernet Shield -#include +//#include #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled @@ -75,7 +75,7 @@ #define RADIO_TX_LED_PIN 9 // the PCB, on board LED -MySensor gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); +MySensor gw; #define IP_PORT 5003 // The port you want to open @@ -107,11 +107,7 @@ void output(const char *fmt, ... ) { void setup() { // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); - // Setup pipes for radio library - gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); - gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); - gw.startListening(); + gw.begin(incomingMessage, 0, true, 0); Ethernet.begin(mac, myIp); setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index b7cb4ca..5526e68 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -89,7 +89,7 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You ////////////////////////////////////////////////////////////////// -MySensor gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); +MySensor gw; EthernetServer server = EthernetServer(TCP_PORT); MyMessage msg; char convBuf[MAX_PAYLOAD*2+1]; @@ -143,12 +143,7 @@ void incomingMessage(const MyMessage &message) { void setup() { // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); - // Setup pipes for radio library - gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); - gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); - gw.startListening(); - + gw.begin(incomingMessage, 0, true, 0); Ethernet.begin(TCP_MAC, TCP_IP); diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index ed50829..3ff423f 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -38,7 +38,7 @@ #define RADIO_TX_LED_PIN 5 // the PCB, on board LED -MySensor gw(DEFAULT_CE_PIN, DEFAULT_CS_PIN); +MySensor gw; char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; @@ -57,11 +57,7 @@ void output(const char *fmt, ... ) { void setup() { - gw.begin(incomingMessage, 0, true, 0, RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE); - // Stetup pipes for radio library - gw.openReadingPipe(WRITE_PIPE, BASE_RADIO_ID); - gw.openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID); - gw.startListening(); + gw.begin(incomingMessage, 0, true, 0); setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); From 2647345c4def221e19a7de67b5622ea5fa162533 Mon Sep 17 00:00:00 2001 From: ToSa27 Date: Mon, 29 Sep 2014 10:33:16 +0200 Subject: [PATCH 016/660] Adding defines for different board layouts in MyConfig Adjusted all Gateway examples but only one sensor example so far (DallasTemperature). Other sensor examples should get the same three lines added (not mandatory but helps avoiding unnecessary debugging when selecting the wrong setup) --- libraries/MySensors/MyConfig.h | 32 ++++++++++++++++--- .../DallasTemperatureSensor.ino | 4 +++ .../EthernetGateway/EthernetGateway.ino | 3 ++ .../examples/MQTTGateway/MQTTGateway.ino | 3 ++ .../examples/SerialGateway/SerialGateway.ino | 5 ++- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 8991e99..31937f1 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -4,17 +4,39 @@ /*** * Configure Sensor Network */ -#define COMMDRIVER_NRF24 + +// pick ONE of these - other board layouts can be easily added this way +#define MYSENSORS_SENSOR +//#define MYSENSORS_SERIAL_GATEWAY +//#define MYSENSORS_ETHERNET_MQTT_GATEWAY + +#ifdef MYSENSORS_SENSOR +#define MYSENSORS_RF_NRF24 +#define RF24_CE_PIN 9 +#define RF24_CS_PIN 10 +#define RF24_PA_LEVEL RF24_PA_MAX +#endif -#ifdef COMMDRIVER_NRF24 +#ifdef MYSENSORS_SERIAL_GATEWAY +#define MYSENSORS_RF_NRF24 +#define RF24_CE_PIN 9 +#define RF24_CS_PIN 10 +#define RF24_PA_LEVEL RF24_PA_LOW +#endif + +#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#define MYSENSORS_RF_NRF24 +#define RF24_CE_PIN 5 +#define RF24_CS_PIN 6 +#define RF24_PA_LEVEL RF24_PA_LOW +#endif + +#ifdef MYSENSORS_RF_NRF24 #include "MyDriverNRF24.h" typedef class MyDriverNRF24 MyDriverClass; #define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 #define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps -#define RF24_PA_LEVEL RF24_PA_MAX //Sensor PA Level == RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBM, and RF24_PA_MAX=0dBm #define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. -#define RF24_CE_PIN 9 -#define RF24_CS_PIN 10 #endif /*** diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 3c6c2c0..a52c49d 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -4,6 +4,10 @@ #include #include +#ifndef MYSENSORS_SENSOR +#error Please switch to MYSENSORS_SENSOR in MyConfig.h +#endif + #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 16 unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index da25fb7..a6ace27 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -56,6 +56,9 @@ #include #include "GatewayUtil.h" +#ifndef MYSENSORS_ETHERNET_MQTT_GATEWAY +#error Please switch to MYSENSORS_ETHERNET_MQTT_GATEWAY in MyConfig.h +#endif // Use this if you have attached a Ethernet ENC28J60 shields #include diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 5526e68..219b4e2 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -62,6 +62,9 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include "MyMQTT.h" +#ifndef MYSENSORS_ETHERNET_MQTT_GATEWAY +#error Please switch to MYSENSORS_ETHERNET_MQTT_GATEWAY in MyConfig.h +#endif #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 3ff423f..6ee18a4 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -20,7 +20,7 @@ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error */ - + #define NO_PORTB_PINCHANGES #include @@ -30,6 +30,9 @@ #include #include "GatewayUtil.h" +#ifndef MYSENSORS_SERIAL_GATEWAY +#error Please switch to MYSENSORS_SERIAL_GATEWAY in MyConfig.h +#endif #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button From b97372ed015fdd61f54af628950202cf572e9df6 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 10 Oct 2014 22:34:14 +0200 Subject: [PATCH 017/660] Added .gitignore to filter stino settings files Stino is a plugin for SublimeText to allow SublimeText to act as an Arduino IDE. --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..619eb92 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +stino.settings From f5ef71230882388da82c5f4571923902a9f0d03c Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 10 Oct 2014 22:24:19 +0200 Subject: [PATCH 018/660] Support for WIZnet W5100 ethernet module SPI_EN The W5100 module has a SPI_EN signal that enables or disables the SPI bus. A bug in the module causes MISO to be continously driven by the module when SPI_EN is pulled high. This is described in this application note: https://www.google.se/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCAQFjAA&url=http%3A%2F%2Fwww.wiznet.co.kr%2FUpLoad_Files%2FReferenceFiles%2FW5100_AN_SPI.pdf&ei=ij84VK7uM6nNygPqvICYDw&usg=AFQjCNGz1qttBEwG1azc1Eza4j69v1rpDQ&sig2=UUUtb4Dr0F35g8ByHMsyig&bvm=bv.77161500,d.bGQ This commit changes the Ethernet gateway sketch to drive SPI_EN high or low, depending on which module is in use (SPI bus is shared between Ethernet and RF modules). The pin attached to SPI_EN is defined by W5100_SPI_EN. This define can be commented out if SPI_EN is not needed (different module) or if the module manages SPI_EN in hardware (some W5100 shields does this). --- .../EthernetGateway/EthernetGateway.ino | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index df3b935..e4d8309 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 Henrik Ekblad * - * Contribution by a-lurker + * Contribution by a-lurker and Anticimex * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,6 +38,7 @@ * 7 Radio error LED (optional) +5V -> LED -> 270-330 Ohm resistor -> pin 7. * 6 Radio SPI Slave Select * 5 Radio Chip Enable + * 4 Ethernet SPI Enable (optional if using a shield/module that manages SPI_EN signal) * 3 Inclusion mode button (optional), 10K pull down to GND, button to VCC) * 2 Radio IRQ pin (optional), W5100 Int, if linked to pin 2) * ----------------------------------------------------------------------------------------------------------- @@ -59,6 +60,7 @@ #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button +#define W5100_SPI_EN 4 // Ethernet SPI enable #define RADIO_CE_PIN 5 // radio chip enable #define RADIO_SPI_SS_PIN 6 // radio SPI serial select #define RADIO_ERROR_LED_PIN 7 // Error led pin @@ -86,23 +88,46 @@ MyGateway gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN, INCLUSION_MODE_TIME); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; +void w5100_spi_en(boolean enable) +{ +#ifdef W5100_SPI_EN + if (enable) + { + // Pull up pin + pinMode(W5100_SPI_EN, INPUT); + digitalWrite(W5100_SPI_EN, HIGH); + } + else + { + // Ground pin + pinMode(W5100_SPI_EN, OUTPUT); + digitalWrite(W5100_SPI_EN, LOW); + } +#endif +} + void setup() { - // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet); - + w5100_spi_en(true); + Ethernet.begin(mac); Ethernet.begin(mac, myIp); // give the Ethernet interface a second to initialize delay(1000); + // Initialize gateway at generic GW PA level, channel 70 and callback for write operations + w5100_spi_en(false); + gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet); + // start listening for clients server.begin(); } // This will be called when data should be written to ethernet void writeEthernet(char *writeBuffer) { + w5100_spi_en(true); server.write(writeBuffer); + w5100_spi_en(false); } @@ -110,6 +135,7 @@ void loop() { // if an incoming client connects, there will be // bytes available to read via the client object + w5100_spi_en(true); EthernetClient client = server.available(); if (client) { @@ -128,7 +154,9 @@ void loop() // echo the string to the serial port Serial.print(inputString); + w5100_spi_en(false); gw.parseAndSend(inputString); + w5100_spi_en(true); // clear the string: inputPos = 0; @@ -143,6 +171,7 @@ void loop() } } } + w5100_spi_en(false); gw.processRadioMessage(); } From d5ca838371ebb91c3cf36d48d29a8a4d63dcb012 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 21 Oct 2014 23:44:52 +0200 Subject: [PATCH 019/660] Update UIPEthernet library --- libraries/UIPEthernet/README | 4 +- libraries/UIPEthernet/UIPClient.cpp | 40 +++++++------ libraries/UIPEthernet/UIPClient.h | 3 + libraries/UIPEthernet/UIPEthernet.cpp | 59 ++++++++++++++----- libraries/UIPEthernet/UIPEthernet.h | 2 +- .../UIPEthernet/utility/Enc28J60Network.cpp | 29 ++++++--- libraries/UIPEthernet/utility/uip-conf.h | 5 +- .../UIPEthernet/utility/uipethernet-conf.h | 12 +++- 8 files changed, 106 insertions(+), 48 deletions(-) diff --git a/libraries/UIPEthernet/README b/libraries/UIPEthernet/README index ec51f2d..321b334 100644 --- a/libraries/UIPEthernet/README +++ b/libraries/UIPEthernet/README @@ -1,4 +1,4 @@ -This is UIPEthernet version 1.07 +This is UIPEthernet version 1.09 An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS. Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib! @@ -28,7 +28,7 @@ On a Mac, you will want to create a folder named "libraries" in in the "Document Or you download the zipped version of the library from https://github.com/ntruchsess/arduino_uip/releases, and copy the contained directory UIPEthernet to [path to Arduino distribution]\libraries\UIPEthernet. -If you are running Arduino-IDE 1.5.x use release-version 1.57 or checkout branch 'Arduino_1.5.5' +If you are running Arduino-IDE 1.5.x use release-version 1.59 or checkout branch 'Arduino_1.5.x' Additional information can be found on the Arduino website: http://www.arduino.cc/en/Hacking/Libraries diff --git a/libraries/UIPEthernet/UIPClient.cpp b/libraries/UIPEthernet/UIPClient.cpp index ffbb3e1..d199cfe 100644 --- a/libraries/UIPEthernet/UIPClient.cpp +++ b/libraries/UIPEthernet/UIPClient.cpp @@ -226,6 +226,9 @@ newpacket: goto newpacket; } ready: +#if UIP_CLIENT_TIMER >= 0 + u->timer = millis()+UIP_CLIENT_TIMER; +#endif return size-remain; } return -1; @@ -326,6 +329,7 @@ UIPClient::flush() void uipclient_appcall(void) { + uint16_t send_len = 0; uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate; if (!u && uip_connected()) { @@ -357,17 +361,16 @@ uipclient_appcall(void) #endif if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { - memhandle newPacket = Enc28J60Network::allocBlock(uip_len); - if (newPacket != NOBLOCK) + for (uint8_t i=0; i < UIP_SOCKET_NUMPACKETS; i++) { - for (uint8_t i=0; i < UIP_SOCKET_NUMPACKETS; i++) + if (u->packets_in[i] == NOBLOCK) { - if (u->packets_in[i] == NOBLOCK) + u->packets_in[i] = Enc28J60Network::allocBlock(uip_len); + if (u->packets_in[i] != NOBLOCK) { + Enc28J60Network::copyPacket(u->packets_in[i],0,UIPEthernetClass::in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len); if (i == UIP_SOCKET_NUMPACKETS-1) uip_stop(); - Enc28J60Network::copyPacket(newPacket,0,UIPEthernetClass::in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len); - u->packets_in[i] = newPacket; goto finish_newdata; } } @@ -404,7 +407,7 @@ finish_newdata: UIPClient::_dumpAllData(); #endif uip_conn->appstate = NULL; - goto nodata; + goto finish; } if (uip_acked()) { @@ -422,26 +425,25 @@ finish_newdata: { if (u->packets_out[1] == NOBLOCK) { - uip_len = u->out_pos; - if (uip_len > 0) + send_len = u->out_pos; + if (send_len > 0) { - Enc28J60Network::resizeBlock(u->packets_out[0],0,uip_len); + Enc28J60Network::resizeBlock(u->packets_out[0],0,send_len); } } else - uip_len = Enc28J60Network::blockSize(u->packets_out[0]); - if (uip_len > 0) + send_len = Enc28J60Network::blockSize(u->packets_out[0]); + if (send_len > 0) { UIPEthernetClass::uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf; - UIPEthernetClass::uip_packet = Enc28J60Network::allocBlock(UIPEthernetClass::uip_hdrlen+uip_len); + UIPEthernetClass::uip_packet = Enc28J60Network::allocBlock(UIPEthernetClass::uip_hdrlen+send_len); if (UIPEthernetClass::uip_packet != NOBLOCK) { - Enc28J60Network::copyPacket(UIPEthernetClass::uip_packet,UIPEthernetClass::uip_hdrlen,u->packets_out[0],0,uip_len); + Enc28J60Network::copyPacket(UIPEthernetClass::uip_packet,UIPEthernetClass::uip_hdrlen,u->packets_out[0],0,send_len); UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET; - uip_send(uip_appdata,uip_len); } - return; } + goto finish; } } // don't close connection unless all outgoing packets are sent @@ -470,9 +472,9 @@ finish_newdata: } } } -nodata: - UIPEthernetClass::uip_packet = NOBLOCK; - uip_len=0; + finish: + uip_send(uip_appdata,send_len); + uip_len = send_len; } uip_userdata_t * diff --git a/libraries/UIPEthernet/UIPClient.h b/libraries/UIPEthernet/UIPClient.h index ac601da..6c0c006 100644 --- a/libraries/UIPEthernet/UIPClient.h +++ b/libraries/UIPEthernet/UIPClient.h @@ -55,6 +55,9 @@ typedef struct { memhandle packets_in[UIP_SOCKET_NUMPACKETS]; memhandle packets_out[UIP_SOCKET_NUMPACKETS]; memaddress out_pos; +#if UIP_CLIENT_TIMER >= 0 + unsigned long timer; +#endif } uip_userdata_t; class UIPClient : public Client { diff --git a/libraries/UIPEthernet/UIPEthernet.cpp b/libraries/UIPEthernet/UIPEthernet.cpp index ea02c97..91ec70a 100644 --- a/libraries/UIPEthernet/UIPEthernet.cpp +++ b/libraries/UIPEthernet/UIPEthernet.cpp @@ -45,7 +45,7 @@ uint8_t UIPEthernetClass::packetstate(0); IPAddress UIPEthernetClass::_dnsServerAddress; DhcpClass* UIPEthernetClass::_dhcp(NULL); -struct uip_timer UIPEthernetClass::periodic_timer; +unsigned long UIPEthernetClass::periodic_timer; // Because uIP isn't encapsulated within a class we have to use global // variables, so we can only have one TCP/IP stack per program. @@ -183,7 +183,7 @@ UIPEthernetClass::tick() Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) { - uip_packet = in_packet; + uip_packet = in_packet; //required for upper_layer_checksum of in_packet! #ifdef UIPETHERNET_DEBUG Serial.print(F("readPacket type IP, uip_len: ")); Serial.println(uip_len); @@ -220,22 +220,50 @@ UIPEthernetClass::tick() } } - if (uip_timer_expired(&periodic_timer)) + unsigned long now = millis(); + +#if UIP_CLIENT_TIMER >= 0 + boolean periodic = (long)( now - periodic_timer ) >= 0; + for (int i = 0; i < UIP_CONNS; i++) { - uip_timer_restart(&periodic_timer); +#else + if ((long)( now - periodic_timer ) >= 0) + { + periodic_timer = now + UIP_PERIODIC_TIMER; + for (int i = 0; i < UIP_CONNS; i++) { - uip_periodic(i); - // If the above function invocation resulted in data that - // should be sent out on the Enc28J60Network, the global variable - // uip_len is set to a value > 0. - if (uip_len > 0) - { - uip_arp_out(); - network_send(); - } +#endif + uip_conn = &uip_conns[i]; +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { +#endif + uip_process(UIP_TIMER); +#if UIP_CLIENT_TIMER >= 0 } - + else + { + if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) + uip_process(UIP_POLL_REQUEST); + else + continue; + } +#endif + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { + periodic_timer = now + UIP_PERIODIC_TIMER; +#endif #if UIP_UDP for (int i = 0; i < UIP_UDP_CONNS; i++) { @@ -263,6 +291,7 @@ boolean UIPEthernetClass::network_send() Serial.println(uip_hdrlen); #endif Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen); + packetstate &= ~ UIPETHERNET_SENDPACKET; goto sendandfree; } uip_packet = Enc28J60Network::allocBlock(uip_len); @@ -286,7 +315,7 @@ sendandfree: } void UIPEthernetClass::init(const uint8_t* mac) { - uip_timer_set(&periodic_timer, CLOCK_SECOND / 4); + periodic_timer = millis() + UIP_PERIODIC_TIMER; Enc28J60Network::init((uint8_t*)mac); uip_seteth_addr(mac); diff --git a/libraries/UIPEthernet/UIPEthernet.h b/libraries/UIPEthernet/UIPEthernet.h index 3bb18d4..c68d578 100644 --- a/libraries/UIPEthernet/UIPEthernet.h +++ b/libraries/UIPEthernet/UIPEthernet.h @@ -90,7 +90,7 @@ private: static IPAddress _dnsServerAddress; static DhcpClass* _dhcp; - static struct uip_timer periodic_timer; + static unsigned long periodic_timer; static void init(const uint8_t* mac); static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); diff --git a/libraries/UIPEthernet/utility/Enc28J60Network.cpp b/libraries/UIPEthernet/utility/Enc28J60Network.cpp index fbef88d..c7c66fb 100644 --- a/libraries/UIPEthernet/utility/Enc28J60Network.cpp +++ b/libraries/UIPEthernet/utility/Enc28J60Network.cpp @@ -155,7 +155,7 @@ Enc28J60Network::receivePacket() // The above does not work. See Rev. B4 Silicon Errata point 6. if (readReg(EPKTCNT) != 0) { - uint16_t readPtr = nextPacketPtr+6; + uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-RXSTOP_INIT+RXSTART_INIT : nextPacketPtr+6; // Set the read pointer to the start of the received packet writeRegPair(ERDPTL, nextPacketPtr); // read the next packet pointer @@ -168,6 +168,20 @@ Enc28J60Network::receivePacket() // read the receive status (see datasheet page 43) rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; +#ifdef ENC28J60DEBUG + Serial.print("receivePacket ["); + Serial.print(readPtr,HEX); + Serial.print("-"); + Serial.print((readPtr+len) % (RXSTOP_INIT+1),HEX); + Serial.print("], next: "); + Serial.print(nextPacketPtr,HEX); + Serial.print(", stat: "); + Serial.print(rxstat,HEX); + Serial.print(", count: "); + Serial.print(readReg(EPKTCNT)); + Serial.print(" -> "); + Serial.println((rxstat & 0x80)!=0 ? "OK" : "failed"); +#endif // decrement the packet counter indicate we are done with this packet writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); // check CRC and symbol errors (see datasheet page 44, table 7-3): @@ -215,10 +229,10 @@ Enc28J60Network::sendPacket(memhandle handle) Serial.print("sendPacket("); Serial.print(handle); Serial.print(") ["); - Serial.print(start); + Serial.print(start,HEX); Serial.print("-"); - Serial.print(end); - Serial.println("]:"); + Serial.print(end,HEX); + Serial.print("]: "); for (uint16_t i=start; i<=end; i++) { Serial.print(readByte(i),HEX); @@ -248,8 +262,8 @@ uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) { memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; - memaddress start = packet->begin + position; - + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && packet->begin + position > RXSTOP_INIT ? packet->begin + position-RXSTOP_INIT+RXSTART_INIT : packet->begin + position; + writeRegPair(ERDPTL, start); if (len > packet->size - position) @@ -313,7 +327,8 @@ Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle s { memblock *dest = &blocks[dest_pkt]; memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; - enc28J60_mempool_block_move_callback(dest->begin+dest_pos,src->begin+src_pos,len); + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ? src->begin + src_pos-RXSTOP_INIT+RXSTART_INIT : src->begin + src_pos; + enc28J60_mempool_block_move_callback(dest->begin+dest_pos,start,len); // Move the RX read pointer to the start of the next received packet // This frees the memory we just read out setERXRDPT(); diff --git a/libraries/UIPEthernet/utility/uip-conf.h b/libraries/UIPEthernet/utility/uip-conf.h index 814aeb9..e7f20d8 100644 --- a/libraries/UIPEthernet/utility/uip-conf.h +++ b/libraries/UIPEthernet/utility/uip-conf.h @@ -87,7 +87,7 @@ typedef unsigned short uip_stats_t; * * \hideinitializer */ -#define UIP_CONF_MAX_LISTENPORTS 4 +#define UIP_CONF_MAX_LISTENPORTS 1 /** * uIP buffer size. @@ -131,12 +131,13 @@ typedef unsigned short uip_stats_t; */ #define UIP_CONF_LOGGING 0 +#define UIP_CONF_UDP 0 /** * UDP support on or off * (see uipethernet-conf.h) * \hideinitializer * - * #define UIP_CONF_UDP 1 + * * #define UIP_CONF_UDP_CONNS 4 */ diff --git a/libraries/UIPEthernet/utility/uipethernet-conf.h b/libraries/UIPEthernet/utility/uipethernet-conf.h index 016e0e3..9dd8b27 100644 --- a/libraries/UIPEthernet/utility/uipethernet-conf.h +++ b/libraries/UIPEthernet/utility/uipethernet-conf.h @@ -5,8 +5,9 @@ #define UIP_SOCKET_NUMPACKETS 5 #define UIP_CONF_MAX_CONNECTIONS 4 -/* for UDP */ -#define UIP_CONF_UDP 0 +/* for UDP + * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */ +#define UIP_CONF_UDP 1 #define UIP_CONF_BROADCAST 1 #define UIP_CONF_UDP_CONNS 4 @@ -18,4 +19,11 @@ * if set to a number <= 0 connect will timeout when uIP does (which might be longer than you expect...) */ #define UIP_CONNECT_TIMEOUT -1 +/* periodic timer for uip (in ms) */ +#define UIP_PERIODIC_TIMER 250 + +/* timer to poll client for data after last write (in ms) + * set to -1 to disable fast polling and rely on periodic only (saves 100 bytes flash) */ +#define UIP_CLIENT_TIMER 10 + #endif From 8ec2ebdfce691eba0a293e76aca385d58982af6c Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 23 Oct 2014 09:02:30 +0200 Subject: [PATCH 020/660] Sent startup message to controller when it connects. --- .../examples/EthernetGateway/EthernetGateway.ino | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 6ad2e78..59599ec 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -62,10 +62,10 @@ #endif // Use this if you have attached a Ethernet ENC28J60 shields -#include +//#include // Use this fo WizNET module and Arduino Ethernet Shield -//#include +#include #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled @@ -97,6 +97,7 @@ EthernetServer server = EthernetServer(IP_PORT); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; +bool sentReady = false; void w5100_spi_en(boolean enable) { @@ -151,7 +152,7 @@ void setup() server.begin(); w5100_spi_en(false); - //output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); + output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); } @@ -170,7 +171,12 @@ void loop() EthernetClient client = server.available(); if (client) { - + if (!sentReady) { + // Send gateway startup message when first client connects + output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); + sentReady = true; + } + // if got 1 or more bytes if (client.available()) { // read the bytes incoming from the client From 3d2d7db84517d80ea398c7a6825d87350ef37a5a Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 25 Oct 2014 10:49:32 +0200 Subject: [PATCH 021/660] Fix problem reported by Yveaux here: https://github.com/mysensors/Arduino/commit/aeb9f30482532122b624fe4f061b5176571b0c6b#commitcomment-8300974 --- libraries/MySensors/MyDriverNRF24.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyDriverNRF24.cpp b/libraries/MySensors/MyDriverNRF24.cpp index f59f2d5..a6b3ac1 100644 --- a/libraries/MySensors/MyDriverNRF24.cpp +++ b/libraries/MySensors/MyDriverNRF24.cpp @@ -15,13 +15,13 @@ void MyDriverNRF24::init() { } rf24->setAutoAck(1); rf24->setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast - rf24->enableAckPayload(); rf24->setChannel(RF24_CHANNEL); rf24->setPALevel(RF24_PA_LEVEL); rf24->setDataRate(RF24_DATARATE); rf24->setRetries(5,15); rf24->setCRCLength(RF24_CRC_16); rf24->enableDynamicPayloads(); + rf24->enableDynamicAck(); // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) rf24->openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); From 26138b79721f391bbdadd7669ef2adf4dadef68c Mon Sep 17 00:00:00 2001 From: Frank Olaf Sem-Jacobsen Date: Fri, 31 Oct 2014 20:27:20 +0100 Subject: [PATCH 022/660] RF69 --- libraries/MySensors/MyConfig.h | 8 +++++ libraries/MySensors/MyDriverRF69.cpp | 47 ++++++++++++++++++++++++++++ libraries/MySensors/MyDriverRF69.h | 33 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 libraries/MySensors/MyDriverRF69.cpp create mode 100644 libraries/MySensors/MyDriverRF69.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index d25a446..4a45ac0 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -12,6 +12,9 @@ // Choose radio type by enabling one of the following #define MYSENSORS_RF_NRF24 +#define MYSENSORS_RF_RF69 + + @@ -20,6 +23,11 @@ typedef class MyDriverNRF24 MyDriverClass; #endif +#ifdef MYSENSORS_RF_RF69 +#include "MyDriverRF69.h" +typedef class MyDriverRF69 MyDriverClass; +#endif + /*** * Enable/Disable debug logging */ diff --git a/libraries/MySensors/MyDriverRF69.cpp b/libraries/MySensors/MyDriverRF69.cpp new file mode 100644 index 0000000..4f733ed --- /dev/null +++ b/libraries/MySensors/MyDriverRF69.cpp @@ -0,0 +1,47 @@ +#include "MyDriver.h" +#include "MyDriverRF69.h" + +MyDriverRF69::MyDriverRF69() : MyDriver() { + driver = new RH_RF69(RF69_CS_PIN, RF69_INTERRUPT_PIN); +} + +void MyDriverRF69::init() { + // Start up the radio library + manager = new RHReliableDatagram(*driver, _address); + driver->setFrequency(RF69_FREQUENCY); + driver->setTxPower(RF69_TRANSMIT_POWER) + +} + +void MyDriverRF69::setAddress(uint8_t address) { + _address = address; + manager->setThisAddress(_address); +} + +uint8_t MyDriverRF69::getAddress() { + return _address; +} + +bool MyDriverRF69::send(uint8_t to, const void* data, uint8_t len) { + // Make sure radio has powered up + uint8_t status = manager->sendtoWait((uint8_t *) data, len, to); + if(status==RH_ROUTER_ERROR_NONE) { + return true; + } else { + return false; + } +} + +bool MyDriverRF69::available(uint8_t *to) { + return manager->available(); +} + +uint8_t MyDriverRF69::receive(void* data) { + uint8_t len = 256; + uint8_t from; + manager->recvfromAck((uint8_t *) data, &len, &from); +} + +void MyDriverRF69::powerDown() { + driver->sleep(); +} diff --git a/libraries/MySensors/MyDriverRF69.h b/libraries/MySensors/MyDriverRF69.h new file mode 100644 index 0000000..635d97f --- /dev/null +++ b/libraries/MySensors/MyDriverRF69.h @@ -0,0 +1,33 @@ +#ifndef MyCommDriver_h +#define MyCommDriver_h + +#include "MyConfig.h" +#include "MyDriver.h" +#include +#include +#include + +#define RF69_FREQUENCY 868; +#define RF69_TRANSMIT_POWER 14; +#define RF69_MODEM_CONFIG RH_RF69::GFSK_Rb250Fd250; +#define RF69_INTERRUPT_PIN 2; +#define RF69_CS_PIN 10; + +class MyDriverRF69 : public MyDriver +{ +public: + MyDriverRF69(); + void init(); + void setAddress(uint8_t address); + uint8_t getAddress(); + bool send(uint8_t to, const void* data, uint8_t len); + bool available(uint8_t *to); + uint8_t receive(void* data); + void powerDown(); +private: + RH_RF69 *driver = NULL; + RHReliableDatagram *manager = NULL; + uint8_t _address; +}; + +#endif \ No newline at end of file From db73e3c7886bbf4254e6787754a2687684b113c0 Mon Sep 17 00:00:00 2001 From: Frank Olaf Sem-Jacobsen Date: Mon, 3 Nov 2014 19:21:40 +0100 Subject: [PATCH 023/660] switched to low-power library --- libraries/MySensors/MyConfig.h | 6 +- libraries/MySensors/MyDriverRF69.cpp | 37 +- libraries/MySensors/MyDriverRF69.h | 29 +- libraries/MySensors/MySensor.cpp | 1 + libraries/MySensors/RFM69.cpp | 464 +++++++++++ libraries/MySensors/RFM69.h | 136 ++++ libraries/MySensors/RFM69registers.h | 1069 ++++++++++++++++++++++++++ 7 files changed, 1713 insertions(+), 29 deletions(-) create mode 100644 libraries/MySensors/RFM69.cpp create mode 100644 libraries/MySensors/RFM69.h create mode 100644 libraries/MySensors/RFM69registers.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 4a45ac0..79b1c95 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -6,12 +6,12 @@ */ // pick ONE of these - other board layouts can be easily added this way -#define MYSENSORS_SENSOR -//#define MYSENSORS_SERIAL_GATEWAY +// #define MYSENSORS_SENSOR +#define MYSENSORS_SERIAL_GATEWAY //#define MYSENSORS_ETHERNET_MQTT_GATEWAY // Choose radio type by enabling one of the following -#define MYSENSORS_RF_NRF24 +//#define MYSENSORS_RF_NRF24 #define MYSENSORS_RF_RF69 diff --git a/libraries/MySensors/MyDriverRF69.cpp b/libraries/MySensors/MyDriverRF69.cpp index 4f733ed..126e364 100644 --- a/libraries/MySensors/MyDriverRF69.cpp +++ b/libraries/MySensors/MyDriverRF69.cpp @@ -1,21 +1,24 @@ +#include #include "MyDriver.h" #include "MyDriverRF69.h" MyDriverRF69::MyDriverRF69() : MyDriver() { - driver = new RH_RF69(RF69_CS_PIN, RF69_INTERRUPT_PIN); + radio = new RFM69(); } void MyDriverRF69::init() { // Start up the radio library - manager = new RHReliableDatagram(*driver, _address); - driver->setFrequency(RF69_FREQUENCY); - driver->setTxPower(RF69_TRANSMIT_POWER) + radio->initialize(FREQUENCY,_address,NETWORKID); +#ifdef IS_RFM69HW + radio->setHighPower(); //uncomment only for RFM69HW! +#endif + // radio->encrypt(ENCRYPTKEY); } void MyDriverRF69::setAddress(uint8_t address) { _address = address; - manager->setThisAddress(_address); + radio->setAddress(address); } uint8_t MyDriverRF69::getAddress() { @@ -24,24 +27,24 @@ uint8_t MyDriverRF69::getAddress() { bool MyDriverRF69::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up - uint8_t status = manager->sendtoWait((uint8_t *) data, len, to); - if(status==RH_ROUTER_ERROR_NONE) { - return true; - } else { - return false; - } + return radio->sendWithRetry(to,data,len); } bool MyDriverRF69::available(uint8_t *to) { - return manager->available(); + return radio->receiveDone(); } uint8_t MyDriverRF69::receive(void* data) { - uint8_t len = 256; - uint8_t from; - manager->recvfromAck((uint8_t *) data, &len, &from); -} + // for (byte i = 0; i < radio->DATALEN; i++){ + // data[i]= (void)radio->DATA[i]; + // } + memcpy(data,(const void *)radio->DATA, radio->DATALEN); + if (radio->ACKRequested()) + { + radio->sendACK(); + } +} void MyDriverRF69::powerDown() { - driver->sleep(); + radio->sleep(); } diff --git a/libraries/MySensors/MyDriverRF69.h b/libraries/MySensors/MyDriverRF69.h index 635d97f..4c53786 100644 --- a/libraries/MySensors/MyDriverRF69.h +++ b/libraries/MySensors/MyDriverRF69.h @@ -4,14 +4,26 @@ #include "MyConfig.h" #include "MyDriver.h" #include -#include -#include +#include "RFM69.h" +#include -#define RF69_FREQUENCY 868; -#define RF69_TRANSMIT_POWER 14; -#define RF69_MODEM_CONFIG RH_RF69::GFSK_Rb250Fd250; -#define RF69_INTERRUPT_PIN 2; -#define RF69_CS_PIN 10; +#define NODEID 2 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +#define GATEWAYID 1 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +// #define FREQUENCY RF69_433MHZ +#define FREQUENCY RF69_868MHZ +//#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ACK_TIME 30 // max # of ms to wait for an ack +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define FLASH_SS 23 // and FLASH SS on D23 +#else + #define LED 9 // Moteinos have LEDs on D9 + #define FLASH_SS 8 // and FLASH SS on D8 +#endif class MyDriverRF69 : public MyDriver { @@ -25,8 +37,7 @@ public: uint8_t receive(void* data); void powerDown(); private: - RH_RF69 *driver = NULL; - RHReliableDatagram *manager = NULL; + RFM69 *radio = NULL; uint8_t _address; }; diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index bf8205f..c56da76 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -275,6 +275,7 @@ boolean MySensor::process() { msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, mGetPayloadType(msg), mGetLength(msg), msg.getString(convBuf)); if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { + debug(PSTR("version: %d\n"),mGetVersion(msg)); debug(PSTR("version mismatch\n")); return false; } diff --git a/libraries/MySensors/RFM69.cpp b/libraries/MySensors/RFM69.cpp new file mode 100644 index 0000000..8b0305f --- /dev/null +++ b/libraries/MySensors/RFM69.cpp @@ -0,0 +1,464 @@ +// ********************************************************************************** +// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#include +#include +#include + +volatile byte RFM69::DATA[RF69_MAX_DATA_LEN]; +volatile byte RFM69::_mode; // current transceiver state +volatile byte RFM69::DATALEN; +volatile byte RFM69::SENDERID; +volatile byte RFM69::TARGETID; //should match _address +volatile byte RFM69::PAYLOADLEN; +volatile byte RFM69::ACK_REQUESTED; +volatile byte RFM69::ACK_RECEIVED; /// Should be polled immediately after sending a packet with ACK request +volatile int RFM69::RSSI; //most accurate RSSI during reception (closest to the reception) +RFM69* RFM69::selfPointer; + +bool RFM69::initialize(byte freqBand, byte nodeID, byte networkID) +{ + const byte CONFIG[][2] = + { + /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, + /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, //no shaping + /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, //default:4.8 KBPS + /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, + /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, //default:5khz, (FDEV + BitRate/2 <= 500Khz) + /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, + + /* 0x07 */ { REG_FRFMSB, (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, + /* 0x08 */ { REG_FRFMID, (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, + /* 0x09 */ { REG_FRFLSB, (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, + + // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm + // +17dBm and +20dBm are possible on RFM69HW + // +13dBm formula: Pout=-18+OutputPower (with PA0 or PA1**) + // +17dBm formula: Pout=-14+OutputPower (with PA1 and PA2)** + // +20dBm formula: Pout=-11+OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) + ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, + ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, //over current protection (default is 95mA) + + // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4khz) + /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, //(BitRate < 2 * RxBw) + //for BR-19200: //* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, + /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, //DIO0 is the only IRQ we're using + /* 0x29 */ { REG_RSSITHRESH, 220 }, //must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm + ///* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA + /* 0x2e */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, + /* 0x2f */ { REG_SYNCVALUE1, 0x2D }, //attempt to make this compatible with sync1 byte of RFM12B lib + /* 0x30 */ { REG_SYNCVALUE2, networkID }, //NETWORK ID + /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, + /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, //in variable length mode: the max frame size, not used in TX + //* 0x39 */ { REG_NODEADRS, nodeID }, //turned off because we're not using address filtering + /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, //TX on FIFO not empty + /* 0x3d */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + //for BR-19200: //* 0x3d */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, //RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + //* 0x6F */ { REG_TESTDAGC, RF_DAGC_CONTINUOUS }, // run DAGC continuously in RX mode + /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0 + {255, 0} + }; + + pinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + + do writeReg(REG_SYNCVALUE1, 0xaa); while (readReg(REG_SYNCVALUE1) != 0xaa); + do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55); + + for (byte i = 0; CONFIG[i][0] != 255; i++) + writeReg(CONFIG[i][0], CONFIG[i][1]); + + // Encryption is persistent between resets and can trip you up during debugging. + // Disable it during initialization so we always start from a known state. + encrypt(0); + + setHighPower(_isRFM69HW); //called regardless if it's a RFM69W or RFM69HW + setMode(RF69_MODE_STANDBY); + while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady + attachInterrupt(_interruptNum, RFM69::isr0, RISING); + + selfPointer = this; + _address = nodeID; + return true; +} + +void RFM69::setFrequency(uint32_t FRF) +{ + writeReg(REG_FRFMSB, FRF >> 16); + writeReg(REG_FRFMID, FRF >> 8); + writeReg(REG_FRFLSB, FRF); +} + +void RFM69::setMode(byte newMode) +{ + if (newMode == _mode) return; //TODO: can remove this? + + switch (newMode) { + case RF69_MODE_TX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); + if (_isRFM69HW) setHighPowerRegs(true); + break; + case RF69_MODE_RX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); + if (_isRFM69HW) setHighPowerRegs(false); + break; + case RF69_MODE_SYNTH: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); + break; + case RF69_MODE_STANDBY: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY); + break; + case RF69_MODE_SLEEP: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP); + break; + default: return; + } + + // we are using packet mode, so this check is not really needed + // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode + while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // Wait for ModeReady + + _mode = newMode; +} + +void RFM69::sleep() { + setMode(RF69_MODE_SLEEP); +} + +void RFM69::setAddress(byte addr) +{ + _address = addr; + writeReg(REG_NODEADRS, _address); +} + +// set output power: 0=min, 31=max +// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver +void RFM69::setPowerLevel(byte powerLevel) +{ + _powerLevel = powerLevel; + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel)); +} + +bool RFM69::canSend() +{ + if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) //if signal stronger than -100dBm is detected assume channel activity + { + setMode(RF69_MODE_STANDBY); + return true; + } + return false; +} + +void RFM69::send(byte toAddress, const void* buffer, byte bufferSize, bool requestACK) +{ + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + long now = millis(); + while (!canSend() && millis()-now < RF69_CSMA_LIMIT_MS) receiveDone(); + sendFrame(toAddress, buffer, bufferSize, requestACK, false); +} + +// to increase the chance of getting a packet across, call this function instead of send +// and it handles all the ACK requesting/retrying for you :) +// The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs +// The reason for the semi-automaton is that the lib is ingterrupt driven and +// requires user action to read the received data and decide what to do with it +// replies usually take only 5-8ms at 50kbps@915Mhz +bool RFM69::sendWithRetry(byte toAddress, const void* buffer, byte bufferSize, byte retries, byte retryWaitTime) { + long sentTime; + for (byte i=0; i<=retries; i++) + { + send(toAddress, buffer, bufferSize, true); + sentTime = millis(); + while (millis()-sentTime RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN; + + //write to FIFO + select(); + SPI.transfer(REG_FIFO | 0x80); + SPI.transfer(bufferSize + 3); + SPI.transfer(toAddress); + SPI.transfer(_address); + + //control byte + if (sendACK) + SPI.transfer(0x80); + else if (requestACK) + SPI.transfer(0x40); + else SPI.transfer(0x00); + + for (byte i = 0; i < bufferSize; i++) + SPI.transfer(((byte*)buffer)[i]); + unselect(); + + /* no need to wait for transmit mode to be ready since its handled by the radio */ + setMode(RF69_MODE_TX); + while (digitalRead(_interruptPin) == 0); //wait for DIO0 to turn HIGH signalling transmission finish + //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // Wait for ModeReady + setMode(RF69_MODE_STANDBY); +} + +void RFM69::interruptHandler() { + //pinMode(4, OUTPUT); + //digitalWrite(4, 1); + if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) + { + //RSSI = readRSSI(); + setMode(RF69_MODE_STANDBY); + select(); + SPI.transfer(REG_FIFO & 0x7f); + PAYLOADLEN = SPI.transfer(0); + PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; //precaution + TARGETID = SPI.transfer(0); + if(!(_promiscuousMode || TARGETID==_address || TARGETID==RF69_BROADCAST_ADDR)) //match this node's address, or broadcast address or anything in promiscuous mode + { + PAYLOADLEN = 0; + unselect(); + //digitalWrite(4, 0); + return; + } + DATALEN = PAYLOADLEN - 3; + SENDERID = SPI.transfer(0); + byte CTLbyte = SPI.transfer(0); + + ACK_RECEIVED = CTLbyte & 0x80; //extract ACK-requested flag + ACK_REQUESTED = CTLbyte & 0x40; //extract ACK-received flag + + for (byte i= 0; i < DATALEN; i++) + { + DATA[i] = SPI.transfer(0); + } + if (DATALENinterruptHandler(); } + +void RFM69::receiveBegin() { + DATALEN = 0; + SENDERID = 0; + TARGETID = 0; + PAYLOADLEN = 0; + ACK_REQUESTED = 0; + ACK_RECEIVED = 0; + RSSI = 0; + if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); //set DIO0 to "PAYLOADREADY" in receive mode + setMode(RF69_MODE_RX); +} + +bool RFM69::receiveDone() { +// ATOMIC_BLOCK(ATOMIC_FORCEON) +// { + noInterrupts(); //re-enabled in unselect() via setMode() or via receiveBegin() + if (_mode == RF69_MODE_RX && PAYLOADLEN>0) + { + setMode(RF69_MODE_STANDBY); //enables interrupts + return true; + } + else if (_mode == RF69_MODE_RX) //already in RX no payload yet + { + interrupts(); //explicitly re-enable interrupts + return false; + } + receiveBegin(); + return false; +//} +} + +// To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP"); +// To disable encryption: radio.encrypt(null) or radio.encrypt(0) +// KEY HAS TO BE 16 bytes !!! +void RFM69::encrypt(const char* key) { + setMode(RF69_MODE_STANDBY); + if (key!=0) + { + select(); + SPI.transfer(REG_AESKEY1 | 0x80); + for (byte i = 0; i<16; i++) + SPI.transfer(key[i]); + unselect(); + } + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); +} + +int RFM69::readRSSI(bool forceTrigger) { + int rssi = 0; + if (forceTrigger) + { + //RSSI trigger not needed if DAGC is in continuous mode + writeReg(REG_RSSICONFIG, RF_RSSI_START); + while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // Wait for RSSI_Ready + } + rssi = -readReg(REG_RSSIVALUE); + rssi >>= 1; + return rssi; +} + +byte RFM69::readReg(byte addr) +{ + select(); + SPI.transfer(addr & 0x7F); + byte regval = SPI.transfer(0); + unselect(); + return regval; +} + +void RFM69::writeReg(byte addr, byte value) +{ + select(); + SPI.transfer(addr | 0x80); + SPI.transfer(value); + unselect(); +} + +/// Select the transceiver +void RFM69::select() { + noInterrupts(); + //save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + //set RFM69 SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + digitalWrite(_slaveSelectPin, LOW); +} + +/// UNselect the transceiver chip +void RFM69::unselect() { + digitalWrite(_slaveSelectPin, HIGH); + //restore SPI settings to what they were before talking to RFM69 + SPCR = _SPCR; + SPSR = _SPSR; + interrupts(); +} + +// ON = disable filtering to capture all frames on network +// OFF = enable node+broadcast filtering to capture only frames sent to this/broadcast address +void RFM69::promiscuous(bool onOff) { + _promiscuousMode=onOff; + //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST)); +} + +void RFM69::setHighPower(bool onOff) { + _isRFM69HW = onOff; + writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); + if (_isRFM69HW) //turning ON + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); //enable P1 & P2 amplifier stages + else + writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); //enable P0 only +} + +void RFM69::setHighPowerRegs(bool onOff) { + writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55); + writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); +} + +void RFM69::setCS(byte newSPISlaveSelect) { + _slaveSelectPin = newSPISlaveSelect; + pinMode(_slaveSelectPin, OUTPUT); +} + +//for debugging +void RFM69::readAllRegs() +{ + byte regVal; + + for (byte regAddr = 1; regAddr <= 0x4F; regAddr++) + { + select(); + SPI.transfer(regAddr & 0x7f); // send address + r/w bit + regVal = SPI.transfer(0); + unselect(); + + Serial.print(regAddr, HEX); + Serial.print(" - "); + Serial.print(regVal,HEX); + Serial.print(" - "); + Serial.println(regVal,BIN); + } + unselect(); +} + +byte RFM69::readTemperature(byte calFactor) //returns centigrade +{ + setMode(RF69_MODE_STANDBY); + writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); + while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)) Serial.print('*'); + return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; //'complement'corrects the slope, rising temp = rising val +} // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction + +void RFM69::rcCalibration() +{ + writeReg(REG_OSC1, RF_OSC1_RCCAL_START); + while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); +} \ No newline at end of file diff --git a/libraries/MySensors/RFM69.h b/libraries/MySensors/RFM69.h new file mode 100644 index 0000000..23eb044 --- /dev/null +++ b/libraries/MySensors/RFM69.h @@ -0,0 +1,136 @@ +// ********************************************************************************** +// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#ifndef RFM69_h +#define RFM69_h +#include //assumes Arduino IDE v1.0 or greater + +#define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead) +#define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on atmega328 + +// INT0 on AVRs should be connected to RFM69's DIO0 (ex on Atmega328 it's D2, on Atmega644/1284 it's D2) +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega32U4__) + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 0 +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 2 +#endif + +#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access +#define RF69_MODE_SLEEP 0 // XTAL OFF +#define RF69_MODE_STANDBY 1 // XTAL ON +#define RF69_MODE_SYNTH 2 // PLL ON +#define RF69_MODE_RX 3 // RX MODE +#define RF69_MODE_TX 4 // TX MODE + +//available frequency bands +#define RF69_315MHZ 31 // non trivial values to avoid misconfiguration +#define RF69_433MHZ 43 +#define RF69_868MHZ 86 +#define RF69_915MHZ 91 + +#define null 0 +#define COURSE_TEMP_COEF -90 // puts the temperature reading in the ballpark, user can fine tune the returned value +#define RF69_BROADCAST_ADDR 255 +#define RF69_CSMA_LIMIT_MS 1000 + +class RFM69 { + public: + static volatile byte DATA[RF69_MAX_DATA_LEN]; // recv/xmit buf, including hdr & crc bytes + static volatile byte DATALEN; + static volatile byte SENDERID; + static volatile byte TARGETID; //should match _address + static volatile byte PAYLOADLEN; + static volatile byte ACK_REQUESTED; + static volatile byte ACK_RECEIVED; /// Should be polled immediately after sending a packet with ACK request + static volatile int RSSI; //most accurate RSSI during reception (closest to the reception) + static volatile byte _mode; //should be protected? + + RFM69(byte slaveSelectPin=RF69_SPI_CS, byte interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, byte interruptNum=RF69_IRQ_NUM) { + _slaveSelectPin = slaveSelectPin; + _interruptPin = interruptPin; + _interruptNum = interruptNum; + _mode = RF69_MODE_STANDBY; + _promiscuousMode = false; + _powerLevel = 31; + _isRFM69HW = isRFM69HW; + } + + bool initialize(byte freqBand, byte ID, byte networkID=1); + void setAddress(byte addr); + bool canSend(); + void send(byte toAddress, const void* buffer, byte bufferSize, bool requestACK=false); + bool sendWithRetry(byte toAddress, const void* buffer, byte bufferSize, byte retries=2, byte retryWaitTime=40); //40ms roundtrip req for 61byte packets + bool receiveDone(); + bool ACKReceived(byte fromNodeID); + bool ACKRequested(); + void sendACK(const void* buffer = "", uint8_t bufferSize=0); + void setFrequency(uint32_t FRF); + void encrypt(const char* key); + void setCS(byte newSPISlaveSelect); + int readRSSI(bool forceTrigger=false); + void promiscuous(bool onOff=true); + void setHighPower(bool onOFF=true); //have to call it after initialize for RFM69HW + void setPowerLevel(byte level); //reduce/increase transmit power level + void sleep(); + byte readTemperature(byte calFactor=0); //get CMOS temperature (8bit) + void rcCalibration(); //calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy] + + // allow hacking registers by making these public + byte readReg(byte addr); + void writeReg(byte addr, byte val); + void readAllRegs(); + + protected: + static void isr0(); + void virtual interruptHandler(); + void sendFrame(byte toAddress, const void* buffer, byte size, bool requestACK=false, bool sendACK=false); + + static RFM69* selfPointer; + byte _slaveSelectPin; + byte _interruptPin; + byte _interruptNum; + byte _address; + bool _promiscuousMode; + byte _powerLevel; + bool _isRFM69HW; + byte _SPCR; + byte _SPSR; + + void receiveBegin(); + void setMode(byte mode); + void setHighPowerRegs(bool onOff); + void select(); + void unselect(); +}; + +#endif diff --git a/libraries/MySensors/RFM69registers.h b/libraries/MySensors/RFM69registers.h new file mode 100644 index 0000000..ff720b1 --- /dev/null +++ b/libraries/MySensors/RFM69registers.h @@ -0,0 +1,1069 @@ +// ********************************************************************************** +// Registers used in driver definition for HopeRF RFM69W/RFM69HW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +// RFM69/SX1231 Internal registers addresses +//************************************************** +#define REG_FIFO 0x00 +#define REG_OPMODE 0x01 +#define REG_DATAMODUL 0x02 +#define REG_BITRATEMSB 0x03 +#define REG_BITRATELSB 0x04 +#define REG_FDEVMSB 0x05 +#define REG_FDEVLSB 0x06 +#define REG_FRFMSB 0x07 +#define REG_FRFMID 0x08 +#define REG_FRFLSB 0x09 +#define REG_OSC1 0x0A +#define REG_AFCCTRL 0x0B +#define REG_LOWBAT 0x0C +#define REG_LISTEN1 0x0D +#define REG_LISTEN2 0x0E +#define REG_LISTEN3 0x0F +#define REG_VERSION 0x10 +#define REG_PALEVEL 0x11 +#define REG_PARAMP 0x12 +#define REG_OCP 0x13 +#define REG_AGCREF 0x14 +#define REG_AGCTHRESH1 0x15 +#define REG_AGCTHRESH2 0x16 +#define REG_AGCTHRESH3 0x17 +#define REG_LNA 0x18 +#define REG_RXBW 0x19 +#define REG_AFCBW 0x1A +#define REG_OOKPEAK 0x1B +#define REG_OOKAVG 0x1C +#define REG_OOKFIX 0x1D +#define REG_AFCFEI 0x1E +#define REG_AFCMSB 0x1F +#define REG_AFCLSB 0x20 +#define REG_FEIMSB 0x21 +#define REG_FEILSB 0x22 +#define REG_RSSICONFIG 0x23 +#define REG_RSSIVALUE 0x24 +#define REG_DIOMAPPING1 0x25 +#define REG_DIOMAPPING2 0x26 +#define REG_IRQFLAGS1 0x27 +#define REG_IRQFLAGS2 0x28 +#define REG_RSSITHRESH 0x29 +#define REG_RXTIMEOUT1 0x2A +#define REG_RXTIMEOUT2 0x2B +#define REG_PREAMBLEMSB 0x2C +#define REG_PREAMBLELSB 0x2D +#define REG_SYNCCONFIG 0x2E +#define REG_SYNCVALUE1 0x2F +#define REG_SYNCVALUE2 0x30 +#define REG_SYNCVALUE3 0x31 +#define REG_SYNCVALUE4 0x32 +#define REG_SYNCVALUE5 0x33 +#define REG_SYNCVALUE6 0x34 +#define REG_SYNCVALUE7 0x35 +#define REG_SYNCVALUE8 0x36 +#define REG_PACKETCONFIG1 0x37 +#define REG_PAYLOADLENGTH 0x38 +#define REG_NODEADRS 0x39 +#define REG_BROADCASTADRS 0x3A +#define REG_AUTOMODES 0x3B +#define REG_FIFOTHRESH 0x3C +#define REG_PACKETCONFIG2 0x3D +#define REG_AESKEY1 0x3E +#define REG_AESKEY2 0x3F +#define REG_AESKEY3 0x40 +#define REG_AESKEY4 0x41 +#define REG_AESKEY5 0x42 +#define REG_AESKEY6 0x43 +#define REG_AESKEY7 0x44 +#define REG_AESKEY8 0x45 +#define REG_AESKEY9 0x46 +#define REG_AESKEY10 0x47 +#define REG_AESKEY11 0x48 +#define REG_AESKEY12 0x49 +#define REG_AESKEY13 0x4A +#define REG_AESKEY14 0x4B +#define REG_AESKEY15 0x4C +#define REG_AESKEY16 0x4D +#define REG_TEMP1 0x4E +#define REG_TEMP2 0x4F +#define REG_TESTPA1 0x5A //only present on RFM69HW/SX1231H +#define REG_TESTPA2 0x5C //only present on RFM69HW/SX1231H +#define REG_TESTDAGC 0x6F + +//****************************************************** +// RF69/SX1231 bit control definition +//****************************************************** +// RegOpMode +#define RF_OPMODE_SEQUENCER_OFF 0x80 +#define RF_OPMODE_SEQUENCER_ON 0x00 // Default + +#define RF_OPMODE_LISTEN_ON 0x40 +#define RF_OPMODE_LISTEN_OFF 0x00 // Default + +#define RF_OPMODE_LISTENABORT 0x20 + +#define RF_OPMODE_SLEEP 0x00 +#define RF_OPMODE_STANDBY 0x04 // Default +#define RF_OPMODE_SYNTHESIZER 0x08 +#define RF_OPMODE_TRANSMITTER 0x0C +#define RF_OPMODE_RECEIVER 0x10 + +// RegDataModul +#define RF_DATAMODUL_DATAMODE_PACKET 0x00 // Default +#define RF_DATAMODUL_DATAMODE_CONTINUOUS 0x40 +#define RF_DATAMODUL_DATAMODE_CONTINUOUSNOBSYNC 0x60 + +#define RF_DATAMODUL_MODULATIONTYPE_FSK 0x00 // Default +#define RF_DATAMODUL_MODULATIONTYPE_OOK 0x08 + +#define RF_DATAMODUL_MODULATIONSHAPING_00 0x00 // Default +#define RF_DATAMODUL_MODULATIONSHAPING_01 0x01 +#define RF_DATAMODUL_MODULATIONSHAPING_10 0x02 +#define RF_DATAMODUL_MODULATIONSHAPING_11 0x03 + +// RegBitRate (bits/sec) example bit rates +#define RF_BITRATEMSB_1200 0x68 +#define RF_BITRATELSB_1200 0x2B +#define RF_BITRATEMSB_2400 0x34 +#define RF_BITRATELSB_2400 0x15 +#define RF_BITRATEMSB_4800 0x1A // Default +#define RF_BITRATELSB_4800 0x0B // Default +#define RF_BITRATEMSB_9600 0x0D +#define RF_BITRATELSB_9600 0x05 +#define RF_BITRATEMSB_19200 0x06 +#define RF_BITRATELSB_19200 0x83 +#define RF_BITRATEMSB_38400 0x03 +#define RF_BITRATELSB_38400 0x41 + +#define RF_BITRATEMSB_38323 0x03 +#define RF_BITRATELSB_38323 0x43 + +#define RF_BITRATEMSB_34482 0x03 +#define RF_BITRATELSB_34482 0xA0 + +#define RF_BITRATEMSB_76800 0x01 +#define RF_BITRATELSB_76800 0xA1 +#define RF_BITRATEMSB_153600 0x00 +#define RF_BITRATELSB_153600 0xD0 +#define RF_BITRATEMSB_57600 0x02 +#define RF_BITRATELSB_57600 0x2C +#define RF_BITRATEMSB_115200 0x01 +#define RF_BITRATELSB_115200 0x16 +#define RF_BITRATEMSB_12500 0x0A +#define RF_BITRATELSB_12500 0x00 +#define RF_BITRATEMSB_25000 0x05 +#define RF_BITRATELSB_25000 0x00 +#define RF_BITRATEMSB_50000 0x02 +#define RF_BITRATELSB_50000 0x80 +#define RF_BITRATEMSB_100000 0x01 +#define RF_BITRATELSB_100000 0x40 +#define RF_BITRATEMSB_150000 0x00 +#define RF_BITRATELSB_150000 0xD5 +#define RF_BITRATEMSB_200000 0x00 +#define RF_BITRATELSB_200000 0xA0 +#define RF_BITRATEMSB_250000 0x00 +#define RF_BITRATELSB_250000 0x80 +#define RF_BITRATEMSB_300000 0x00 +#define RF_BITRATELSB_300000 0x6B +#define RF_BITRATEMSB_32768 0x03 +#define RF_BITRATELSB_32768 0xD1 +//custom bit rates +#define RF_BITRATEMSB_55555 0x02 +#define RF_BITRATELSB_55555 0x40 +#define RF_BITRATEMSB_200KBPS 0x00 +#define RF_BITRATELSB_200KBPS 0xa0 + +// RegFdev - frequency deviation (Hz) +#define RF_FDEVMSB_2000 0x00 +#define RF_FDEVLSB_2000 0x21 +#define RF_FDEVMSB_5000 0x00 // Default +#define RF_FDEVLSB_5000 0x52 // Default +#define RF_FDEVMSB_7500 0x00 +#define RF_FDEVLSB_7500 0x7B +#define RF_FDEVMSB_10000 0x00 +#define RF_FDEVLSB_10000 0xA4 +#define RF_FDEVMSB_15000 0x00 +#define RF_FDEVLSB_15000 0xF6 +#define RF_FDEVMSB_20000 0x01 +#define RF_FDEVLSB_20000 0x48 +#define RF_FDEVMSB_25000 0x01 +#define RF_FDEVLSB_25000 0x9A +#define RF_FDEVMSB_30000 0x01 +#define RF_FDEVLSB_30000 0xEC +#define RF_FDEVMSB_35000 0x02 +#define RF_FDEVLSB_35000 0x3D +#define RF_FDEVMSB_40000 0x02 +#define RF_FDEVLSB_40000 0x8F +#define RF_FDEVMSB_45000 0x02 +#define RF_FDEVLSB_45000 0xE1 +#define RF_FDEVMSB_50000 0x03 +#define RF_FDEVLSB_50000 0x33 +#define RF_FDEVMSB_55000 0x03 +#define RF_FDEVLSB_55000 0x85 +#define RF_FDEVMSB_60000 0x03 +#define RF_FDEVLSB_60000 0xD7 +#define RF_FDEVMSB_65000 0x04 +#define RF_FDEVLSB_65000 0x29 +#define RF_FDEVMSB_70000 0x04 +#define RF_FDEVLSB_70000 0x7B +#define RF_FDEVMSB_75000 0x04 +#define RF_FDEVLSB_75000 0xCD +#define RF_FDEVMSB_80000 0x05 +#define RF_FDEVLSB_80000 0x1F +#define RF_FDEVMSB_85000 0x05 +#define RF_FDEVLSB_85000 0x71 +#define RF_FDEVMSB_90000 0x05 +#define RF_FDEVLSB_90000 0xC3 +#define RF_FDEVMSB_95000 0x06 +#define RF_FDEVLSB_95000 0x14 +#define RF_FDEVMSB_100000 0x06 +#define RF_FDEVLSB_100000 0x66 +#define RF_FDEVMSB_110000 0x07 +#define RF_FDEVLSB_110000 0x0A +#define RF_FDEVMSB_120000 0x07 +#define RF_FDEVLSB_120000 0xAE +#define RF_FDEVMSB_130000 0x08 +#define RF_FDEVLSB_130000 0x52 +#define RF_FDEVMSB_140000 0x08 +#define RF_FDEVLSB_140000 0xF6 +#define RF_FDEVMSB_150000 0x09 +#define RF_FDEVLSB_150000 0x9A +#define RF_FDEVMSB_160000 0x0A +#define RF_FDEVLSB_160000 0x3D +#define RF_FDEVMSB_170000 0x0A +#define RF_FDEVLSB_170000 0xE1 +#define RF_FDEVMSB_180000 0x0B +#define RF_FDEVLSB_180000 0x85 +#define RF_FDEVMSB_190000 0x0C +#define RF_FDEVLSB_190000 0x29 +#define RF_FDEVMSB_200000 0x0C +#define RF_FDEVLSB_200000 0xCD +#define RF_FDEVMSB_210000 0x0D +#define RF_FDEVLSB_210000 0x71 +#define RF_FDEVMSB_220000 0x0E +#define RF_FDEVLSB_220000 0x14 +#define RF_FDEVMSB_230000 0x0E +#define RF_FDEVLSB_230000 0xB8 +#define RF_FDEVMSB_240000 0x0F +#define RF_FDEVLSB_240000 0x5C +#define RF_FDEVMSB_250000 0x10 +#define RF_FDEVLSB_250000 0x00 +#define RF_FDEVMSB_260000 0x10 +#define RF_FDEVLSB_260000 0xA4 +#define RF_FDEVMSB_270000 0x11 +#define RF_FDEVLSB_270000 0x48 +#define RF_FDEVMSB_280000 0x11 +#define RF_FDEVLSB_280000 0xEC +#define RF_FDEVMSB_290000 0x12 +#define RF_FDEVLSB_290000 0x8F +#define RF_FDEVMSB_300000 0x13 +#define RF_FDEVLSB_300000 0x33 + +// RegFrf (MHz) - carrier frequency +// 315Mhz band +#define RF_FRFMSB_314 0x4E +#define RF_FRFMID_314 0x80 +#define RF_FRFLSB_314 0x00 +#define RF_FRFMSB_315 0x4E +#define RF_FRFMID_315 0xC0 +#define RF_FRFLSB_315 0x00 +#define RF_FRFMSB_316 0x4F +#define RF_FRFMID_316 0x00 +#define RF_FRFLSB_316 0x00 +// 433mhz band +#define RF_FRFMSB_433 0x6C +#define RF_FRFMID_433 0x40 +#define RF_FRFLSB_433 0x00 +#define RF_FRFMSB_434 0x6C +#define RF_FRFMID_434 0x80 +#define RF_FRFLSB_434 0x00 +#define RF_FRFMSB_435 0x6C +#define RF_FRFMID_435 0xC0 +#define RF_FRFLSB_435 0x00 +// 868Mhz band +#define RF_FRFMSB_863 0xD7 +#define RF_FRFMID_863 0xC0 +#define RF_FRFLSB_863 0x00 +#define RF_FRFMSB_864 0xD8 +#define RF_FRFMID_864 0x00 +#define RF_FRFLSB_864 0x00 +#define RF_FRFMSB_865 0xD8 +#define RF_FRFMID_865 0x40 +#define RF_FRFLSB_865 0x00 +#define RF_FRFMSB_866 0xD8 +#define RF_FRFMID_866 0x80 +#define RF_FRFLSB_866 0x00 +#define RF_FRFMSB_867 0xD8 +#define RF_FRFMID_867 0xC0 +#define RF_FRFLSB_867 0x00 +#define RF_FRFMSB_868 0xD9 +#define RF_FRFMID_868 0x00 +#define RF_FRFLSB_868 0x00 +#define RF_FRFMSB_869 0xD9 +#define RF_FRFMID_869 0x40 +#define RF_FRFLSB_869 0x00 +#define RF_FRFMSB_870 0xD9 +#define RF_FRFMID_870 0x80 +#define RF_FRFLSB_870 0x00 +// 915Mhz band +#define RF_FRFMSB_902 0xE1 +#define RF_FRFMID_902 0x80 +#define RF_FRFLSB_902 0x00 +#define RF_FRFMSB_903 0xE1 +#define RF_FRFMID_903 0xC0 +#define RF_FRFLSB_903 0x00 +#define RF_FRFMSB_904 0xE2 +#define RF_FRFMID_904 0x00 +#define RF_FRFLSB_904 0x00 +#define RF_FRFMSB_905 0xE2 +#define RF_FRFMID_905 0x40 +#define RF_FRFLSB_905 0x00 +#define RF_FRFMSB_906 0xE2 +#define RF_FRFMID_906 0x80 +#define RF_FRFLSB_906 0x00 +#define RF_FRFMSB_907 0xE2 +#define RF_FRFMID_907 0xC0 +#define RF_FRFLSB_907 0x00 +#define RF_FRFMSB_908 0xE3 +#define RF_FRFMID_908 0x00 +#define RF_FRFLSB_908 0x00 +#define RF_FRFMSB_909 0xE3 +#define RF_FRFMID_909 0x40 +#define RF_FRFLSB_909 0x00 +#define RF_FRFMSB_910 0xE3 +#define RF_FRFMID_910 0x80 +#define RF_FRFLSB_910 0x00 +#define RF_FRFMSB_911 0xE3 +#define RF_FRFMID_911 0xC0 +#define RF_FRFLSB_911 0x00 +#define RF_FRFMSB_912 0xE4 +#define RF_FRFMID_912 0x00 +#define RF_FRFLSB_912 0x00 +#define RF_FRFMSB_913 0xE4 +#define RF_FRFMID_913 0x40 +#define RF_FRFLSB_913 0x00 +#define RF_FRFMSB_914 0xE4 +#define RF_FRFMID_914 0x80 +#define RF_FRFLSB_914 0x00 +#define RF_FRFMSB_915 0xE4 // Default +#define RF_FRFMID_915 0xC0 // Default +#define RF_FRFLSB_915 0x00 // Default +#define RF_FRFMSB_916 0xE5 +#define RF_FRFMID_916 0x00 +#define RF_FRFLSB_916 0x00 +#define RF_FRFMSB_917 0xE5 +#define RF_FRFMID_917 0x40 +#define RF_FRFLSB_917 0x00 +#define RF_FRFMSB_918 0xE5 +#define RF_FRFMID_918 0x80 +#define RF_FRFLSB_918 0x00 +#define RF_FRFMSB_919 0xE5 +#define RF_FRFMID_919 0xC0 +#define RF_FRFLSB_919 0x00 +#define RF_FRFMSB_920 0xE6 +#define RF_FRFMID_920 0x00 +#define RF_FRFLSB_920 0x00 +#define RF_FRFMSB_921 0xE6 +#define RF_FRFMID_921 0x40 +#define RF_FRFLSB_921 0x00 +#define RF_FRFMSB_922 0xE6 +#define RF_FRFMID_922 0x80 +#define RF_FRFLSB_922 0x00 +#define RF_FRFMSB_923 0xE6 +#define RF_FRFMID_923 0xC0 +#define RF_FRFLSB_923 0x00 +#define RF_FRFMSB_924 0xE7 +#define RF_FRFMID_924 0x00 +#define RF_FRFLSB_924 0x00 +#define RF_FRFMSB_925 0xE7 +#define RF_FRFMID_925 0x40 +#define RF_FRFLSB_925 0x00 +#define RF_FRFMSB_926 0xE7 +#define RF_FRFMID_926 0x80 +#define RF_FRFLSB_926 0x00 +#define RF_FRFMSB_927 0xE7 +#define RF_FRFMID_927 0xC0 +#define RF_FRFLSB_927 0x00 +#define RF_FRFMSB_928 0xE8 +#define RF_FRFMID_928 0x00 +#define RF_FRFLSB_928 0x00 + + +// RegOsc1 +#define RF_OSC1_RCCAL_START 0x80 +#define RF_OSC1_RCCAL_DONE 0x40 + +// RegLowBat +#define RF_LOWBAT_MONITOR 0x10 +#define RF_LOWBAT_ON 0x08 +#define RF_LOWBAT_OFF 0x00 // Default + +#define RF_LOWBAT_TRIM_1695 0x00 +#define RF_LOWBAT_TRIM_1764 0x01 +#define RF_LOWBAT_TRIM_1835 0x02 // Default +#define RF_LOWBAT_TRIM_1905 0x03 +#define RF_LOWBAT_TRIM_1976 0x04 +#define RF_LOWBAT_TRIM_2045 0x05 +#define RF_LOWBAT_TRIM_2116 0x06 +#define RF_LOWBAT_TRIM_2185 0x07 + + +// RegListen1 +#define RF_LISTEN1_RESOL_64 0x50 +#define RF_LISTEN1_RESOL_4100 0xA0 // Default +#define RF_LISTEN1_RESOL_262000 0xF0 + +#define RF_LISTEN1_CRITERIA_RSSI 0x00 // Default +#define RF_LISTEN1_CRITERIA_RSSIANDSYNC 0x08 + +#define RF_LISTEN1_END_00 0x00 +#define RF_LISTEN1_END_01 0x02 // Default +#define RF_LISTEN1_END_10 0x04 + + +// RegListen2 +#define RF_LISTEN2_COEFIDLE_VALUE 0xF5 // Default + +// RegListen3 +#define RF_LISTEN3_COEFRX_VALUE 0x20 // Default + +// RegPaLevel +#define RF_PALEVEL_PA0_ON 0x80 // Default +#define RF_PALEVEL_PA0_OFF 0x00 +#define RF_PALEVEL_PA1_ON 0x40 +#define RF_PALEVEL_PA1_OFF 0x00 // Default +#define RF_PALEVEL_PA2_ON 0x20 +#define RF_PALEVEL_PA2_OFF 0x00 // Default + +#define RF_PALEVEL_OUTPUTPOWER_00000 0x00 +#define RF_PALEVEL_OUTPUTPOWER_00001 0x01 +#define RF_PALEVEL_OUTPUTPOWER_00010 0x02 +#define RF_PALEVEL_OUTPUTPOWER_00011 0x03 +#define RF_PALEVEL_OUTPUTPOWER_00100 0x04 +#define RF_PALEVEL_OUTPUTPOWER_00101 0x05 +#define RF_PALEVEL_OUTPUTPOWER_00110 0x06 +#define RF_PALEVEL_OUTPUTPOWER_00111 0x07 +#define RF_PALEVEL_OUTPUTPOWER_01000 0x08 +#define RF_PALEVEL_OUTPUTPOWER_01001 0x09 +#define RF_PALEVEL_OUTPUTPOWER_01010 0x0A +#define RF_PALEVEL_OUTPUTPOWER_01011 0x0B +#define RF_PALEVEL_OUTPUTPOWER_01100 0x0C +#define RF_PALEVEL_OUTPUTPOWER_01101 0x0D +#define RF_PALEVEL_OUTPUTPOWER_01110 0x0E +#define RF_PALEVEL_OUTPUTPOWER_01111 0x0F +#define RF_PALEVEL_OUTPUTPOWER_10000 0x10 +#define RF_PALEVEL_OUTPUTPOWER_10001 0x11 +#define RF_PALEVEL_OUTPUTPOWER_10010 0x12 +#define RF_PALEVEL_OUTPUTPOWER_10011 0x13 +#define RF_PALEVEL_OUTPUTPOWER_10100 0x14 +#define RF_PALEVEL_OUTPUTPOWER_10101 0x15 +#define RF_PALEVEL_OUTPUTPOWER_10110 0x16 +#define RF_PALEVEL_OUTPUTPOWER_10111 0x17 +#define RF_PALEVEL_OUTPUTPOWER_11000 0x18 +#define RF_PALEVEL_OUTPUTPOWER_11001 0x19 +#define RF_PALEVEL_OUTPUTPOWER_11010 0x1A +#define RF_PALEVEL_OUTPUTPOWER_11011 0x1B +#define RF_PALEVEL_OUTPUTPOWER_11100 0x1C +#define RF_PALEVEL_OUTPUTPOWER_11101 0x1D +#define RF_PALEVEL_OUTPUTPOWER_11110 0x1E +#define RF_PALEVEL_OUTPUTPOWER_11111 0x1F // Default + + +// RegPaRamp +#define RF_PARAMP_3400 0x00 +#define RF_PARAMP_2000 0x01 +#define RF_PARAMP_1000 0x02 +#define RF_PARAMP_500 0x03 +#define RF_PARAMP_250 0x04 +#define RF_PARAMP_125 0x05 +#define RF_PARAMP_100 0x06 +#define RF_PARAMP_62 0x07 +#define RF_PARAMP_50 0x08 +#define RF_PARAMP_40 0x09 // Default +#define RF_PARAMP_31 0x0A +#define RF_PARAMP_25 0x0B +#define RF_PARAMP_20 0x0C +#define RF_PARAMP_15 0x0D +#define RF_PARAMP_12 0x0E +#define RF_PARAMP_10 0x0F + + +// RegOcp +#define RF_OCP_OFF 0x0F +#define RF_OCP_ON 0x1A // Default + +#define RF_OCP_TRIM_45 0x00 +#define RF_OCP_TRIM_50 0x01 +#define RF_OCP_TRIM_55 0x02 +#define RF_OCP_TRIM_60 0x03 +#define RF_OCP_TRIM_65 0x04 +#define RF_OCP_TRIM_70 0x05 +#define RF_OCP_TRIM_75 0x06 +#define RF_OCP_TRIM_80 0x07 +#define RF_OCP_TRIM_85 0x08 +#define RF_OCP_TRIM_90 0x09 +#define RF_OCP_TRIM_95 0x0A +#define RF_OCP_TRIM_100 0x0B // Default +#define RF_OCP_TRIM_105 0x0C +#define RF_OCP_TRIM_110 0x0D +#define RF_OCP_TRIM_115 0x0E +#define RF_OCP_TRIM_120 0x0F + + +// RegAgcRef +#define RF_AGCREF_AUTO_ON 0x40 // Default +#define RF_AGCREF_AUTO_OFF 0x00 + +#define RF_AGCREF_LEVEL_MINUS80 0x00 // Default +#define RF_AGCREF_LEVEL_MINUS81 0x01 +#define RF_AGCREF_LEVEL_MINUS82 0x02 +#define RF_AGCREF_LEVEL_MINUS83 0x03 +#define RF_AGCREF_LEVEL_MINUS84 0x04 +#define RF_AGCREF_LEVEL_MINUS85 0x05 +#define RF_AGCREF_LEVEL_MINUS86 0x06 +#define RF_AGCREF_LEVEL_MINUS87 0x07 +#define RF_AGCREF_LEVEL_MINUS88 0x08 +#define RF_AGCREF_LEVEL_MINUS89 0x09 +#define RF_AGCREF_LEVEL_MINUS90 0x0A +#define RF_AGCREF_LEVEL_MINUS91 0x0B +#define RF_AGCREF_LEVEL_MINUS92 0x0C +#define RF_AGCREF_LEVEL_MINUS93 0x0D +#define RF_AGCREF_LEVEL_MINUS94 0x0E +#define RF_AGCREF_LEVEL_MINUS95 0x0F +#define RF_AGCREF_LEVEL_MINUS96 0x10 +#define RF_AGCREF_LEVEL_MINUS97 0x11 +#define RF_AGCREF_LEVEL_MINUS98 0x12 +#define RF_AGCREF_LEVEL_MINUS99 0x13 +#define RF_AGCREF_LEVEL_MINUS100 0x14 +#define RF_AGCREF_LEVEL_MINUS101 0x15 +#define RF_AGCREF_LEVEL_MINUS102 0x16 +#define RF_AGCREF_LEVEL_MINUS103 0x17 +#define RF_AGCREF_LEVEL_MINUS104 0x18 +#define RF_AGCREF_LEVEL_MINUS105 0x19 +#define RF_AGCREF_LEVEL_MINUS106 0x1A +#define RF_AGCREF_LEVEL_MINUS107 0x1B +#define RF_AGCREF_LEVEL_MINUS108 0x1C +#define RF_AGCREF_LEVEL_MINUS109 0x1D +#define RF_AGCREF_LEVEL_MINUS110 0x1E +#define RF_AGCREF_LEVEL_MINUS111 0x1F +#define RF_AGCREF_LEVEL_MINUS112 0x20 +#define RF_AGCREF_LEVEL_MINUS113 0x21 +#define RF_AGCREF_LEVEL_MINUS114 0x22 +#define RF_AGCREF_LEVEL_MINUS115 0x23 +#define RF_AGCREF_LEVEL_MINUS116 0x24 +#define RF_AGCREF_LEVEL_MINUS117 0x25 +#define RF_AGCREF_LEVEL_MINUS118 0x26 +#define RF_AGCREF_LEVEL_MINUS119 0x27 +#define RF_AGCREF_LEVEL_MINUS120 0x28 +#define RF_AGCREF_LEVEL_MINUS121 0x29 +#define RF_AGCREF_LEVEL_MINUS122 0x2A +#define RF_AGCREF_LEVEL_MINUS123 0x2B +#define RF_AGCREF_LEVEL_MINUS124 0x2C +#define RF_AGCREF_LEVEL_MINUS125 0x2D +#define RF_AGCREF_LEVEL_MINUS126 0x2E +#define RF_AGCREF_LEVEL_MINUS127 0x2F +#define RF_AGCREF_LEVEL_MINUS128 0x30 +#define RF_AGCREF_LEVEL_MINUS129 0x31 +#define RF_AGCREF_LEVEL_MINUS130 0x32 +#define RF_AGCREF_LEVEL_MINUS131 0x33 +#define RF_AGCREF_LEVEL_MINUS132 0x34 +#define RF_AGCREF_LEVEL_MINUS133 0x35 +#define RF_AGCREF_LEVEL_MINUS134 0x36 +#define RF_AGCREF_LEVEL_MINUS135 0x37 +#define RF_AGCREF_LEVEL_MINUS136 0x38 +#define RF_AGCREF_LEVEL_MINUS137 0x39 +#define RF_AGCREF_LEVEL_MINUS138 0x3A +#define RF_AGCREF_LEVEL_MINUS139 0x3B +#define RF_AGCREF_LEVEL_MINUS140 0x3C +#define RF_AGCREF_LEVEL_MINUS141 0x3D +#define RF_AGCREF_LEVEL_MINUS142 0x3E +#define RF_AGCREF_LEVEL_MINUS143 0x3F + + +// RegAgcThresh1 +#define RF_AGCTHRESH1_SNRMARGIN_000 0x00 +#define RF_AGCTHRESH1_SNRMARGIN_001 0x20 +#define RF_AGCTHRESH1_SNRMARGIN_010 0x40 +#define RF_AGCTHRESH1_SNRMARGIN_011 0x60 +#define RF_AGCTHRESH1_SNRMARGIN_100 0x80 +#define RF_AGCTHRESH1_SNRMARGIN_101 0xA0 // Default +#define RF_AGCTHRESH1_SNRMARGIN_110 0xC0 +#define RF_AGCTHRESH1_SNRMARGIN_111 0xE0 + +#define RF_AGCTHRESH1_STEP1_0 0x00 +#define RF_AGCTHRESH1_STEP1_1 0x01 +#define RF_AGCTHRESH1_STEP1_2 0x02 +#define RF_AGCTHRESH1_STEP1_3 0x03 +#define RF_AGCTHRESH1_STEP1_4 0x04 +#define RF_AGCTHRESH1_STEP1_5 0x05 +#define RF_AGCTHRESH1_STEP1_6 0x06 +#define RF_AGCTHRESH1_STEP1_7 0x07 +#define RF_AGCTHRESH1_STEP1_8 0x08 +#define RF_AGCTHRESH1_STEP1_9 0x09 +#define RF_AGCTHRESH1_STEP1_10 0x0A +#define RF_AGCTHRESH1_STEP1_11 0x0B +#define RF_AGCTHRESH1_STEP1_12 0x0C +#define RF_AGCTHRESH1_STEP1_13 0x0D +#define RF_AGCTHRESH1_STEP1_14 0x0E +#define RF_AGCTHRESH1_STEP1_15 0x0F +#define RF_AGCTHRESH1_STEP1_16 0x10 // Default +#define RF_AGCTHRESH1_STEP1_17 0x11 +#define RF_AGCTHRESH1_STEP1_18 0x12 +#define RF_AGCTHRESH1_STEP1_19 0x13 +#define RF_AGCTHRESH1_STEP1_20 0x14 +#define RF_AGCTHRESH1_STEP1_21 0x15 +#define RF_AGCTHRESH1_STEP1_22 0x16 +#define RF_AGCTHRESH1_STEP1_23 0x17 +#define RF_AGCTHRESH1_STEP1_24 0x18 +#define RF_AGCTHRESH1_STEP1_25 0x19 +#define RF_AGCTHRESH1_STEP1_26 0x1A +#define RF_AGCTHRESH1_STEP1_27 0x1B +#define RF_AGCTHRESH1_STEP1_28 0x1C +#define RF_AGCTHRESH1_STEP1_29 0x1D +#define RF_AGCTHRESH1_STEP1_30 0x1E +#define RF_AGCTHRESH1_STEP1_31 0x1F + + +// RegAgcThresh2 +#define RF_AGCTHRESH2_STEP2_0 0x00 +#define RF_AGCTHRESH2_STEP2_1 0x10 +#define RF_AGCTHRESH2_STEP2_2 0x20 +#define RF_AGCTHRESH2_STEP2_3 0x30 // XXX wrong -- Default +#define RF_AGCTHRESH2_STEP2_4 0x40 +#define RF_AGCTHRESH2_STEP2_5 0x50 +#define RF_AGCTHRESH2_STEP2_6 0x60 +#define RF_AGCTHRESH2_STEP2_7 0x70 // default +#define RF_AGCTHRESH2_STEP2_8 0x80 +#define RF_AGCTHRESH2_STEP2_9 0x90 +#define RF_AGCTHRESH2_STEP2_10 0xA0 +#define RF_AGCTHRESH2_STEP2_11 0xB0 +#define RF_AGCTHRESH2_STEP2_12 0xC0 +#define RF_AGCTHRESH2_STEP2_13 0xD0 +#define RF_AGCTHRESH2_STEP2_14 0xE0 +#define RF_AGCTHRESH2_STEP2_15 0xF0 + +#define RF_AGCTHRESH2_STEP3_0 0x00 +#define RF_AGCTHRESH2_STEP3_1 0x01 +#define RF_AGCTHRESH2_STEP3_2 0x02 +#define RF_AGCTHRESH2_STEP3_3 0x03 +#define RF_AGCTHRESH2_STEP3_4 0x04 +#define RF_AGCTHRESH2_STEP3_5 0x05 +#define RF_AGCTHRESH2_STEP3_6 0x06 +#define RF_AGCTHRESH2_STEP3_7 0x07 +#define RF_AGCTHRESH2_STEP3_8 0x08 +#define RF_AGCTHRESH2_STEP3_9 0x09 +#define RF_AGCTHRESH2_STEP3_10 0x0A +#define RF_AGCTHRESH2_STEP3_11 0x0B // Default +#define RF_AGCTHRESH2_STEP3_12 0x0C +#define RF_AGCTHRESH2_STEP3_13 0x0D +#define RF_AGCTHRESH2_STEP3_14 0x0E +#define RF_AGCTHRESH2_STEP3_15 0x0F + + +// RegAgcThresh3 +#define RF_AGCTHRESH3_STEP4_0 0x00 +#define RF_AGCTHRESH3_STEP4_1 0x10 +#define RF_AGCTHRESH3_STEP4_2 0x20 +#define RF_AGCTHRESH3_STEP4_3 0x30 +#define RF_AGCTHRESH3_STEP4_4 0x40 +#define RF_AGCTHRESH3_STEP4_5 0x50 +#define RF_AGCTHRESH3_STEP4_6 0x60 +#define RF_AGCTHRESH3_STEP4_7 0x70 +#define RF_AGCTHRESH3_STEP4_8 0x80 +#define RF_AGCTHRESH3_STEP4_9 0x90 // Default +#define RF_AGCTHRESH3_STEP4_10 0xA0 +#define RF_AGCTHRESH3_STEP4_11 0xB0 +#define RF_AGCTHRESH3_STEP4_12 0xC0 +#define RF_AGCTHRESH3_STEP4_13 0xD0 +#define RF_AGCTHRESH3_STEP4_14 0xE0 +#define RF_AGCTHRESH3_STEP4_15 0xF0 + +#define RF_AGCTHRESH3_STEP5_0 0x00 +#define RF_AGCTHRESH3_STEP5_1 0x01 +#define RF_AGCTHRESH3_STEP5_2 0x02 +#define RF_AGCTHRESH3_STEP5_3 0x03 +#define RF_AGCTHRESH3_STEP5_4 0x04 +#define RF_AGCTHRESH3_STEP5_5 0x05 +#define RF_AGCTHRESH3_STEP5_6 0x06 +#define RF_AGCTHRESH3_STEP5_7 0x07 +#define RF_AGCTHRES33_STEP5_8 0x08 +#define RF_AGCTHRESH3_STEP5_9 0x09 +#define RF_AGCTHRESH3_STEP5_10 0x0A +#define RF_AGCTHRESH3_STEP5_11 0x0B // Default +#define RF_AGCTHRESH3_STEP5_12 0x0C +#define RF_AGCTHRESH3_STEP5_13 0x0D +#define RF_AGCTHRESH3_STEP5_14 0x0E +#define RF_AGCTHRESH3_STEP5_15 0x0F + + +// RegLna +#define RF_LNA_ZIN_50 0x00 +#define RF_LNA_ZIN_200 0x80 // Default + +#define RF_LNA_LOWPOWER_OFF 0x00 // Default +#define RF_LNA_LOWPOWER_ON 0x40 + +#define RF_LNA_CURRENTGAIN 0x08 + +#define RF_LNA_GAINSELECT_AUTO 0x00 // Default +#define RF_LNA_GAINSELECT_MAX 0x01 +#define RF_LNA_GAINSELECT_MAXMINUS6 0x02 +#define RF_LNA_GAINSELECT_MAXMINUS12 0x03 +#define RF_LNA_GAINSELECT_MAXMINUS24 0x04 +#define RF_LNA_GAINSELECT_MAXMINUS36 0x05 +#define RF_LNA_GAINSELECT_MAXMINUS48 0x06 + + +// RegRxBw +#define RF_RXBW_DCCFREQ_000 0x00 +#define RF_RXBW_DCCFREQ_001 0x20 +#define RF_RXBW_DCCFREQ_010 0x40 // Default +#define RF_RXBW_DCCFREQ_011 0x60 +#define RF_RXBW_DCCFREQ_100 0x80 +#define RF_RXBW_DCCFREQ_101 0xA0 +#define RF_RXBW_DCCFREQ_110 0xC0 +#define RF_RXBW_DCCFREQ_111 0xE0 + +#define RF_RXBW_MANT_16 0x00 +#define RF_RXBW_MANT_20 0x08 +#define RF_RXBW_MANT_24 0x10 // Default + +#define RF_RXBW_EXP_0 0x00 +#define RF_RXBW_EXP_1 0x01 +#define RF_RXBW_EXP_2 0x02 +#define RF_RXBW_EXP_3 0x03 +#define RF_RXBW_EXP_4 0x04 +#define RF_RXBW_EXP_5 0x05 // Default +#define RF_RXBW_EXP_6 0x06 +#define RF_RXBW_EXP_7 0x07 + + +// RegAfcBw +#define RF_AFCBW_DCCFREQAFC_000 0x00 +#define RF_AFCBW_DCCFREQAFC_001 0x20 +#define RF_AFCBW_DCCFREQAFC_010 0x40 +#define RF_AFCBW_DCCFREQAFC_011 0x60 +#define RF_AFCBW_DCCFREQAFC_100 0x80 // Default +#define RF_AFCBW_DCCFREQAFC_101 0xA0 +#define RF_AFCBW_DCCFREQAFC_110 0xC0 +#define RF_AFCBW_DCCFREQAFC_111 0xE0 + +#define RF_AFCBW_MANTAFC_16 0x00 +#define RF_AFCBW_MANTAFC_20 0x08 // Default +#define RF_AFCBW_MANTAFC_24 0x10 + +#define RF_AFCBW_EXPAFC_0 0x00 +#define RF_AFCBW_EXPAFC_1 0x01 +#define RF_AFCBW_EXPAFC_2 0x02 +#define RF_AFCBW_EXPAFC_3 0x03 // Default +#define RF_AFCBW_EXPAFC_4 0x04 +#define RF_AFCBW_EXPAFC_5 0x05 +#define RF_AFCBW_EXPAFC_6 0x06 +#define RF_AFCBW_EXPAFC_7 0x07 + + +// RegOokPeak +#define RF_OOKPEAK_THRESHTYPE_FIXED 0x00 +#define RF_OOKPEAK_THRESHTYPE_PEAK 0x40 // Default +#define RF_OOKPEAK_THRESHTYPE_AVERAGE 0x80 + +#define RF_OOKPEAK_PEAKTHRESHSTEP_000 0x00 // Default +#define RF_OOKPEAK_PEAKTHRESHSTEP_001 0x08 +#define RF_OOKPEAK_PEAKTHRESHSTEP_010 0x10 +#define RF_OOKPEAK_PEAKTHRESHSTEP_011 0x18 +#define RF_OOKPEAK_PEAKTHRESHSTEP_100 0x20 +#define RF_OOKPEAK_PEAKTHRESHSTEP_101 0x28 +#define RF_OOKPEAK_PEAKTHRESHSTEP_110 0x30 +#define RF_OOKPEAK_PEAKTHRESHSTEP_111 0x38 + +#define RF_OOKPEAK_PEAKTHRESHDEC_000 0x00 // Default +#define RF_OOKPEAK_PEAKTHRESHDEC_001 0x01 +#define RF_OOKPEAK_PEAKTHRESHDEC_010 0x02 +#define RF_OOKPEAK_PEAKTHRESHDEC_011 0x03 +#define RF_OOKPEAK_PEAKTHRESHDEC_100 0x04 +#define RF_OOKPEAK_PEAKTHRESHDEC_101 0x05 +#define RF_OOKPEAK_PEAKTHRESHDEC_110 0x06 +#define RF_OOKPEAK_PEAKTHRESHDEC_111 0x07 + + +// RegOokAvg +#define RF_OOKAVG_AVERAGETHRESHFILT_00 0x00 +#define RF_OOKAVG_AVERAGETHRESHFILT_01 0x40 +#define RF_OOKAVG_AVERAGETHRESHFILT_10 0x80 // Default +#define RF_OOKAVG_AVERAGETHRESHFILT_11 0xC0 + + +// RegOokFix +#define RF_OOKFIX_FIXEDTHRESH_VALUE 0x06 // Default + + +// RegAfcFei +#define RF_AFCFEI_FEI_DONE 0x40 +#define RF_AFCFEI_FEI_START 0x20 +#define RF_AFCFEI_AFC_DONE 0x10 +#define RF_AFCFEI_AFCAUTOCLEAR_ON 0x08 +#define RF_AFCFEI_AFCAUTOCLEAR_OFF 0x00 // Default + +#define RF_AFCFEI_AFCAUTO_ON 0x04 +#define RF_AFCFEI_AFCAUTO_OFF 0x00 // Default + +#define RF_AFCFEI_AFC_CLEAR 0x02 +#define RF_AFCFEI_AFC_START 0x01 + +// RegRssiConfig +#define RF_RSSI_FASTRX_ON 0x08 +#define RF_RSSI_FASTRX_OFF 0x00 // Default +#define RF_RSSI_DONE 0x02 +#define RF_RSSI_START 0x01 + + +// RegDioMapping1 +#define RF_DIOMAPPING1_DIO0_00 0x00 // Default +#define RF_DIOMAPPING1_DIO0_01 0x40 +#define RF_DIOMAPPING1_DIO0_10 0x80 +#define RF_DIOMAPPING1_DIO0_11 0xC0 + +#define RF_DIOMAPPING1_DIO1_00 0x00 // Default +#define RF_DIOMAPPING1_DIO1_01 0x10 +#define RF_DIOMAPPING1_DIO1_10 0x20 +#define RF_DIOMAPPING1_DIO1_11 0x30 + +#define RF_DIOMAPPING1_DIO2_00 0x00 // Default +#define RF_DIOMAPPING1_DIO2_01 0x04 +#define RF_DIOMAPPING1_DIO2_10 0x08 +#define RF_DIOMAPPING1_DIO2_11 0x0C + +#define RF_DIOMAPPING1_DIO3_00 0x00 // Default +#define RF_DIOMAPPING1_DIO3_01 0x01 +#define RF_DIOMAPPING1_DIO3_10 0x02 +#define RF_DIOMAPPING1_DIO3_11 0x03 + + +// RegDioMapping2 +#define RF_DIOMAPPING2_DIO4_00 0x00 // Default +#define RF_DIOMAPPING2_DIO4_01 0x40 +#define RF_DIOMAPPING2_DIO4_10 0x80 +#define RF_DIOMAPPING2_DIO4_11 0xC0 + +#define RF_DIOMAPPING2_DIO5_00 0x00 // Default +#define RF_DIOMAPPING2_DIO5_01 0x10 +#define RF_DIOMAPPING2_DIO5_10 0x20 +#define RF_DIOMAPPING2_DIO5_11 0x30 + +#define RF_DIOMAPPING2_CLKOUT_32 0x00 +#define RF_DIOMAPPING2_CLKOUT_16 0x01 +#define RF_DIOMAPPING2_CLKOUT_8 0x02 +#define RF_DIOMAPPING2_CLKOUT_4 0x03 +#define RF_DIOMAPPING2_CLKOUT_2 0x04 +#define RF_DIOMAPPING2_CLKOUT_1 0x05 +#define RF_DIOMAPPING2_CLKOUT_RC 0x06 +#define RF_DIOMAPPING2_CLKOUT_OFF 0x07 // Default + + +// RegIrqFlags1 +#define RF_IRQFLAGS1_MODEREADY 0x80 +#define RF_IRQFLAGS1_RXREADY 0x40 +#define RF_IRQFLAGS1_TXREADY 0x20 +#define RF_IRQFLAGS1_PLLLOCK 0x10 +#define RF_IRQFLAGS1_RSSI 0x08 +#define RF_IRQFLAGS1_TIMEOUT 0x04 +#define RF_IRQFLAGS1_AUTOMODE 0x02 +#define RF_IRQFLAGS1_SYNCADDRESSMATCH 0x01 + +// RegIrqFlags2 +#define RF_IRQFLAGS2_FIFOFULL 0x80 +#define RF_IRQFLAGS2_FIFONOTEMPTY 0x40 +#define RF_IRQFLAGS2_FIFOLEVEL 0x20 +#define RF_IRQFLAGS2_FIFOOVERRUN 0x10 +#define RF_IRQFLAGS2_PACKETSENT 0x08 +#define RF_IRQFLAGS2_PAYLOADREADY 0x04 +#define RF_IRQFLAGS2_CRCOK 0x02 +#define RF_IRQFLAGS2_LOWBAT 0x01 + +// RegRssiThresh +#define RF_RSSITHRESH_VALUE 0xE4 // Default + +// RegRxTimeout1 +#define RF_RXTIMEOUT1_RXSTART_VALUE 0x00 // Default + +// RegRxTimeout2 +#define RF_RXTIMEOUT2_RSSITHRESH_VALUE 0x00 // Default + +// RegPreamble +#define RF_PREAMBLESIZE_MSB_VALUE 0x00 // Default +#define RF_PREAMBLESIZE_LSB_VALUE 0x03 // Default + + +// RegSyncConfig +#define RF_SYNC_ON 0x80 // Default +#define RF_SYNC_OFF 0x00 + +#define RF_SYNC_FIFOFILL_AUTO 0x00 // Default -- when sync interrupt occurs +#define RF_SYNC_FIFOFILL_MANUAL 0x40 + +#define RF_SYNC_SIZE_1 0x00 +#define RF_SYNC_SIZE_2 0x08 +#define RF_SYNC_SIZE_3 0x10 +#define RF_SYNC_SIZE_4 0x18 // Default +#define RF_SYNC_SIZE_5 0x20 +#define RF_SYNC_SIZE_6 0x28 +#define RF_SYNC_SIZE_7 0x30 +#define RF_SYNC_SIZE_8 0x38 + +#define RF_SYNC_TOL_0 0x00 // Default +#define RF_SYNC_TOL_1 0x01 +#define RF_SYNC_TOL_2 0x02 +#define RF_SYNC_TOL_3 0x03 +#define RF_SYNC_TOL_4 0x04 +#define RF_SYNC_TOL_5 0x05 +#define RF_SYNC_TOL_6 0x06 +#define RF_SYNC_TOL_7 0x07 + + +// RegSyncValue1-8 +#define RF_SYNC_BYTE1_VALUE 0x00 // Default +#define RF_SYNC_BYTE2_VALUE 0x00 // Default +#define RF_SYNC_BYTE3_VALUE 0x00 // Default +#define RF_SYNC_BYTE4_VALUE 0x00 // Default +#define RF_SYNC_BYTE5_VALUE 0x00 // Default +#define RF_SYNC_BYTE6_VALUE 0x00 // Default +#define RF_SYNC_BYTE7_VALUE 0x00 // Default +#define RF_SYNC_BYTE8_VALUE 0x00 // Default + + +// RegPacketConfig1 +#define RF_PACKET1_FORMAT_FIXED 0x00 // Default +#define RF_PACKET1_FORMAT_VARIABLE 0x80 + +#define RF_PACKET1_DCFREE_OFF 0x00 // Default +#define RF_PACKET1_DCFREE_MANCHESTER 0x20 +#define RF_PACKET1_DCFREE_WHITENING 0x40 + +#define RF_PACKET1_CRC_ON 0x10 // Default +#define RF_PACKET1_CRC_OFF 0x00 + +#define RF_PACKET1_CRCAUTOCLEAR_ON 0x00 // Default +#define RF_PACKET1_CRCAUTOCLEAR_OFF 0x08 + +#define RF_PACKET1_ADRSFILTERING_OFF 0x00 // Default +#define RF_PACKET1_ADRSFILTERING_NODE 0x02 +#define RF_PACKET1_ADRSFILTERING_NODEBROADCAST 0x04 + + +// RegPayloadLength +#define RF_PAYLOADLENGTH_VALUE 0x40 // Default + +// RegBroadcastAdrs +#define RF_BROADCASTADDRESS_VALUE 0x00 + + +// RegAutoModes +#define RF_AUTOMODES_ENTER_OFF 0x00 // Default +#define RF_AUTOMODES_ENTER_FIFONOTEMPTY 0x20 +#define RF_AUTOMODES_ENTER_FIFOLEVEL 0x40 +#define RF_AUTOMODES_ENTER_CRCOK 0x60 +#define RF_AUTOMODES_ENTER_PAYLOADREADY 0x80 +#define RF_AUTOMODES_ENTER_SYNCADRSMATCH 0xA0 +#define RF_AUTOMODES_ENTER_PACKETSENT 0xC0 +#define RF_AUTOMODES_ENTER_FIFOEMPTY 0xE0 + +#define RF_AUTOMODES_EXIT_OFF 0x00 // Default +#define RF_AUTOMODES_EXIT_FIFOEMPTY 0x04 +#define RF_AUTOMODES_EXIT_FIFOLEVEL 0x08 +#define RF_AUTOMODES_EXIT_CRCOK 0x0C +#define RF_AUTOMODES_EXIT_PAYLOADREADY 0x10 +#define RF_AUTOMODES_EXIT_SYNCADRSMATCH 0x14 +#define RF_AUTOMODES_EXIT_PACKETSENT 0x18 +#define RF_AUTOMODES_EXIT_RXTIMEOUT 0x1C + +#define RF_AUTOMODES_INTERMEDIATE_SLEEP 0x00 // Default +#define RF_AUTOMODES_INTERMEDIATE_STANDBY 0x01 +#define RF_AUTOMODES_INTERMEDIATE_RECEIVER 0x02 +#define RF_AUTOMODES_INTERMEDIATE_TRANSMITTER 0x03 + + +// RegFifoThresh +#define RF_FIFOTHRESH_TXSTART_FIFOTHRESH 0x00 +#define RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY 0x80 // Default + +#define RF_FIFOTHRESH_VALUE 0x0F // Default + + +// RegPacketConfig2 +#define RF_PACKET2_RXRESTARTDELAY_1BIT 0x00 // Default +#define RF_PACKET2_RXRESTARTDELAY_2BITS 0x10 +#define RF_PACKET2_RXRESTARTDELAY_4BITS 0x20 +#define RF_PACKET2_RXRESTARTDELAY_8BITS 0x30 +#define RF_PACKET2_RXRESTARTDELAY_16BITS 0x40 +#define RF_PACKET2_RXRESTARTDELAY_32BITS 0x50 +#define RF_PACKET2_RXRESTARTDELAY_64BITS 0x60 +#define RF_PACKET2_RXRESTARTDELAY_128BITS 0x70 +#define RF_PACKET2_RXRESTARTDELAY_256BITS 0x80 +#define RF_PACKET2_RXRESTARTDELAY_512BITS 0x90 +#define RF_PACKET2_RXRESTARTDELAY_1024BITS 0xA0 +#define RF_PACKET2_RXRESTARTDELAY_2048BITS 0xB0 +#define RF_PACKET2_RXRESTARTDELAY_NONE 0xC0 +#define RF_PACKET2_RXRESTART 0x04 + +#define RF_PACKET2_AUTORXRESTART_ON 0x02 // Default +#define RF_PACKET2_AUTORXRESTART_OFF 0x00 + +#define RF_PACKET2_AES_ON 0x01 +#define RF_PACKET2_AES_OFF 0x00 // Default + + +// RegAesKey1-16 +#define RF_AESKEY1_VALUE 0x00 // Default +#define RF_AESKEY2_VALUE 0x00 // Default +#define RF_AESKEY3_VALUE 0x00 // Default +#define RF_AESKEY4_VALUE 0x00 // Default +#define RF_AESKEY5_VALUE 0x00 // Default +#define RF_AESKEY6_VALUE 0x00 // Default +#define RF_AESKEY7_VALUE 0x00 // Default +#define RF_AESKEY8_VALUE 0x00 // Default +#define RF_AESKEY9_VALUE 0x00 // Default +#define RF_AESKEY10_VALUE 0x00 // Default +#define RF_AESKEY11_VALUE 0x00 // Default +#define RF_AESKEY12_VALUE 0x00 // Default +#define RF_AESKEY13_VALUE 0x00 // Default +#define RF_AESKEY14_VALUE 0x00 // Default +#define RF_AESKEY15_VALUE 0x00 // Default +#define RF_AESKEY16_VALUE 0x00 // Default + + +// RegTemp1 +#define RF_TEMP1_MEAS_START 0x08 +#define RF_TEMP1_MEAS_RUNNING 0x04 +#define RF_TEMP1_ADCLOWPOWER_ON 0x01 // Default +#define RF_TEMP1_ADCLOWPOWER_OFF 0x00 + +// RegTestDagc 0x6F: demodulator config and IO mode config +#define RF_DAGC_NORMAL 0x00 // Reset value +#define RF_DAGC_IMPROVED_LOWBETA1 0x20 // +#define RF_DAGC_IMPROVED_LOWBETA0 0x30 // Recommended default + From f143fcd7a2d2e6f093cb11908ef72fc439a05987 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 3 Nov 2014 20:08:56 +0100 Subject: [PATCH 024/660] Moved RFM69 library to utility --- libraries/MySensors/MyDriverRF69.cpp | 1 - libraries/MySensors/MyDriverRF69.h | 4 ++-- libraries/MySensors/{ => utility}/RFM69.cpp | 6 +++--- libraries/MySensors/{ => utility}/RFM69.h | 0 libraries/MySensors/{ => utility}/RFM69registers.h | 0 5 files changed, 5 insertions(+), 6 deletions(-) rename libraries/MySensors/{ => utility}/RFM69.cpp (99%) rename libraries/MySensors/{ => utility}/RFM69.h (100%) rename libraries/MySensors/{ => utility}/RFM69registers.h (100%) diff --git a/libraries/MySensors/MyDriverRF69.cpp b/libraries/MySensors/MyDriverRF69.cpp index 126e364..2363da7 100644 --- a/libraries/MySensors/MyDriverRF69.cpp +++ b/libraries/MySensors/MyDriverRF69.cpp @@ -1,4 +1,3 @@ -#include #include "MyDriver.h" #include "MyDriverRF69.h" diff --git a/libraries/MySensors/MyDriverRF69.h b/libraries/MySensors/MyDriverRF69.h index 4c53786..6b14772 100644 --- a/libraries/MySensors/MyDriverRF69.h +++ b/libraries/MySensors/MyDriverRF69.h @@ -4,7 +4,7 @@ #include "MyConfig.h" #include "MyDriver.h" #include -#include "RFM69.h" +#include "utility/RFM69.h" #include #define NODEID 2 //unique for each node on same network @@ -41,4 +41,4 @@ private: uint8_t _address; }; -#endif \ No newline at end of file +#endif diff --git a/libraries/MySensors/RFM69.cpp b/libraries/MySensors/utility/RFM69.cpp similarity index 99% rename from libraries/MySensors/RFM69.cpp rename to libraries/MySensors/utility/RFM69.cpp index 8b0305f..24bb2d3 100644 --- a/libraries/MySensors/RFM69.cpp +++ b/libraries/MySensors/utility/RFM69.cpp @@ -29,8 +29,8 @@ // Please maintain this license information along with authorship // and copyright notices in any redistribution of this code // ********************************************************************************** -#include -#include +#include "RFM69.h" +#include "RFM69registers.h" #include volatile byte RFM69::DATA[RF69_MAX_DATA_LEN]; @@ -461,4 +461,4 @@ void RFM69::rcCalibration() { writeReg(REG_OSC1, RF_OSC1_RCCAL_START); while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); -} \ No newline at end of file +} diff --git a/libraries/MySensors/RFM69.h b/libraries/MySensors/utility/RFM69.h similarity index 100% rename from libraries/MySensors/RFM69.h rename to libraries/MySensors/utility/RFM69.h diff --git a/libraries/MySensors/RFM69registers.h b/libraries/MySensors/utility/RFM69registers.h similarity index 100% rename from libraries/MySensors/RFM69registers.h rename to libraries/MySensors/utility/RFM69registers.h From 9fd41b403064dd8c0d1c06f536ec8b1d5bb4229d Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 10 Jan 2015 12:30:10 +0100 Subject: [PATCH 025/660] Added sha204 library Taken from the sha204_library folder in https://github.com/jimblom/sha204-Breakout Commit 8e1ac05ef987b1869605ad067db2bdbaec1c109f ATSHA204 is a crypto cirquit from Atmel that enables SHA256-based MAC and HMAC calculations as well as secure key storage and random number generation. This can be used to sign messages passed between sensor nodes and prevent both man-in-the-middle and replay attacking. --- .../atsha204_simple_example.ino | 103 +++ .../sha204_includes/sha204_lib_return_codes.h | 48 ++ libraries/sha204/sha204_library.cpp | 809 ++++++++++++++++++ libraries/sha204/sha204_library.h | 320 +++++++ 4 files changed, 1280 insertions(+) create mode 100644 libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino create mode 100644 libraries/sha204/sha204_includes/sha204_lib_return_codes.h create mode 100644 libraries/sha204/sha204_library.cpp create mode 100644 libraries/sha204/sha204_library.h diff --git a/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino b/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino new file mode 100644 index 0000000..b55ce49 --- /dev/null +++ b/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino @@ -0,0 +1,103 @@ +/* ATSHA204 Library Simple Example + by: Jim Lindblom + SparkFun Electronics + date: November 8, 2012 + + This code shows how to wake up and verify that an SHA204 is + connected and operational. And how to obtain an SHA204's unique serial + number, and send it a MAC challenge. + + The ATSHA204's SDA pin can be connected to any of the Arduino's digital pins. + When constructing your atsha204Class, pass the constructor the pin you want to use. + In this example we'll attach SDA to pin 7. + + The ATSHA204 can be powered between 3.3V and 5V. +*/ +#include + +const int sha204Pin = 7; + +atsha204Class sha204(sha204Pin); + +void setup() +{ + Serial.begin(9600); + Serial.println("Sending a Wakup Command. Response should be:\r\n4 11 33 43:"); + Serial.println("Response is:"); + wakeupExample(); + Serial.println(); + Serial.println("Asking the SHA204's serial number. Response should be:"); + Serial.println("1 23 x x x x x x x EE"); + Serial.println("Response is:"); + serialNumberExample(); + Serial.println(); + Serial.println("Sending a MAC Challenge. Response should be:"); + Serial.println("23 6 67 0 4F 28 4D 6E 98 62 4 F4 60 A3 E8 75 8A 59 85 A6 79 96 C4 8A 88 46 43 4E B3 DB 58 A4 FB E5 73"); + Serial.println("Response is:"); + macChallengeExample(); +} + +void loop() +{ +} + +byte wakeupExample() +{ + uint8_t response[SHA204_RSP_SIZE_MIN]; + byte returnValue; + + returnValue = sha204.sha204c_wakeup(&response[0]); + for (int i=0; i // data type definitions + +/** \todo Use same values for same meanings for SHA204 and AES132. + * */ + +#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded. +#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error +#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error +#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error +#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown +#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state. +#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error +#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.) +#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set +#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size. +#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received +#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0. +#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response. +#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up + +#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules. +#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0. + +#endif diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp new file mode 100644 index 0000000..075242f --- /dev/null +++ b/libraries/sha204/sha204_library.cpp @@ -0,0 +1,809 @@ +#include "Arduino.h" +#include "sha204_library.h" +#include "sha204_includes/sha204_lib_return_codes.h" + + +// atsha204Class Constructor +// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin +// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin +// As well as the bit value for each of those registers +atsha204Class::atsha204Class(uint8_t pin) +{ + device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin + uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers + + // Point to data direction register port of pin + device_port_DDR = portModeRegister(port); + // Point to output register of pin + device_port_OUT = portOutputRegister(port); + // Point to input register of pin + device_port_IN = portInputRegister(port); +} + +/* Puts a the ATSHA204's unique, 4-byte serial number in the response array + returns an SHA204 Return code */ +uint8_t atsha204Class::getSerialNumber(uint8_t * response) +{ + uint8_t readCommand[READ_COUNT]; + uint8_t readResponse[READ_4_RSP_SIZE]; + + /* read from bytes 0->3 of config zone */ + uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + if (!returnCode) // should return 0 if successful + { + for (int i=0; i<4; i++) // store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + + /* read from bytes 8->11 of config zone */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + + for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + + if (!returnCode) + { /* Finally if last two reads were successful, read byte 8 of the SN */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE + } + } + + return returnCode; +} + +/* SWI bit bang functions */ + +void atsha204Class::swi_set_signal_pin(uint8_t is_high) +{ + *device_port_DDR |= device_pin; + + if (is_high) + *device_port_OUT |= device_pin; + else + *device_port_OUT &= ~device_pin; +} + +uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + *device_port_OUT |= device_pin; + *device_port_DDR |= device_pin; + + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + if (bit_mask & buffer[i]) + { + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } + else + { + // Send a zero bit. + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; +} + +uint8_t atsha204Class::swi_send_byte(uint8_t value) +{ + return swi_send_bytes(1, &value); +} + +uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input. + *device_port_DDR &= ~device_pin; + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) + { + // Wait for falling edge. + if ((*device_port_IN & device_pin) == 0) + break; + } + + if (timeout_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do + { + // Wait for rising edge. + if ((*device_port_IN & device_pin) != 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do + { + if ((*device_port_IN & device_pin) == 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) + { + do + { + if ((*device_port_IN & device_pin) != 0) + break; + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else + buffer[i] |= bit_mask; // received "one" bit + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) + break; + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) + { + if (i > 0) + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + return status; +} + +/* Physical functions */ + +uint8_t atsha204Class::sha204p_wakeup() +{ + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); + + return SHA204_SUCCESS; +} + +uint8_t atsha204Class::sha204p_sleep() +{ + return swi_send_byte(SHA204_SWI_FLAG_SLEEP); +} + +uint8_t atsha204Class::sha204p_resync(uint8_t size, uint8_t *response) +{ + delay(SHA204_SYNC_TIMEOUT); + return sha204p_receive_response(size, response); +} + +uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) +{ + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) + response[i] = 0; + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) + { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) + return SHA204_INVALID_SIZE; + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) + return SHA204_RX_NO_RESPONSE; + else + return SHA204_RX_FAIL; +} + +uint8_t atsha204Class::sha204p_send_command(uint8_t count, uint8_t * command) +{ + uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) + return SHA204_COMM_FAIL; + + return swi_send_bytes(count, command); +} + +/* Communication functions */ + +uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) +{ + uint8_t ret_code = sha204p_wakeup(); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) + ret_code = SHA204_INVALID_SIZE; + else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) + ret_code = SHA204_COMM_FAIL; + else + { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) + ret_code = SHA204_BAD_CRC; + } + if (ret_code != SHA204_SUCCESS) + delay(SHA204_COMMAND_EXEC_MAX); + + return ret_code; +} + +uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) +{ + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + uint8_t ret_code = sha204p_resync(size, response); + if (ret_code == SHA204_SUCCESS) + return ret_code; + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + (void) sha204p_sleep(); + ret_code = sha204c_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); +} + +uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +{ + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) + { + // Send command. + ret_code = sha204p_send_command(count, tx_buffer); + if (ret_code != SHA204_SUCCESS) + { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + return ret_code; // The device seems to be dead in the water. + else + continue; + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) + { + // Reset response buffer. + for (i = 0; i < rx_size; i++) + rx_buffer[i] = 0; + + // Poll for response. + timeout_countdown = execution_timeout_us; + do + { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } + while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) + { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + // The device seems to be dead in the water. + return ret_code; + else + break; + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) + { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) + { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + // Received non-status response. We are done. + return ret_code; + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) + return SHA204_PARSE_ERROR; + if (status_byte == SHA204_STATUS_BYTE_EXEC) + return SHA204_CMD_FAIL; + if (status_byte == SHA204_STATUS_BYTE_COMM) + { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else + { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; +} + + +/* Marshaling functions */ + +uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode) +{ + if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE)) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM; + tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE; + + tx_buffer[RANDOM_PARAM2_IDX] = + tx_buffer[RANDOM_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY); +} + +uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer) +{ + if (!tx_buffer || !rx_buffer) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV; + + // Parameters are 0. + tx_buffer[DEVREV_PARAM1_IDX] = + tx_buffer[DEVREV_PARAM2_IDX] = + tx_buffer[DEVREV_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0], + DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY); +} + +uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +{ + uint8_t rx_size; + + if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0) + || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + + address >>= 2; + if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) + { + if (address > SHA204_ADDRESS_MASK_CONFIG) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) + { + if (address > SHA204_ADDRESS_MASK_OTP) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) + { + if (address > SHA204_ADDRESS_MASK) + return SHA204_BAD_PARAM; + } + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); +} + +uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ + uint8_t poll_delay, poll_timeout, response_size; + uint8_t *p_buffer; + uint8_t len; + + uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2, + datalen1, data1, datalen2, data2, datalen3, data3, + tx_size, tx_buffer, rx_size, rx_buffer); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Supply delays and response size. + switch (op_code) + { + case SHA204_CHECKMAC: + poll_delay = CHECKMAC_DELAY; + poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY; + response_size = CHECKMAC_RSP_SIZE; + break; + + case SHA204_DERIVE_KEY: + poll_delay = DERIVE_KEY_DELAY; + poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY; + response_size = DERIVE_KEY_RSP_SIZE; + break; + + case SHA204_DEVREV: + poll_delay = DEVREV_DELAY; + poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY; + response_size = DEVREV_RSP_SIZE; + break; + + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_LOCK: + poll_delay = LOCK_DELAY; + poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY; + response_size = LOCK_RSP_SIZE; + break; + + case SHA204_MAC: + poll_delay = MAC_DELAY; + poll_timeout = MAC_EXEC_MAX - MAC_DELAY; + response_size = MAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_PAUSE: + poll_delay = PAUSE_DELAY; + poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY; + response_size = PAUSE_RSP_SIZE; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_READ: + poll_delay = READ_DELAY; + poll_timeout = READ_EXEC_MAX - READ_DELAY; + response_size = (param1 & SHA204_ZONE_COUNT_FLAG) + ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + break; + + case SHA204_UPDATE_EXTRA: + poll_delay = UPDATE_DELAY; + poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY; + response_size = UPDATE_RSP_SIZE; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; + } + + // Assemble command. + len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + p_buffer = tx_buffer; + *p_buffer++ = len; + *p_buffer++ = op_code; + *p_buffer++ = param1; + *p_buffer++ = param2 & 0xFF; + *p_buffer++ = param2 >> 8; + + if (datalen1 > 0) { + memcpy(p_buffer, data1, datalen1); + p_buffer += datalen1; + } + if (datalen2 > 0) { + memcpy(p_buffer, data2, datalen2); + p_buffer += datalen2; + } + if (datalen3 > 0) { + memcpy(p_buffer, data3, datalen3); + p_buffer += datalen3; + } + + sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer); + + // Send command and receive response. + return sha204c_send_and_receive(&tx_buffer[0], response_size, + &rx_buffer[0], poll_delay, poll_timeout); +} + +uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ +#ifdef SHA204_CHECK_PARAMETERS + + uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer) + return SHA204_BAD_PARAM; + + if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3)) + return SHA204_BAD_PARAM; + + // Check parameters depending on op-code. + switch (op_code) + { + case SHA204_CHECKMAC: + if ( + // no null pointers allowed + !data1 || !data2 + // No reserved bits should be set. + || (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK + // key_id > 15 not allowed + || param2 > SHA204_KEY_ID_MAX + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_DERIVE_KEY: + if (param2 > SHA204_KEY_ID_MAX) + return SHA204_BAD_PARAM; + break; + + case SHA204_DEVREV: + break; + + case SHA204_GENDIG: + if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA)) + return SHA204_BAD_PARAM; + break; + + case SHA204_HMAC: + if ((param1 & ~HMAC_MODE_MASK) != 0) + return SHA204_BAD_PARAM; + break; + + case SHA204_LOCK: + if (((param1 & ~LOCK_ZONE_MASK) != 0) + || ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0))) + return SHA204_BAD_PARAM; + break; + + case SHA204_MAC: + if (((param1 & ~MAC_MODE_MASK) != 0) + || (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1)) + return SHA204_BAD_PARAM; + break; + + case SHA204_NONCE: + if ( !data1 + || (param1 > NONCE_MODE_PASSTHROUGH) + || (param1 == NONCE_MODE_INVALID) + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_PAUSE: + break; + + case SHA204_RANDOM: + if (param1 > RANDOM_NO_SEED_UPDATE) + return SHA204_BAD_PARAM; + break; + + case SHA204_READ: + if (((param1 & ~READ_ZONE_MASK) != 0) + || ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + break; + + case SHA204_TEMPSENSE: + break; + + case SHA204_UPDATE_EXTRA: + if (param1 > UPDATE_CONFIG_BYTE_86) + return SHA204_BAD_PARAM; + break; + + case SHA204_WRITE: + if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0)) + return SHA204_BAD_PARAM; + break; + + default: + // unknown op-code + return SHA204_BAD_PARAM; + } + + return SHA204_SUCCESS; + +#else + return SHA204_SUCCESS; +#endif +} + +/* CRC Calculator and Checker */ + +void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint8_t counter; + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + } + } + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); +} + +uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) +{ + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; +} \ No newline at end of file diff --git a/libraries/sha204/sha204_library.h b/libraries/sha204/sha204_library.h new file mode 100644 index 0000000..caf0d0b --- /dev/null +++ b/libraries/sha204/sha204_library.h @@ -0,0 +1,320 @@ +#include "Arduino.h" + +#ifndef sha204_library_H +#define sha204_library_H + +/* bitbang_config.h */ + +#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns) +#define START_PULSE_WIDTH (4340) //! width of start pulse (ns) +#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns) +#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit +#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse. +#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse. + +/* swi_phys.h */ + +#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded. +#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out. +#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received. + +/* sha204_physical.h */ + +#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response +#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet +#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response +#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response +#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units +#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms + +/* sha204_swi.c */ +#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command +#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response +#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode +#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode + +/* sha204_comm_marshaling.h */ +// command op-code definitions +#define SHA204_CHECKMAC ((uint8_t) 0x28) //!< CheckMac command op-code +#define SHA204_DERIVE_KEY ((uint8_t) 0x1C) //!< DeriveKey command op-code +#define SHA204_DEVREV ((uint8_t) 0x30) //!< DevRev command op-code +#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code +#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code +#define SHA204_LOCK ((uint8_t) 0x17) //!< Lock command op-code +#define SHA204_MAC ((uint8_t) 0x08) //!< MAC command op-code +#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code +#define SHA204_PAUSE ((uint8_t) 0x01) //!< Pause command op-code +#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code +#define SHA204_UPDATE_EXTRA ((uint8_t) 0x20) //!< UpdateExtra command op-code +#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code + +// packet size definitions +#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data + +// parameter range definitions +#define SHA204_KEY_ID_MAX ((uint8_t) 15) //!< maximum value for key id +#define SHA204_OTP_BLOCK_MAX ((uint8_t) 1) //!< maximum value for OTP block + +// definitions for command packet indexes common to all commands +#define SHA204_COUNT_IDX ( 0) //!< command packet index for count +#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code +#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter +#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter +#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter + +// zone definitions +#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone +#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone +#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone +#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask +#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes. +#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes. +#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0. + +// CheckMAC command definitions +#define CHECKMAC_MODE_IDX SHA204_PARAM1_IDX //!< CheckMAC command index for mode +#define CHECKMAC_KEYID_IDX SHA204_PARAM2_IDX //!< CheckMAC command index for key identifier +#define CHECKMAC_CLIENT_CHALLENGE_IDX SHA204_DATA_IDX //!< CheckMAC command index for client challenge +#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response +#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data +#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size +#define CHECKMAC_MODE_MASK ((uint8_t) 0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0. +#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge +#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response +#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data" + +// DeriveKey command definitions +#define DERIVE_KEY_RANDOM_IDX SHA204_PARAM1_IDX //!< DeriveKey command index for random bit +#define DERIVE_KEY_TARGETKEY_IDX SHA204_PARAM2_IDX //!< DeriveKey command index for target slot +#define DERIVE_KEY_MAC_IDX SHA204_DATA_IDX //!< DeriveKey command index for optional MAC +#define DERIVE_KEY_COUNT_SMALL SHA204_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC +#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC +#define DERIVE_KEY_RANDOM_FLAG ((uint8_t) 4) //!< DeriveKey 1. parameter +#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size + +// DevRev command definitions +#define DEVREV_PARAM1_IDX SHA204_PARAM1_IDX //!< DevRev command index for 1. parameter (ignored) +#define DEVREV_PARAM2_IDX SHA204_PARAM2_IDX //!< DevRev command index for 2. parameter (ignored) +#define DEVREV_COUNT SHA204_CMD_SIZE_MIN //!< DevRev command packet size + +// GenDig command definitions +#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT SHA204_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data" +#define GENDIG_OTHER_DATA_SIZE (4) //!< GenDig size of "other data" +#define GENDIG_ZONE_CONFIG ((uint8_t) 0) //!< GenDig zone id config +#define GENDIG_ZONE_OTP ((uint8_t) 1) //!< GenDig zone id OTP +#define GENDIG_ZONE_DATA ((uint8_t) 2) //!< GenDig zone id data + +// HMAC command definitions +#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. + +// Lock command definitions +#define LOCK_ZONE_IDX SHA204_PARAM1_IDX //!< Lock command index for zone +#define LOCK_SUMMARY_IDX SHA204_PARAM2_IDX //!< Lock command index for summary +#define LOCK_COUNT SHA204_CMD_SIZE_MIN //!< Lock command packet size +#define LOCK_ZONE_NO_CONFIG ((uint8_t) 0x01) //!< Lock zone is OTP or Data +#define LOCK_ZONE_NO_CRC ((uint8_t) 0x80) //!< Lock command: Ignore summary. +#define LOCK_ZONE_MASK (0x81) //!< Lock parameter 1 bits 2 to 6 are 0. + +// Mac command definitions +#define MAC_MODE_IDX SHA204_PARAM1_IDX //!< MAC command index for mode +#define MAC_KEYID_IDX SHA204_PARAM2_IDX //!< MAC command index for key id +#define MAC_CHALLENGE_IDX SHA204_DATA_IDX //!< MAC command index for optional challenge +#define MAC_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< MAC command packet size without challenge +#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge +#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t) 0x01) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t) 0x02) //!< MAC mode bit 1: first SHA block from TempKey +#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t) 0x04) //!< MAC mode bit 2: match TempKey.SourceFlag +#define MAC_MODE_PASSTHROUGH ((uint8_t) 0x07) //!< MAC mode bit 0-2: pass-through mode +#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t) 0x10) //!< MAC mode bit 4: include first 88 OTP bits +#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t) 0x20) //!< MAC mode bit 5: include first 64 OTP bits +#define MAC_MODE_INCLUDE_SN ((uint8_t) 0x40) //!< MAC mode bit 6: include serial number +#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge +#define MAC_MODE_MASK ((uint8_t) 0x77) //!< MAC mode bits 3 and 7 are 0. + +// Nonce command definitions +#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX SHA204_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data +#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data +#define NONCE_MODE_MASK ((uint8_t) 3) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t) 0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t) 0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t) 0x03) //!< Nonce mode: pass-through +#define NONCE_NUMIN_SIZE (20) //!< Nonce data length +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3) + +// Pause command definitions +#define PAUSE_SELECT_IDX SHA204_PARAM1_IDX //!< Pause command index for Selector +#define PAUSE_PARAM2_IDX SHA204_PARAM2_IDX //!< Pause command index for 2. parameter +#define PAUSE_COUNT SHA204_CMD_SIZE_MIN //!< Pause command packet size + +// Random command definitions +#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT SHA204_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update + +// Read command definitions +#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address +#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0. +#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes + +// UpdateExtra command definitions +#define UPDATE_MODE_IDX SHA204_PARAM1_IDX //!< UpdateExtra command index for mode +#define UPDATE_VALUE_IDX SHA204_PARAM2_IDX //!< UpdateExtra command index for new value +#define UPDATE_COUNT SHA204_CMD_SIZE_MIN //!< UpdateExtra command packet size +#define UPDATE_CONFIG_BYTE_86 ((uint8_t) 0x01) //!< UpdateExtra mode: update Config byte 86 + +// Write command definitions +#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX SHA204_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC +#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC +#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC +#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t) 0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t) 0x40) //!< Write zone bit 6: write encrypted with MAC + +// Response size definitions +#define CHECKMAC_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DERIVE_KEY_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DEVREV_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of DevRev command returns 4 bytes +#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command +#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command +#define LOCK_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Lock command +#define MAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of MAC command +#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 +#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command +#define PAUSE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Pause command +#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes +#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes +#define TEMP_SENSE_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of TempSense command returns 4 bytes +#define UPDATE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of UpdateExtra command +#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command + +// command timing definitions for minimum execution times (ms) +#define CHECKMAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DERIVE_KEY_DELAY ((uint8_t) (14.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DEVREV_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define LOCK_DELAY ((uint8_t) ( 5.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define MAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define PAUSE_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define TEMP_SENSE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define UPDATE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) + +// command timing definitions for maximum execution times (ms) +#define CHECKMAC_EXEC_MAX ((uint8_t) (38.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DERIVE_KEY_EXEC_MAX ((uint8_t) (62.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DEVREV_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define LOCK_EXEC_MAX ((uint8_t) (24.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define MAC_EXEC_MAX ((uint8_t) (35.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define PAUSE_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define TEMP_SENSE_EXEC_MAX ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define UPDATE_EXEC_MAX ((uint8_t) ( 6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) + +/* from sha204_config.h */ + +#define CPU_CLOCK_DEVIATION_POSITIVE (1.01) +#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99) +#define SHA204_RETRY_COUNT (1) +#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts +#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits). +#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine +#define SHA204_RESPONSE_TIMEOUT ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE) //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag. + +/* from sha204_comm.h */ + +#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay +#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) +#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes +#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response +#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response +#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error +#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error +#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error +#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error + +/* EEPROM Addresses */ +/* Configuration Zone */ +#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone +#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum +#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone +#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE +#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status +#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204 +#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode +#define ADDRESS_SELECTOR 19 // Controls writability of Selector + + +class atsha204Class +{ +private: + uint8_t device_pin; + volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; + void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); + uint8_t sha204c_check_crc(uint8_t *response); + void swi_set_signal_pin(uint8_t is_high); + uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_byte(uint8_t value); + uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); + uint8_t sha204p_wakeup(); + uint8_t sha204p_send_command(uint8_t count, uint8_t * command); + uint8_t sha204p_sleep(); + uint8_t sha204p_resync(uint8_t size, uint8_t *response); + + +public: + atsha204Class(uint8_t pin); // Constructor + uint8_t sha204c_wakeup(uint8_t *response); + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + uint8_t sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode); + uint8_t sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer); + uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); + uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + + uint8_t getSerialNumber(uint8_t *response); + +}; + +#endif From 1ac6f0a2916ecad0b0372592e558c3f56d32d52d Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 10 Jan 2015 12:33:27 +0100 Subject: [PATCH 026/660] Removed examples from sha204 libraries MySensors will have native support for sha204 and the source for usage and personalization of sha204 will be much more elaborate than this example so it does not provide additional understanding for the chip. --- .../atsha204_simple_example.ino | 103 ------------------ 1 file changed, 103 deletions(-) delete mode 100644 libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino diff --git a/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino b/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino deleted file mode 100644 index b55ce49..0000000 --- a/libraries/sha204/examples/atsha204_simple_example/atsha204_simple_example.ino +++ /dev/null @@ -1,103 +0,0 @@ -/* ATSHA204 Library Simple Example - by: Jim Lindblom - SparkFun Electronics - date: November 8, 2012 - - This code shows how to wake up and verify that an SHA204 is - connected and operational. And how to obtain an SHA204's unique serial - number, and send it a MAC challenge. - - The ATSHA204's SDA pin can be connected to any of the Arduino's digital pins. - When constructing your atsha204Class, pass the constructor the pin you want to use. - In this example we'll attach SDA to pin 7. - - The ATSHA204 can be powered between 3.3V and 5V. -*/ -#include - -const int sha204Pin = 7; - -atsha204Class sha204(sha204Pin); - -void setup() -{ - Serial.begin(9600); - Serial.println("Sending a Wakup Command. Response should be:\r\n4 11 33 43:"); - Serial.println("Response is:"); - wakeupExample(); - Serial.println(); - Serial.println("Asking the SHA204's serial number. Response should be:"); - Serial.println("1 23 x x x x x x x EE"); - Serial.println("Response is:"); - serialNumberExample(); - Serial.println(); - Serial.println("Sending a MAC Challenge. Response should be:"); - Serial.println("23 6 67 0 4F 28 4D 6E 98 62 4 F4 60 A3 E8 75 8A 59 85 A6 79 96 C4 8A 88 46 43 4E B3 DB 58 A4 FB E5 73"); - Serial.println("Response is:"); - macChallengeExample(); -} - -void loop() -{ -} - -byte wakeupExample() -{ - uint8_t response[SHA204_RSP_SIZE_MIN]; - byte returnValue; - - returnValue = sha204.sha204c_wakeup(&response[0]); - for (int i=0; i Date: Sat, 10 Jan 2015 18:17:32 +0100 Subject: [PATCH 027/660] sha204 library extended with CRC calculator Locking operations are recommended to include CRC and since sha204 library internally carries the proper algorithm for this, it has now been refactored to support both static and incremental calculations needed for both command marchalling and locking. --- libraries/sha204/sha204_library.cpp | 46 ++++++++++++++++++----------- libraries/sha204/sha204_library.h | 1 + 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp index 075242f..44e59bd 100644 --- a/libraries/sha204/sha204_library.cpp +++ b/libraries/sha204/sha204_library.cpp @@ -50,6 +50,33 @@ uint8_t atsha204Class::getSerialNumber(uint8_t * response) return returnCode; } +/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data) + returns the calculated CRC16 value */ +uint16_t atsha204Class::calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc) +{ + uint8_t counter; + uint16_t crc_register = current_crc; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + } + } + return crc_register; +} + /* SWI bit bang functions */ void atsha204Class::swi_set_signal_pin(uint8_t is_high) @@ -772,26 +799,9 @@ uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) { - uint8_t counter; uint16_t crc_register = 0; - uint16_t polynom = 0x8005; - uint8_t shift_register; - uint8_t data_bit, crc_bit; - for (counter = 0; counter < length; counter++) - { - for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) - { - data_bit = (data[counter] & shift_register) ? 1 : 0; - crc_bit = crc_register >> 15; - - // Shift CRC to the left by 1. - crc_register <<= 1; - - if ((data_bit ^ crc_bit) != 0) - crc_register ^= polynom; - } - } + crc_register = calculateAndUpdateCrc(length, data, crc_register); crc[0] = (uint8_t) (crc_register & 0x00FF); crc[1] = (uint8_t) (crc_register >> 8); } diff --git a/libraries/sha204/sha204_library.h b/libraries/sha204/sha204_library.h index caf0d0b..3e2c9f0 100644 --- a/libraries/sha204/sha204_library.h +++ b/libraries/sha204/sha204_library.h @@ -314,6 +314,7 @@ public: uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); uint8_t getSerialNumber(uint8_t *response); + uint16_t calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc); }; From 6aa370d6f21ceca89ec79bcc8caecbd969b8e362 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 10 Jan 2015 18:42:04 +0100 Subject: [PATCH 028/660] Personalization sketch for ATSHA204 This sketch is used to personalize the ATSHA204 crypto circuit. This is required in order to use the device for secure communication. The sketch also supports random key generation. To personalize a ATSHA204 device, do the following: 1. Ensure the correct pin is used for the ATSHA204. 2. Execute the sketch without other changes to verify that it can communicate properly with the device. 3g. For a device used in a gateway: Enable LOCK_CONFIGURATION to lock the configuration and enable random key generation as well as key storage. 4g. Execute the sketch to lock the configuration and obtain a unique key. Be sure to note down the key printed in the UART log as it has been stored in the chip and will never be accessible again (a new key is calculated on subsequent runs). The key can still be changed. 5g. Enable SKIP_KEY_STORAGE to prevent generating new random keys on sketch re-execution. 3n. For a device used as a node: Enable USER_KEY_DATA and enter your private key data in user_key_data. Then enable LOCK_CONFIGURATION to lock the configuration 4n. Execute the sketch to lock the configuration and store the user-supplied key. 5n. Optionally: Enable SKIP_KEY_STORAGE to prevent re-writing the user supplied key on sketch re-execution. 6. Optionally: Enable LOCK_DATA to prevent the key to be changed. --- .../sha204_personalizer.ino | 947 ++++++++++++++++++ 1 file changed, 947 insertions(+) create mode 100644 libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino diff --git a/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino b/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino new file mode 100644 index 0000000..771d024 --- /dev/null +++ b/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino @@ -0,0 +1,947 @@ +/* SHA204 personalization sketch + by: Patrick Fallberg + date: January 10, 2015 + + This sketch will write factory default settings to the configuration zone + and then lock it. + It will then either + a. Generate a random value to use as a key which will be stored in + slot 0. The key is printed on UART (115200) in clear text for the user to be + able to use it as a user-supplied key in other personalization executions + where the same key is needed. + b. Use a user-supplied value to use as a key which will be stored in + slot 0. + Finally it will lock the data zone. + + By default, no locking is performed. User have to manually enable the flags that + turn on the locking. Furthermore, user have to send a SPACE character on serial + console when prompted to do any locking. + Default settings use ATSHA204 on pin 7. +*/ +#include +#include + +// The pin the ATSHA204 is connected on +#define ATSHA204_PIN 7 + +// Uncomment this to enable locking the configuration zone. +// *** BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP *** +// It is still possible to change the key, and this also enable random key generation +//#define LOCK_CONFIGURATION + +// Uncomment this to enable locking the data zone. +// *** BE AWARE THAT THIS PREVENTS THE KEY TO BE CHANGED *** +// It is not required to lock data, key cannot be retrieved anyway, but by locking +// data, it can be guaranteed that nobody even with physical access to the chip, +// will be able to change the key. +//#define LOCK_DATA + +// Uncomment this to skip key storage (typically once key has been written once) +//#define SKIP_KEY_STORAGE + +// Uncomment this to skip key data storage (once configuration is locked, key +// will aways randomize ) +// Uncomment this to skip key generation and use 'user_key_data' as key instead. +//#define USER_KEY_DATA + +#ifdef USER_KEY_DATA +const uint8_t user_key_data[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +#endif + +const int sha204Pin = ATSHA204_PIN; +atsha204Class sha204(sha204Pin); + +void halt() +{ + Serial.println(F("Halting!")); + while(1); +} + +uint16_t write_config_and_get_crc() +{ + uint16_t crc = 0; + uint8_t config_word[4]; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + bool do_write; + + // We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key + // as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest + // calculationon as that slot can be written in clear text even when the datazone is locked. + // Other settings which are not relevant are kept as is. + + for (int i=0; i < 88; i += 4) + { + do_write = true; + if (i == 20) + { + config_word[0] = 0x8F; + config_word[1] = 0x80; + config_word[2] = 0x80; + config_word[3] = 0xA1; + } + else if (i == 24) + { + config_word[0] = 0x82; + config_word[1] = 0xE0; + config_word[2] = 0xA3; + config_word[3] = 0x60; + } + else if (i == 28) + { + config_word[0] = 0x94; + config_word[1] = 0x40; + config_word[2] = 0xA0; + config_word[3] = 0x85; + } + else if (i == 32) + { + config_word[0] = 0x86; + config_word[1] = 0x40; + config_word[2] = 0x87; + config_word[3] = 0x07; + } + else if (i == 36) + { + config_word[0] = 0x0F; + config_word[1] = 0x00; + config_word[2] = 0x89; + config_word[3] = 0xF2; + } + else if (i == 40) + { + config_word[0] = 0x8A; + config_word[1] = 0x7A; + config_word[2] = 0x0B; + config_word[3] = 0x8B; + } + else if (i == 44) + { + config_word[0] = 0x0C; + config_word[1] = 0x4C; + config_word[2] = 0xDD; + config_word[3] = 0x4D; + } + else if (i == 48) + { + config_word[0] = 0xC2; + config_word[1] = 0x42; + config_word[2] = 0xAF; + config_word[3] = 0x8F; + } + else if (i == 52 || i == 56 || i == 60 || i == 64) + { + config_word[0] = 0xFF; + config_word[1] = 0x00; + config_word[2] = 0xFF; + config_word[3] = 0x00; + } + else if (i == 68 || i == 72 || i == 76 || i == 80) + { + config_word[0] = 0xFF; + config_word[1] = 0xFF; + config_word[2] = 0xFF; + config_word[3] = 0xFF; + } + else + { + // All other configs are untouched + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + // Set config_word to the read data + config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0]; + config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1]; + config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + do_write = false; + } + + // Update crc with CRC for the current word + crc = sha204.calculateAndUpdateCrc(4, config_word, crc); + + // Write config word + if (do_write) + { + ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG, + i >> 2, 4, config_word, 0, NULL, 0, NULL, + WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to write config word at address ")); Serial.print(i); + Serial.print(F(". Response: ")); Serial.println(ret_code, HEX); + halt(); + } + } + } + return crc; +} + +void write_key(uint8_t* key) +{ + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + + // Write key to slot 0 + ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, + 0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL, + WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to write key to slot 0. Response: ")); Serial.println(ret_code, HEX); + halt(); + } +} + +void dump_configuration() +{ + uint8_t config_word[4]; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + + for (int i=0; i < 88; i += 4) + { + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + if (i == 0x00) + { + Serial.print(F(" SN[0:1] | SN[2:3] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x04) + { + Serial.print(F(" Revnum | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x08) + { + Serial.print(F(" SN[4:7] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x0C) + { + Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x10) + { + Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x14) + { + Serial.print(F(" SlotConfig00 | SlotConfig01 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x18) + { + Serial.print(F(" SlotConfig02 | SlotConfig03 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x1C) + { + Serial.print(F(" SlotConfig04 | SlotConfig05 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x20) + { + Serial.print(F(" SlotConfig06 | SlotConfig07 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x24) + { + Serial.print(F(" SlotConfig08 | SlotConfig09 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x28) + { + Serial.print(F(" SlotConfig0A | SlotConfig0B | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x2C) + { + Serial.print(F(" SlotConfig0C | SlotConfig0D | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x30) + { + Serial.print(F(" SlotConfig0E | SlotConfig0F | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x34) + { + Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x38) + { + Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x3C) + { + Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x40) + { + Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + else if (i == 0x44) + { + Serial.print(F(" LastKeyUse[0:3] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x48) + { + Serial.print(F(" LastKeyUse[4:7] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x4C) + { + Serial.print(F(" LastKeyUse[8:B] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x50) + { + Serial.print(F(" LastKeyUse[C:F] | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } + else if (i == 0x54) + { + Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | ")); + for (int j=0; j<4; j++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) + { + Serial.print(F(" | ")); + } + else + { + Serial.print(F(" ")); + } + } + Serial.println(); + } + } +} + +void setup() +{ + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t key[32]; + uint8_t ret_code; + uint8_t lockConfig = 0; + uint8_t lockValue = 0; + uint16_t crc; + Serial.begin(115200); + + Serial.println(F("ATSHA204 personalization sketch for MySensors usage.")); + Serial.println(F("----------------------------------------------------")); + + // Wake device before starting operations + ret_code = sha204.sha204c_wakeup(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + + // Output device revision on console + ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to determine device revision. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + Serial.print(F("Device revision: ")); + for (int i=0; i<4; i++) + { + if (rx_buffer[SHA204_BUFFER_POS_DATA+i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX); + } + Serial.println(); + } + + // Output serial number on console + ret_code = sha204.getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + Serial.print(F("Device serial: ")); + for (int i=0; i<9; i++) + { + if (rx_buffer[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(); + } + + // Read out lock config bits to determine if locking is possible + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } + + if (lockConfig != 0x00) + { + // Write config and get CRC for the updated config + crc = write_config_and_get_crc(); + + // List current configuration before attempting to lock + Serial.println(F("Chip configuration:")); + dump_configuration(); + +#ifdef LOCK_CONFIGURATION + // Purge serial input buffer + while (Serial.available()) + { + Serial.read(); + } + Serial.println(F("Send SPACE character now to lock the configuration...")); + + while (Serial.available() == 0); + if (Serial.read() == ' ') + { + Serial.println(F("Locking configuration...")); + + // Correct sequence, resync chip + ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); + if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) + { + Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + + // Lock configuration zone + ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG, + crc, 0, NULL, 0, NULL, 0, NULL, + LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Configuration lock failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + Serial.println(F("Configuration locked.")); + + // Update lock flags after locking + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } + } + } + else + { + Serial.println(F("Unexpected answer. Skipping lock.")); + } +#else //LOCK_CONFIGURATION + Serial.println(F("Dry-run. Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); +#endif + } + else + { + Serial.println(F("Skipping configuration write and lock (configuration already locked).")); + Serial.println(F("Chip configuration:")); + dump_configuration(); + } + +#ifdef SKIP_KEY_STORAGE + Serial.println(F("Disable SKIP_KEY_STORAGE to store key.")); +#else +#ifdef USER_KEY_DATA + memcpy(key, user_key_data, 32); + Serial.print(F("Using this user supplied key: ")); +#else + // Retrieve random value to use as key + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) + { + Serial.println(F("Take note of this key, it will never be the shown again:")); + } + else + { + Serial.println(F("Key is not randomized (configuration not locked):")); + } +#endif + for (int i=0; i<32; i++) + { + if (key[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + } + Serial.println(); + + // It will not be possible to write the key if the configuration zone is unlocked + if (lockConfig == 0x00) + { + // Write the key to the appropriate slot in the data zone + Serial.println(F("Writing key to slot 0...")); + write_key(key); + } + else + { + Serial.println(F("Skipping key storage (configuration not locked).")); + Serial.println(F("The configuration must be locked to be able to write a key.")); + } +#endif + + if (lockValue != 0x00) + { +#ifdef LOCK_DATA + while (Serial.available()) + { + Serial.read(); + } + Serial.println(F("Send SPACE character to lock data...")); + while (Serial.available() == 0); + if (Serial.read() == ' ') + { + // Correct sequence, resync chip + ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); + if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) + { + Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + + // If configuration is unlocked, key is not updated. Locking data in this case will cause + // slot 0 to contain an unknown (or factory default) key, and this is in practically any + // usecase not the desired behaviour, so ask for additional confirmation in this case. + if (lockConfig != 0x00) + { + while (Serial.available()) + { + Serial.read(); + } + Serial.println(F("*** ATTENTION ***")); + Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?")); + Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key")); + Serial.println(F("which cannot be change after locking is done. This is in practically any usecase")); + Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway...")); + while (Serial.available() == 0); + if (Serial.read() != ' ') + { + Serial.println(F("Unexpected answer. Skipping lock.")); + halt(); + } + } + + // Lock data zone + ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC, + 0x0000, 0, NULL, 0, NULL, 0, NULL, + LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Data lock failed. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + Serial.println(F("Data locked.")); + + // Update lock flags after locking + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); + halt(); + } + else + { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } + } + } + else + { + Serial.println(F("Unexpected answer. Skipping lock.")); + } +#else //LOCK_DATA + Serial.println(F("Dry-run. Data not locked. Define LOCK_DATA to lock for real.")); +#endif + } + else + { + Serial.println(F("Skipping OTP/data zone lock (zone already locked).")); + } + + Serial.println(F("--------------------------------")); + Serial.println(F("Personalization is now complete.")); + Serial.print(F("Configuration is ")); + if (lockConfig == 0x00) + { + Serial.println("LOCKED"); + } + else + { + Serial.println("UNLOCKED"); + } + Serial.print(F("Data is ")); + if (lockValue == 0x00) + { + Serial.println("LOCKED"); + } + else + { + Serial.println("UNLOCKED"); + } +} + +void loop() +{ +} From f1f8aec324f754f4fe221c4d2b72196702eec3ca Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 11 Jan 2015 20:29:22 +0100 Subject: [PATCH 029/660] Change order of ethernet/radio intialization to avoid troubles. --- .../MySensors/examples/EthernetGateway/EthernetGateway.ino | 6 ++++-- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 2c191f9..54e6252 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -101,8 +101,6 @@ void output(const char *fmt, ... ) { void setup() { - // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(incomingMessage, 0, true, 0); Ethernet.begin(mac, myIp); setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); @@ -116,6 +114,10 @@ void setup() // give the Ethernet interface a second to initialize delay(1000); + + // Initialize gateway at maximum PA level, channel 70 and callback for write operations + gw.begin(incomingMessage, 0, true, 0); + // start listening for clients server.begin(); diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 219b4e2..de61f13 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -145,8 +145,6 @@ void incomingMessage(const MyMessage &message) { void setup() { - // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(incomingMessage, 0, true, 0); Ethernet.begin(TCP_MAC, TCP_IP); @@ -177,6 +175,10 @@ void setup() // give the Ethernet interface a second to initialize delay(1000); + + // Initialize gateway at maximum PA level, channel 70 and callback for write operations + gw.begin(incomingMessage, 0, true, 0); + // start listening for clients server.begin(); From 7d37cd9aa5a3c6b70c442cb86d6763369f989b83 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 28 Jan 2015 21:25:19 +0100 Subject: [PATCH 030/660] MyDriver structure renamed to MyRFDriver The MyDriver scheme is radio specific, so it is renamed accordingly to permit other driver schemes to coexist with it without confusion. --- libraries/MySensors/MyConfig.h | 8 +++---- libraries/MySensors/MyDriver.cpp | 4 ---- libraries/MySensors/MyRFDriver.cpp | 4 ++++ .../MySensors/{MyDriver.h => MyRFDriver.h} | 10 ++++----- ...{MyDriverNRF24.cpp => MyRFDriverNRF24.cpp} | 20 ++++++++--------- .../{MyDriverNRF24.h => MyRFDriverNRF24.h} | 10 ++++----- .../{MyDriverRF69.cpp => MyRFDriverRF69.cpp} | 20 ++++++++--------- .../{MyDriverRF69.h => MyRFDriverRF69.h} | 12 +++++----- libraries/MySensors/MySensor.cpp | 22 +++++++++---------- libraries/MySensors/MySensor.h | 4 ++-- .../examples/EthernetGateway/GatewayUtil.h | 2 +- .../examples/SerialGateway/GatewayUtil.h | 2 +- 12 files changed, 59 insertions(+), 59 deletions(-) delete mode 100644 libraries/MySensors/MyDriver.cpp create mode 100644 libraries/MySensors/MyRFDriver.cpp rename libraries/MySensors/{MyDriver.h => MyRFDriver.h} (94%) rename libraries/MySensors/{MyDriverNRF24.cpp => MyRFDriverNRF24.cpp} (75%) rename libraries/MySensors/{MyDriverNRF24.h => MyRFDriverNRF24.h} (90%) rename libraries/MySensors/{MyDriverRF69.cpp => MyRFDriverRF69.cpp} (60%) rename libraries/MySensors/{MyDriverRF69.h => MyRFDriverRF69.h} (88%) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 3b7d3ed..4d0182a 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -19,13 +19,13 @@ #ifdef MYSENSORS_RF_NRF24 -#include "MyDriverNRF24.h" -typedef class MyDriverNRF24 MyDriverClass; +#include "MyRFDriverNRF24.h" +typedef class MyRFDriverNRF24 MyRFDriverClass; #endif #ifdef MYSENSORS_RF_RF69 -#include "MyDriverRF69.h" -typedef class MyDriverRF69 MyDriverClass; +#include "MyRFDriverRF69.h" +typedef class MyRFDriverRF69 MyRFDriverClass; #endif /*** diff --git a/libraries/MySensors/MyDriver.cpp b/libraries/MySensors/MyDriver.cpp deleted file mode 100644 index e592552..0000000 --- a/libraries/MySensors/MyDriver.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "MyDriver.h" - -MyDriver::MyDriver() { -} diff --git a/libraries/MySensors/MyRFDriver.cpp b/libraries/MySensors/MyRFDriver.cpp new file mode 100644 index 0000000..cf669a0 --- /dev/null +++ b/libraries/MySensors/MyRFDriver.cpp @@ -0,0 +1,4 @@ +#include "MyRFDriver.h" + +MyRFDriver::MyRFDriver() { +} diff --git a/libraries/MySensors/MyDriver.h b/libraries/MySensors/MyRFDriver.h similarity index 94% rename from libraries/MySensors/MyDriver.h rename to libraries/MySensors/MyRFDriver.h index fe35f5f..8157af1 100644 --- a/libraries/MySensors/MyDriver.h +++ b/libraries/MySensors/MyRFDriver.h @@ -1,5 +1,5 @@ -#ifndef MyDriver_h -#define MyDriver_h +#ifndef MyRFDriver_h +#define MyRFDriver_h #include @@ -16,13 +16,13 @@ #define GATEWAY_ADDRESS ((uint8_t)0) #define BROADCAST_ADDRESS ((uint8_t)0xFF) -class MyDriver +class MyRFDriver { public: - // MyDriver constructor + // MyRFDriver constructor // different parameters would be needed depending on radio module (e.g. pins connected etc.) // keeping these parameters as #define's in MyConfig to streamline the driver interface - MyDriver(); + MyRFDriver(); // init() // different parameters would be needed depending on radio module (e.g. channel, power, crc, etc.) // keeping these parameters as #define's in MyConfig to streamline the driver interface diff --git a/libraries/MySensors/MyDriverNRF24.cpp b/libraries/MySensors/MyRFDriverNRF24.cpp similarity index 75% rename from libraries/MySensors/MyDriverNRF24.cpp rename to libraries/MySensors/MyRFDriverNRF24.cpp index a6b3ac1..adfabc8 100644 --- a/libraries/MySensors/MyDriverNRF24.cpp +++ b/libraries/MySensors/MyRFDriverNRF24.cpp @@ -1,11 +1,11 @@ -#include "MyDriver.h" -#include "MyDriverNRF24.h" +#include "MyRFDriver.h" +#include "MyRFDriverNRF24.h" -MyDriverNRF24::MyDriverNRF24() : MyDriver() { +MyRFDriverNRF24::MyRFDriverNRF24() : MyRFDriver() { rf24 = new RF24(RF24_CE_PIN, RF24_CS_PIN); } -void MyDriverNRF24::init() { +void MyRFDriverNRF24::init() { // Start up the radio library rf24->begin(); @@ -27,18 +27,18 @@ void MyDriverNRF24::init() { rf24->openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); } -void MyDriverNRF24::setAddress(uint8_t address) { +void MyRFDriverNRF24::setAddress(uint8_t address) { _address = address; rf24->openReadingPipe(WRITE_PIPE, TO_ADDR(address)); rf24->openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); rf24->startListening(); } -uint8_t MyDriverNRF24::getAddress() { +uint8_t MyRFDriverNRF24::getAddress() { return _address; } -bool MyDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { +bool MyRFDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up rf24->powerUp(); rf24->stopListening(); @@ -48,7 +48,7 @@ bool MyDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { return ok; } -bool MyDriverNRF24::available(uint8_t *to) { +bool MyRFDriverNRF24::available(uint8_t *to) { uint8_t pipe = 255; boolean avail = rf24->available(&pipe); if (pipe == CURRENT_NODE_PIPE) @@ -58,11 +58,11 @@ bool MyDriverNRF24::available(uint8_t *to) { return (rf24->available() && pipe < 6); } -uint8_t MyDriverNRF24::receive(void* data) { +uint8_t MyRFDriverNRF24::receive(void* data) { uint8_t len = rf24->getDynamicPayloadSize(); rf24->read(data, len); } -void MyDriverNRF24::powerDown() { +void MyRFDriverNRF24::powerDown() { rf24->powerDown(); } diff --git a/libraries/MySensors/MyDriverNRF24.h b/libraries/MySensors/MyRFDriverNRF24.h similarity index 90% rename from libraries/MySensors/MyDriverNRF24.h rename to libraries/MySensors/MyRFDriverNRF24.h index 8ad9b4d..66a78fe 100644 --- a/libraries/MySensors/MyDriverNRF24.h +++ b/libraries/MySensors/MyRFDriverNRF24.h @@ -1,8 +1,8 @@ -#ifndef MyCommDriver_h -#define MyCommDriver_h +#ifndef MyRFDriverNRF24_h +#define MyRFDriverNRF24_h #include "MyConfig.h" -#include "MyDriver.h" +#include "MyRFDriver.h" #include #include "utility/RF24.h" #include "utility/RF24_config.h" @@ -37,10 +37,10 @@ #define CURRENT_NODE_PIPE ((uint8_t)1) #define BROADCAST_PIPE ((uint8_t)2) -class MyDriverNRF24 : public MyDriver +class MyRFDriverNRF24 : public MyRFDriver { public: - MyDriverNRF24(); + MyRFDriverNRF24(); void init(); void setAddress(uint8_t address); uint8_t getAddress(); diff --git a/libraries/MySensors/MyDriverRF69.cpp b/libraries/MySensors/MyRFDriverRF69.cpp similarity index 60% rename from libraries/MySensors/MyDriverRF69.cpp rename to libraries/MySensors/MyRFDriverRF69.cpp index 2363da7..360671d 100644 --- a/libraries/MySensors/MyDriverRF69.cpp +++ b/libraries/MySensors/MyRFDriverRF69.cpp @@ -1,11 +1,11 @@ -#include "MyDriver.h" -#include "MyDriverRF69.h" +#include "MyRFDriver.h" +#include "MyRFDriverRF69.h" -MyDriverRF69::MyDriverRF69() : MyDriver() { +MyRFDriverRF69::MyRFDriverRF69() : MyRFDriver() { radio = new RFM69(); } -void MyDriverRF69::init() { +void MyRFDriverRF69::init() { // Start up the radio library radio->initialize(FREQUENCY,_address,NETWORKID); #ifdef IS_RFM69HW @@ -15,25 +15,25 @@ void MyDriverRF69::init() { } -void MyDriverRF69::setAddress(uint8_t address) { +void MyRFDriverRF69::setAddress(uint8_t address) { _address = address; radio->setAddress(address); } -uint8_t MyDriverRF69::getAddress() { +uint8_t MyRFDriverRF69::getAddress() { return _address; } -bool MyDriverRF69::send(uint8_t to, const void* data, uint8_t len) { +bool MyRFDriverRF69::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up return radio->sendWithRetry(to,data,len); } -bool MyDriverRF69::available(uint8_t *to) { +bool MyRFDriverRF69::available(uint8_t *to) { return radio->receiveDone(); } -uint8_t MyDriverRF69::receive(void* data) { +uint8_t MyRFDriverRF69::receive(void* data) { // for (byte i = 0; i < radio->DATALEN; i++){ // data[i]= (void)radio->DATA[i]; // } @@ -44,6 +44,6 @@ uint8_t MyDriverRF69::receive(void* data) { } } -void MyDriverRF69::powerDown() { +void MyRFDriverRF69::powerDown() { radio->sleep(); } diff --git a/libraries/MySensors/MyDriverRF69.h b/libraries/MySensors/MyRFDriverRF69.h similarity index 88% rename from libraries/MySensors/MyDriverRF69.h rename to libraries/MySensors/MyRFDriverRF69.h index 6b14772..256cc4d 100644 --- a/libraries/MySensors/MyDriverRF69.h +++ b/libraries/MySensors/MyRFDriverRF69.h @@ -1,8 +1,8 @@ -#ifndef MyCommDriver_h -#define MyCommDriver_h +#ifndef MyRFDriverRF69_h +#define MyRFDriverRF69_h #include "MyConfig.h" -#include "MyDriver.h" +#include "MyRFDriver.h" #include #include "utility/RFM69.h" #include @@ -25,10 +25,10 @@ #define FLASH_SS 8 // and FLASH SS on D8 #endif -class MyDriverRF69 : public MyDriver +class MyRFDriverRF69 : public MyRFDriver { public: - MyDriverRF69(); + MyRFDriverRF69(); void init(); void setAddress(uint8_t address); uint8_t getAddress(); @@ -37,7 +37,7 @@ public: uint8_t receive(void* data); void powerDown(); private: - RFM69 *radio = NULL; + RFM69 *radio; uint8_t _address; }; diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index c56da76..21ac36c 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -34,7 +34,7 @@ static inline bool isValidDistance( const uint8_t distance ) { } MySensor::MySensor() { - driver = (MyDriver*) new MyDriverClass(); + radio = (MyRFDriver*) new MyRFDriverClass(); } @@ -89,7 +89,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } // Open reading pipe for messages directed to this node (set write pipe to same) - driver->setAddress(nc.nodeId); + radio->setAddress(nc.nodeId); // Send presentation for this radio node (attach present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); @@ -105,7 +105,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b void MySensor::setupRadio() { failedTransmissions = 0; - driver->init(); + radio->init(); } void MySensor::setupRepeaterMode(){ @@ -124,7 +124,7 @@ ControllerConfig MySensor::getConfig() { void MySensor::requestNodeId() { debug(PSTR("req node id\n")); - driver->setAddress(nc.nodeId); + radio->setAddress(nc.nodeId); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); waitForReply(); } @@ -202,7 +202,7 @@ boolean MySensor::sendWrite(uint8_t next, MyMessage &message, const bool allowFi uint8_t length = mGetLength(message); message.last = nc.nodeId; mSetVersion(message, PROTOCOL_VERSION); - bool ok = driver->send(next, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); + bool ok = radio->send(next, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, @@ -264,10 +264,10 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { boolean MySensor::process() { uint8_t to = 0; - if (!driver->available(&to)) + if (!radio->available(&to)) return false; - uint8_t len = driver->receive((uint8_t *)&msg); + uint8_t len = radio->receive((uint8_t *)&msg); // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; @@ -351,7 +351,7 @@ boolean MySensor::process() { debug(PSTR("full\n")); while (1); // Wait here. Nothing else we can do... } else { - driver->setAddress(nc.nodeId); + radio->setAddress(nc.nodeId); eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId); } debug(PSTR("id=%d\n"), nc.nodeId); @@ -482,7 +482,7 @@ void MySensor::internalSleep(unsigned long ms) { void MySensor::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); - driver->powerDown(); + radio->powerDown(); pinIntTrigger = 0; internalSleep(ms); } @@ -491,7 +491,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; Serial.flush(); - driver->powerDown(); + radio->powerDown(); attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; @@ -510,7 +510,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; Serial.flush(); // Let serial prints finish (debug, log etc) - driver->powerDown(); + radio->powerDown(); attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 5cb6d5e..8aafaa0 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -13,7 +13,7 @@ #define MySensor_h #include "Version.h" // Auto generated by bot -#include "MyDriver.h" +#include "MyRFDriver.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -232,7 +232,7 @@ class MySensor MyMessage msg; // Buffer for incoming messages. MyMessage ack; // Buffer for ack messages. - MyDriver *driver; + MyRFDriver *radio; void setupRepeaterMode(); void setupRadio(); diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 5ce7be4..b5ac2ba 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -1,7 +1,7 @@ #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ -#include +#include #ifdef ARDUINO diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index 5ce7be4..b5ac2ba 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -1,7 +1,7 @@ #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ -#include +#include #ifdef ARDUINO From 615da4509ced6fb15ca37ae84099efe6ac94adb1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 3 Feb 2015 23:58:38 +0100 Subject: [PATCH 031/660] Fix ack problems RF24 --- libraries/MySensors/MyRFDriverNRF24.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyRFDriverNRF24.cpp b/libraries/MySensors/MyRFDriverNRF24.cpp index adfabc8..faaf73d 100644 --- a/libraries/MySensors/MyRFDriverNRF24.cpp +++ b/libraries/MySensors/MyRFDriverNRF24.cpp @@ -15,13 +15,13 @@ void MyRFDriverNRF24::init() { } rf24->setAutoAck(1); rf24->setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast + rf24->enableAckPayload(); rf24->setChannel(RF24_CHANNEL); rf24->setPALevel(RF24_PA_LEVEL); rf24->setDataRate(RF24_DATARATE); rf24->setRetries(5,15); rf24->setCRCLength(RF24_CRC_16); rf24->enableDynamicPayloads(); - rf24->enableDynamicAck(); // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) rf24->openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); From 83be24d2bead9482b7c4223f851378501278f6cf Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 4 Feb 2015 22:04:32 +0100 Subject: [PATCH 032/660] Return length from receive() --- libraries/MySensors/MyRFDriverNRF24.cpp | 1 + libraries/MySensors/MyRFDriverRF69.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/MySensors/MyRFDriverNRF24.cpp b/libraries/MySensors/MyRFDriverNRF24.cpp index faaf73d..1667fc6 100644 --- a/libraries/MySensors/MyRFDriverNRF24.cpp +++ b/libraries/MySensors/MyRFDriverNRF24.cpp @@ -61,6 +61,7 @@ bool MyRFDriverNRF24::available(uint8_t *to) { uint8_t MyRFDriverNRF24::receive(void* data) { uint8_t len = rf24->getDynamicPayloadSize(); rf24->read(data, len); + return len; } void MyRFDriverNRF24::powerDown() { diff --git a/libraries/MySensors/MyRFDriverRF69.cpp b/libraries/MySensors/MyRFDriverRF69.cpp index 360671d..57b9f8d 100644 --- a/libraries/MySensors/MyRFDriverRF69.cpp +++ b/libraries/MySensors/MyRFDriverRF69.cpp @@ -42,6 +42,7 @@ uint8_t MyRFDriverRF69::receive(void* data) { { radio->sendACK(); } + return radio->DATALEN; } void MyRFDriverRF69::powerDown() { From 17a680f1de54867115af92b2e25ab95fb48f3cf1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 11 Feb 2015 00:07:19 +0100 Subject: [PATCH 033/660] Fix broadcast check for RF69 --- libraries/MySensors/MyRFDriverRF69.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/MySensors/MyRFDriverRF69.cpp b/libraries/MySensors/MyRFDriverRF69.cpp index 57b9f8d..80e8874 100644 --- a/libraries/MySensors/MyRFDriverRF69.cpp +++ b/libraries/MySensors/MyRFDriverRF69.cpp @@ -30,6 +30,10 @@ bool MyRFDriverRF69::send(uint8_t to, const void* data, uint8_t len) { } bool MyRFDriverRF69::available(uint8_t *to) { + if (radio->TARGETID == BROADCAST_ADDRESS) + *to = BROADCAST_ADDRESS; + else + *to = _address; return radio->receiveDone(); } From c8883c61e67447dccb3c2021b3567d46161e118d Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 12 Feb 2015 21:58:16 +0100 Subject: [PATCH 034/660] Request parent missing in setup() --- libraries/MySensors/MySensor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index b24ef75..50445a4 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -74,8 +74,8 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b // If the current node is also repeater, be aware of this. nc.distance = 1; } else if (!isValidParent(nc.parentNodeId)) { - // Auto find parent, but parent in eeprom is invalid. Force parent search on first transmit. - nc.distance = DISTANCE_INVALID; + // Auto find parent, but parent in eeprom is invalid. Try find one. + findParentNode(); } if ( (_nodeId != AUTO) && (nc.nodeId != _nodeId) ) { From f3c60a068f06a913b8953c4d70210641d642788b Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 13 Feb 2015 02:01:18 -0200 Subject: [PATCH 035/660] process() uses sendRoute() for routing decisions To keep routing decisions in one place, and avoid rewriting the same code to add failedTransmissions count to process() --- libraries/MySensors/MySensor.cpp | 127 +++++++++++++++---------------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index d34aa61..6636214 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -125,7 +125,8 @@ ControllerConfig MySensor::getConfig() { void MySensor::requestNodeId() { debug(PSTR("req node id\n")); radio->setAddress(nc.nodeId); - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); + build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); + sendWrite(nc.parentNodeId, msg); wait(2000); } @@ -160,49 +161,82 @@ void MySensor::findParentNode() { } boolean MySensor::sendRoute(MyMessage &message) { - // Make sure to process any incoming messages before sending (could this end up in recursive loop?) - // process(); - bool isInternal = mGetCommand(message) == C_INTERNAL; + uint8_t sender = message.sender; + uint8_t dest = message.destination; + uint8_t last = message.last; + bool ok; + + // If we still don't have any parent id, re-request and skip this message. + if (nc.parentNodeId == AUTO) { + findParentNode(); + return false; + } // If we still don't have any node id, re-request and skip this message. - if (nc.nodeId == AUTO && !(isInternal && message.type == I_ID_REQUEST)) { + if (nc.nodeId == AUTO) { requestNodeId(); return false; } - if (repeaterMode) { - uint8_t dest = message.destination; + if (dest == GATEWAY_ADDRESS || !repeaterMode) { + // If destination is the gateway or if we aren't a repeater, let + // our parent take care of the message + ok = sendWrite(nc.parentNodeId, message); + } else { + // Relay the message uint8_t route = getChildRoute(dest); - if (route>GATEWAY_ADDRESS && route GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { + // This message should be forwarded to a child node. If we send message + // to this nodes pipe then all children will receive it because the are + // all listening to this nodes pipe. + // + // +----B + // -A + // +----C------D + // + // We're node C, Message comes from A and has destination D + // // Message destination is not gateway and is in routing table for this node. // Send it downstream return sendWrite(route, message); - } else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) { + } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { // Node has not yet received any id. We need to send it // by doing a broadcast sending, return sendWrite(BROADCAST_ADDRESS, message); + } else if (isGateway) { + // Destination isn't in our routing table and isn't a broadcast address + // Nothing to do here + return false; + } else { + // A message comes from a child node and we have no + // route for it. + // + // +----B + // -A + // +----C------D <-- Message comes from D + // + // We're node C + // + // Message should be passed to node A (this nodes relay) + + // This message should be routed back towards sensor net gateway + ok = sendWrite(nc.parentNodeId, message); + // Add this child to our "routing table" if it not already exist + addChildRoute(sender, last); } } - if (!isGateway) { - // Should be routed back to gateway. - bool ok = sendWrite(nc.parentNodeId, message); - - if (!ok) { - // Failure when sending to parent node. The parent node might be down and we - // need to find another route to gateway. - if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { - findParentNode(); - } else { - failedTransmissions++; - } - } else { - failedTransmissions = 0; + if (!ok) { + // Failure when sending to parent node. The parent node might be down and we + // need to find another route to gateway. + failedTransmissions++; + if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { + findParentNode(); } - return ok; + } else { + failedTransmissions = 0; } - return false; + return ok; } boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { @@ -369,10 +403,10 @@ boolean MySensor::process() { // Return true if message was addressed for this node... return true; } else if (repeaterMode && nc.nodeId != AUTO) { - // Relaying nodes should answer only after set an id + // If this node have an id, relay the message if (command == C_INTERNAL && type == I_FIND_PARENT) { - if (nc.distance == 255) { + if (nc.distance == DISTANCE_INVALID) { findParentNode(); } else if (sender != nc.parentNodeId) { // Relaying nodes should always answer ping messages @@ -383,42 +417,7 @@ boolean MySensor::process() { } } else if (to == nc.nodeId) { // We should try to relay this message to another node - - uint8_t route = getChildRoute(msg.destination); - if (route>0 && route<255) { - // This message should be forwarded to a child node. If we send message - // to this nodes pipe then all children will receive it because the are - // all listening to this nodes pipe. - // - // +----B - // -A - // +----C------D - // - // We're node C, Message comes from A and has destination D - // - // lookup route in table and send message there - sendWrite(route, msg); - } else if (sender == GATEWAY_ADDRESS && destination == BROADCAST_ADDRESS) { - // A net gateway reply to a message previously sent by us from a 255 node - // We should broadcast this back to the node - sendWrite(BROADCAST_ADDRESS, msg); - } else { - // A message comes from a child node and we have no - // route for it. - // - // +----B - // -A - // +----C------D <-- Message comes from D - // - // We're node C - // - // Message should be passed to node A (this nodes relay) - - // This message should be routed back towards sensor net gateway - sendWrite(nc.parentNodeId, msg); - // Add this child to our "routing table" if it not already exist - addChildRoute(sender, last); - } + sendRoute(msg); } } return false; From 4d3fc96ebfdd25f40c48e18e52e2ac96b7afcf22 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 16 Feb 2015 22:21:22 +0100 Subject: [PATCH 036/660] ATSHA204 personalization sketch updated New default pin is A3. New option to skip UART confirmation: SKIP_UART_CONFIRMATION This option prohibits the possibility to auto-generate key as there will probably not be a way to show the generated key to the user. More copy+paste friendly serial output of the generated key for insertion into personalization sketch. --- .../sha204_personalizer.ino | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino b/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino index 771d024..a39ceeb 100644 --- a/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino +++ b/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino @@ -15,14 +15,15 @@ By default, no locking is performed. User have to manually enable the flags that turn on the locking. Furthermore, user have to send a SPACE character on serial - console when prompted to do any locking. - Default settings use ATSHA204 on pin 7. + console when prompted to do any locking. On boards that does not provide UART + input it is possible to configure the sketch to skip this confirmation. + Default settings use ATSHA204 on pin 17 (A3). */ #include #include // The pin the ATSHA204 is connected on -#define ATSHA204_PIN 7 +#define ATSHA204_PIN 17 // A3 // Uncomment this to enable locking the configuration zone. // *** BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP *** @@ -44,11 +45,24 @@ // Uncomment this to skip key generation and use 'user_key_data' as key instead. //#define USER_KEY_DATA +// Uncomment this for boards that lack UART +// IMPORTANT: No confirmation will be required for locking any zones with this +// configuration! +// Also, key generation is not permitted in this mode as there is no way of +// presenting the generated key. +//#define SKIP_UART_CONFIRMATION + +#if defined(SKIP_UART_CONFIRMATION) && !defined(USER_KEY_DATA) +#error You have to define USER_KEY_DATA for boards that does not have UART +#endif + #ifdef USER_KEY_DATA -const uint8_t user_key_data[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const uint8_t user_key_data[32] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; #endif const int sha204Pin = ATSHA204_PIN; @@ -727,6 +741,7 @@ void setup() #ifdef LOCK_CONFIGURATION // Purge serial input buffer +#ifndef SKIP_UART_CONFIRMATION while (Serial.available()) { Serial.read(); @@ -735,6 +750,7 @@ void setup() while (Serial.available() == 0); if (Serial.read() == ' ') +#endif //not SKIP_UART_CONFIRMATION { Serial.println(F("Locking configuration...")); @@ -773,10 +789,12 @@ void setup() } } } +#ifndef SKIP_UART_CONFIRMATION else { Serial.println(F("Unexpected answer. Skipping lock.")); } +#endif //not SKIP_UART_CONFIRMATION #else //LOCK_CONFIGURATION Serial.println(F("Dry-run. Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); #endif @@ -793,7 +811,7 @@ void setup() #else #ifdef USER_KEY_DATA memcpy(key, user_key_data, 32); - Serial.print(F("Using this user supplied key: ")); + Serial.println(F("Using this user supplied key:")); #else // Retrieve random value to use as key ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); @@ -817,11 +835,14 @@ void setup() #endif for (int i=0; i<32; i++) { + Serial.print("0x"); if (key[i] < 0x10) { Serial.print('0'); // Because Serial.print does not 0-pad HEX } Serial.print(key[i], HEX); + if (i < 31) Serial.print(','); + if (!((i+1) % 8)) Serial.println(); } Serial.println(); @@ -842,6 +863,7 @@ void setup() if (lockValue != 0x00) { #ifdef LOCK_DATA +#ifndef SKIP_UART_CONFIRMATION while (Serial.available()) { Serial.read(); @@ -849,6 +871,7 @@ void setup() Serial.println(F("Send SPACE character to lock data...")); while (Serial.available() == 0); if (Serial.read() == ' ') +#endif //not SKIP_UART_CONFIRMATION { // Correct sequence, resync chip ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); @@ -907,10 +930,12 @@ void setup() } } } +#ifndef SKIP_UART_CONFIRMATION else { Serial.println(F("Unexpected answer. Skipping lock.")); } +#endif //not SKIP_UART_CONFIRMATION #else //LOCK_DATA Serial.println(F("Dry-run. Data not locked. Define LOCK_DATA to lock for real.")); #endif From 93a23442e18517e5b03d5493ea98d00def84210d Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 17 Feb 2015 14:31:52 +0100 Subject: [PATCH 037/660] Add V_RGB, V_RGBW payload types and S_COLOR device type. --- libraries/MySensors/MyMessage.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 643bdb2..a46fbee 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -39,7 +39,7 @@ typedef enum { V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF, V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME, V_LOCK_STATUS, - V_DUST_LEVEL, V_VOLTAGE, V_CURRENT + V_DUST_LEVEL, V_VOLTAGE, V_CURRENT, V_RGB, V_RGBW } mysensor_data; // Type of internal messages (for internal messages) @@ -55,7 +55,7 @@ typedef enum { S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER + S_SCENE_CONTROLLER,S_COLOR } mysensor_sensor; // Type of data stream (for streamed message) From 60d6c4fc3cc8c13e9f365e7534e2ee886a21c248 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 17 Feb 2015 17:24:51 -0200 Subject: [PATCH 038/660] add MYSENSORS_MQTT_GATEWAY definition --- libraries/MySensors/MyConfig.h | 3 ++- libraries/MySensors/MyRFDriverNRF24.h | 2 +- .../MySensors/examples/EthernetGateway/EthernetGateway.ino | 4 ++-- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index d9cb7c2..96f2253 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -8,7 +8,8 @@ // pick ONE of these - other board layouts can be easily added this way #define MYSENSORS_SENSOR //#define MYSENSORS_SERIAL_GATEWAY -//#define MYSENSORS_ETHERNET_MQTT_GATEWAY +//#define MYSENSORS_ETHERNET_GATEWAY +//#define MYSENSORS_MQTT_GATEWAY // Choose radio type by enabling one of the following #define MYSENSORS_RF_NRF24 diff --git a/libraries/MySensors/MyRFDriverNRF24.h b/libraries/MySensors/MyRFDriverNRF24.h index 66a78fe..267b19c 100644 --- a/libraries/MySensors/MyRFDriverNRF24.h +++ b/libraries/MySensors/MyRFDriverNRF24.h @@ -21,7 +21,7 @@ #define RF24_PA_LEVEL RF24_PA_LOW #endif -#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) #define RF24_CE_PIN 5 #define RF24_CS_PIN 6 #define RF24_PA_LEVEL RF24_PA_LOW diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 143a6fe..f0f941c 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -48,8 +48,8 @@ #include #include "GatewayUtil.h" -#ifndef MYSENSORS_ETHERNET_MQTT_GATEWAY -#error Please switch to MYSENSORS_ETHERNET_MQTT_GATEWAY in MyConfig.h +#ifndef MYSENSORS_ETHERNET_GATEWAY +#error Please switch to MYSENSORS_ETHERNET_GATEWAY in MyConfig.h #endif // Use this if you have attached a Ethernet ENC28J60 shields diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index de61f13..a9a497d 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -62,8 +62,8 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include "MyMQTT.h" -#ifndef MYSENSORS_ETHERNET_MQTT_GATEWAY -#error Please switch to MYSENSORS_ETHERNET_MQTT_GATEWAY in MyConfig.h +#ifndef MYSENSORS_MQTT_GATEWAY +#error Please switch to MYSENSORS_MQTT_GATEWAY in MyConfig.h #endif #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled From 8b6463608a0eb8d0ddea2693563caa7daff65bda Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 17 Feb 2015 22:28:47 +0100 Subject: [PATCH 039/660] Fix merge error --- libraries/MySensors/MySensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 6636214..7c8bff6 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -413,7 +413,7 @@ boolean MySensor::process() { // Wait a random delay of 0-2 seconds to minimize collision // between ping ack messages from other relaying nodes delay(millis() & 0x3ff); - sendWrite(BROADCAST_ADDRESS, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); + sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); } } else if (to == nc.nodeId) { // We should try to relay this message to another node From 9f337e3cae654fb95a2a1563f7190283fa80bd76 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 5 Feb 2015 22:49:05 +0100 Subject: [PATCH 040/660] Message header updates for signing support One bit in the protocol version field is converted to a sign indicator. '1' means the message carries a signature in the unused part of the payload data buffer. Three new internal message types have been defined: * I_REQUEST_SIGNING carries a boolean and is used to exchange signing requirement information between nodes. If the I_REQUEST_SIGNING carries 'true' the receiver is informed that the sender require properly signed messages in order to be able to accept the messages. * I_GET_NONCE is passed from sender to a receiver that require signing tellig it to submit a cryptographic 'nonce' that the sender needs in order to be able to sign the message it intend to send. The I_GET_NONCE carries no payload. * I_GET_NONCE_RESPONSE is sent by the receiver of a signed message in response to I_GET_NONCE. The first byte of the payload is a signing identifier informing the sender of the signed message about the type of signature the receiver is expecting. --- libraries/MySensors/MyMessage.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index a46fbee..fcc0540 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -47,7 +47,7 @@ typedef enum { I_BATTERY_LEVEL, I_TIME, I_VERSION, I_ID_REQUEST, I_ID_RESPONSE, I_INCLUSION_MODE, I_CONFIG, I_FIND_PARENT, I_FIND_PARENT_RESPONSE, I_LOG_MESSAGE, I_CHILDREN, I_SKETCH_NAME, I_SKETCH_VERSION, - I_REBOOT, I_GATEWAY_READY + I_REBOOT, I_GATEWAY_READY, I_REQUEST_SIGNING, I_GET_NONCE, I_GET_NONCE_RESPONSE } mysensor_internal; // Type of sensor (for presentation message) @@ -84,8 +84,11 @@ typedef enum { #define BF_SET(y, x, start, len) ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) // Getters/setters for special bit fields in header -#define mSetVersion(_msg,_version) BF_SET(_msg.version_length, _version, 0, 3) -#define mGetVersion(_msg) BF_GET(_msg.version_length, 0, 3) +#define mSetVersion(_msg,_version) BF_SET(_msg.version_length, _version, 0, 2) +#define mGetVersion(_msg) BF_GET(_msg.version_length, 0, 2) + +#define mSetSigned(_msg,_signed) BF_SET(_msg.version_length, _signed, 2, 1) +#define mGetSigned(_msg) BF_GET(_msg.version_length, 2, 1) #define mSetLength(_msg,_length) BF_SET(_msg.version_length, _length, 3, 5) #define mGetLength(_msg) BF_GET(_msg.version_length, 3, 5) @@ -179,7 +182,8 @@ struct uint8_t sender; // 8 bit - Id of sender node (origin) uint8_t destination; // 8 bit - Id of destination node - uint8_t version_length; // 3 bit - Protocol version + uint8_t version_length; // 2 bit - Protocol version + // 1 bit - Signed flag // 5 bit - Length of payload uint8_t command_ack_payload; // 3 bit - Command type // 1 bit - Request an ack - Indicator that receiver should send an ack back. From c2a75d064e05e841ca386d1318a275cd658af882 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Feb 2015 00:19:13 +0100 Subject: [PATCH 041/660] Signing driver framework The signing driver framework resembles the radio driver framework in the sense that it relies on MyConfig.h for driver specific settings. This allows the constructor to be clean and the API less likely to need change. The API is designed with function pairs for sender and receiver of a signed message. The sender of a signed message uses putNonce() and signMsg() and the receiver of a signed message uses getNonce() and verifyMsg(). In addition, receiver is expected to call checkTimer() at regular intervals to make sure the message session does not time out. The program flow is that the sender transmit, after determining that the message needs signing, a request to the receiver for a nonce (I_GET_NONCE). The receiver calls getNonce() to obtain a nonce and transmits the nonce back to the sender (I_GET_NONCE_RESPONSE). The sender stores the received nonce in the driver with putNonce() and then calls signMsg() to sign the message to be transmitted. The receiver then calls verifyMsg() to authenticate the signed message using the nonce transmitted earlier. The flow is described below: ---------------- -------- ---------- ------------------ |senders driver| |sender| |receiver| |receivers driver| ---------------- -------- ---------- ------------------ | | I_GET_NONCE | getNonce() | | |------------------->|------------->| | | | | | setNonce() |I_GET_NONCE_RESPONSE| | |<-----------|<-------------------|<-------------| | signMsg() | | | |<-----------| | verifyMsg() | |----------->|------------------->|------------->| | | | OK / not OK | | | |<-------------| It is expected that all signing schemes is built upon this principle. --- libraries/MySensors/MySigningDriver.cpp | 4 ++ libraries/MySensors/MySigningDriver.h | 60 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 libraries/MySensors/MySigningDriver.cpp create mode 100644 libraries/MySensors/MySigningDriver.h diff --git a/libraries/MySensors/MySigningDriver.cpp b/libraries/MySensors/MySigningDriver.cpp new file mode 100644 index 0000000..b109a3f --- /dev/null +++ b/libraries/MySensors/MySigningDriver.cpp @@ -0,0 +1,4 @@ +#include "MySigningDriver.h" + +MySigningDriver::MySigningDriver() { +} diff --git a/libraries/MySensors/MySigningDriver.h b/libraries/MySensors/MySigningDriver.h new file mode 100644 index 0000000..28a75ea --- /dev/null +++ b/libraries/MySensors/MySigningDriver.h @@ -0,0 +1,60 @@ +/* + The MySigning driver provides a generic API for various signing backends to offer + signing of MySensors messages. + + Created by Patrick "Anticimex" Fallberg +*/ +#ifndef MySigningDriver_h +#define MySigningDriver_h + +#include +#include "MyMessage.h" + +class MySigningDriver +{ +public: + // MySigningDriver constructor. + // Different parameters would be needed depending on signing backend (e.g. pins connected etc.). + // Keeping these parameters as #define's in MyConfig to streamline the driver interface. + MySigningDriver(); + + // Stores signing identifier and a new nonce in provided message for signing operations. + // All space in message payload buffer is used for signing identifier and nonce. + // Returns false if subsystem is busy processing an ongoing signing operation. + // If successful, this marks the start of a signing operation at the receiving side so + // implementation is expected to do any necessary initializations within this call. + virtual bool getNonce(MyMessage &msg) = 0; + + // Check timeout of verification session. + // Nonce will be purged if it takes too long for a signed message to be sent to the receiver. + // This function should be called on regular intervals. + virtual bool checkTimer(void) = 0; + + // Get nonce from provided message and store for signing operations. + // Returns false if subsystem is busy processing an ongoing signing operation. + // Returns false if signing identifier found in message is not supported by the used backend. + // If successful, this marks the start of a signing operation at the sending side so + // implementation is expected to do any necessary initializations within this call. + virtual bool putNonce(MyMessage &msg) = 0; + + // Signs provided message. All remaining space in message payload buffer is used for signing + // identifier and signature. + // Nonce used for signature calculation is the one generated previously using getNonce(). + // Nonce will be cleared when this function is called to prevent re-use of nonce. + // Returns false if subsystem is busy processing an ongoing signing operation. + // Returns false if not two bytes or more of free payload space is left in provided message. + // This ends a signing operation at the sending side so implementation is expected to do any + // deinitializations and enter a power saving state within this call. + virtual bool signMsg(MyMessage &msg) = 0; + + // Verifies signature in provided message. + // Nonce used for verification is the one previously set using putNonce(). + // Nonce will be cleared when this function is called to prevent re-use of nonce. + // Returns false if subsystem is busy processing an ongoing signing operation. + // Returns false if signing identifier found in message is not supported by the used backend. + // This ends a signing operation at the receiving side so implementation is expected to do any + // deinitializations and enter a power saving state within this call. + virtual bool verifyMsg(MyMessage &msg) = 0; +}; + +#endif From fca0d4b5449c6ae6ab73f1e555be7deab99a650e Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Feb 2015 09:52:37 +0100 Subject: [PATCH 042/660] Dummy signing driver backend The dummy signing driver implements the most rudimentary form of signing. No pre-shared key is used, nonce is simply incremeted each turn and signature is only calculated on the fist byte using data XOR nonce. This driver is intended for library debugging and sensor network integrity verification (signed messages will force the radio to transmit all 32 bytes of data). It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing backends in the network (as seen by this node) and it does verify proper execution order on the API. The dummy driver rejects all other signing backend protocols. Signing backend is selected in MyConfig.h --- libraries/MySensors/MyConfig.h | 14 +- libraries/MySensors/MySigningDriverDummy.cpp | 143 +++++++++++++++++++ libraries/MySensors/MySigningDriverDummy.h | 36 +++++ 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 libraries/MySensors/MySigningDriverDummy.cpp create mode 100644 libraries/MySensors/MySigningDriverDummy.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 96f2253..ce4f0aa 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -15,9 +15,13 @@ #define MYSENSORS_RF_NRF24 //#define MYSENSORS_RF_RF69 +// Choose signing backend by enabling one of the following +#define MYSENSORS_SIGNING_DUMMY - - +// Define a suitable timeout for a signature verification session +// Consider the turnaround from a nonce being generated to a signed message being received +// which might vary, especially in networks with many hops. 5s ought to be enough for anyone. +#define VERIFICATION_TIMEOUT_MS 5000 #ifdef MYSENSORS_RF_NRF24 #include "MyRFDriverNRF24.h" @@ -29,6 +33,12 @@ typedef class MyRFDriverNRF24 MyRFDriverClass; typedef class MyRFDriverRF69 MyRFDriverClass; #endif +#ifdef MYSENSORS_SIGNING_DUMMY +#include "MySigningDriverDummy.h" +#define SIGNING_IDENTIFIER (0) // Reserved for dummy implementation, will not work with other backends +typedef class MySigningDriverDummy MySigningDriverClass; +#endif + /*** * Enable/Disable debug logging */ diff --git a/libraries/MySensors/MySigningDriverDummy.cpp b/libraries/MySensors/MySigningDriverDummy.cpp new file mode 100644 index 0000000..51d418f --- /dev/null +++ b/libraries/MySensors/MySigningDriverDummy.cpp @@ -0,0 +1,143 @@ +/* + Dummy signing backend. Does not provide any security measures. + + Created by Patrick "Anticimex" Fallberg +*/ +#include "MySigningDriver.h" +#include "MySigningDriverDummy.h" + +#ifdef MYSENSORS_SIGNING_DUMMY +// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) +//#define DEBUG_DUMMY_SIGNING + +#ifdef DEBUG_DUMMY_SIGNING +#define DEBUG_DUMMY_PRINTLN(args) Serial.println(args) +#else +#define DEBUG_DUMMY_PRINTLN(args) +#endif + +#ifdef DEBUG_DUMMY_SIGNING +static void DEBUG_DUMMY_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +{ + int i; + Serial.println(str); + for (int i=0; i timestamp + VERIFICATION_TIMEOUT_MS) { + DEBUG_DUMMY_PRINTLN("Verification timeout"); + // Purge nonce + current_nonce = 0; // purge nonce when used + verification_ongoing = false; + return false; + } + } + return true; +} + +bool MySigningDriverDummy::putNonce(MyMessage &msg) { + if (mGetLength(msg) != 2) { + DEBUG_DUMMY_PRINTLN("Incoming nonce with incorrect size"); + return false; // We require a signing identifier and a 1byte nonce + } + + if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { + DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); + return false; + } + + current_nonce = ((uint8_t*)msg.getCustom())[1]; + return true; +} + +bool MySigningDriverDummy::signMsg(MyMessage &msg) { + // If we cannot fit any signature in the message, refuse to sign it + if (mGetLength(msg) > MAX_PAYLOAD-2) { + DEBUG_DUMMY_PRINTLN("Cannot fit any signature to this message"); + return false; + } + + // Calculate signature of message + mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated + DEBUG_DUMMY_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + uint8_t signature = msg.data[0] ^ current_nonce; + msg.data[mGetLength(msg)] = SIGNING_IDENTIFIER; // Add signing identifier + msg.data[mGetLength(msg)+1] = signature; + current_nonce = 0; // purge nonce when used + return true; +} + +bool MySigningDriverDummy::verifyMsg(MyMessage &msg) { + if (!verification_ongoing) { + DEBUG_DUMMY_PRINTLN("No active verification session"); + return false; + } else { + // Make sure we have not expired + if (!checkTimer()) { + return false; + } + + verification_ongoing = false; + + if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { + DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); + return false; + } + + DEBUG_DUMMY_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_DUMMY_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], 2); + + // The dummy signing is the nonce XOR the first payload byte, + // so we "verify" by redoing that calculation with the nonce we transmitted + // Message without a payload this implementation always accepts as signed and messages that cannot + // fit a signature are also accepted as signed + if (mGetLength(msg) && mGetLength(msg) < MAX_PAYLOAD-2) { + uint8_t signature = msg.data[0] ^ current_nonce; + if (msg.data[mGetLength(msg)+1] != signature) { + DEBUG_DUMMY_PRINTBUF("Signature bad. Calculated signature:", &signature, 1); + return false; + } else { + DEBUG_DUMMY_PRINTLN("Signature ok"); + return true; + } + } else { + DEBUG_DUMMY_PRINTLN("No signature in message"); + return false; + } + } +} +#endif diff --git a/libraries/MySensors/MySigningDriverDummy.h b/libraries/MySensors/MySigningDriverDummy.h new file mode 100644 index 0000000..74b88a6 --- /dev/null +++ b/libraries/MySensors/MySigningDriverDummy.h @@ -0,0 +1,36 @@ +/* + Dummy signing backend. Does not provide any security measures. + + Created by Patrick "Anticimex" Fallberg +*/ +#ifndef MySigningDriverDummy_h +#define MySigningDriverDummy_h + +#include "MyConfig.h" +#include "MySigningDriver.h" +#include + +// The dummy signing driver implements the most rudimentary form of signing +// No pre-shared key is used, nonce is simply incremeted each turn and signature +// is only calculated on the fist byte using data XOR nonce. +// This driver is intended for library debugging and sensor network integrity +// verification (signed messages will force the radio to transmit all 32 bytes of data). +// It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in +// the network (as seen by this node) and it does verify proper execution order on the API. +// The dummy driver rejects all other back-ends. +class MySigningDriverDummy : public MySigningDriver +{ +public: + MySigningDriverDummy(); + bool getNonce(MyMessage &msg); + bool checkTimer(void); + bool putNonce(MyMessage &msg); + bool signMsg(MyMessage &msg); + bool verifyMsg(MyMessage &msg); +private: + unsigned long timestamp; + bool verification_ongoing; + uint8_t current_nonce; +}; + +#endif From ce290e280ea03e77bcb1288e6861f5e1557a8085 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 9 Feb 2015 20:11:11 +0100 Subject: [PATCH 043/660] ATSHA204 signing backend Default SDA pin is A3 for single wire communication. The pin is selected in MyConfig.h. I2C variant of ATSHA204 is not supported. Messages are signed using HMAC-SHA256 where some parts of the message digest are ATSHA204 specific. --- libraries/MySensors/MyConfig.h | 19 + .../MySensors/MySigningDriverAtsha204.cpp | 217 ++++++++ libraries/MySensors/MySigningDriverAtsha204.h | 37 ++ libraries/MySensors/utility/ATSHA204.cpp | 521 ++++++++++++++++++ libraries/MySensors/utility/ATSHA204.h | 206 +++++++ 5 files changed, 1000 insertions(+) create mode 100644 libraries/MySensors/MySigningDriverAtsha204.cpp create mode 100644 libraries/MySensors/MySigningDriverAtsha204.h create mode 100644 libraries/MySensors/utility/ATSHA204.cpp create mode 100644 libraries/MySensors/utility/ATSHA204.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index ce4f0aa..82c02da 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -17,6 +17,7 @@ // Choose signing backend by enabling one of the following #define MYSENSORS_SIGNING_DUMMY +//#define MYSENSORS_SIGNING_ATSHA204 // Define a suitable timeout for a signature verification session // Consider the turnaround from a nonce being generated to a signed message being received @@ -39,6 +40,24 @@ typedef class MyRFDriverRF69 MyRFDriverClass; typedef class MySigningDriverDummy MySigningDriverClass; #endif +#ifdef MYSENSORS_SIGNING_ATSHA204 +#ifdef MYSENSORS_SENSOR +#define ATSHA204_PIN 17 //A3 +#endif + +#ifdef MYSENSORS_SERIAL_GATEWAY +#define ATSHA204_PIN 17 //A3 +#endif + +#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#define ATSHA204_PIN 17 //A3 +#endif + +#include "MySigningDriverAtsha204.h" +#define SIGNING_IDENTIFIER (1) // SHA256-based HMAC (ATSHA204 specific) +typedef class MySigningDriverAtsha204 MySigningDriverClass; +#endif + /*** * Enable/Disable debug logging */ diff --git a/libraries/MySensors/MySigningDriverAtsha204.cpp b/libraries/MySensors/MySigningDriverAtsha204.cpp new file mode 100644 index 0000000..a71a30a --- /dev/null +++ b/libraries/MySensors/MySigningDriverAtsha204.cpp @@ -0,0 +1,217 @@ +/* + ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and + HMAC-SHA256 authentication with a readout-protected key. + + Created by Patrick "Anticimex" Fallberg +*/ +#include "MySigningDriver.h" +#include "MySigningDriverAtsha204.h" + +#ifdef MYSENSORS_SIGNING_ATSHA204 +// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) +//#define DEBUG_ATSHA_SIGNING + +#ifdef DEBUG_ATSHA_SIGNING +#define DEBUG_ATSHA_PRINTLN(args) Serial.println(args) +#else +#define DEBUG_ATSHA_PRINTLN(args) +#endif + +#ifdef DEBUG_ATSHA_SIGNING +static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +{ + int i; + Serial.println(str); + for (int i=0; i timestamp + VERIFICATION_TIMEOUT_MS) { + DEBUG_ATSHA_PRINTLN("Verification timeout"); + // Purge nonce + memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + verification_ongoing = false; + return false; + } + } + return true; +} + +bool MySigningDriverAtsha204::putNonce(MyMessage &msg) { + if (mGetLength(msg) != MAX_PAYLOAD) { + DEBUG_ATSHA_PRINTLN("Incoming nonce with incorrect size"); + return false; // We require as big nonce as possible + } + + if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { + DEBUG_ATSHA_PRINTLN("Incorrect signing identifier"); + return false; + } + + memcpy(current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); + return true; +} + +bool MySigningDriverAtsha204::signMsg(MyMessage &msg) { + // If we cannot fit any signature in the message, refuse to sign it + if (mGetLength(msg) > MAX_PAYLOAD-2) { + DEBUG_ATSHA_PRINTLN("Cannot fit any signature to this message"); + return false; + } + + // Calculate signature of message + mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated + DEBUG_ATSHA_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + if (!calculateSignature(msg)) { + DEBUG_ATSHA_PRINTLN("Failed to calculate signature"); + mSetSigned(msg, 0); // make sure signing flag is truthful + return false; + } + + // Transfer as much signature data as the remaining space in the message permits + memcpy(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); + + return true; +} + +bool MySigningDriverAtsha204::verifyMsg(MyMessage &msg) { + if (!verification_ongoing) { + DEBUG_ATSHA_PRINTLN("No active verification session"); + return false; + } else { + // Make sure we have not expired + if (!checkTimer()) { + return false; + } + + verification_ongoing = false; + + if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { + DEBUG_ATSHA_PRINTLN("Incorrect signing identifier"); + return false; + } + + DEBUG_ATSHA_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_ATSHA_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + + // Get signature of message + if (!calculateSignature(msg)) { + DEBUG_ATSHA_PRINTLN("Failed to calculate signature"); + return false; + } + + // Compare the caluclated signature with the provided signature + if (memcmp(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { + DEBUG_ATSHA_PRINTBUF("Signature bad. Calculated signature:", &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); + return false; + } else { + DEBUG_ATSHA_PRINTLN("Signature ok"); + return true; + } + } +} + +// Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) +bool MySigningDriverAtsha204::calculateSignature(MyMessage &msg) { + memset(temp_message, 0, 32); + memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + + // Wake device before starting operations + if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) return false; + + // Program the data to sign into the ATSHA204 + if (atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, temp_message, + WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to program data"); + return false; + } + + // Program the nonce to use for the signature (has to be done just before GENDIG due to chip limitations) + if (atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, current_nonce, + NONCE_COUNT_LONG, tx_buffer, NONCE_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to program nonce"); + // Purge nonce when used + memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + return false; + } + + // Purge nonce when used + memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + + // Generate digest of data and nonce + if (atsha204.sha204m_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL, + GENDIG_COUNT_DATA, tx_buffer, GENDIG_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to generate digest"); + return false; + } + + // Calculate HMAC of message+nonce digest and secret key + if (atsha204.sha204m_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, + HMAC_COUNT, tx_buffer, HMAC_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to generate HMAC"); + return false; + } + + // Put device back to sleep + atsha204.sha204c_sleep(); + + // Overwrite the first byte in the signature with the signing identifier + rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; + + DEBUG_ATSHA_PRINTBUF("HMAC:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); + return true; // We return with the signature in rx_buffer[SHA204_BUFFER_POS_DATA] +} +#endif diff --git a/libraries/MySensors/MySigningDriverAtsha204.h b/libraries/MySensors/MySigningDriverAtsha204.h new file mode 100644 index 0000000..a2f6b9d --- /dev/null +++ b/libraries/MySensors/MySigningDriverAtsha204.h @@ -0,0 +1,37 @@ +/* + ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and + HMAC-SHA256 authentication with a readout-protected key. + + Created by Patrick "Anticimex" Fallberg +*/ +#ifndef MySigningDriverAtsha204_h +#define MySigningDriverAtsha204_h + +#include "MyConfig.h" +#include "MySigningDriver.h" +#include "utility/ATSHA204.h" +#include + +// The ATSHA204 is capable of generating proper random numbers for nonce +// and can calculate HMAC-SHA256 signatures. This is enterprise- +// level of security and ought to implement the signing needs for anybody. +class MySigningDriverAtsha204 : public MySigningDriver +{ +public: + MySigningDriverAtsha204(); + bool getNonce(MyMessage &msg); + bool checkTimer(void); + bool putNonce(MyMessage &msg); + bool signMsg(MyMessage &msg); + bool verifyMsg(MyMessage &msg); +private: + unsigned long timestamp; + bool verification_ongoing; + uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; + uint8_t temp_message[32]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + bool calculateSignature(MyMessage &msg); +}; + +#endif diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp new file mode 100644 index 0000000..da63668 --- /dev/null +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -0,0 +1,521 @@ +#include "Arduino.h" +#include "ATSHA204.h" + +// atsha204Class Constructor +// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin +// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin +// As well as the bit value for each of those registers +atsha204Class::atsha204Class(uint8_t pin) +{ + device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin + uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers + + // Point to data direction register port of pin + device_port_DDR = portModeRegister(port); + // Point to output register of pin + device_port_OUT = portOutputRegister(port); + // Point to input register of pin + device_port_IN = portInputRegister(port); +} + +/* SWI bit bang functions */ + +void atsha204Class::swi_set_signal_pin(uint8_t is_high) +{ + *device_port_DDR |= device_pin; + + if (is_high) + *device_port_OUT |= device_pin; + else + *device_port_OUT &= ~device_pin; +} + +uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + *device_port_OUT |= device_pin; + *device_port_DDR |= device_pin; + + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + if (bit_mask & buffer[i]) + { + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } + else + { + // Send a zero bit. + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; +} + +uint8_t atsha204Class::swi_send_byte(uint8_t value) +{ + return swi_send_bytes(1, &value); +} + +uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input. + *device_port_DDR &= ~device_pin; + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) + { + // Wait for falling edge. + if ((*device_port_IN & device_pin) == 0) + break; + } + + if (timeout_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do + { + // Wait for rising edge. + if ((*device_port_IN & device_pin) != 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do + { + if ((*device_port_IN & device_pin) == 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) + { + do + { + if ((*device_port_IN & device_pin) != 0) + break; + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else + buffer[i] |= bit_mask; // received "one" bit + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) + break; + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) + { + if (i > 0) + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + return status; +} + +/* Physical functions */ + +uint8_t atsha204Class::sha204c_sleep() +{ + return swi_send_byte(SHA204_SWI_FLAG_SLEEP); +} + +uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) +{ + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) + response[i] = 0; + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) + { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) + return SHA204_INVALID_SIZE; + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) + return SHA204_RX_NO_RESPONSE; + else + return SHA204_RX_FAIL; +} + +/* Communication functions */ + +uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) +{ + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); + + uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) + ret_code = SHA204_INVALID_SIZE; + else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) + ret_code = SHA204_COMM_FAIL; + else + { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) + ret_code = SHA204_BAD_CRC; + } + if (ret_code != SHA204_SUCCESS) + delay(SHA204_COMMAND_EXEC_MAX); + + return ret_code; +} + +uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) +{ + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + delay(SHA204_SYNC_TIMEOUT); + uint8_t ret_code = sha204p_receive_response(size, response); + if (ret_code == SHA204_SUCCESS) + return ret_code; + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + (void) sha204c_sleep(); + ret_code = sha204c_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); +} + +uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +{ + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) + { + // Send command. + ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) + ret_code = SHA204_COMM_FAIL; + else + ret_code = swi_send_bytes(count, tx_buffer); + + if (ret_code != SHA204_SUCCESS) + { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + return ret_code; // The device seems to be dead in the water. + else + continue; + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) + { + // Reset response buffer. + for (i = 0; i < rx_size; i++) + rx_buffer[i] = 0; + + // Poll for response. + timeout_countdown = execution_timeout_us; + do + { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } + while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) + { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + // The device seems to be dead in the water. + return ret_code; + else + break; + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) + { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) + { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + // Received non-status response. We are done. + return ret_code; + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) + return SHA204_PARSE_ERROR; + if (status_byte == SHA204_STATUS_BYTE_EXEC) + return SHA204_CMD_FAIL; + if (status_byte == SHA204_STATUS_BYTE_COMM) + { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else + { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; +} + + +/* Marshaling functions */ +uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ + uint8_t poll_delay, poll_timeout, response_size; + uint8_t *p_buffer; + uint8_t len; + + // Supply delays and response size. + switch (op_code) + { + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; + } + + // Assemble command. + len = datalen1 + SHA204_CMD_SIZE_MIN; + p_buffer = tx_buffer; + *p_buffer++ = len; + *p_buffer++ = op_code; + *p_buffer++ = param1; + *p_buffer++ = param2 & 0xFF; + *p_buffer++ = param2 >> 8; + + if (datalen1 > 0) { + memcpy(p_buffer, data1, datalen1); + p_buffer += datalen1; + } + + sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer); + + // Send command and receive response. + return sha204c_send_and_receive(&tx_buffer[0], response_size, + &rx_buffer[0], poll_delay, poll_timeout); +} + +/* CRC Calculator and Checker */ + +void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint8_t counter; + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + } + } + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); +} + +uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) +{ + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; +} \ No newline at end of file diff --git a/libraries/MySensors/utility/ATSHA204.h b/libraries/MySensors/utility/ATSHA204.h new file mode 100644 index 0000000..cb2abc8 --- /dev/null +++ b/libraries/MySensors/utility/ATSHA204.h @@ -0,0 +1,206 @@ +#ifndef ATSHA204_H +#define ATSHA204_H +#include "Arduino.h" + +/* This is a scaled down variant of the ATSHA204 library, tweaked to meet the specific needs of MySensors. */ + +/* Library return codes */ +#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded. +#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error +#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error +#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error +#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown +#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state. +#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error +#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.) +#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set +#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size. +#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received +#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0. +#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response. +#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up + +#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules. +#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0. + +/* bitbang_config.h */ + +#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns) +#define START_PULSE_WIDTH (4340) //! width of start pulse (ns) +#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns) +#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit +#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse. +#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse. + +/* swi_phys.h */ + +#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded. +#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out. +#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received. + +/* sha204_physical.h */ + +#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response +#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet +#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response +#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response +#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units +#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms + +/* sha204_swi.c */ +#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command +#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response +#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode +#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode + +/* sha204_comm_marshaling.h */ +// command op-code definitions +#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code +#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code +#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code +#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code + +// packet size definitions +#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data + +// definitions for command packet indexes common to all commands +#define SHA204_COUNT_IDX ( 0) //!< command packet index for count +#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code +#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter +#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter +#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter + +// zone definitions +#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone +#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone +#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone +#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask +#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes. +#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes. +#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0. + +// GenDig command definitions +#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT SHA204_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data" +#define GENDIG_OTHER_DATA_SIZE (4) //!< GenDig size of "other data" +#define GENDIG_ZONE_CONFIG ((uint8_t) 0) //!< GenDig zone id config +#define GENDIG_ZONE_OTP ((uint8_t) 1) //!< GenDig zone id OTP +#define GENDIG_ZONE_DATA ((uint8_t) 2) //!< GenDig zone id data + +// HMAC command definitions +#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. +#define HMAC_MODE_SOURCE_FLAG_MATCH ((uint8_t) 0x04) //!< HMAC mode bit 2: match TempKey.SourceFlag + +// Nonce command definitions +#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX SHA204_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data +#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data +#define NONCE_MODE_MASK ((uint8_t) 3) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t) 0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t) 0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t) 0x03) //!< Nonce mode: pass-through +#define NONCE_NUMIN_SIZE (20) //!< Nonce data length +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3) + +// Random command definitions +#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT SHA204_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update + +// Write command definitions +#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX SHA204_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC +#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC +#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC +#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t) 0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t) 0x40) //!< Write zone bit 6: write encrypted with MAC + +// Response size definitions +#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command +#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command +#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 +#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command +#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command + +// command timing definitions for minimum execution times (ms) +#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) + +// command timing definitions for maximum execution times (ms) +#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) + +/* from sha204_config.h */ + +#define CPU_CLOCK_DEVIATION_POSITIVE (1.01) +#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99) +#define SHA204_RETRY_COUNT (1) +#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts +#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits). +#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine +#define SHA204_RESPONSE_TIMEOUT ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE) //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag. + +/* from sha204_comm.h */ + +#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay +#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#define SHA204_CMD_SIZE_MAX ((uint8_t) NONCE_COUNT_LONG) //! maximum size of command packet (Nonce) +#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes +#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response +#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response +#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error +#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error +#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error +#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error + +class atsha204Class +{ +private: + uint8_t device_pin; + volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; + void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); + uint8_t sha204c_check_crc(uint8_t *response); + void swi_set_signal_pin(uint8_t is_high); + uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_byte(uint8_t value); + uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); +public: + atsha204Class(uint8_t pin); // Constructor + uint8_t sha204c_wakeup(uint8_t *response); + uint8_t sha204c_sleep(); + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); +}; + +#endif From 911ae9c9d924ca879610112fa71d1b9823b17ae2 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Tue, 17 Feb 2015 23:10:56 +0100 Subject: [PATCH 044/660] ATSHA204 emulated signing backend ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end could compromise the key used in the signed message infrastructure if device is lost and its memory dumped. The seed for the random number generated is sampled from an analog pin. The pin is set in MyConfig.h using RANDOMSEED_PIN. The pin should be unconnected. The key to use for HMAC calculations must match the key used by other nodes this node will exchange signed messages with. The key for ATSHA204 emulator is set in MyConfig.h using hmacKey. --- libraries/MySensors/MyConfig.h | 28 +++ .../MySensors/MySigningDriverAtsha204Soft.cpp | 225 ++++++++++++++++++ .../MySensors/MySigningDriverAtsha204Soft.h | 43 ++++ libraries/MySensors/utility/sha256.cpp | 167 +++++++++++++ libraries/MySensors/utility/sha256.h | 40 ++++ 5 files changed, 503 insertions(+) create mode 100644 libraries/MySensors/MySigningDriverAtsha204Soft.cpp create mode 100644 libraries/MySensors/MySigningDriverAtsha204Soft.h create mode 100644 libraries/MySensors/utility/sha256.cpp create mode 100644 libraries/MySensors/utility/sha256.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 82c02da..0ffab4e 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -18,6 +18,7 @@ // Choose signing backend by enabling one of the following #define MYSENSORS_SIGNING_DUMMY //#define MYSENSORS_SIGNING_ATSHA204 +//#define MYSENSORS_SIGNING_ATSHA204SOFT // Define a suitable timeout for a signature verification session // Consider the turnaround from a nonce being generated to a signed message being received @@ -58,6 +59,33 @@ typedef class MySigningDriverDummy MySigningDriverClass; typedef class MySigningDriverAtsha204 MySigningDriverClass; #endif +#ifdef MYSENSORS_SIGNING_ATSHA204SOFT +// Key to use for HMAC calculation +static uint8_t hmacKey[32] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +// Pick an unconnected analog pin for RANDOMSEED_PIN +#ifdef MYSENSORS_SENSOR +#define RANDOMSEED_PIN 7 //A7 +#endif + +#ifdef MYSENSORS_SERIAL_GATEWAY +#define RANDOMSEED_PIN 7 //A7 +#endif + +#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#define RANDOMSEED_PIN 7 //A7 +#endif + +#include "MySigningDriverAtsha204Soft.h" +#define SIGNING_IDENTIFIER (1) // SHA256-based HMAC (ATSHA204 specific) +typedef class MySigningDriverAtsha204Soft MySigningDriverClass; +#endif + /*** * Enable/Disable debug logging */ diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp new file mode 100644 index 0000000..aaff71f --- /dev/null +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp @@ -0,0 +1,225 @@ +/* + ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random + number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. + NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end + could compromise the key used in the signed message infrastructure if device is lost and its memory + dumped. + + Created by Patrick "Anticimex" Fallberg +*/ +#include "MySigningDriver.h" +#include "MySigningDriverAtsha204Soft.h" +#include "sha256.h" + +#ifdef MYSENSORS_SIGNING_ATSHA204SOFT +// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) +//#define DEBUG_ATSHASOFT_SIGNING + +#ifdef DEBUG_ATSHASOFT_SIGNING +#define DEBUG_ATSHASOFT_PRINTLN(args) Serial.println(args) +#else +#define DEBUG_ATSHASOFT_PRINTLN(args) +#endif + +#ifdef DEBUG_ATSHASOFT_SIGNING +static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +{ + int i; + Serial.println(str); + for (int i=0; i timestamp + VERIFICATION_TIMEOUT_MS) { + DEBUG_ATSHASOFT_PRINTLN("Verification timeout"); + // Purge nonce + memset(current_nonce, 0xAA, 32); + verification_ongoing = false; + return false; + } + } + return true; +} + +bool MySigningDriverAtsha204Soft::putNonce(MyMessage &msg) { + if (mGetLength(msg) != MAX_PAYLOAD) { + DEBUG_ATSHASOFT_PRINTLN("Incoming nonce with incorrect size"); + return false; // We require as big nonce as possible + } + + if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { + DEBUG_ATSHASOFT_PRINTLN("Incorrect signing identifier"); + return false; + } + + memcpy(current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); + return true; +} + +bool MySigningDriverAtsha204Soft::signMsg(MyMessage &msg) { + // If we cannot fit any signature in the message, refuse to sign it + if (mGetLength(msg) > MAX_PAYLOAD-2) { + DEBUG_ATSHASOFT_PRINTLN("Cannot fit any signature to this message"); + return false; + } + + // Calculate signature of message + mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated + DEBUG_ATSHASOFT_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + if (!calculateSignature(msg)) { + DEBUG_ATSHASOFT_PRINTLN("Failed to calculate signature"); + mSetSigned(msg, 0); // make sure signing flag is truthful + return false; + } + + // Transfer as much signature data as the remaining space in the message permits + memcpy(&msg.data[mGetLength(msg)], hmac, MAX_PAYLOAD-mGetLength(msg)); + + return true; +} + +bool MySigningDriverAtsha204Soft::verifyMsg(MyMessage &msg) { + if (!verification_ongoing) { + DEBUG_ATSHASOFT_PRINTLN("No active verification session"); + return false; + } else { + // Make sure we have not expired + if (!checkTimer()) { + return false; + } + + verification_ongoing = false; + + if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { + DEBUG_ATSHASOFT_PRINTLN("Incorrect signing identifier"); + return false; + } + + DEBUG_ATSHASOFT_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_ATSHASOFT_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + + // Get signature of message + if (!calculateSignature(msg)) { + DEBUG_ATSHASOFT_PRINTLN("Failed to calculate signature"); + return false; + } + + // Compare the caluclated signature with the provided signature + if (memcmp(&msg.data[mGetLength(msg)], hmac, MAX_PAYLOAD-mGetLength(msg))) { + DEBUG_ATSHASOFT_PRINTBUF("Signature bad. Calculated signature:", hmac, MAX_PAYLOAD-mGetLength(msg)); + return false; + } else { + DEBUG_ATSHASOFT_PRINTLN("Signature ok"); + return true; + } + } +} + +// Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) +bool MySigningDriverAtsha204Soft::calculateSignature(MyMessage &msg) { + memset(temp_message, 0, 32); + memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + + // ATSHA204 calculates the HMAC with a PSK and a SHA256 digest of the following data: + // 32 bytes zeroes + // 32 bytes digest, + // 1 byte OPCODE (0x11) + // 1 byte Mode (0x04) + // 2 bytes SlotID (0x0000) + // 11 bytes zeroes + // SN[8] (0xEE) + // 4 bytes zeroes + // SN[0:1] (0x0123) + // 2 bytes zeroes + + // The digest is calculated as a SHA256 digest of the following: + // 32 bytes message + // 1 byte OPCODE (0x15) + // 1 byte param1 (0x02) + // 2 bytes param2 (0x0800) + // SN[8] (0xEE) + // SN[0:1] (0x0123) + // 25 bytes zeroes + // 32 bytes nonce + + // Calculate message digest first + Sha256.init(); + for (int i=0; i<32; i++) Sha256.write(temp_message[i]); + Sha256.write(0x15); // OPCODE + Sha256.write(0x02); // param1 + Sha256.write(0x08); // param2(1) + Sha256.write(0x00); // param2(2) + Sha256.write(0xEE); // SN[8] + Sha256.write(0x01); // SN[0] + Sha256.write(0x23); // SN[1] + for (int i=0; i<25; i++) Sha256.write(0x00); + for (int i=0; i<32; i++) Sha256.write(current_nonce[i]); + // Purge nonce when used + memset(current_nonce, 0xAA, 32); + memcpy(temp_message, Sha256.result(), 32); + + // Feed "message" to HMAC calculator + Sha256.initHmac(hmacKey,32); // Set the key to use + for (int i=0; i<32; i++) Sha256.write(0x00); // 32 bytes zeroes + for (int i=0; i<32; i++) Sha256.write(temp_message[i]); // 32 bytes digest + Sha256.write(0x11); // OPCODE + Sha256.write(0x04); // Mode + Sha256.write(0x00); // SlotID(1) + Sha256.write(0x00); // SlotID(2) + for (int i=0; i<11; i++) Sha256.write(0x00); // 11 bytes zeroes + Sha256.write(0xEE); // SN[8] + for (int i=0; i<4; i++) Sha256.write(0x00); // 4 bytes zeroes + Sha256.write(0x01); // SN[0] + Sha256.write(0x23); // SN[1] + for (int i=0; i<2; i++) Sha256.write(0x00); // 2 bytes zeroes + + hmac = Sha256.resultHmac(); + + // Overwrite the first byte in the signature with the signing identifier + hmac[0] = SIGNING_IDENTIFIER; + + DEBUG_ATSHASOFT_PRINTBUF("HMAC:", hmac, 32); + return true; +} +#endif diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.h b/libraries/MySensors/MySigningDriverAtsha204Soft.h new file mode 100644 index 0000000..16d8d3e --- /dev/null +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.h @@ -0,0 +1,43 @@ +/* + ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random + number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. + NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end + could compromise the key used in the signed message infrastructure if device is lost and its memory + dumped. + + Created by Patrick "Anticimex" Fallberg +*/ +#ifndef MySigningDriverHmac256Soft_h +#define MySigningDriverHmac256Soft_h + +#include "MyConfig.h" +#include "MySigningDriver.h" +#include "utility/ATSHA204.h" +#include + +// This implementation is the pure software variant of the ATSHA204. +// It is designed to work fully compliant with nodes using ATSHA204 in the network +// and therefore uses the same signing identifier as ATSHA204. +// Because it is completly software based, the quality of the generated random numbers +// is weaker though. Random numbers are generated using the Arduino library and seed +// is sampled from an analog pin. This pin should unconnected in the hardware. +// The pin is selected using RANDOMSEED_PIN in MyConfig.h. +class MySigningDriverAtsha204Soft : public MySigningDriver +{ +public: + MySigningDriverAtsha204Soft(); + bool getNonce(MyMessage &msg); + bool checkTimer(void); + bool putNonce(MyMessage &msg); + bool signMsg(MyMessage &msg); + bool verifyMsg(MyMessage &msg); +private: + unsigned long timestamp; + bool verification_ongoing; + uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; + uint8_t temp_message[32]; + uint8_t* hmac; + bool calculateSignature(MyMessage &msg); +}; + +#endif diff --git a/libraries/MySensors/utility/sha256.cpp b/libraries/MySensors/utility/sha256.cpp new file mode 100644 index 0000000..8434499 --- /dev/null +++ b/libraries/MySensors/utility/sha256.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include "sha256.h" + +uint32_t sha256K[] PROGMEM = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define BUFFER_SIZE 64 + +uint8_t sha256InitState[] PROGMEM = { + 0x67,0xe6,0x09,0x6a, // H0 + 0x85,0xae,0x67,0xbb, // H1 + 0x72,0xf3,0x6e,0x3c, // H2 + 0x3a,0xf5,0x4f,0xa5, // H3 + 0x7f,0x52,0x0e,0x51, // H4 + 0x8c,0x68,0x05,0x9b, // H5 + 0xab,0xd9,0x83,0x1f, // H6 + 0x19,0xcd,0xe0,0x5b // H7 +}; + +void Sha256Class::init(void) { + memcpy_P(state.b,sha256InitState,32); + byteCount = 0; + bufferOffset = 0; +} + +uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) { + return ((number << (32-bits)) | (number >> bits)); +} + +void Sha256Class::hashBlock() { + uint8_t i; + uint32_t a,b,c,d,e,f,g,h,t1,t2; + + a=state.w[0]; + b=state.w[1]; + c=state.w[2]; + d=state.w[3]; + e=state.w[4]; + f=state.w[5]; + g=state.w[6]; + h=state.w[7]; + + for (i=0; i<64; i++) { + if (i>=16) { + t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; + t2 = buffer.w[(i-2)&15]; + t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10); + t2 = buffer.w[(i-15)&15]; + t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3); + buffer.w[i&15] = t1; + } + t1 = h; + t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) + t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) + t1 += pgm_read_dword(sha256K+i); // Ki + t1 += buffer.w[i&15]; // Wi + t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) + t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) + h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; + } + state.w[0] += a; + state.w[1] += b; + state.w[2] += c; + state.w[3] += d; + state.w[4] += e; + state.w[5] += f; + state.w[6] += g; + state.w[7] += h; +} + +void Sha256Class::addUncounted(uint8_t data) { + buffer.b[bufferOffset ^ 3] = data; + bufferOffset++; + if (bufferOffset == BUFFER_SIZE) { + hashBlock(); + bufferOffset = 0; + } +} + +void Sha256Class::write(uint8_t data) { + ++byteCount; + addUncounted(data); +} + +void Sha256Class::pad() { + // Implement SHA-256 padding (fips180-2 §5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + addUncounted(0x80); + while (bufferOffset != 56) addUncounted(0x00); + + // Append length in the last 8 bytes + addUncounted(0); // We're only using 32 bit lengths + addUncounted(0); // But SHA-1 supports 64 bit lengths + addUncounted(0); // So zero pad the top bits + addUncounted(byteCount >> 29); // Shifting to multiply by 8 + addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as + addUncounted(byteCount >> 13); // byte. + addUncounted(byteCount >> 5); + addUncounted(byteCount << 3); +} + + +uint8_t* Sha256Class::result(void) { + // Pad to complete the last block + pad(); + + // Swap byte order back + for (int i=0; i<8; i++) { + uint32_t a,b; + a=state.w[i]; + b=a<<24; + b|=(a<<8) & 0x00ff0000; + b|=(a>>8) & 0x0000ff00; + b|=a>>24; + state.w[i]=b; + } + + // Return pointer to hash (20 characters) + return state.b; +} + +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +uint8_t keyBuffer[BLOCK_LENGTH]; // K0 in FIPS-198a +uint8_t innerHash[HASH_LENGTH]; + +void Sha256Class::initHmac(const uint8_t* key, int keyLength) { + uint8_t i; + memset(keyBuffer,0,BLOCK_LENGTH); + if (keyLength > BLOCK_LENGTH) { + // Hash long keys + init(); + for (;keyLength--;) write(*key++); + memcpy(keyBuffer,result(),HASH_LENGTH); + } else { + // Block length keys are used as is + memcpy(keyBuffer,key,keyLength); + } + // Start inner hash + init(); + for (i=0; i + +#define HASH_LENGTH 32 +#define BLOCK_LENGTH 64 + +union _buffer { + uint8_t b[BLOCK_LENGTH]; + uint32_t w[BLOCK_LENGTH/4]; +}; +union _state { + uint8_t b[HASH_LENGTH]; + uint32_t w[HASH_LENGTH/4]; +}; + +class Sha256Class +{ + public: + void init(void); + void initHmac(const uint8_t* secret, int secretLength); + uint8_t* result(void); + uint8_t* resultHmac(void); + virtual void write(uint8_t); + private: + void pad(); + void addUncounted(uint8_t data); + void hashBlock(); + uint32_t ror32(uint32_t number, uint8_t bits); + _buffer buffer; + uint8_t bufferOffset; + _state state; + uint32_t byteCount; + uint8_t keyBuffer[BLOCK_LENGTH]; + uint8_t innerHash[HASH_LENGTH]; +}; + +#endif From 644eac1712d74f8f149ab57877253129a2546c6b Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Feb 2015 13:49:08 +0100 Subject: [PATCH 045/660] Signing support implemented in the MySensors library The dummy signing driver backend is used. But with this commit all framework logic for managing signed messages in the MySensors ecosystem is implemented and enables more sophisticated signing backends to be added later on. For a sensor (or gateway) that require a gateway to send signed messages to it, add 'true' as the fifth argument to 'begin'. The gateway will automatically inform a node of it's signing requirements as soon as it receivs the nodes signing preference. It is important to understand that if the gateway require signing, it will in this implementation only require signing from nodes that require signing by the gateway. If the sensor requires signing from another node on the network which it communicates directly with, it needs to send 'true' in an internal message of type I_REQUEST_SIGNING. --- Bootloader/MyOtaBootloader.c | 6 ++ libraries/MySensors/MySensor.cpp | 99 +++++++++++++++++++++++++++++--- libraries/MySensors/MySensor.h | 13 ++++- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/Bootloader/MyOtaBootloader.c b/Bootloader/MyOtaBootloader.c index fe4f24f..8dc1ef5 100644 --- a/Bootloader/MyOtaBootloader.c +++ b/Bootloader/MyOtaBootloader.c @@ -152,6 +152,12 @@ int main () { address(nc.nodeId); } + // Inform gateway that bootloader does not accept signed messages + msg.type = I_REQUEST_SIGNING; + mSetLength(msg, 1); + msg.data[0] = 0; + sendWrite(msg); + // Read settings from EEPROM eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig)); diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 7c8bff6..c227c0c 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -13,6 +13,10 @@ #define DISTANCE_INVALID (0xFF) +// Macros for manipulating signing requirement table +#define DO_SIGN(node) (doSign[node>>4]&(node%16)) +#define SET_SIGN(node) (doSign[node>>4]|=(node%16)) +#define CLEAR_SIGN(node) (doSign[node>>4]&=~(node%16)) // Inline function and macros static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { @@ -35,14 +39,17 @@ static inline bool isValidDistance( const uint8_t distance ) { MySensor::MySensor() { radio = (MyRFDriver*) new MyRFDriverClass(); + signer = (MySigningDriver*) new MySigningDriverClass(); } -void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { +void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId, bool requestSignatures) { Serial.begin(BAUD_RATE); repeaterMode = _repeaterMode; msgCallback = _msgCallback; failedTransmissions = 0; + requireSigning = requestSignatures; + // Only gateway should use node id 0 isGateway = _nodeId == 0; @@ -55,6 +62,8 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM eeprom_read_block((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + // Read out the signing requirements from EEPROM + eeprom_read_block((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); if (isGateway) { nc.distance = 0; @@ -137,6 +146,9 @@ void MySensor::setupNode() { // Send presentation for this radio node (attach present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); + // Notify gateway (and possibly controller) about the signing preferences of this node + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(requireSigning)); + // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration // which is picked up in process() @@ -178,6 +190,19 @@ boolean MySensor::sendRoute(MyMessage &message) { return false; } + mSetVersion(message, PROTOCOL_VERSION); + + // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a signing handshake message + if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) && + (mGetCommand(message) != C_INTERNAL || (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING))) { + if (!sign(message)) { + debug(PSTR("Message signing failed\n")); + return false; + } + // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, + // or signature will become invalid and the message rejected by the receiver + } else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned + if (dest == GATEWAY_ADDRESS || !repeaterMode) { // If destination is the gateway or if we aren't a repeater, let // our parent take care of the message @@ -240,14 +265,13 @@ boolean MySensor::sendRoute(MyMessage &message) { } boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { - uint8_t length = mGetLength(message); + uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = nc.nodeId; - mSetVersion(message, PROTOCOL_VERSION); bool ok = radio->send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); + mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); return ok; } @@ -290,12 +314,26 @@ boolean MySensor::process() { if (!radio->available(&to)) return false; + (void)signer->checkTimer(); // Manage signing timeout + uint8_t len = radio->receive((uint8_t *)&msg); + // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) + // Note that we do not care at all about any signature found if we do not require signing + if (requireSigning && msg.destination == nc.nodeId && mGetLength(msg) && + (mGetCommand(msg) != C_INTERNAL || (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING))) { + if (!mGetSigned(msg)) return false; // Received an unsigned message but we do require signing. This message gets nowhere! + else if (!signer->verifyMsg(msg)) { + debug(PSTR("Message verification failed\n")); + return false; // This signed message has been tampered with! + } + } + // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; - debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d:%s\n"), - msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, mGetPayloadType(msg), mGetLength(msg), msg.getString(convBuf)); + debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), + msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, mGetPayloadType(msg), mGetLength(msg), mGetSigned(msg), msg.getString(convBuf)); + mSetSigned(msg,0); // Clear the sign-flag now as verification (and debug printing) is completed if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { debug(PSTR("version: %d\n"),mGetVersion(msg)); @@ -349,6 +387,32 @@ boolean MySensor::process() { } } return false; + } else if (type == I_GET_NONCE) { + if (signer->getNonce(msg)) { + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); + } else { + return false; + } + } else if (type == I_REQUEST_SIGNING) { + if (msg.getBool()) { + // We received an indicator that the sender require us to sign all messages we send to it + SET_SIGN(msg.sender); + } else { + // We received an indicator that the sender does not require us to sign all messages we send to it + CLEAR_SIGN(msg.sender); + } + // Save updated table + eeprom_write_block((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); + + // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing + // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node + // to sign it's messages + if (isGateway) { + if (requireSigning) + sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(requireSigning)); + else + sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + } } else if (sender == GATEWAY_ADDRESS) { bool isMetric; @@ -543,6 +607,27 @@ int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, ui return retVal; } +bool MySensor::sign(MyMessage &message) { + MyMessage msgNonce; + if (!sendRoute(build(msgNonce, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + return false; + } else { + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust process() takes care of them + unsigned long enter = millis(); + while (millis() - enter < 5000) { + if (process()) { + if (getLastMessage().type == I_GET_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + if (signer->putNonce(getLastMessage()) && signer->signMsg(message)) return true; + break; + } + } + } + } + return false; +} + #ifdef DEBUG void MySensor::debugPrint(const char *fmt, ... ) { char fmtBuffer[300]; diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index c9e79a7..8541492 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -14,6 +14,7 @@ #include "Version.h" // Auto generated by bot #include "MyRFDriver.h" +#include "MySigningDriver.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -50,7 +51,8 @@ #define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) #define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) #define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) // First free address for sketch static configuration +#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration // Search for a new parent node after this many transmission failures #define SEARCH_FAILURES 5 @@ -86,9 +88,10 @@ class MySensor * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. + * @param requestSignatures Set this to true if you want destination node to sign all messages sent to this node. Default is not to require signing. */ - void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); + void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO, bool requestSignatures=false); /** * Return the nodes nodeId. @@ -238,10 +241,15 @@ class MySensor bool repeaterMode; bool autoFindParent; bool isGateway; + bool requireSigning; + uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication + MyMessage msg; // Buffer for incoming messages. MyMessage ack; // Buffer for ack messages. MyRFDriver *radio; + + MySigningDriver *signer; void setupRepeaterMode(); void setupRadio(); @@ -264,6 +272,7 @@ class MySensor void addChildRoute(uint8_t childId, uint8_t route); void removeChildRoute(uint8_t childId); void internalSleep(unsigned long ms); + bool sign(MyMessage &message); }; #endif From cfc8d9f28a9c74e0854c4e41cf39d4f488c13364 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Feb 2015 14:35:19 +0100 Subject: [PATCH 046/660] Added example sketch for a secure actuator The sketch closely resembles the RelayActuator example. The difference is that this sketch require gateway to sign all messages addressed to the actuator. --- .../SecureActuator/SecureActuator.ino | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 libraries/MySensors/examples/SecureActuator/SecureActuator.ino diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino new file mode 100644 index 0000000..c86ff49 --- /dev/null +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -0,0 +1,57 @@ +// Example sketch showing how to securely control locks. +// This example will remember lock state even after power failure. + +#include +#include + +#ifndef MYSENSORS_SENSOR +#error Please switch to MYSENSORS_SENSOR in MyConfig.h +#endif + +#define LOCK_1 3 // Arduino Digital I/O pin number for first lock (second on pin+1 etc) +#define NOF_LOCKS 1 // Total number of attached locks +#define LOCK_LOCK 1 // GPIO value to write to lock attached lock +#define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock + +MySensor gw; + +void setup() +{ + // Initialize library and add callback for incoming messages (signing is required) + gw.begin(incomingMessage, AUTO, true, AUTO, true); + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("Secure Lock", "1.0"); + + // Fetch lock status + for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) { + // Register all locks to gw (they will be created as child devices) + gw.present(lock, S_LOCK, false); + // Then set lock pins in output mode + pinMode(pin, OUTPUT); + // Set lock to last known state (using eeprom storage) + digitalWrite(pin, gw.loadState(lock)?LOCK_LOCK:LOCK_UNLOCK); + } +} + + +void loop() +{ + // Alway process incoming messages whenever possible + gw.process(); +} + +void incomingMessage(const MyMessage &message) { + // We only expect one type of message from controller. But we better check anyway. + if (message.type==V_LOCK_STATUS && message.sensor<=NOF_LOCKS) { + // Change relay state + digitalWrite(message.sensor-1+LOCK_1, message.getBool()?LOCK_LOCK:LOCK_UNLOCK); + // Store state in eeprom + gw.saveState(message.sensor, message.getBool()); + // Write some debug info + Serial.print("Incoming change for lock:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + } +} + From d7474a7b8d8711c5f6fa50709690f88b4667a5f5 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 18 Feb 2015 11:15:54 -0200 Subject: [PATCH 047/660] fix ifdef for MYSENSORS_ETHERNET_MQTT_GATEWAY --- libraries/MySensors/MyConfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 0ffab4e..ecae372 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -50,7 +50,7 @@ typedef class MySigningDriverDummy MySigningDriverClass; #define ATSHA204_PIN 17 //A3 #endif -#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) #define ATSHA204_PIN 17 //A3 #endif @@ -77,7 +77,7 @@ static uint8_t hmacKey[32] = { #define RANDOMSEED_PIN 7 //A7 #endif -#ifdef MYSENSORS_ETHERNET_MQTT_GATEWAY +#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) #define RANDOMSEED_PIN 7 //A7 #endif From 729cf8da5d4ad9eeeb99736e390e5dbceef6b113 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 18 Feb 2015 23:40:58 +0100 Subject: [PATCH 048/660] Bugifx: GW should not send presentation --- libraries/MySensors/MySensor.cpp | 38 +++++++++++++++----------------- libraries/MySensors/MySensor.h | 1 - 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 7c8bff6..3a74892 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -49,7 +49,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b if (repeaterMode) { setupRepeaterMode(); } - setupRadio(); + + // Setup radio + radio->init(); // Read settings from eeprom eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); @@ -92,21 +94,10 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b requestNodeId(); } - if (!isGateway) { - debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), repeaterMode?"repeater":"sensor", nc.nodeId, nc.parentNodeId, nc.distance); - } + setupNode(); - // If we got an id, set this node to use it - if (nc.nodeId != AUTO) { - setupNode(); - // Wait configuration reply. - wait(2000); - } -} + debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), isGateway?"gateway":(repeaterMode?"repeater":"sensor"), nc.nodeId, nc.parentNodeId, nc.distance); -void MySensor::setupRadio() { - failedTransmissions = 0; - radio->init(); } void MySensor::setupRepeaterMode(){ @@ -134,13 +125,20 @@ void MySensor::setupNode() { // Open reading pipe for messages directed to this node (set write pipe to same) radio->setAddress(nc.nodeId); - // Send presentation for this radio node (attach - present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); + // Present node and request config + if (!isGateway && nc.nodeId != AUTO) { + // Send presentation for this radio node (attach + present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); + + // Send a configuration exchange request to controller + // Node sends parent node. Controller answers with latest node configuration + // which is picked up in process() + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(nc.parentNodeId)); + + // Wait configuration reply. + wait(2000); + } - // Send a configuration exchange request to controller - // Node sends parent node. Controller answers with latest node configuration - // which is picked up in process() - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(nc.parentNodeId)); } void MySensor::findParentNode() { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index c9e79a7..2e4af82 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -244,7 +244,6 @@ class MySensor MyRFDriver *radio; void setupRepeaterMode(); - void setupRadio(); boolean sendWrite(uint8_t dest, MyMessage &message); private: From e25f4974b226174d49f1e2213cd57da3b85418cc Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 19 Feb 2015 09:09:38 +0100 Subject: [PATCH 049/660] Save some bytes by removing new when initalizing drivers --- libraries/MySensors/MySensor.cpp | 28 +++++++++++++--------------- libraries/MySensors/MySensor.h | 4 ++-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 120f7ef..9466e5e 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -38,8 +38,6 @@ static inline bool isValidDistance( const uint8_t distance ) { } MySensor::MySensor() { - radio = (MyRFDriver*) new MyRFDriverClass(); - signer = (MySigningDriver*) new MySigningDriverClass(); } @@ -58,7 +56,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } // Setup radio - radio->init(); + radio.init(); // Read settings from eeprom eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); @@ -124,7 +122,7 @@ ControllerConfig MySensor::getConfig() { void MySensor::requestNodeId() { debug(PSTR("req node id\n")); - radio->setAddress(nc.nodeId); + radio.setAddress(nc.nodeId); build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); sendWrite(nc.parentNodeId, msg); wait(2000); @@ -132,7 +130,7 @@ void MySensor::requestNodeId() { void MySensor::setupNode() { // Open reading pipe for messages directed to this node (set write pipe to same) - radio->setAddress(nc.nodeId); + radio.setAddress(nc.nodeId); // Present node and request config if (!isGateway && nc.nodeId != AUTO) { @@ -264,7 +262,7 @@ boolean MySensor::sendRoute(MyMessage &message) { boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = nc.nodeId; - bool ok = radio->send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); + bool ok = radio.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, @@ -308,19 +306,19 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { boolean MySensor::process() { uint8_t to = 0; - if (!radio->available(&to)) + if (!radio.available(&to)) return false; - (void)signer->checkTimer(); // Manage signing timeout + (void)signer.checkTimer(); // Manage signing timeout - uint8_t len = radio->receive((uint8_t *)&msg); + uint8_t len = radio.receive((uint8_t *)&msg); // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) // Note that we do not care at all about any signature found if we do not require signing if (requireSigning && msg.destination == nc.nodeId && mGetLength(msg) && (mGetCommand(msg) != C_INTERNAL || (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING))) { if (!mGetSigned(msg)) return false; // Received an unsigned message but we do require signing. This message gets nowhere! - else if (!signer->verifyMsg(msg)) { + else if (!signer.verifyMsg(msg)) { debug(PSTR("Message verification failed\n")); return false; // This signed message has been tampered with! } @@ -385,7 +383,7 @@ boolean MySensor::process() { } return false; } else if (type == I_GET_NONCE) { - if (signer->getNonce(msg)) { + if (signer.getNonce(msg)) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); } else { return false; @@ -541,7 +539,7 @@ void MySensor::internalSleep(unsigned long ms) { void MySensor::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); - radio->powerDown(); + radio.powerDown(); pinIntTrigger = 0; internalSleep(ms); } @@ -561,7 +559,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; Serial.flush(); - radio->powerDown(); + radio.powerDown(); attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; @@ -580,7 +578,7 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; Serial.flush(); // Let serial prints finish (debug, log etc) - radio->powerDown(); + radio.powerDown(); attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { @@ -616,7 +614,7 @@ bool MySensor::sign(MyMessage &message) { if (process()) { if (getLastMessage().type == I_GET_NONCE_RESPONSE) { // Proceed with signing if nonce has been received - if (signer->putNonce(getLastMessage()) && signer->signMsg(message)) return true; + if (signer.putNonce(getLastMessage()) && signer.signMsg(message)) return true; break; } } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index b995aae..7c6405e 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -247,9 +247,9 @@ class MySensor MyMessage msg; // Buffer for incoming messages. MyMessage ack; // Buffer for ack messages. - MyRFDriver *radio; + MyRFDriverClass radio; - MySigningDriver *signer; + MySigningDriverClass signer; void setupRepeaterMode(); boolean sendWrite(uint8_t dest, MyMessage &message); From 8274188b43bf3b68099bc71c1058ac8952fb6f19 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 19 Feb 2015 09:15:50 +0100 Subject: [PATCH 050/660] Use eeprom_update_* when writing to EEPROM Saves a few bytes and minimizes the number of write cycles. --- libraries/MySensors/MySensor.cpp | 44 ++++++++++++-------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 9466e5e..725572a 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -76,11 +76,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b autoFindParent = _parentNodeId == AUTO; if (!autoFindParent) { - if (_parentNodeId != nc.parentNodeId) { - nc.parentNodeId = _parentNodeId; - // Save static parent id in eeprom (used by bootloader) - eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); - } + nc.parentNodeId = _parentNodeId; + // Save static parent id in eeprom (used by bootloader) + eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); // We don't actually know the distance to gw here. Let's pretend it is 1. // If the current node is also repeater, be aware of this. nc.distance = 1; @@ -93,7 +91,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b // Set static id nc.nodeId = _nodeId; // Save static id in eeprom - eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, _nodeId); + eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, _nodeId); } // Try to fetch node-id from gateway @@ -375,8 +373,8 @@ boolean MySensor::process() { // Found a neighbor closer to GW than previously found nc.distance = distance; nc.parentNodeId = msg.sender; - eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); - eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance); + eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); + eeprom_update_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance); debug(PSTR("new parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); } } @@ -397,7 +395,7 @@ boolean MySensor::process() { CLEAR_SIGN(msg.sender); } // Save updated table - eeprom_write_block((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); + eeprom_update_block((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node @@ -425,17 +423,15 @@ boolean MySensor::process() { } setupNode(); // Write id to EEPROM - eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId); + eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId); debug(PSTR("id=%d\n"), nc.nodeId); } } else if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) // and store it in eeprom if changed isMetric = msg.getString()[0] == 'M' ; - if (cc.isMetric != isMetric) { - cc.isMetric = isMetric; - eeprom_write_byte((uint8_t*)EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); - } + cc.isMetric = isMetric; + eeprom_update_byte((uint8_t*)EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); } else if (type == I_CHILDREN) { if (repeaterMode && msg.getString()[0] == 'C') { // Clears child relay data for this node @@ -445,8 +441,8 @@ boolean MySensor::process() { removeChildRoute(i); } while (i--); // Clear parent node id & distance to gw - eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); - eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, 0xFF); + eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); + eeprom_update_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, 0xFF); // Find parent node findParentNode(); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); @@ -487,26 +483,20 @@ MyMessage& MySensor::getLastMessage() { } void MySensor::saveState(uint8_t pos, uint8_t value) { - if (loadState(pos) != value) { - eeprom_write_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos), value); - } + eeprom_update_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos), value); } uint8_t MySensor::loadState(uint8_t pos) { return eeprom_read_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos)); } void MySensor::addChildRoute(uint8_t childId, uint8_t route) { - if (childNodeTable[childId] != route) { - childNodeTable[childId] = route; - eeprom_write_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, route); - } + childNodeTable[childId] = route; + eeprom_update_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, route); } void MySensor::removeChildRoute(uint8_t childId) { - if (childNodeTable[childId] != 0xff) { - childNodeTable[childId] = 0xff; - eeprom_write_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, 0xff); - } + childNodeTable[childId] = 0xff; + eeprom_update_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, 0xff); } uint8_t MySensor::getChildRoute(uint8_t childId) { From 85501622355a5b926c537c7b0aeb7770bc41848a Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 19 Feb 2015 11:22:36 +0100 Subject: [PATCH 051/660] Slim down dummy signing driver. --- libraries/MySensors/MySigningDriverDummy.cpp | 81 +------------------- libraries/MySensors/MySigningDriverDummy.h | 11 +-- 2 files changed, 6 insertions(+), 86 deletions(-) diff --git a/libraries/MySensors/MySigningDriverDummy.cpp b/libraries/MySensors/MySigningDriverDummy.cpp index 51d418f..f5bac3f 100644 --- a/libraries/MySensors/MySigningDriverDummy.cpp +++ b/libraries/MySensors/MySigningDriverDummy.cpp @@ -36,51 +36,17 @@ static void DEBUG_DUMMY_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #endif MySigningDriverDummy::MySigningDriverDummy() : MySigningDriver() { - verification_ongoing = false; - current_nonce = 0; } bool MySigningDriverDummy::getNonce(MyMessage &msg) { - uint8_t nonce_buf[2]; - nonce_buf[0] = SIGNING_IDENTIFIER; - // This is normally a buffer but for our minimal driver we use a single byte - // We at least use a new nonce for every session - nonce_buf[1] = ++current_nonce; - msg.set(nonce_buf, 2); - verification_ongoing = true; - timestamp = millis(); // Set timestamp to determine when to purge nonce - // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) - // Note that if message is "too" quick, and arrives before turnover, it will be rejected - // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (timestamp + VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; return true; } bool MySigningDriverDummy::checkTimer() { - if (verification_ongoing) { - if (millis() < timestamp || millis() > timestamp + VERIFICATION_TIMEOUT_MS) { - DEBUG_DUMMY_PRINTLN("Verification timeout"); - // Purge nonce - current_nonce = 0; // purge nonce when used - verification_ongoing = false; - return false; - } - } return true; } bool MySigningDriverDummy::putNonce(MyMessage &msg) { - if (mGetLength(msg) != 2) { - DEBUG_DUMMY_PRINTLN("Incoming nonce with incorrect size"); - return false; // We require a signing identifier and a 1byte nonce - } - - if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { - DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); - return false; - } - - current_nonce = ((uint8_t*)msg.getCustom())[1]; return true; } @@ -90,54 +56,15 @@ bool MySigningDriverDummy::signMsg(MyMessage &msg) { DEBUG_DUMMY_PRINTLN("Cannot fit any signature to this message"); return false; } - - // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated - DEBUG_DUMMY_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - uint8_t signature = msg.data[0] ^ current_nonce; msg.data[mGetLength(msg)] = SIGNING_IDENTIFIER; // Add signing identifier - msg.data[mGetLength(msg)+1] = signature; - current_nonce = 0; // purge nonce when used return true; } bool MySigningDriverDummy::verifyMsg(MyMessage &msg) { - if (!verification_ongoing) { - DEBUG_DUMMY_PRINTLN("No active verification session"); - return false; - } else { - // Make sure we have not expired - if (!checkTimer()) { - return false; - } - - verification_ongoing = false; - - if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { - DEBUG_DUMMY_PRINTLN("Incorrect signing identifier"); - return false; - } - - DEBUG_DUMMY_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_DUMMY_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], 2); - - // The dummy signing is the nonce XOR the first payload byte, - // so we "verify" by redoing that calculation with the nonce we transmitted - // Message without a payload this implementation always accepts as signed and messages that cannot - // fit a signature are also accepted as signed - if (mGetLength(msg) && mGetLength(msg) < MAX_PAYLOAD-2) { - uint8_t signature = msg.data[0] ^ current_nonce; - if (msg.data[mGetLength(msg)+1] != signature) { - DEBUG_DUMMY_PRINTBUF("Signature bad. Calculated signature:", &signature, 1); - return false; - } else { - DEBUG_DUMMY_PRINTLN("Signature ok"); - return true; - } - } else { - DEBUG_DUMMY_PRINTLN("No signature in message"); - return false; - } - } + if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) + return false; + else + return true; } #endif diff --git a/libraries/MySensors/MySigningDriverDummy.h b/libraries/MySensors/MySigningDriverDummy.h index 74b88a6..bf5ee81 100644 --- a/libraries/MySensors/MySigningDriverDummy.h +++ b/libraries/MySensors/MySigningDriverDummy.h @@ -10,11 +10,8 @@ #include "MySigningDriver.h" #include -// The dummy signing driver implements the most rudimentary form of signing -// No pre-shared key is used, nonce is simply incremeted each turn and signature -// is only calculated on the fist byte using data XOR nonce. -// This driver is intended for library debugging and sensor network integrity -// verification (signed messages will force the radio to transmit all 32 bytes of data). +// The dummy signing driver that can be used for nodes +// not requiring signing // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in // the network (as seen by this node) and it does verify proper execution order on the API. // The dummy driver rejects all other back-ends. @@ -27,10 +24,6 @@ public: bool putNonce(MyMessage &msg); bool signMsg(MyMessage &msg); bool verifyMsg(MyMessage &msg); -private: - unsigned long timestamp; - bool verification_ongoing; - uint8_t current_nonce; }; #endif From 70b476ede4a5d32fad992b8c7b5ef7fe73397420 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 19 Feb 2015 13:47:45 +0100 Subject: [PATCH 052/660] Bugfix: setVersion missing in sendWrite --- libraries/MySensors/MySensor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 725572a..149f3d8 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -258,6 +258,7 @@ boolean MySensor::sendRoute(MyMessage &message) { } boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { + mSetVersion(message, PROTOCOL_VERSION); uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = nc.nodeId; bool ok = radio.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); From c358d8705a738f249f531d3b45fe45c058d11ee7 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 19 Feb 2015 21:39:46 -0200 Subject: [PATCH 053/660] add parser class for serial and ethernet gateways --- libraries/MySensors/MyConfig.h | 5 + libraries/MySensors/MyParser.cpp | 4 + libraries/MySensors/MyParser.h | 16 +++ libraries/MySensors/MyParserSerial.cpp | 81 +++++++++++++ libraries/MySensors/MyParserSerial.h | 15 +++ libraries/MySensors/MySensor.h | 1 + .../examples/EthernetGateway/GatewayUtil.h | 110 ++++-------------- .../examples/SerialGateway/GatewayUtil.h | 110 ++++-------------- 8 files changed, 162 insertions(+), 180 deletions(-) create mode 100644 libraries/MySensors/MyParser.cpp create mode 100644 libraries/MySensors/MyParser.h create mode 100644 libraries/MySensors/MyParserSerial.cpp create mode 100644 libraries/MySensors/MyParserSerial.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index ecae372..deb31c1 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -35,6 +35,11 @@ typedef class MyRFDriverNRF24 MyRFDriverClass; typedef class MyRFDriverRF69 MyRFDriverClass; #endif +#if defined(MYSENSORS_SERIAL_GATEWAY) || defined(MYSENSORS_ETHERNET_GATEWAY) +#include "MyParserSerial.h" +typedef class MyParserSerial MyParserClass; +#endif + #ifdef MYSENSORS_SIGNING_DUMMY #include "MySigningDriverDummy.h" #define SIGNING_IDENTIFIER (0) // Reserved for dummy implementation, will not work with other backends diff --git a/libraries/MySensors/MyParser.cpp b/libraries/MySensors/MyParser.cpp new file mode 100644 index 0000000..dacd32b --- /dev/null +++ b/libraries/MySensors/MyParser.cpp @@ -0,0 +1,4 @@ +#include "MyParser.h" + +MyParser::MyParser() { +} diff --git a/libraries/MySensors/MyParser.h b/libraries/MySensors/MyParser.h new file mode 100644 index 0000000..e606a0d --- /dev/null +++ b/libraries/MySensors/MyParser.h @@ -0,0 +1,16 @@ +#ifndef MyParser_h +#define MyParser_h + +#include "MyMessage.h" + +class MyParser +{ +public: + // MyParser constructor + MyParser(); + // parse(message, inputString) + // parse a string into a message element + // returns true if successfully parsed the input string + virtual bool parse(MyMessage &message, char *inputString) = 0; +}; +#endif \ No newline at end of file diff --git a/libraries/MySensors/MyParserSerial.cpp b/libraries/MySensors/MyParserSerial.cpp new file mode 100644 index 0000000..dc233c0 --- /dev/null +++ b/libraries/MySensors/MyParserSerial.cpp @@ -0,0 +1,81 @@ +#include "MyParser.h" +#include "MyParserSerial.h" + +MyParserSerial::MyParserSerial() : MyParser() {} + +bool MyParserSerial::parse(MyMessage &message, char *inputString) { + char *str, *p, *value=NULL; + uint8_t bvalue[MAX_PAYLOAD]; + uint8_t blen = 0; + int i = 0; + uint8_t command = 0; + uint8_t ack = 0; + + // Extract command data coming on serial line + for (str = strtok_r(inputString, ";", &p); // split using semicolon + str && i < 6; // loop while str is not null an max 5 times + str = strtok_r(NULL, ";", &p) // get subsequent tokens + ) { + switch (i) { + case 0: // Radioid (destination) + message.destination = atoi(str); + break; + case 1: // Childid + message.sensor = atoi(str); + break; + case 2: // Message type + command = atoi(str); + mSetCommand(message, command); + break; + case 3: // Should we request ack from destination? + ack = atoi(str); + break; + case 4: // Data type + message.type = atoi(str); + break; + case 5: // Variable value + if (command == C_STREAM) { + blen = 0; + uint8_t val; + while (*str) { + val = h2i(*str++) << 4; + val += h2i(*str++); + bvalue[blen] = val; + blen++; + } + } else { + value = str; + // Remove ending carriage return character (if it exists) + uint8_t lastCharacter = strlen(value)-1; + if (value[lastCharacter] == '\r') + value[lastCharacter] = 0; + } + break; + } + i++; + } + // Check for invalid input + if (i < 5) + return false; + + message.sender = GATEWAY_ADDRESS; + message.last = GATEWAY_ADDRESS; + mSetRequestAck(message, ack?1:0); + mSetAck(message, false); + if (command == C_STREAM) + message.set(bvalue, blen); + else + message.set(value); + return true; +} + +uint8_t MyParserSerial::h2i(char c) { + uint8_t i = 0; + if (c <= '9') + i += c - '0'; + else if (c >= 'a') + i += c - 'a' + 10; + else + i += c - 'A' + 10; + return i; +} diff --git a/libraries/MySensors/MyParserSerial.h b/libraries/MySensors/MyParserSerial.h new file mode 100644 index 0000000..e7baf9b --- /dev/null +++ b/libraries/MySensors/MyParserSerial.h @@ -0,0 +1,15 @@ +#ifndef MyParserSerial_h +#define MyParserSerial_h + +#include "MyConfig.h" +#include "MyParser.h" + +class MyParserSerial : public MyParser +{ +public: + MyParserSerial(); + bool parse(MyMessage &message, char *inputString); +private: + uint8_t h2i(char c); +}; +#endif \ No newline at end of file diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 7c6405e..cdac00c 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -14,6 +14,7 @@ #include "Version.h" // Auto generated by bot #include "MyRFDriver.h" +#include "MyParser.h" #include "MySigningDriver.h" #include "MyConfig.h" #include "MyMessage.h" diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index b5ac2ba..109f330 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -23,7 +23,7 @@ volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyMessage msg; +MyParserClass parser; void setInclusionMode(boolean newMode); void txBlink(uint8_t cnt); @@ -104,102 +104,32 @@ void checkInclusionFinished() { } } -uint8_t h2i(char c) { - uint8_t i = 0; - if (c <= '9') - i += c - '0'; - else if (c >= 'a') - i += c - 'a' + 10; - else - i += c - 'A' + 10; - return i; -} - void parseAndSend(MySensor gw, char *commandBuffer) { - boolean ok = false; - char *str, *p, *value=NULL; - uint8_t bvalue[MAX_PAYLOAD]; - uint8_t blen = 0; - int i = 0; - uint16_t destination = 0; - uint8_t sensor = 0; - uint8_t command = 0; - uint8_t type = 0; - uint8_t ack = 0; + boolean ok; + MyMessage &msg = gw.getLastMessage(); - // Extract command data coming on serial line - for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon - str && i < 6; // loop while str is not null an max 5 times - str = strtok_r(NULL, ";", &p) // get subsequent tokens - ) { - switch (i) { - case 0: // Radioid (destination) - destination = atoi(str); - break; - case 1: // Childid - sensor = atoi(str); - break; - case 2: // Message type - command = atoi(str); - break; - case 3: // Should we request ack from destination? - ack = atoi(str); - break; - case 4: // Data type - type = atoi(str); - break; - case 5: // Variable value - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*str) { - val = h2i(*str++) << 4; - val += h2i(*str++); - bvalue[blen] = val; - blen++; - } - } else { - value = str; - // Remove ending carriage return character (if it exists) - uint8_t lastCharacter = strlen(value)-1; - if (value[lastCharacter] == '\r') - value[lastCharacter] = 0; - } - break; - } - i++; - } + if (parser.parse(msg, commandBuffer)) { + uint8_t command = mGetCommand(msg); - if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { - // Handle messages directed to gateway - if (type == I_VERSION) { - // Request for version - serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); - } else if (type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(value) == 1); - } - } else { - txBlink(1); - msg.sender = GATEWAY_ADDRESS; - msg.destination = destination; - msg.sensor = sensor; - msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,ack?1:0); - mSetAck(msg,false); - if (command == C_STREAM) - msg.set(bvalue, blen); - else - msg.set(value); - ok = gw.sendRoute(msg); - if (!ok) { - errBlink(1); + if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { + // Handle messages directed to gateway + if (msg.type == I_VERSION) { + // Request for version + serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); + } else if (msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(msg.data) == 1); + } + } else { + txBlink(1); + ok = gw.sendRoute(msg); + if (!ok) { + errBlink(1); + } } } } - void setInclusionMode(boolean newMode) { if (newMode != inclusionMode) inclusionMode = newMode; diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index b5ac2ba..109f330 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -23,7 +23,7 @@ volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyMessage msg; +MyParserClass parser; void setInclusionMode(boolean newMode); void txBlink(uint8_t cnt); @@ -104,102 +104,32 @@ void checkInclusionFinished() { } } -uint8_t h2i(char c) { - uint8_t i = 0; - if (c <= '9') - i += c - '0'; - else if (c >= 'a') - i += c - 'a' + 10; - else - i += c - 'A' + 10; - return i; -} - void parseAndSend(MySensor gw, char *commandBuffer) { - boolean ok = false; - char *str, *p, *value=NULL; - uint8_t bvalue[MAX_PAYLOAD]; - uint8_t blen = 0; - int i = 0; - uint16_t destination = 0; - uint8_t sensor = 0; - uint8_t command = 0; - uint8_t type = 0; - uint8_t ack = 0; + boolean ok; + MyMessage &msg = gw.getLastMessage(); - // Extract command data coming on serial line - for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon - str && i < 6; // loop while str is not null an max 5 times - str = strtok_r(NULL, ";", &p) // get subsequent tokens - ) { - switch (i) { - case 0: // Radioid (destination) - destination = atoi(str); - break; - case 1: // Childid - sensor = atoi(str); - break; - case 2: // Message type - command = atoi(str); - break; - case 3: // Should we request ack from destination? - ack = atoi(str); - break; - case 4: // Data type - type = atoi(str); - break; - case 5: // Variable value - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*str) { - val = h2i(*str++) << 4; - val += h2i(*str++); - bvalue[blen] = val; - blen++; - } - } else { - value = str; - // Remove ending carriage return character (if it exists) - uint8_t lastCharacter = strlen(value)-1; - if (value[lastCharacter] == '\r') - value[lastCharacter] = 0; - } - break; - } - i++; - } + if (parser.parse(msg, commandBuffer)) { + uint8_t command = mGetCommand(msg); - if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { - // Handle messages directed to gateway - if (type == I_VERSION) { - // Request for version - serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); - } else if (type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(value) == 1); - } - } else { - txBlink(1); - msg.sender = GATEWAY_ADDRESS; - msg.destination = destination; - msg.sensor = sensor; - msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,ack?1:0); - mSetAck(msg,false); - if (command == C_STREAM) - msg.set(bvalue, blen); - else - msg.set(value); - ok = gw.sendRoute(msg); - if (!ok) { - errBlink(1); + if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { + // Handle messages directed to gateway + if (msg.type == I_VERSION) { + // Request for version + serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); + } else if (msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(msg.data) == 1); + } + } else { + txBlink(1); + ok = gw.sendRoute(msg); + if (!ok) { + errBlink(1); + } } } } - void setInclusionMode(boolean newMode) { if (newMode != inclusionMode) inclusionMode = newMode; From 2d8fddcb051dda404b0c133e364f9dc658662646 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 21 Feb 2015 23:41:00 -0200 Subject: [PATCH 054/660] check valid parentNodeId before requestNodeId --- libraries/MySensors/MySensor.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 149f3d8..c104c24 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -87,22 +87,19 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b findParentNode(); } - if ( (_nodeId != AUTO) && (nc.nodeId != _nodeId) ) { - // Set static id - nc.nodeId = _nodeId; - // Save static id in eeprom - eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, _nodeId); - } - - // Try to fetch node-id from gateway - if (nc.nodeId == AUTO) { + if (_nodeId != AUTO) { + // Set static id + nc.nodeId = _nodeId; + // Save static id in eeprom + eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, _nodeId); + } else if (isValidParent(nc.parentNodeId)) { + // Try to fetch node-id from gateway requestNodeId(); } setupNode(); debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), isGateway?"gateway":(repeaterMode?"repeater":"sensor"), nc.nodeId, nc.parentNodeId, nc.distance); - } void MySensor::setupRepeaterMode(){ From fb1c542862221f0678485a553b46120bf09c6a91 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 22 Feb 2015 23:22:06 +0100 Subject: [PATCH 055/660] Move SHA204 personalizer sketch to MySensors examples Fix include errors. --- .../examples/Sha204Personalizer/Sha204Personalizer.ino} | 0 .../sha204/{sha204_includes => }/sha204_lib_return_codes.h | 0 libraries/sha204/sha204_library.cpp | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename libraries/{sha204/examples/sha204_personalizer/sha204_personalizer.ino => MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino} (100%) rename libraries/sha204/{sha204_includes => }/sha204_lib_return_codes.h (100%) diff --git a/libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino similarity index 100% rename from libraries/sha204/examples/sha204_personalizer/sha204_personalizer.ino rename to libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino diff --git a/libraries/sha204/sha204_includes/sha204_lib_return_codes.h b/libraries/sha204/sha204_lib_return_codes.h similarity index 100% rename from libraries/sha204/sha204_includes/sha204_lib_return_codes.h rename to libraries/sha204/sha204_lib_return_codes.h diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp index 44e59bd..8e43890 100644 --- a/libraries/sha204/sha204_library.cpp +++ b/libraries/sha204/sha204_library.cpp @@ -1,6 +1,6 @@ #include "Arduino.h" #include "sha204_library.h" -#include "sha204_includes/sha204_lib_return_codes.h" +#include "sha204_lib_return_codes.h" // atsha204Class Constructor @@ -816,4 +816,4 @@ uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) return (crc[0] == response[count] && crc[1] == response[count + 1]) ? SHA204_SUCCESS : SHA204_BAD_CRC; -} \ No newline at end of file +} From 2ab9822172aae1a06be8d115f60daf8347a801b1 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 22 Feb 2015 23:31:18 +0100 Subject: [PATCH 056/660] Bugfix for gateway signing requirements Gateway now only indicate signing requirements for sensors that in turn have indicated signing requirements. --- libraries/MySensors/MySensor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 149f3d8..4c7e837 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -402,8 +402,8 @@ boolean MySensor::process() { // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node // to sign it's messages if (isGateway) { - if (requireSigning) - sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(requireSigning)); + if (requireSigning && DO_SIGN(msg.sender)) + sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); else sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); } From 961366313bcd1911d72d462e179ea0df2e7c1cd9 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 25 Feb 2015 22:24:44 +0100 Subject: [PATCH 057/660] Fixed bug that caused the wrong message to be signed process() altered the message buffer pending signing when called in sign() causing the wrong message to be sent to the signing backend. This is resolved by copying the original message before processing incoming messages to make sure the original message is kept. After it is successfully signed, it is copied back to its original location again. Also, the old 'ack' message buffer is renamed to tmpMsg to indicate its use as a temporary message buffer for various purposes. --- libraries/MySensors/MySensor.cpp | 23 +++++++++++++---------- libraries/MySensors/MySensor.h | 3 ++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 3012a5d..ce971f7 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -349,12 +349,12 @@ boolean MySensor::process() { // Check if sender requests an ack back. if (mGetRequestAck(msg)) { // Copy message - ack = msg; - mSetRequestAck(ack,false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(ack,true); - ack.sender = nc.nodeId; - ack.destination = msg.sender; - sendRoute(ack); + tmpMsg = msg; + mSetRequestAck(tmpMsg,false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(tmpMsg,true); + tmpMsg.sender = nc.nodeId; + tmpMsg.destination = msg.sender; + sendRoute(tmpMsg); } if (command == C_INTERNAL) { @@ -591,18 +591,21 @@ int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, ui } bool MySensor::sign(MyMessage &message) { - MyMessage msgNonce; - if (!sendRoute(build(msgNonce, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { return false; } else { // We have to wait for the nonce to arrive before we can sign our original message // Other messages could come in-between. We trust process() takes care of them unsigned long enter = millis(); + msgSign = message; // Copy the message to sign since message buffer might be touched in process() while (millis() - enter < 5000) { if (process()) { - if (getLastMessage().type == I_GET_NONCE_RESPONSE) { + if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { // Proceed with signing if nonce has been received - if (signer.putNonce(getLastMessage()) && signer.signMsg(message)) return true; + if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) { + message = msgSign; // Write the signed message back + return true; + } break; } } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index cdac00c..747990a 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -246,7 +246,8 @@ class MySensor uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication MyMessage msg; // Buffer for incoming messages. - MyMessage ack; // Buffer for ack messages. + MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). + MyMessage msgSign; // Buffer for message to sign. MyRFDriverClass radio; From 23a8a48f8e48630a4cf4aae5a46fe7f622c85df3 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 25 Feb 2015 23:18:26 +0100 Subject: [PATCH 058/660] Rename "Dummy" signing driver to "None" --- libraries/MySensors/MyConfig.h | 8 ++--- ...riverDummy.cpp => MySigningDriverNone.cpp} | 34 +++++++++---------- ...ingDriverDummy.h => MySigningDriverNone.h} | 14 ++++---- 3 files changed, 28 insertions(+), 28 deletions(-) rename libraries/MySensors/{MySigningDriverDummy.cpp => MySigningDriverNone.cpp} (52%) rename libraries/MySensors/{MySigningDriverDummy.h => MySigningDriverNone.h} (63%) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index deb31c1..c574b58 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -16,7 +16,7 @@ //#define MYSENSORS_RF_RF69 // Choose signing backend by enabling one of the following -#define MYSENSORS_SIGNING_DUMMY +#define MYSENSORS_SIGNING_NONE //#define MYSENSORS_SIGNING_ATSHA204 //#define MYSENSORS_SIGNING_ATSHA204SOFT @@ -40,10 +40,10 @@ typedef class MyRFDriverRF69 MyRFDriverClass; typedef class MyParserSerial MyParserClass; #endif -#ifdef MYSENSORS_SIGNING_DUMMY -#include "MySigningDriverDummy.h" +#ifdef MYSENSORS_SIGNING_NONE +#include "MySigningDriverNone.h" #define SIGNING_IDENTIFIER (0) // Reserved for dummy implementation, will not work with other backends -typedef class MySigningDriverDummy MySigningDriverClass; +typedef class MySigningDriverNone MySigningDriverClass; #endif #ifdef MYSENSORS_SIGNING_ATSHA204 diff --git a/libraries/MySensors/MySigningDriverDummy.cpp b/libraries/MySensors/MySigningDriverNone.cpp similarity index 52% rename from libraries/MySensors/MySigningDriverDummy.cpp rename to libraries/MySensors/MySigningDriverNone.cpp index f5bac3f..fed6e6c 100644 --- a/libraries/MySensors/MySigningDriverDummy.cpp +++ b/libraries/MySensors/MySigningDriverNone.cpp @@ -1,23 +1,23 @@ /* - Dummy signing backend. Does not provide any security measures. + Disabled signing backend. Does not provide any security measures. Created by Patrick "Anticimex" Fallberg */ #include "MySigningDriver.h" -#include "MySigningDriverDummy.h" +#include "MySigningDriverNone.h" -#ifdef MYSENSORS_SIGNING_DUMMY +#ifdef MYSENSORS_SIGNING_NONE // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) -//#define DEBUG_DUMMY_SIGNING +//#define DEBUG_NONE_SIGNING -#ifdef DEBUG_DUMMY_SIGNING -#define DEBUG_DUMMY_PRINTLN(args) Serial.println(args) +#ifdef DEBUG_NONE_SIGNING +#define DEBUG_NONE_PRINTLN(args) Serial.println(args) #else -#define DEBUG_DUMMY_PRINTLN(args) +#define DEBUG_NONE_PRINTLN(args) #endif -#ifdef DEBUG_DUMMY_SIGNING -static void DEBUG_DUMMY_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +#ifdef DEBUG_NONE_SIGNING +static void DEBUG_NONE_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) { int i; Serial.println(str); @@ -32,28 +32,28 @@ static void DEBUG_DUMMY_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) Serial.println(); } #else -#define DEBUG_DUMMY_PRINTBUF(str, buf, sz) +#define DEBUG_NONE_PRINTBUF(str, buf, sz) #endif -MySigningDriverDummy::MySigningDriverDummy() : MySigningDriver() { +MySigningDriverNone::MySigningDriverNone() : MySigningDriver() { } -bool MySigningDriverDummy::getNonce(MyMessage &msg) { +bool MySigningDriverNone::getNonce(MyMessage &msg) { return true; } -bool MySigningDriverDummy::checkTimer() { +bool MySigningDriverNone::checkTimer() { return true; } -bool MySigningDriverDummy::putNonce(MyMessage &msg) { +bool MySigningDriverNone::putNonce(MyMessage &msg) { return true; } -bool MySigningDriverDummy::signMsg(MyMessage &msg) { +bool MySigningDriverNone::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { - DEBUG_DUMMY_PRINTLN("Cannot fit any signature to this message"); + DEBUG_NONE_PRINTLN("Cannot fit any signature to this message"); return false; } mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated @@ -61,7 +61,7 @@ bool MySigningDriverDummy::signMsg(MyMessage &msg) { return true; } -bool MySigningDriverDummy::verifyMsg(MyMessage &msg) { +bool MySigningDriverNone::verifyMsg(MyMessage &msg) { if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) return false; else diff --git a/libraries/MySensors/MySigningDriverDummy.h b/libraries/MySensors/MySigningDriverNone.h similarity index 63% rename from libraries/MySensors/MySigningDriverDummy.h rename to libraries/MySensors/MySigningDriverNone.h index bf5ee81..8c30367 100644 --- a/libraries/MySensors/MySigningDriverDummy.h +++ b/libraries/MySensors/MySigningDriverNone.h @@ -1,24 +1,24 @@ /* - Dummy signing backend. Does not provide any security measures. + Disabled signing backend. Does not provide any security measures. Created by Patrick "Anticimex" Fallberg */ -#ifndef MySigningDriverDummy_h -#define MySigningDriverDummy_h +#ifndef MySigningDriverNone_h +#define MySigningDriverNone_h #include "MyConfig.h" #include "MySigningDriver.h" #include -// The dummy signing driver that can be used for nodes +// The "none" signing driver that can be used for nodes // not requiring signing // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in // the network (as seen by this node) and it does verify proper execution order on the API. -// The dummy driver rejects all other back-ends. -class MySigningDriverDummy : public MySigningDriver +// The "none" driver rejects all other back-ends. +class MySigningDriverNone : public MySigningDriver { public: - MySigningDriverDummy(); + MySigningDriverNone(); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); From bf8102ecadd53772e7887c75248c61194e9dd182 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 26 Feb 2015 23:53:37 +0100 Subject: [PATCH 059/660] For discussion --- libraries/MySensors/MyConfig.h | 103 ++++-------------- libraries/MySensors/MyParserSerial.cpp | 1 + libraries/MySensors/MyRFDriverNRF24.cpp | 58 +++++----- libraries/MySensors/MyRFDriverNRF24.h | 25 +---- libraries/MySensors/MySensor.cpp | 6 +- libraries/MySensors/MySensor.h | 7 +- .../MySensors/MySigningDriverAtsha204.cpp | 16 +-- libraries/MySensors/MySigningDriverAtsha204.h | 3 + .../MySensors/MySigningDriverAtsha204Soft.cpp | 14 +-- .../MySensors/MySigningDriverAtsha204Soft.h | 3 + libraries/MySensors/MySigningDriverNone.cpp | 2 - libraries/MySensors/MySigningDriverNone.h | 2 + .../examples/RelayActuator/RelayActuator.ino | 6 +- 13 files changed, 90 insertions(+), 156 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index c574b58..168a5fc 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -1,99 +1,36 @@ #ifndef MyConfig_h #define MyConfig_h -/*** - * Configure Sensor Network - */ - -// pick ONE of these - other board layouts can be easily added this way -#define MYSENSORS_SENSOR -//#define MYSENSORS_SERIAL_GATEWAY -//#define MYSENSORS_ETHERNET_GATEWAY -//#define MYSENSORS_MQTT_GATEWAY +/********************************** +* Enable/Disable debug logging +***********************************/ +#define DEBUG -// Choose radio type by enabling one of the following -#define MYSENSORS_RF_NRF24 -//#define MYSENSORS_RF_RF69 - -// Choose signing backend by enabling one of the following -#define MYSENSORS_SIGNING_NONE -//#define MYSENSORS_SIGNING_ATSHA204 -//#define MYSENSORS_SIGNING_ATSHA204SOFT +/********************************** +* Message Signing Settings +***********************************/ // Define a suitable timeout for a signature verification session // Consider the turnaround from a nonce being generated to a signed message being received // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. -#define VERIFICATION_TIMEOUT_MS 5000 +#define MY_VERIFICATION_TIMEOUT_MS 5000 -#ifdef MYSENSORS_RF_NRF24 -#include "MyRFDriverNRF24.h" -typedef class MyRFDriverNRF24 MyRFDriverClass; -#endif +// MySigningDriverAtsha204 settinga +#define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached -#ifdef MYSENSORS_RF_RF69 -#include "MyRFDriverRF69.h" -typedef class MyRFDriverRF69 MyRFDriverClass; -#endif +// MySigningDriverAtsha204Soft settings +#define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) +// Key to use for HMAC calculation in MySigningDriverAtsha204Soft (32 bytes) +#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -#if defined(MYSENSORS_SERIAL_GATEWAY) || defined(MYSENSORS_ETHERNET_GATEWAY) -#include "MyParserSerial.h" -typedef class MyParserSerial MyParserClass; -#endif -#ifdef MYSENSORS_SIGNING_NONE -#include "MySigningDriverNone.h" -#define SIGNING_IDENTIFIER (0) // Reserved for dummy implementation, will not work with other backends -typedef class MySigningDriverNone MySigningDriverClass; -#endif +/********************************** +* NRF24L01 Driver Defaults +***********************************/ +#define RF24_CE_PIN 9 +#define RF24_CS_PIN 10 +#define RF24_PA_LEVEL RF24_PA_MAX -#ifdef MYSENSORS_SIGNING_ATSHA204 -#ifdef MYSENSORS_SENSOR -#define ATSHA204_PIN 17 //A3 -#endif -#ifdef MYSENSORS_SERIAL_GATEWAY -#define ATSHA204_PIN 17 //A3 -#endif - -#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) -#define ATSHA204_PIN 17 //A3 -#endif - -#include "MySigningDriverAtsha204.h" -#define SIGNING_IDENTIFIER (1) // SHA256-based HMAC (ATSHA204 specific) -typedef class MySigningDriverAtsha204 MySigningDriverClass; -#endif - -#ifdef MYSENSORS_SIGNING_ATSHA204SOFT -// Key to use for HMAC calculation -static uint8_t hmacKey[32] = { -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -// Pick an unconnected analog pin for RANDOMSEED_PIN -#ifdef MYSENSORS_SENSOR -#define RANDOMSEED_PIN 7 //A7 -#endif - -#ifdef MYSENSORS_SERIAL_GATEWAY -#define RANDOMSEED_PIN 7 //A7 -#endif - -#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) -#define RANDOMSEED_PIN 7 //A7 -#endif - -#include "MySigningDriverAtsha204Soft.h" -#define SIGNING_IDENTIFIER (1) // SHA256-based HMAC (ATSHA204 specific) -typedef class MySigningDriverAtsha204Soft MySigningDriverClass; -#endif - -/*** - * Enable/Disable debug logging - */ -#define DEBUG #endif diff --git a/libraries/MySensors/MyParserSerial.cpp b/libraries/MySensors/MyParserSerial.cpp index dc233c0..8c020b5 100644 --- a/libraries/MySensors/MyParserSerial.cpp +++ b/libraries/MySensors/MyParserSerial.cpp @@ -1,5 +1,6 @@ #include "MyParser.h" #include "MyParserSerial.h" +#include "MyRFDriver.h" MyParserSerial::MyParserSerial() : MyParser() {} diff --git a/libraries/MySensors/MyRFDriverNRF24.cpp b/libraries/MySensors/MyRFDriverNRF24.cpp index 1667fc6..9b4fe45 100644 --- a/libraries/MySensors/MyRFDriverNRF24.cpp +++ b/libraries/MySensors/MyRFDriverNRF24.cpp @@ -1,37 +1,41 @@ #include "MyRFDriver.h" #include "MyRFDriverNRF24.h" -MyRFDriverNRF24::MyRFDriverNRF24() : MyRFDriver() { - rf24 = new RF24(RF24_CE_PIN, RF24_CS_PIN); +MyRFDriverNRF24::MyRFDriverNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) + : + MyRFDriver(), + rf24(ce, cs), + _paLevel(paLevel) +{ } void MyRFDriverNRF24::init() { // Start up the radio library - rf24->begin(); + rf24.begin(); - if (!rf24->isPVariant()) { + if (!rf24.isPVariant()) { debug(PSTR("check wires\n")); while(1); } - rf24->setAutoAck(1); - rf24->setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast - rf24->enableAckPayload(); - rf24->setChannel(RF24_CHANNEL); - rf24->setPALevel(RF24_PA_LEVEL); - rf24->setDataRate(RF24_DATARATE); - rf24->setRetries(5,15); - rf24->setCRCLength(RF24_CRC_16); - rf24->enableDynamicPayloads(); + rf24.setAutoAck(1); + rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast + rf24.enableAckPayload(); + rf24.setChannel(RF24_CHANNEL); + rf24.setPALevel(_paLevel); + rf24.setDataRate(RF24_DATARATE); + rf24.setRetries(5,15); + rf24.setCRCLength(RF24_CRC_16); + rf24.enableDynamicPayloads(); // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) - rf24->openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); + rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); } void MyRFDriverNRF24::setAddress(uint8_t address) { _address = address; - rf24->openReadingPipe(WRITE_PIPE, TO_ADDR(address)); - rf24->openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); - rf24->startListening(); + rf24.openReadingPipe(WRITE_PIPE, TO_ADDR(address)); + rf24.openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); + rf24.startListening(); } uint8_t MyRFDriverNRF24::getAddress() { @@ -40,30 +44,30 @@ uint8_t MyRFDriverNRF24::getAddress() { bool MyRFDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up - rf24->powerUp(); - rf24->stopListening(); - rf24->openWritingPipe(TO_ADDR(to)); - bool ok = rf24->write(data, len, to == BROADCAST_ADDRESS); - rf24->startListening(); + rf24.powerUp(); + rf24.stopListening(); + rf24.openWritingPipe(TO_ADDR(to)); + bool ok = rf24.write(data, len, to == BROADCAST_ADDRESS); + rf24.startListening(); return ok; } bool MyRFDriverNRF24::available(uint8_t *to) { uint8_t pipe = 255; - boolean avail = rf24->available(&pipe); + boolean avail = rf24.available(&pipe); if (pipe == CURRENT_NODE_PIPE) *to = _address; else if (pipe == BROADCAST_PIPE) *to = BROADCAST_ADDRESS; - return (rf24->available() && pipe < 6); + return (rf24.available() && pipe < 6); } uint8_t MyRFDriverNRF24::receive(void* data) { - uint8_t len = rf24->getDynamicPayloadSize(); - rf24->read(data, len); + uint8_t len = rf24.getDynamicPayloadSize(); + rf24.read(data, len); return len; } void MyRFDriverNRF24::powerDown() { - rf24->powerDown(); + rf24.powerDown(); } diff --git a/libraries/MySensors/MyRFDriverNRF24.h b/libraries/MySensors/MyRFDriverNRF24.h index 267b19c..21607e2 100644 --- a/libraries/MySensors/MyRFDriverNRF24.h +++ b/libraries/MySensors/MyRFDriverNRF24.h @@ -7,26 +7,6 @@ #include "utility/RF24.h" #include "utility/RF24_config.h" - - -#ifdef MYSENSORS_SENSOR -#define RF24_CE_PIN 9 -#define RF24_CS_PIN 10 -#define RF24_PA_LEVEL RF24_PA_MAX -#endif - -#ifdef MYSENSORS_SERIAL_GATEWAY -#define RF24_CE_PIN 9 -#define RF24_CS_PIN 10 -#define RF24_PA_LEVEL RF24_PA_LOW -#endif - -#if defined(MYSENSORS_ETHERNET_GATEWAY) || defined(MYSENSORS_MQTT_GATEWAY) -#define RF24_CE_PIN 5 -#define RF24_CS_PIN 6 -#define RF24_PA_LEVEL RF24_PA_LOW -#endif - #define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 #define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps #define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. @@ -40,7 +20,7 @@ class MyRFDriverNRF24 : public MyRFDriver { public: - MyRFDriverNRF24(); + MyRFDriverNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); void init(); void setAddress(uint8_t address); uint8_t getAddress(); @@ -49,8 +29,9 @@ public: uint8_t receive(void* data); void powerDown(); private: - RF24 *rf24; + RF24 rf24; uint8_t _address; + uint8_t _paLevel; }; #endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index ce971f7..aab91ec 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -37,7 +37,11 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } -MySensor::MySensor() { +MySensor::MySensor(MyRFDriver &_radio, MySigningDriver &_signer) + : + radio(_radio), + signer(_signer) +{ } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 747990a..01ca2b4 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -79,7 +79,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(); + MySensor(MyRFDriver &radio, MySigningDriver &signer); /** * Begin operation of the MySensors library @@ -249,9 +249,8 @@ class MySensor MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). MyMessage msgSign; // Buffer for message to sign. - MyRFDriverClass radio; - - MySigningDriverClass signer; + MyRFDriver& radio; + MySigningDriver& signer; void setupRepeaterMode(); boolean sendWrite(uint8_t dest, MyMessage &message); diff --git a/libraries/MySensors/MySigningDriverAtsha204.cpp b/libraries/MySensors/MySigningDriverAtsha204.cpp index a71a30a..fab6942 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.cpp +++ b/libraries/MySensors/MySigningDriverAtsha204.cpp @@ -7,7 +7,6 @@ #include "MySigningDriver.h" #include "MySigningDriverAtsha204.h" -#ifdef MYSENSORS_SIGNING_ATSHA204 // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_ATSHA_SIGNING @@ -36,11 +35,13 @@ static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_ATSHA_PRINTBUF(str, buf, sz) #endif -static atsha204Class atsha204(ATSHA204_PIN); - -MySigningDriverAtsha204::MySigningDriverAtsha204() : MySigningDriver() { - verification_ongoing = false; +MySigningDriverAtsha204::MySigningDriverAtsha204() + : + MySigningDriver(), + atsha204(MY_ATSHA204_PIN), + verification_ongoing(false) +{ // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(current_nonce, 0xAA, sizeof(current_nonce)); } @@ -73,13 +74,13 @@ bool MySigningDriverAtsha204::getNonce(MyMessage &msg) { // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (timestamp + VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; + if (timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; return true; } bool MySigningDriverAtsha204::checkTimer() { if (verification_ongoing) { - if (millis() < timestamp || millis() > timestamp + VERIFICATION_TIMEOUT_MS) { + if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_ATSHA_PRINTLN("Verification timeout"); // Purge nonce memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); @@ -214,4 +215,3 @@ bool MySigningDriverAtsha204::calculateSignature(MyMessage &msg) { DEBUG_ATSHA_PRINTBUF("HMAC:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return true; // We return with the signature in rx_buffer[SHA204_BUFFER_POS_DATA] } -#endif diff --git a/libraries/MySensors/MySigningDriverAtsha204.h b/libraries/MySensors/MySigningDriverAtsha204.h index a2f6b9d..57bb2f3 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.h +++ b/libraries/MySensors/MySigningDriverAtsha204.h @@ -12,6 +12,8 @@ #include "utility/ATSHA204.h" #include +#define SIGNING_IDENTIFIER (1) + // The ATSHA204 is capable of generating proper random numbers for nonce // and can calculate HMAC-SHA256 signatures. This is enterprise- // level of security and ought to implement the signing needs for anybody. @@ -25,6 +27,7 @@ public: bool signMsg(MyMessage &msg); bool verifyMsg(MyMessage &msg); private: + atsha204Class atsha204; unsigned long timestamp; bool verification_ongoing; uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp index aaff71f..47b57f3 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp @@ -7,11 +7,11 @@ Created by Patrick "Anticimex" Fallberg */ +#include "MyConfig.h" #include "MySigningDriver.h" #include "MySigningDriverAtsha204Soft.h" -#include "sha256.h" +#include "utility/sha256.h" -#ifdef MYSENSORS_SIGNING_ATSHA204SOFT // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_ATSHASOFT_SIGNING @@ -42,16 +42,15 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) static Sha256Class Sha256; -MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() : MySigningDriver() { +MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() : MySigningDriver(), hmacKey({MY_HMAC_KEY}) { verification_ongoing = false; - // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(current_nonce, 0xAA, sizeof(current_nonce)); } bool MySigningDriverAtsha204Soft::getNonce(MyMessage &msg) { // Set randomseed - randomSeed(analogRead(RANDOMSEED_PIN)); + randomSeed(analogRead(MY_RANDOMSEED_PIN)); for (int i = 0; i < MAX_PAYLOAD; i++) { current_nonce[i] = random(255); @@ -65,13 +64,13 @@ bool MySigningDriverAtsha204Soft::getNonce(MyMessage &msg) { // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (timestamp + VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; + if (timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; return true; } bool MySigningDriverAtsha204Soft::checkTimer() { if (verification_ongoing) { - if (millis() < timestamp || millis() > timestamp + VERIFICATION_TIMEOUT_MS) { + if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_ATSHASOFT_PRINTLN("Verification timeout"); // Purge nonce memset(current_nonce, 0xAA, 32); @@ -222,4 +221,3 @@ bool MySigningDriverAtsha204Soft::calculateSignature(MyMessage &msg) { DEBUG_ATSHASOFT_PRINTBUF("HMAC:", hmac, 32); return true; } -#endif diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.h b/libraries/MySensors/MySigningDriverAtsha204Soft.h index 16d8d3e..53d8426 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.h +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.h @@ -15,6 +15,8 @@ #include "utility/ATSHA204.h" #include +#define SIGNING_IDENTIFIER (1) + // This implementation is the pure software variant of the ATSHA204. // It is designed to work fully compliant with nodes using ATSHA204 in the network // and therefore uses the same signing identifier as ATSHA204. @@ -36,6 +38,7 @@ private: bool verification_ongoing; uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; uint8_t temp_message[32]; + uint8_t hmacKey[32]; uint8_t* hmac; bool calculateSignature(MyMessage &msg); }; diff --git a/libraries/MySensors/MySigningDriverNone.cpp b/libraries/MySensors/MySigningDriverNone.cpp index fed6e6c..a7ace62 100644 --- a/libraries/MySensors/MySigningDriverNone.cpp +++ b/libraries/MySensors/MySigningDriverNone.cpp @@ -6,7 +6,6 @@ #include "MySigningDriver.h" #include "MySigningDriverNone.h" -#ifdef MYSENSORS_SIGNING_NONE // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_NONE_SIGNING @@ -67,4 +66,3 @@ bool MySigningDriverNone::verifyMsg(MyMessage &msg) { else return true; } -#endif diff --git a/libraries/MySensors/MySigningDriverNone.h b/libraries/MySensors/MySigningDriverNone.h index 8c30367..9718a78 100644 --- a/libraries/MySensors/MySigningDriverNone.h +++ b/libraries/MySensors/MySigningDriverNone.h @@ -10,6 +10,8 @@ #include "MySigningDriver.h" #include +#define SIGNING_IDENTIFIER (0) + // The "none" signing driver that can be used for nodes // not requiring signing // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 3f0e94f..c0e8a7c 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -1,6 +1,8 @@ // Example sketch showing how to control physical relays. // This example will remember relay state even after power failure. +#include +#include #include #include @@ -9,7 +11,9 @@ #define RELAY_ON 1 // GPIO value to write to turn on attached relay #define RELAY_OFF 0 // GPIO value to write to turn off attached relay -MySensor gw; +MyRFDriverNRF24 radio; // NRFRF24L01 radio driver +MySigningDriverNone signer; // Message signing disabled +MySensor gw(radio, signer); void setup() { From ee6e34b59a4330348eb5777db195faed8f4a800d Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 27 Feb 2015 00:25:08 +0100 Subject: [PATCH 060/660] Remove global initialization of sha256 --- libraries/MySensors/MySigningDriverAtsha204Soft.cpp | 10 +++++++--- libraries/MySensors/MySigningDriverAtsha204Soft.h | 2 ++ libraries/MySensors/utility/sha256.cpp | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp index 47b57f3..b57ab11 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp @@ -40,10 +40,14 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_ATSHASOFT_PRINTBUF(str, buf, sz) #endif -static Sha256Class Sha256; +MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() + : + MySigningDriver(), + hmacKey({MY_HMAC_KEY}), + verification_ongoing(false), + Sha256() -MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() : MySigningDriver(), hmacKey({MY_HMAC_KEY}) { - verification_ongoing = false; +{ // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(current_nonce, 0xAA, sizeof(current_nonce)); } diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.h b/libraries/MySensors/MySigningDriverAtsha204Soft.h index 53d8426..014589a 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.h +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.h @@ -13,6 +13,7 @@ #include "MyConfig.h" #include "MySigningDriver.h" #include "utility/ATSHA204.h" +#include "utility/sha256.h" #include #define SIGNING_IDENTIFIER (1) @@ -34,6 +35,7 @@ public: bool signMsg(MyMessage &msg); bool verifyMsg(MyMessage &msg); private: + Sha256Class Sha256; unsigned long timestamp; bool verification_ongoing; uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; diff --git a/libraries/MySensors/utility/sha256.cpp b/libraries/MySensors/utility/sha256.cpp index f492690..f0376ab 100644 --- a/libraries/MySensors/utility/sha256.cpp +++ b/libraries/MySensors/utility/sha256.cpp @@ -3,6 +3,7 @@ #include #include "sha256.h" + const uint32_t sha256K[] PROGMEM = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, From afce932cffbf2f86714f2ec0d12a2641df50fc98 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 27 Feb 2015 22:17:05 +0100 Subject: [PATCH 061/660] Remove the last "new" to reduce size --- libraries/MySensors/MyRFDriverRF69.cpp | 7 +++++-- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyRFDriverRF69.cpp b/libraries/MySensors/MyRFDriverRF69.cpp index 80e8874..c8e32ef 100644 --- a/libraries/MySensors/MyRFDriverRF69.cpp +++ b/libraries/MySensors/MyRFDriverRF69.cpp @@ -1,8 +1,11 @@ #include "MyRFDriver.h" #include "MyRFDriverRF69.h" -MyRFDriverRF69::MyRFDriverRF69() : MyRFDriver() { - radio = new RFM69(); +MyRFDriverRF69::MyRFDriverRF69() + : + MyRFDriver(), + radio() +{ } void MyRFDriverRF69::init() { diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index aab91ec..acd8bfb 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -107,7 +107,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } void MySensor::setupRepeaterMode(){ - childNodeTable = new uint8_t[256]; +// childNodeTable = new uint8_t[256]; eeprom_read_block((void*)childNodeTable, (void*)EEPROM_ROUTES_ADDRESS, 256); } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 01ca2b4..d139bda 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -260,7 +260,7 @@ class MySensor char convBuf[MAX_PAYLOAD*2+1]; #endif uint8_t failedTransmissions; - uint8_t *childNodeTable; // In memory buffer for routing information to other nodes. also stored in EEPROM + uint8_t childNodeTable[256]; // In memory buffer for routing information to other nodes. also stored in EEPROM void (*timeCallback)(unsigned long); // Callback for requested time messages void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. From 5aebe80711e52d50a86926eb7ddc3702013fadc3 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 3 Mar 2015 00:24:13 +0100 Subject: [PATCH 062/660] Cleanup driver initialization --- libraries/MySensors/MyConfig.h | 20 +++++++++++++++---- libraries/MySensors/MyRFDriverNRF24.h | 4 ---- libraries/MySensors/MySensor.cpp | 9 ++++----- libraries/MySensors/MySensor.h | 8 ++++---- libraries/MySensors/MySigningDriver.cpp | 7 ++++++- libraries/MySensors/MySigningDriver.h | 9 ++++++++- .../MySensors/MySigningDriverAtsha204.cpp | 6 +++--- libraries/MySensors/MySigningDriverAtsha204.h | 2 +- .../MySensors/MySigningDriverAtsha204Soft.cpp | 7 ++++--- .../MySensors/MySigningDriverAtsha204Soft.h | 5 +++-- .../DallasTemperatureSensor.ino | 4 ---- .../EthernetGateway/EthernetGateway.ino | 9 ++++----- .../examples/EthernetGateway/GatewayUtil.h | 2 +- .../examples/MQTTGateway/MQTTGateway.ino | 3 --- .../examples/RelayActuator/RelayActuator.ino | 6 +----- .../SecureActuator/SecureActuator.ino | 12 +++++------ .../examples/SerialGateway/GatewayUtil.h | 2 +- .../examples/SerialGateway/SerialGateway.ino | 5 +---- libraries/MySensors/utility/RF24_config.h | 9 +++++---- 19 files changed, 68 insertions(+), 61 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 168a5fc..4ee4ac1 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -1,6 +1,6 @@ #ifndef MyConfig_h #define MyConfig_h - +#include /********************************** * Enable/Disable debug logging ***********************************/ @@ -15,13 +15,14 @@ // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. #define MY_VERIFICATION_TIMEOUT_MS 5000 -// MySigningDriverAtsha204 settinga +// MySigningDriverAtsha204 default setting #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached -// MySigningDriverAtsha204Soft settings +// MySigningDriverAtsha204Soft default settings #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) // Key to use for HMAC calculation in MySigningDriverAtsha204Soft (32 bytes) -#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /********************************** @@ -30,7 +31,18 @@ #define RF24_CE_PIN 9 #define RF24_CS_PIN 10 #define RF24_PA_LEVEL RF24_PA_MAX +#define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 +#define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps +#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. +// Enable SOFTSPI for the W5100 Ethernet module +//#define SOFTSPI +#ifdef SOFTSPI + // Define the soft SPI pins used for NRF radio + const uint8_t SOFT_SPI_MISO_PIN = 16; + const uint8_t SOFT_SPI_MOSI_PIN = 15; + const uint8_t SOFT_SPI_SCK_PIN = 14; +#endif #endif diff --git a/libraries/MySensors/MyRFDriverNRF24.h b/libraries/MySensors/MyRFDriverNRF24.h index 21607e2..6fcf3f8 100644 --- a/libraries/MySensors/MyRFDriverNRF24.h +++ b/libraries/MySensors/MyRFDriverNRF24.h @@ -7,10 +7,6 @@ #include "utility/RF24.h" #include "utility/RF24_config.h" -#define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 -#define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps -#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. - #define TO_ADDR(x) (RF24_BASE_RADIO_ID + x) #define WRITE_PIPE ((uint8_t)0) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index acd8bfb..0935791 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -45,12 +45,11 @@ MySensor::MySensor(MyRFDriver &_radio, MySigningDriver &_signer) } -void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId, bool requestSignatures) { +void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { Serial.begin(BAUD_RATE); repeaterMode = _repeaterMode; msgCallback = _msgCallback; failedTransmissions = 0; - requireSigning = requestSignatures; // Only gateway should use node id 0 isGateway = _nodeId == 0; @@ -137,7 +136,7 @@ void MySensor::setupNode() { present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); // Notify gateway (and possibly controller) about the signing preferences of this node - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(requireSigning)); + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration @@ -315,7 +314,7 @@ boolean MySensor::process() { // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) // Note that we do not care at all about any signature found if we do not require signing - if (requireSigning && msg.destination == nc.nodeId && mGetLength(msg) && + if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && (mGetCommand(msg) != C_INTERNAL || (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING))) { if (!mGetSigned(msg)) return false; // Received an unsigned message but we do require signing. This message gets nowhere! else if (!signer.verifyMsg(msg)) { @@ -403,7 +402,7 @@ boolean MySensor::process() { // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node // to sign it's messages if (isGateway) { - if (requireSigning && DO_SIGN(msg.sender)) + if (signer.requestSignatures() && DO_SIGN(msg.sender)) sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); else sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index d139bda..cc15075 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -14,8 +14,10 @@ #include "Version.h" // Auto generated by bot #include "MyRFDriver.h" +#include "MyRFDriverNRF24.h" #include "MyParser.h" #include "MySigningDriver.h" +#include "MySigningDriverNone.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -79,7 +81,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyRFDriver &radio, MySigningDriver &signer); + MySensor(MyRFDriver &radio =*new MyRFDriverNRF24(), MySigningDriver &signer=*new MySigningDriverNone()); /** * Begin operation of the MySensors library @@ -89,10 +91,9 @@ class MySensor * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. - * @param requestSignatures Set this to true if you want destination node to sign all messages sent to this node. Default is not to require signing. */ - void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO, bool requestSignatures=false); + void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); /** * Return the nodes nodeId. @@ -242,7 +243,6 @@ class MySensor bool repeaterMode; bool autoFindParent; bool isGateway; - bool requireSigning; uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication MyMessage msg; // Buffer for incoming messages. diff --git a/libraries/MySensors/MySigningDriver.cpp b/libraries/MySensors/MySigningDriver.cpp index b109a3f..aa718fc 100644 --- a/libraries/MySensors/MySigningDriver.cpp +++ b/libraries/MySensors/MySigningDriver.cpp @@ -1,4 +1,9 @@ #include "MySigningDriver.h" -MySigningDriver::MySigningDriver() { +MySigningDriver::MySigningDriver(bool requestSignatures) : _requestSignatures(requestSignatures) { +} + + +bool MySigningDriver::requestSignatures() { + return _requestSignatures; } diff --git a/libraries/MySensors/MySigningDriver.h b/libraries/MySensors/MySigningDriver.h index 28a75ea..ebabde8 100644 --- a/libraries/MySensors/MySigningDriver.h +++ b/libraries/MySensors/MySigningDriver.h @@ -16,7 +16,11 @@ public: // MySigningDriver constructor. // Different parameters would be needed depending on signing backend (e.g. pins connected etc.). // Keeping these parameters as #define's in MyConfig to streamline the driver interface. - MySigningDriver(); + // @param requestSignatures Set this to true if you want destination node to sign all messages sent to this node. Default is not to require signing. + MySigningDriver(bool requestSignatures=false); + + // Returns the current requestSignature setting + bool requestSignatures(); // Stores signing identifier and a new nonce in provided message for signing operations. // All space in message payload buffer is used for signing identifier and nonce. @@ -55,6 +59,9 @@ public: // This ends a signing operation at the receiving side so implementation is expected to do any // deinitializations and enter a power saving state within this call. virtual bool verifyMsg(MyMessage &msg) = 0; + + public: + bool _requestSignatures; }; #endif diff --git a/libraries/MySensors/MySigningDriverAtsha204.cpp b/libraries/MySensors/MySigningDriverAtsha204.cpp index fab6942..401a82c 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.cpp +++ b/libraries/MySensors/MySigningDriverAtsha204.cpp @@ -36,10 +36,10 @@ static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #endif -MySigningDriverAtsha204::MySigningDriverAtsha204() +MySigningDriverAtsha204::MySigningDriverAtsha204(bool requestSignatures, uint8_t atshaPin) : - MySigningDriver(), - atsha204(MY_ATSHA204_PIN), + MySigningDriver(requestSignatures), + atsha204(atshaPin), verification_ongoing(false) { // We set the part of the 32-byte nonce that does not fit into a message to 0xAA diff --git a/libraries/MySensors/MySigningDriverAtsha204.h b/libraries/MySensors/MySigningDriverAtsha204.h index 57bb2f3..8da91ae 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.h +++ b/libraries/MySensors/MySigningDriverAtsha204.h @@ -20,7 +20,7 @@ class MySigningDriverAtsha204 : public MySigningDriver { public: - MySigningDriverAtsha204(); + MySigningDriverAtsha204(bool requestSignatures=true, uint8_t atshaPin = MY_ATSHA204_PIN); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp index b57ab11..c9f6e44 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.cpp @@ -40,9 +40,10 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_ATSHASOFT_PRINTBUF(str, buf, sz) #endif -MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() +MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft(bool requestSignatures, uint8_t randomseedPin) : - MySigningDriver(), + MySigningDriver(requestSignatures), + rndPin(randomseedPin), hmacKey({MY_HMAC_KEY}), verification_ongoing(false), Sha256() @@ -54,7 +55,7 @@ MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft() bool MySigningDriverAtsha204Soft::getNonce(MyMessage &msg) { // Set randomseed - randomSeed(analogRead(MY_RANDOMSEED_PIN)); + randomSeed(analogRead(rndPin)); for (int i = 0; i < MAX_PAYLOAD; i++) { current_nonce[i] = random(255); diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.h b/libraries/MySensors/MySigningDriverAtsha204Soft.h index 014589a..eef0a31 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.h +++ b/libraries/MySensors/MySigningDriverAtsha204Soft.h @@ -24,11 +24,11 @@ // Because it is completly software based, the quality of the generated random numbers // is weaker though. Random numbers are generated using the Arduino library and seed // is sampled from an analog pin. This pin should unconnected in the hardware. -// The pin is selected using RANDOMSEED_PIN in MyConfig.h. +// The pin is selected using MY_RANDOMSEED_PIN in MyConfig.h. class MySigningDriverAtsha204Soft : public MySigningDriver { public: - MySigningDriverAtsha204Soft(); + MySigningDriverAtsha204Soft(bool requestSignatures=true, uint8_t randomseedPin = MY_RANDOMSEED_PIN); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); @@ -41,6 +41,7 @@ private: uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; uint8_t temp_message[32]; uint8_t hmacKey[32]; + uint8_t rndPin; uint8_t* hmac; bool calculateSignature(MyMessage &msg); }; diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index a52c49d..3c6c2c0 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -4,10 +4,6 @@ #include #include -#ifndef MYSENSORS_SENSOR -#error Please switch to MYSENSORS_SENSOR in MyConfig.h -#endif - #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 16 unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index f0f941c..26fe33f 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -17,7 +17,7 @@ * * * COMPILING WIZNET (W5100) ETHERNET MODULE - * > Edit RF24_config.h in (libraries\MySensors\utility) to enable softspi (remove // before "#define SOFTSPI"). + * > Edit MyConfig.h in (libraries\MySensors\) to enable softspi (remove // before "#define SOFTSPI"). * * COMPILING ENC28J60 ETHERNET MODULE * > Use Arduino IDE 1.5.7 (or later) @@ -42,18 +42,17 @@ #include // This include can be removed when using UIPEthernet module #include + +#include #include #include #include #include #include "GatewayUtil.h" -#ifndef MYSENSORS_ETHERNET_GATEWAY -#error Please switch to MYSENSORS_ETHERNET_GATEWAY in MyConfig.h -#endif // Use this if you have attached a Ethernet ENC28J60 shields -//#include +// #include // Use this for WizNET W5100 module and Arduino Ethernet Shield #include diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 109f330..fa5f1b6 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -23,7 +23,7 @@ volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyParserClass parser; +MyParserSerial parser; void setInclusionMode(boolean newMode); void txBlink(uint8_t cnt); diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index a9a497d..bea3ef4 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -62,9 +62,6 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include "MyMQTT.h" -#ifndef MYSENSORS_MQTT_GATEWAY -#error Please switch to MYSENSORS_MQTT_GATEWAY in MyConfig.h -#endif #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index c0e8a7c..3f0e94f 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -1,8 +1,6 @@ // Example sketch showing how to control physical relays. // This example will remember relay state even after power failure. -#include -#include #include #include @@ -11,9 +9,7 @@ #define RELAY_ON 1 // GPIO value to write to turn on attached relay #define RELAY_OFF 0 // GPIO value to write to turn off attached relay -MyRFDriverNRF24 radio; // NRFRF24L01 radio driver -MySigningDriverNone signer; // Message signing disabled -MySensor gw(radio, signer); +MySensor gw; void setup() { diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index c86ff49..65f0fe7 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -1,24 +1,24 @@ // Example sketch showing how to securely control locks. // This example will remember lock state even after power failure. +#include +#include #include #include -#ifndef MYSENSORS_SENSOR -#error Please switch to MYSENSORS_SENSOR in MyConfig.h -#endif - #define LOCK_1 3 // Arduino Digital I/O pin number for first lock (second on pin+1 etc) #define NOF_LOCKS 1 // Total number of attached locks #define LOCK_LOCK 1 // GPIO value to write to lock attached lock #define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock -MySensor gw; +MyRFDriverNRF24 radio; // NRFRF24L01 radio driver +MySigningDriverAtsha204Soft signer; // Message signing driver +MySensor gw(radio, signer); void setup() { // Initialize library and add callback for incoming messages (signing is required) - gw.begin(incomingMessage, AUTO, true, AUTO, true); + gw.begin(incomingMessage, AUTO, true, AUTO); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Secure Lock", "1.0"); diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index 109f330..fa5f1b6 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -23,7 +23,7 @@ volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyParserClass parser; +MyParserSerial parser; void setInclusionMode(boolean newMode); void txBlink(uint8_t cnt); diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 6ee18a4..dddacdb 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -24,16 +24,13 @@ #define NO_PORTB_PINCHANGES #include +#include #include #include #include #include #include "GatewayUtil.h" -#ifndef MYSENSORS_SERIAL_GATEWAY -#error Please switch to MYSENSORS_SERIAL_GATEWAY in MyConfig.h -#endif - #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button #define RADIO_ERROR_LED_PIN 4 // Error led pin diff --git a/libraries/MySensors/utility/RF24_config.h b/libraries/MySensors/utility/RF24_config.h index 3c394c7..2addc27 100755 --- a/libraries/MySensors/utility/RF24_config.h +++ b/libraries/MySensors/utility/RF24_config.h @@ -11,6 +11,7 @@ #ifndef __RF24_CONFIG_H__ #define __RF24_CONFIG_H__ + #include #if ARDUINO < 100 #include @@ -39,10 +40,10 @@ #define _SPI uspi #elif defined SOFTSPI // change these pins to your liking - // - const uint8_t SOFT_SPI_MISO_PIN = 16; - const uint8_t SOFT_SPI_MOSI_PIN = 15; - const uint8_t SOFT_SPI_SCK_PIN = 14; + //const uint8_t SOFT_SPI_MISO_PIN = 16; // <-- Moved to MyConfig.h + //const uint8_t SOFT_SPI_MOSI_PIN = 15; // <-- Moved to MyConfig.h + //const uint8_t SOFT_SPI_SCK_PIN = 14; // <-- Moved to MyConfig.h + const uint8_t SPI_MODE = 0; #define _SPI spi From 7d67ad5c829a1e5bff760a6fe12a2cb7d55cca03 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 4 Mar 2015 19:24:13 +0100 Subject: [PATCH 063/660] Add new sensor type S_MULTIMETER To be used with V_CURRENT, V_VOLTAGE, V_IMPEDANCE --- libraries/MySensors/MyMessage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index fcc0540..c182f34 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -55,7 +55,7 @@ typedef enum { S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER,S_COLOR + S_SCENE_CONTROLLER,S_COLOR, S_MULTMETER } mysensor_sensor; // Type of data stream (for streamed message) From 89076d58d1cfcea8c815ccc3aaa156aeb4238317 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 4 Mar 2015 20:17:53 +0100 Subject: [PATCH 064/660] Fix spelling error. --- libraries/MySensors/MyMessage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index c182f34..2616c32 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -55,7 +55,7 @@ typedef enum { S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER,S_COLOR, S_MULTMETER + S_SCENE_CONTROLLER,S_COLOR, S_MULTIMETER } mysensor_sensor; // Type of data stream (for streamed message) From 79be69b08d36d5928b18d40ba036969a8d35aaba Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Mar 2015 00:34:42 +0100 Subject: [PATCH 065/660] Support for gateways to request signed messages Various fixes and tweaks to permit a gateway to request signatures from nodes. The following messages will not be signed (nor verified): * All signing-related handshake messages * All ID-related handshake messages * All ACKs An important change is that the polarity for the signing request flags stored in EEPROM has changed. '0' now means signing required. This ensures that if the "ClearEepromConfig" sketch is executed, signing requests will be turned off by default. As a consequence, it is recommended to clear EEPROM if signing will be used to ensure all nodes default to a non-signing state. --- libraries/MySensors/MySensor.cpp | 46 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 0935791..1eb28d9 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -14,9 +14,9 @@ #define DISTANCE_INVALID (0xFF) // Macros for manipulating signing requirement table -#define DO_SIGN(node) (doSign[node>>4]&(node%16)) -#define SET_SIGN(node) (doSign[node>>4]|=(node%16)) -#define CLEAR_SIGN(node) (doSign[node>>4]&=~(node%16)) +#define DO_SIGN(node) (node == 0 ? (~doSign[0]&1) : (~doSign[node>>4]&(node%16))) +#define SET_SIGN(node) (node == 0 ? (doSign[0]&=~1) : (doSign[node>>4]&=~(node%16))) +#define CLEAR_SIGN(node) (node == 0 ? (doSign[0]|=1) : (doSign[node>>4]|=(node%16))) // Inline function and macros static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { @@ -132,12 +132,17 @@ void MySensor::setupNode() { // Present node and request config if (!isGateway && nc.nodeId != AUTO) { - // Send presentation for this radio node (attach - present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); - // Notify gateway (and possibly controller) about the signing preferences of this node sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); + // If we do require signing, wait for the gateway to tell us how it perfer us to transmit our messages + if (signer.requestSignatures()) { + wait(2000); + } + + // Send presentation for this radio node (attach + present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); + // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration // which is picked up in process() @@ -185,9 +190,12 @@ boolean MySensor::sendRoute(MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); - // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a signing handshake message + // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) && - (mGetCommand(message) != C_INTERNAL || (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING))) { + (mGetCommand(message) != C_INTERNAL || + (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && + message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && + message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { if (!sign(message)) { debug(PSTR("Message signing failed\n")); return false; @@ -313,10 +321,16 @@ boolean MySensor::process() { uint8_t len = radio.receive((uint8_t *)&msg); // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) - // Note that we do not care at all about any signature found if we do not require signing - if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && - (mGetCommand(msg) != C_INTERNAL || (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING))) { - if (!mGetSigned(msg)) return false; // Received an unsigned message but we do require signing. This message gets nowhere! + // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) + if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && !mGetAck(msg) && + (mGetCommand(msg) != C_INTERNAL || + (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING && + msg.type != I_ID_REQUEST && msg.type != I_ID_RESPONSE && + msg.type != I_FIND_PARENT && msg.type != I_FIND_PARENT_RESPONSE))) { + if (!mGetSigned(msg)) { + debug(PSTR("Got unsigned message that should have been signed\n")); + return false; + } else if (!signer.verifyMsg(msg)) { debug(PSTR("Message verification failed\n")); return false; // This signed message has been tampered with! @@ -383,10 +397,9 @@ boolean MySensor::process() { return false; } else if (type == I_GET_NONCE) { if (signer.getNonce(msg)) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); - } else { - return false; + sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); } + return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this } else if (type == I_REQUEST_SIGNING) { if (msg.getBool()) { // We received an indicator that the sender require us to sign all messages we send to it @@ -407,6 +420,9 @@ boolean MySensor::process() { else sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); } + return false; // Signing request is an internal MySensor protocol message, no need to inform caller about this + } else if (type == I_GET_NONCE_RESPONSE) { + return true; // Just pass along nonce silently (no need to call callback for these) } else if (sender == GATEWAY_ADDRESS) { bool isMetric; From a21715d4159d7afcac38145c7151d1eae0c88cbb Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 8 Mar 2015 11:29:57 +0100 Subject: [PATCH 066/660] SHA204 personalizer updated to handle HMAC key better HMAC key is now configured and printed exactly as it is set in MyConfig.h. This makes it easier to move the key around. --- libraries/MySensors/MyConfig.h | 2 +- .../Sha204Personalizer/Sha204Personalizer.ino | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 4ee4ac1..fd6358c 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -22,7 +22,7 @@ #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) // Key to use for HMAC calculation in MySigningDriverAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /********************************** diff --git a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino index a39ceeb..066c834 100644 --- a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino +++ b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino @@ -57,12 +57,9 @@ #endif #ifdef USER_KEY_DATA -const uint8_t user_key_data[32] = { -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; +#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +const uint8_t user_key_data[32] = {MY_HMAC_KEY}; #endif const int sha204Pin = ATSHA204_PIN; @@ -796,7 +793,7 @@ void setup() } #endif //not SKIP_UART_CONFIRMATION #else //LOCK_CONFIGURATION - Serial.println(F("Dry-run. Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); + Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); #endif } else @@ -833,6 +830,7 @@ void setup() Serial.println(F("Key is not randomized (configuration not locked):")); } #endif + Serial.print("#define MY_HMAC_KEY "); for (int i=0; i<32; i++) { Serial.print("0x"); @@ -842,7 +840,7 @@ void setup() } Serial.print(key[i], HEX); if (i < 31) Serial.print(','); - if (!((i+1) % 8)) Serial.println(); + if (i+1 == 16) Serial.print("\\\n "); } Serial.println(); @@ -937,7 +935,7 @@ void setup() } #endif //not SKIP_UART_CONFIRMATION #else //LOCK_DATA - Serial.println(F("Dry-run. Data not locked. Define LOCK_DATA to lock for real.")); + Serial.println(F("Data not locked. Define LOCK_DATA to lock for real.")); #endif } else From 7e6aa8bda8466a42b2cbb59e0cdbe54f502e2eec Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 9 Mar 2015 22:58:05 +0100 Subject: [PATCH 067/660] Add the default constructors to gateway sketches --- libraries/MySensors/MyConfig.h | 1 + .../examples/EthernetGateway/EthernetGateway.ino | 10 ++++++++-- .../MySensors/examples/MQTTGateway/MQTTGateway.ino | 10 +++++++++- .../MySensors/examples/SerialGateway/SerialGateway.ino | 9 ++++++++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index fd6358c..b259a1c 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -31,6 +31,7 @@ #define RF24_CE_PIN 9 #define RF24_CS_PIN 10 #define RF24_PA_LEVEL RF24_PA_MAX +#define RF24_PA_LEVEL_GW RF24_PA_LOW #define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 #define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps #define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 26fe33f..def707b 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -43,6 +43,8 @@ #include // This include can be removed when using UIPEthernet module #include +#include +#include #include #include #include @@ -69,8 +71,12 @@ #define RADIO_TX_LED_PIN 9 // the PCB, on board LED -MySensor gw; - +// NRFRF24L01 radio driver (set low transmit power by default) +MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +// Message signing driver (none default) +MySigningDriverNone signer; +// Construct MySensors library +MySensor gw(radio, signer); #define IP_PORT 5003 // The port you want to open IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later! diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index bea3ef4..706ca3c 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -56,6 +56,8 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ +#include +#include #include #include #include @@ -89,7 +91,13 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You ////////////////////////////////////////////////////////////////// -MySensor gw; +// NRFRF24L01 radio driver (set low transmit power by default) +MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +// Message signing driver (none default) +MySigningDriverNone signer; +// Construct MySensors library +MySensor gw(radio, signer); + EthernetServer server = EthernetServer(TCP_PORT); MyMessage msg; char convBuf[MAX_PAYLOAD*2+1]; diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index dddacdb..c178b19 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -23,6 +23,8 @@ #define NO_PORTB_PINCHANGES +#include +#include #include #include #include @@ -38,7 +40,12 @@ #define RADIO_TX_LED_PIN 5 // the PCB, on board LED -MySensor gw; +// NRFRF24L01 radio driver (set low transmit power by default) +MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +// Message signing driver (none default) +MySigningDriverNone signer; +// Construct MySensors library +MySensor gw(radio, signer); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; From 7a1cdd06e1c883e62c6f4e6e0232b4a8576c26ac Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 9 Mar 2015 23:45:05 +0100 Subject: [PATCH 068/660] Rename RFDriver to Transport --- libraries/MySensors/MyParserSerial.cpp | 2 +- libraries/MySensors/MyRFDriver.cpp | 4 ---- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 8 +++---- libraries/MySensors/MyTransport.cpp | 4 ++++ .../MySensors/{MyRFDriver.h => MyTransport.h} | 10 ++++----- ...RFDriverNRF24.cpp => MyTransportNRF24.cpp} | 22 +++++++++---------- .../{MyRFDriverNRF24.h => MyTransportNRF24.h} | 10 ++++----- ...MyRFDriverRF69.cpp => MyTransportRF69.cpp} | 22 +++++++++---------- .../{MyRFDriverRF69.h => MyTransportRF69.h} | 10 ++++----- .../EthernetGateway/EthernetGateway.ino | 4 ++-- .../examples/EthernetGateway/GatewayUtil.h | 2 +- .../examples/MQTTGateway/MQTTGateway.ino | 4 ++-- .../SecureActuator/SecureActuator.ino | 4 ++-- .../examples/SerialGateway/GatewayUtil.h | 2 +- .../examples/SerialGateway/SerialGateway.ino | 4 ++-- 16 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 libraries/MySensors/MyRFDriver.cpp create mode 100644 libraries/MySensors/MyTransport.cpp rename libraries/MySensors/{MyRFDriver.h => MyTransport.h} (94%) rename libraries/MySensors/{MyRFDriverNRF24.cpp => MyTransportNRF24.cpp} (73%) rename libraries/MySensors/{MyRFDriverNRF24.h => MyTransportNRF24.h} (71%) rename libraries/MySensors/{MyRFDriverRF69.cpp => MyTransportRF69.cpp} (63%) rename libraries/MySensors/{MyRFDriverRF69.h => MyTransportRF69.h} (89%) diff --git a/libraries/MySensors/MyParserSerial.cpp b/libraries/MySensors/MyParserSerial.cpp index 8c020b5..9c1aa88 100644 --- a/libraries/MySensors/MyParserSerial.cpp +++ b/libraries/MySensors/MyParserSerial.cpp @@ -1,6 +1,6 @@ #include "MyParser.h" #include "MyParserSerial.h" -#include "MyRFDriver.h" +#include "MyTransport.h" MyParserSerial::MyParserSerial() : MyParser() {} diff --git a/libraries/MySensors/MyRFDriver.cpp b/libraries/MySensors/MyRFDriver.cpp deleted file mode 100644 index cf669a0..0000000 --- a/libraries/MySensors/MyRFDriver.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "MyRFDriver.h" - -MyRFDriver::MyRFDriver() { -} diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 1eb28d9..e34b22f 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -37,7 +37,7 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } -MySensor::MySensor(MyRFDriver &_radio, MySigningDriver &_signer) +MySensor::MySensor(MyTransport &_radio, MySigningDriver &_signer) : radio(_radio), signer(_signer) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index cc15075..b3a451d 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -13,8 +13,8 @@ #define MySensor_h #include "Version.h" // Auto generated by bot -#include "MyRFDriver.h" -#include "MyRFDriverNRF24.h" +#include "MyTransport.h" +#include "MyTransportNRF24.h" #include "MyParser.h" #include "MySigningDriver.h" #include "MySigningDriverNone.h" @@ -81,7 +81,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyRFDriver &radio =*new MyRFDriverNRF24(), MySigningDriver &signer=*new MySigningDriverNone()); + MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigningDriver &signer=*new MySigningDriverNone()); /** * Begin operation of the MySensors library @@ -249,7 +249,7 @@ class MySensor MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). MyMessage msgSign; // Buffer for message to sign. - MyRFDriver& radio; + MyTransport& radio; MySigningDriver& signer; void setupRepeaterMode(); diff --git a/libraries/MySensors/MyTransport.cpp b/libraries/MySensors/MyTransport.cpp new file mode 100644 index 0000000..56cfdf9 --- /dev/null +++ b/libraries/MySensors/MyTransport.cpp @@ -0,0 +1,4 @@ +#include "MyTransport.h" + +MyTransport::MyTransport() { +} diff --git a/libraries/MySensors/MyRFDriver.h b/libraries/MySensors/MyTransport.h similarity index 94% rename from libraries/MySensors/MyRFDriver.h rename to libraries/MySensors/MyTransport.h index 8157af1..5c7b728 100644 --- a/libraries/MySensors/MyRFDriver.h +++ b/libraries/MySensors/MyTransport.h @@ -1,5 +1,5 @@ -#ifndef MyRFDriver_h -#define MyRFDriver_h +#ifndef MyTransport_h +#define MyTransport_h #include @@ -16,13 +16,13 @@ #define GATEWAY_ADDRESS ((uint8_t)0) #define BROADCAST_ADDRESS ((uint8_t)0xFF) -class MyRFDriver +class MyTransport { public: - // MyRFDriver constructor + // MyTransport constructor // different parameters would be needed depending on radio module (e.g. pins connected etc.) // keeping these parameters as #define's in MyConfig to streamline the driver interface - MyRFDriver(); + MyTransport(); // init() // different parameters would be needed depending on radio module (e.g. channel, power, crc, etc.) // keeping these parameters as #define's in MyConfig to streamline the driver interface diff --git a/libraries/MySensors/MyRFDriverNRF24.cpp b/libraries/MySensors/MyTransportNRF24.cpp similarity index 73% rename from libraries/MySensors/MyRFDriverNRF24.cpp rename to libraries/MySensors/MyTransportNRF24.cpp index 9b4fe45..9cc63fb 100644 --- a/libraries/MySensors/MyRFDriverNRF24.cpp +++ b/libraries/MySensors/MyTransportNRF24.cpp @@ -1,15 +1,15 @@ -#include "MyRFDriver.h" -#include "MyRFDriverNRF24.h" +#include "MyTransport.h" +#include "MyTransportNRF24.h" -MyRFDriverNRF24::MyRFDriverNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) +MyTransportNRF24::MyTransportNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) : - MyRFDriver(), + MyTransport(), rf24(ce, cs), _paLevel(paLevel) { } -void MyRFDriverNRF24::init() { +void MyTransportNRF24::init() { // Start up the radio library rf24.begin(); @@ -31,18 +31,18 @@ void MyRFDriverNRF24::init() { rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); } -void MyRFDriverNRF24::setAddress(uint8_t address) { +void MyTransportNRF24::setAddress(uint8_t address) { _address = address; rf24.openReadingPipe(WRITE_PIPE, TO_ADDR(address)); rf24.openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); rf24.startListening(); } -uint8_t MyRFDriverNRF24::getAddress() { +uint8_t MyTransportNRF24::getAddress() { return _address; } -bool MyRFDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { +bool MyTransportNRF24::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up rf24.powerUp(); rf24.stopListening(); @@ -52,7 +52,7 @@ bool MyRFDriverNRF24::send(uint8_t to, const void* data, uint8_t len) { return ok; } -bool MyRFDriverNRF24::available(uint8_t *to) { +bool MyTransportNRF24::available(uint8_t *to) { uint8_t pipe = 255; boolean avail = rf24.available(&pipe); if (pipe == CURRENT_NODE_PIPE) @@ -62,12 +62,12 @@ bool MyRFDriverNRF24::available(uint8_t *to) { return (rf24.available() && pipe < 6); } -uint8_t MyRFDriverNRF24::receive(void* data) { +uint8_t MyTransportNRF24::receive(void* data) { uint8_t len = rf24.getDynamicPayloadSize(); rf24.read(data, len); return len; } -void MyRFDriverNRF24::powerDown() { +void MyTransportNRF24::powerDown() { rf24.powerDown(); } diff --git a/libraries/MySensors/MyRFDriverNRF24.h b/libraries/MySensors/MyTransportNRF24.h similarity index 71% rename from libraries/MySensors/MyRFDriverNRF24.h rename to libraries/MySensors/MyTransportNRF24.h index 6fcf3f8..c5ac75e 100644 --- a/libraries/MySensors/MyRFDriverNRF24.h +++ b/libraries/MySensors/MyTransportNRF24.h @@ -1,8 +1,8 @@ -#ifndef MyRFDriverNRF24_h -#define MyRFDriverNRF24_h +#ifndef MyTransportNRF24_h +#define MyTransportNRF24_h #include "MyConfig.h" -#include "MyRFDriver.h" +#include "MyTransport.h" #include #include "utility/RF24.h" #include "utility/RF24_config.h" @@ -13,10 +13,10 @@ #define CURRENT_NODE_PIPE ((uint8_t)1) #define BROADCAST_PIPE ((uint8_t)2) -class MyRFDriverNRF24 : public MyRFDriver +class MyTransportNRF24 : public MyTransport { public: - MyRFDriverNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); + MyTransportNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); void init(); void setAddress(uint8_t address); uint8_t getAddress(); diff --git a/libraries/MySensors/MyRFDriverRF69.cpp b/libraries/MySensors/MyTransportRF69.cpp similarity index 63% rename from libraries/MySensors/MyRFDriverRF69.cpp rename to libraries/MySensors/MyTransportRF69.cpp index c8e32ef..b55ce14 100644 --- a/libraries/MySensors/MyRFDriverRF69.cpp +++ b/libraries/MySensors/MyTransportRF69.cpp @@ -1,14 +1,14 @@ -#include "MyRFDriver.h" -#include "MyRFDriverRF69.h" +#include "MyTransport.h" +#include "MyTransportRF69.h" -MyRFDriverRF69::MyRFDriverRF69() +MyTransportRF69::MyTransportRF69() : - MyRFDriver(), + MyTransport(), radio() { } -void MyRFDriverRF69::init() { +void MyTransportRF69::init() { // Start up the radio library radio->initialize(FREQUENCY,_address,NETWORKID); #ifdef IS_RFM69HW @@ -18,21 +18,21 @@ void MyRFDriverRF69::init() { } -void MyRFDriverRF69::setAddress(uint8_t address) { +void MyTransportRF69::setAddress(uint8_t address) { _address = address; radio->setAddress(address); } -uint8_t MyRFDriverRF69::getAddress() { +uint8_t MyTransportRF69::getAddress() { return _address; } -bool MyRFDriverRF69::send(uint8_t to, const void* data, uint8_t len) { +bool MyTransportRF69::send(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up return radio->sendWithRetry(to,data,len); } -bool MyRFDriverRF69::available(uint8_t *to) { +bool MyTransportRF69::available(uint8_t *to) { if (radio->TARGETID == BROADCAST_ADDRESS) *to = BROADCAST_ADDRESS; else @@ -40,7 +40,7 @@ bool MyRFDriverRF69::available(uint8_t *to) { return radio->receiveDone(); } -uint8_t MyRFDriverRF69::receive(void* data) { +uint8_t MyTransportRF69::receive(void* data) { // for (byte i = 0; i < radio->DATALEN; i++){ // data[i]= (void)radio->DATA[i]; // } @@ -52,6 +52,6 @@ uint8_t MyRFDriverRF69::receive(void* data) { return radio->DATALEN; } -void MyRFDriverRF69::powerDown() { +void MyTransportRF69::powerDown() { radio->sleep(); } diff --git a/libraries/MySensors/MyRFDriverRF69.h b/libraries/MySensors/MyTransportRF69.h similarity index 89% rename from libraries/MySensors/MyRFDriverRF69.h rename to libraries/MySensors/MyTransportRF69.h index 256cc4d..687259d 100644 --- a/libraries/MySensors/MyRFDriverRF69.h +++ b/libraries/MySensors/MyTransportRF69.h @@ -1,8 +1,8 @@ -#ifndef MyRFDriverRF69_h -#define MyRFDriverRF69_h +#ifndef MyTransportRF69_h +#define MyTransportRF69_h #include "MyConfig.h" -#include "MyRFDriver.h" +#include "MyTransport.h" #include #include "utility/RFM69.h" #include @@ -25,10 +25,10 @@ #define FLASH_SS 8 // and FLASH SS on D8 #endif -class MyRFDriverRF69 : public MyRFDriver +class MyTransportRF69 : public MyTransport { public: - MyRFDriverRF69(); + MyTransportRF69(); void init(); void setAddress(uint8_t address); uint8_t getAddress(); diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index def707b..d7433e4 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -44,7 +44,7 @@ #include #include -#include +#include #include #include #include @@ -72,7 +72,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) -MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) MySigningDriverNone signer; // Construct MySensors library diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index fa5f1b6..d564ea6 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -1,7 +1,7 @@ #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ -#include +#include #ifdef ARDUINO diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 706ca3c..979440c 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -57,7 +57,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ #include -#include +#include #include #include #include @@ -92,7 +92,7 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You ////////////////////////////////////////////////////////////////// // NRFRF24L01 radio driver (set low transmit power by default) -MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) MySigningDriverNone signer; // Construct MySensors library diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 65f0fe7..3517ef9 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -2,7 +2,7 @@ // This example will remember lock state even after power failure. #include -#include +#include #include #include @@ -11,7 +11,7 @@ #define LOCK_LOCK 1 // GPIO value to write to lock attached lock #define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock -MyRFDriverNRF24 radio; // NRFRF24L01 radio driver +MyTransportNRF24 radio; // NRFRF24L01 radio driver MySigningDriverAtsha204Soft signer; // Message signing driver MySensor gw(radio, signer); diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index fa5f1b6..d564ea6 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -1,7 +1,7 @@ #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ -#include +#include #ifdef ARDUINO diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index c178b19..d300793 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -24,7 +24,7 @@ #define NO_PORTB_PINCHANGES #include -#include +#include #include #include #include @@ -41,7 +41,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) -MyRFDriverNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) MySigningDriverNone signer; // Construct MySensors library From 6d0ae813c4220c28ac43c5b843f3f6c37aec31c5 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 10 Mar 2015 00:07:57 +0100 Subject: [PATCH 069/660] Rename MySigningDriver* to MySigning* --- libraries/MySensors/MyConfig.h | 6 +++--- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 8 ++++---- libraries/MySensors/MySigning.cpp | 9 +++++++++ .../{MySigningDriver.h => MySigning.h} | 10 +++++----- ...iverAtsha204.cpp => MySigningAtsha204.cpp} | 20 +++++++++---------- ...ngDriverAtsha204.h => MySigningAtsha204.h} | 10 +++++----- ...a204Soft.cpp => MySigningAtsha204Soft.cpp} | 20 +++++++++---------- ...Atsha204Soft.h => MySigningAtsha204Soft.h} | 10 +++++----- libraries/MySensors/MySigningDriver.cpp | 9 --------- ...igningDriverNone.cpp => MySigningNone.cpp} | 16 +++++++-------- ...{MySigningDriverNone.h => MySigningNone.h} | 10 +++++----- .../EthernetGateway/EthernetGateway.ino | 4 ++-- .../examples/MQTTGateway/MQTTGateway.ino | 4 ++-- .../SecureActuator/SecureActuator.ino | 4 ++-- .../examples/SerialGateway/SerialGateway.ino | 4 ++-- 16 files changed, 73 insertions(+), 73 deletions(-) create mode 100644 libraries/MySensors/MySigning.cpp rename libraries/MySensors/{MySigningDriver.h => MySigning.h} (95%) rename libraries/MySensors/{MySigningDriverAtsha204.cpp => MySigningAtsha204.cpp} (93%) rename libraries/MySensors/{MySigningDriverAtsha204.h => MySigningAtsha204.h} (80%) rename libraries/MySensors/{MySigningDriverAtsha204Soft.cpp => MySigningAtsha204Soft.cpp} (92%) rename libraries/MySensors/{MySigningDriverAtsha204Soft.h => MySigningAtsha204Soft.h} (85%) delete mode 100644 libraries/MySensors/MySigningDriver.cpp rename libraries/MySensors/{MySigningDriverNone.cpp => MySigningNone.cpp} (77%) rename libraries/MySensors/{MySigningDriverNone.h => MySigningNone.h} (81%) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index b259a1c..9898fab 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -15,12 +15,12 @@ // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. #define MY_VERIFICATION_TIMEOUT_MS 5000 -// MySigningDriverAtsha204 default setting +// MySigningAtsha204 default setting #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached -// MySigningDriverAtsha204Soft default settings +// MySigningAtsha204Soft default settings #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) -// Key to use for HMAC calculation in MySigningDriverAtsha204Soft (32 bytes) +// Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index e34b22f..c558e43 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -37,7 +37,7 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } -MySensor::MySensor(MyTransport &_radio, MySigningDriver &_signer) +MySensor::MySensor(MyTransport &_radio, MySigning &_signer) : radio(_radio), signer(_signer) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index b3a451d..f9d75bb 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -16,8 +16,8 @@ #include "MyTransport.h" #include "MyTransportNRF24.h" #include "MyParser.h" -#include "MySigningDriver.h" -#include "MySigningDriverNone.h" +#include "MySigning.h" +#include "MySigningNone.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -81,7 +81,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigningDriver &signer=*new MySigningDriverNone()); + MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone()); /** * Begin operation of the MySensors library @@ -250,7 +250,7 @@ class MySensor MyMessage msgSign; // Buffer for message to sign. MyTransport& radio; - MySigningDriver& signer; + MySigning& signer; void setupRepeaterMode(); boolean sendWrite(uint8_t dest, MyMessage &message); diff --git a/libraries/MySensors/MySigning.cpp b/libraries/MySensors/MySigning.cpp new file mode 100644 index 0000000..835b947 --- /dev/null +++ b/libraries/MySensors/MySigning.cpp @@ -0,0 +1,9 @@ +#include "MySigning.h" + +MySigning::MySigning(bool requestSignatures) : _requestSignatures(requestSignatures) { +} + + +bool MySigning::requestSignatures() { + return _requestSignatures; +} diff --git a/libraries/MySensors/MySigningDriver.h b/libraries/MySensors/MySigning.h similarity index 95% rename from libraries/MySensors/MySigningDriver.h rename to libraries/MySensors/MySigning.h index ebabde8..dc4407d 100644 --- a/libraries/MySensors/MySigningDriver.h +++ b/libraries/MySensors/MySigning.h @@ -4,20 +4,20 @@ Created by Patrick "Anticimex" Fallberg */ -#ifndef MySigningDriver_h -#define MySigningDriver_h +#ifndef MySigning_h +#define MySigning_h #include #include "MyMessage.h" -class MySigningDriver +class MySigning { public: - // MySigningDriver constructor. + // MySigning constructor. // Different parameters would be needed depending on signing backend (e.g. pins connected etc.). // Keeping these parameters as #define's in MyConfig to streamline the driver interface. // @param requestSignatures Set this to true if you want destination node to sign all messages sent to this node. Default is not to require signing. - MySigningDriver(bool requestSignatures=false); + MySigning(bool requestSignatures=false); // Returns the current requestSignature setting bool requestSignatures(); diff --git a/libraries/MySensors/MySigningDriverAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp similarity index 93% rename from libraries/MySensors/MySigningDriverAtsha204.cpp rename to libraries/MySensors/MySigningAtsha204.cpp index 401a82c..1effefc 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -4,8 +4,8 @@ Created by Patrick "Anticimex" Fallberg */ -#include "MySigningDriver.h" -#include "MySigningDriverAtsha204.h" +#include "MySigning.h" +#include "MySigningAtsha204.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_ATSHA_SIGNING @@ -36,9 +36,9 @@ static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #endif -MySigningDriverAtsha204::MySigningDriverAtsha204(bool requestSignatures, uint8_t atshaPin) +MySigningAtsha204::MySigningAtsha204(bool requestSignatures, uint8_t atshaPin) : - MySigningDriver(requestSignatures), + MySigning(requestSignatures), atsha204(atshaPin), verification_ongoing(false) { @@ -46,7 +46,7 @@ MySigningDriverAtsha204::MySigningDriverAtsha204(bool requestSignatures, uint8_t memset(current_nonce, 0xAA, sizeof(current_nonce)); } -bool MySigningDriverAtsha204::getNonce(MyMessage &msg) { +bool MySigningAtsha204::getNonce(MyMessage &msg) { // Wake device before starting operations if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { DEBUG_ATSHA_PRINTLN("Failed to wake device"); @@ -78,7 +78,7 @@ bool MySigningDriverAtsha204::getNonce(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204::checkTimer() { +bool MySigningAtsha204::checkTimer() { if (verification_ongoing) { if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_ATSHA_PRINTLN("Verification timeout"); @@ -91,7 +91,7 @@ bool MySigningDriverAtsha204::checkTimer() { return true; } -bool MySigningDriverAtsha204::putNonce(MyMessage &msg) { +bool MySigningAtsha204::putNonce(MyMessage &msg) { if (mGetLength(msg) != MAX_PAYLOAD) { DEBUG_ATSHA_PRINTLN("Incoming nonce with incorrect size"); return false; // We require as big nonce as possible @@ -106,7 +106,7 @@ bool MySigningDriverAtsha204::putNonce(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204::signMsg(MyMessage &msg) { +bool MySigningAtsha204::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_ATSHA_PRINTLN("Cannot fit any signature to this message"); @@ -128,7 +128,7 @@ bool MySigningDriverAtsha204::signMsg(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204::verifyMsg(MyMessage &msg) { +bool MySigningAtsha204::verifyMsg(MyMessage &msg) { if (!verification_ongoing) { DEBUG_ATSHA_PRINTLN("No active verification session"); return false; @@ -166,7 +166,7 @@ bool MySigningDriverAtsha204::verifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) -bool MySigningDriverAtsha204::calculateSignature(MyMessage &msg) { +bool MySigningAtsha204::calculateSignature(MyMessage &msg) { memset(temp_message, 0, 32); memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); diff --git a/libraries/MySensors/MySigningDriverAtsha204.h b/libraries/MySensors/MySigningAtsha204.h similarity index 80% rename from libraries/MySensors/MySigningDriverAtsha204.h rename to libraries/MySensors/MySigningAtsha204.h index 8da91ae..8850b2c 100644 --- a/libraries/MySensors/MySigningDriverAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -4,11 +4,11 @@ Created by Patrick "Anticimex" Fallberg */ -#ifndef MySigningDriverAtsha204_h -#define MySigningDriverAtsha204_h +#ifndef MySigningAtsha204_h +#define MySigningAtsha204_h #include "MyConfig.h" -#include "MySigningDriver.h" +#include "MySigning.h" #include "utility/ATSHA204.h" #include @@ -17,10 +17,10 @@ // The ATSHA204 is capable of generating proper random numbers for nonce // and can calculate HMAC-SHA256 signatures. This is enterprise- // level of security and ought to implement the signing needs for anybody. -class MySigningDriverAtsha204 : public MySigningDriver +class MySigningAtsha204 : public MySigning { public: - MySigningDriverAtsha204(bool requestSignatures=true, uint8_t atshaPin = MY_ATSHA204_PIN); + MySigningAtsha204(bool requestSignatures=true, uint8_t atshaPin = MY_ATSHA204_PIN); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp similarity index 92% rename from libraries/MySensors/MySigningDriverAtsha204Soft.cpp rename to libraries/MySensors/MySigningAtsha204Soft.cpp index c9f6e44..3ac6f38 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -8,8 +8,8 @@ Created by Patrick "Anticimex" Fallberg */ #include "MyConfig.h" -#include "MySigningDriver.h" -#include "MySigningDriverAtsha204Soft.h" +#include "MySigning.h" +#include "MySigningAtsha204Soft.h" #include "utility/sha256.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) @@ -40,9 +40,9 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_ATSHASOFT_PRINTBUF(str, buf, sz) #endif -MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft(bool requestSignatures, uint8_t randomseedPin) +MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, uint8_t randomseedPin) : - MySigningDriver(requestSignatures), + MySigning(requestSignatures), rndPin(randomseedPin), hmacKey({MY_HMAC_KEY}), verification_ongoing(false), @@ -53,7 +53,7 @@ MySigningDriverAtsha204Soft::MySigningDriverAtsha204Soft(bool requestSignatures, memset(current_nonce, 0xAA, sizeof(current_nonce)); } -bool MySigningDriverAtsha204Soft::getNonce(MyMessage &msg) { +bool MySigningAtsha204Soft::getNonce(MyMessage &msg) { // Set randomseed randomSeed(analogRead(rndPin)); for (int i = 0; i < MAX_PAYLOAD; i++) @@ -73,7 +73,7 @@ bool MySigningDriverAtsha204Soft::getNonce(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204Soft::checkTimer() { +bool MySigningAtsha204Soft::checkTimer() { if (verification_ongoing) { if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_ATSHASOFT_PRINTLN("Verification timeout"); @@ -86,7 +86,7 @@ bool MySigningDriverAtsha204Soft::checkTimer() { return true; } -bool MySigningDriverAtsha204Soft::putNonce(MyMessage &msg) { +bool MySigningAtsha204Soft::putNonce(MyMessage &msg) { if (mGetLength(msg) != MAX_PAYLOAD) { DEBUG_ATSHASOFT_PRINTLN("Incoming nonce with incorrect size"); return false; // We require as big nonce as possible @@ -101,7 +101,7 @@ bool MySigningDriverAtsha204Soft::putNonce(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204Soft::signMsg(MyMessage &msg) { +bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_ATSHASOFT_PRINTLN("Cannot fit any signature to this message"); @@ -123,7 +123,7 @@ bool MySigningDriverAtsha204Soft::signMsg(MyMessage &msg) { return true; } -bool MySigningDriverAtsha204Soft::verifyMsg(MyMessage &msg) { +bool MySigningAtsha204Soft::verifyMsg(MyMessage &msg) { if (!verification_ongoing) { DEBUG_ATSHASOFT_PRINTLN("No active verification session"); return false; @@ -161,7 +161,7 @@ bool MySigningDriverAtsha204Soft::verifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) -bool MySigningDriverAtsha204Soft::calculateSignature(MyMessage &msg) { +bool MySigningAtsha204Soft::calculateSignature(MyMessage &msg) { memset(temp_message, 0, 32); memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); diff --git a/libraries/MySensors/MySigningDriverAtsha204Soft.h b/libraries/MySensors/MySigningAtsha204Soft.h similarity index 85% rename from libraries/MySensors/MySigningDriverAtsha204Soft.h rename to libraries/MySensors/MySigningAtsha204Soft.h index eef0a31..daf954d 100644 --- a/libraries/MySensors/MySigningDriverAtsha204Soft.h +++ b/libraries/MySensors/MySigningAtsha204Soft.h @@ -7,11 +7,11 @@ Created by Patrick "Anticimex" Fallberg */ -#ifndef MySigningDriverHmac256Soft_h -#define MySigningDriverHmac256Soft_h +#ifndef MySigningHmac256Soft_h +#define MySigningHmac256Soft_h #include "MyConfig.h" -#include "MySigningDriver.h" +#include "MySigning.h" #include "utility/ATSHA204.h" #include "utility/sha256.h" #include @@ -25,10 +25,10 @@ // is weaker though. Random numbers are generated using the Arduino library and seed // is sampled from an analog pin. This pin should unconnected in the hardware. // The pin is selected using MY_RANDOMSEED_PIN in MyConfig.h. -class MySigningDriverAtsha204Soft : public MySigningDriver +class MySigningAtsha204Soft : public MySigning { public: - MySigningDriverAtsha204Soft(bool requestSignatures=true, uint8_t randomseedPin = MY_RANDOMSEED_PIN); + MySigningAtsha204Soft(bool requestSignatures=true, uint8_t randomseedPin = MY_RANDOMSEED_PIN); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); diff --git a/libraries/MySensors/MySigningDriver.cpp b/libraries/MySensors/MySigningDriver.cpp deleted file mode 100644 index aa718fc..0000000 --- a/libraries/MySensors/MySigningDriver.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "MySigningDriver.h" - -MySigningDriver::MySigningDriver(bool requestSignatures) : _requestSignatures(requestSignatures) { -} - - -bool MySigningDriver::requestSignatures() { - return _requestSignatures; -} diff --git a/libraries/MySensors/MySigningDriverNone.cpp b/libraries/MySensors/MySigningNone.cpp similarity index 77% rename from libraries/MySensors/MySigningDriverNone.cpp rename to libraries/MySensors/MySigningNone.cpp index a7ace62..e15f724 100644 --- a/libraries/MySensors/MySigningDriverNone.cpp +++ b/libraries/MySensors/MySigningNone.cpp @@ -3,8 +3,8 @@ Created by Patrick "Anticimex" Fallberg */ -#include "MySigningDriver.h" -#include "MySigningDriverNone.h" +#include "MySigning.h" +#include "MySigningNone.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_NONE_SIGNING @@ -34,22 +34,22 @@ static void DEBUG_NONE_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_NONE_PRINTBUF(str, buf, sz) #endif -MySigningDriverNone::MySigningDriverNone() : MySigningDriver() { +MySigningNone::MySigningNone() : MySigning() { } -bool MySigningDriverNone::getNonce(MyMessage &msg) { +bool MySigningNone::getNonce(MyMessage &msg) { return true; } -bool MySigningDriverNone::checkTimer() { +bool MySigningNone::checkTimer() { return true; } -bool MySigningDriverNone::putNonce(MyMessage &msg) { +bool MySigningNone::putNonce(MyMessage &msg) { return true; } -bool MySigningDriverNone::signMsg(MyMessage &msg) { +bool MySigningNone::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_NONE_PRINTLN("Cannot fit any signature to this message"); @@ -60,7 +60,7 @@ bool MySigningDriverNone::signMsg(MyMessage &msg) { return true; } -bool MySigningDriverNone::verifyMsg(MyMessage &msg) { +bool MySigningNone::verifyMsg(MyMessage &msg) { if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) return false; else diff --git a/libraries/MySensors/MySigningDriverNone.h b/libraries/MySensors/MySigningNone.h similarity index 81% rename from libraries/MySensors/MySigningDriverNone.h rename to libraries/MySensors/MySigningNone.h index 9718a78..dd8f319 100644 --- a/libraries/MySensors/MySigningDriverNone.h +++ b/libraries/MySensors/MySigningNone.h @@ -3,11 +3,11 @@ Created by Patrick "Anticimex" Fallberg */ -#ifndef MySigningDriverNone_h -#define MySigningDriverNone_h +#ifndef MySigningNone_h +#define MySigningNone_h #include "MyConfig.h" -#include "MySigningDriver.h" +#include "MySigning.h" #include #define SIGNING_IDENTIFIER (0) @@ -17,10 +17,10 @@ // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in // the network (as seen by this node) and it does verify proper execution order on the API. // The "none" driver rejects all other back-ends. -class MySigningDriverNone : public MySigningDriver +class MySigningNone : public MySigning { public: - MySigningDriverNone(); + MySigningNone(); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index d7433e4..bde2cf1 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -43,7 +43,7 @@ #include // This include can be removed when using UIPEthernet module #include -#include +#include #include #include #include @@ -74,7 +74,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) -MySigningDriverNone signer; +MySigningNone signer; // Construct MySensors library MySensor gw(radio, signer); diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 979440c..bb1ea20 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -56,7 +56,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ -#include +#include #include #include #include @@ -94,7 +94,7 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) -MySigningDriverNone signer; +MySigningNone signer; // Construct MySensors library MySensor gw(radio, signer); diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 3517ef9..d249f29 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -1,7 +1,7 @@ // Example sketch showing how to securely control locks. // This example will remember lock state even after power failure. -#include +#include #include #include #include @@ -12,7 +12,7 @@ #define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock MyTransportNRF24 radio; // NRFRF24L01 radio driver -MySigningDriverAtsha204Soft signer; // Message signing driver +MySigningAtsha204Soft signer; // Message signing driver MySensor gw(radio, signer); void setup() diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index d300793..8dc5e26 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -23,7 +23,7 @@ #define NO_PORTB_PINCHANGES -#include +#include #include #include #include @@ -43,7 +43,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) -MySigningDriverNone signer; +MySigningNone signer; // Construct MySensors library MySensor gw(radio, signer); From 9e85fac74546456552d38b9feeeaaa7c710bf4b3 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 12 Mar 2015 22:59:51 +0100 Subject: [PATCH 070/660] Separate the HW specifics from the MySensor library --- libraries/MySensors/MyConfig.h | 2 + libraries/MySensors/MyHw.cpp | 4 + libraries/MySensors/MyHw.h | 35 +++ libraries/MySensors/MyHwATMega328.cpp | 141 ++++++++++++ libraries/MySensors/MyHwATMega328.h | 40 ++++ libraries/MySensors/MySensor.cpp | 206 +++++------------- libraries/MySensors/MySensor.h | 38 ++-- libraries/MySensors/MyTransport.h | 2 +- .../ClearEepromConfig/ClearEepromConfig.ino | 4 + .../examples/RelayActuator/RelayActuator.ino | 12 +- 10 files changed, 308 insertions(+), 176 deletions(-) create mode 100644 libraries/MySensors/MyHw.cpp create mode 100644 libraries/MySensors/MyHw.h create mode 100644 libraries/MySensors/MyHwATMega328.cpp create mode 100644 libraries/MySensors/MyHwATMega328.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 9898fab..3e09981 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -6,6 +6,8 @@ ***********************************/ #define DEBUG +#define BAUD_RATE 115200 + /********************************** * Message Signing Settings diff --git a/libraries/MySensors/MyHw.cpp b/libraries/MySensors/MyHw.cpp new file mode 100644 index 0000000..75f020d --- /dev/null +++ b/libraries/MySensors/MyHw.cpp @@ -0,0 +1,4 @@ +#include "MyHw.h" + +MyHw::MyHw() { +} diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/MyHw.h new file mode 100644 index 0000000..a7ce870 --- /dev/null +++ b/libraries/MySensors/MyHw.h @@ -0,0 +1,35 @@ +#ifndef MyHw_h +#define MyHw_h + +#include +#include +#include "MyConfig.h" + +//#include "MySensor.h" +/** + * The Hw contains all hardware specific details of the platform + */ + +class MyHw +{ +public: + // MyHw constructor + MyHw(); + virtual void init() = 0; + virtual void watchdogReset() = 0; + virtual void reboot() = 0; + virtual unsigned long millisec() = 0; + virtual void sleep(unsigned long ms) = 0; + virtual bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) = 0; + virtual uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) = 0; + virtual uint8_t readConfigByte(uint8_t pos) = 0; + virtual void writeConfigByte(uint8_t pos, uint8_t value) = 0; + virtual void readConfigBlock(void* buf, void * pos, size_t length) = 0; + virtual void writeConfigBlock(void* pos, void* buf, uint16_t length) = 0; + #ifdef DEBUG + virtual void debugPrint(bool isGW, const char *fmt, ... ) = 0; + #endif + +}; + +#endif diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp new file mode 100644 index 0000000..3f42fc9 --- /dev/null +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -0,0 +1,141 @@ +#include "MyHw.h" +#include "MyHwATMega328.h" + +int8_t pinIntTrigger = 0; +void wakeUp() //place to send the interrupts +{ + pinIntTrigger = 1; +} +void wakeUp2() //place to send the second interrupts +{ + pinIntTrigger = 2; +} + +MyHwATMega328::MyHwATMega328() : MyHw() +{ +} + + +void MyHwATMega328::init() { + Serial.begin(BAUD_RATE); +} + +void MyHwATMega328::watchdogReset() { + wdt_reset(); +} + +void MyHwATMega328::reboot() { + wdt_enable(WDTO_15MS); + for (;;); +} + +unsigned long MyHwATMega328::millisec() { + return millis(); +} + + +void MyHwATMega328::sleep(unsigned long ms) { + // Let serial prints finish (debug, log etc) + Serial.flush(); + pinIntTrigger = 0; + while (!pinIntTrigger && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } + if (!pinIntTrigger && ms >= 4000) { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); ms -= 4000; } + if (!pinIntTrigger && ms >= 2000) { LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); ms -= 2000; } + if (!pinIntTrigger && ms >= 1000) { LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); ms -= 1000; } + if (!pinIntTrigger && ms >= 500) { LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); ms -= 500; } + if (!pinIntTrigger && ms >= 250) { LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); ms -= 250; } + if (!pinIntTrigger && ms >= 125) { LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF); ms -= 120; } + if (!pinIntTrigger && ms >= 64) { LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); ms -= 60; } + if (!pinIntTrigger && ms >= 32) { LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF); ms -= 30; } + if (!pinIntTrigger && ms >= 16) { LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); ms -= 15; } +} + +bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { + // Let serial prints finish (debug, log etc) + bool pinTriggeredWakeup = true; + Serial.flush(); + attachInterrupt(interrupt, wakeUp, mode); + if (ms>0) { + pinIntTrigger = 0; + sleep(ms); + if (0 == pinIntTrigger) { + pinTriggeredWakeup = false; + } + } else { + Serial.flush(); + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + } + detachInterrupt(interrupt); + return pinTriggeredWakeup; +} + +uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { + int8_t retVal = 1; + Serial.flush(); // Let serial prints finish (debug, log etc) + attachInterrupt(interrupt1, wakeUp, mode1); + attachInterrupt(interrupt2, wakeUp2, mode2); + if (ms>0) { + pinIntTrigger = 0; + sleep(ms); + if (0 == pinIntTrigger) { + retVal = -1; + } + } else { + Serial.flush(); + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + } + detachInterrupt(interrupt1); + detachInterrupt(interrupt2); + + if (1 == pinIntTrigger) { + retVal = (int8_t)interrupt1; + } else if (2 == pinIntTrigger) { + retVal = (int8_t)interrupt2; + } + return retVal; +} + +uint8_t MyHwATMega328::readConfigByte(uint8_t pos) { + return eeprom_read_byte((uint8_t*)pos); +} + +void MyHwATMega328::writeConfigByte(uint8_t pos, uint8_t value) { + eeprom_update_byte((uint8_t*)pos, value); +} + +void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { + eeprom_read_block(buf, (void*)pos, length); +} + +void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { + eeprom_write_block((void*)pos, (void*)buf, length); +} + + +#ifdef DEBUG +void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) { + char fmtBuffer[300]; + if (isGW) { + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + Serial.print(fmtBuffer); + } + va_list args; + va_start (args, fmt ); + va_end (args); + if (isGW) { + // Truncate message if this is gateway node + vsnprintf_P(fmtBuffer, 60, fmt, args); + fmtBuffer[59] = '\n'; + fmtBuffer[60] = '\0'; + } else { + vsnprintf_P(fmtBuffer, 299, fmt, args); + } + va_end (args); + Serial.print(fmtBuffer); + Serial.flush(); + + //Serial.write(freeRam()); +} +#endif + diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h new file mode 100644 index 0000000..90e6e82 --- /dev/null +++ b/libraries/MySensors/MyHwATMega328.h @@ -0,0 +1,40 @@ +#ifndef MyHwATMega328_h +#define MyHwATMega328_h + +#include "MyConfig.h" +#include "MyMessage.h" +#include +#include +#include +#include "utility/LowPower.h" + +#include "MyHw.h" + +#ifdef __cplusplus +#include +#include +#endif + + +class MyHwATMega328 : public MyHw +{ +public: + MyHwATMega328(); + + void init(); + void watchdogReset(); + void reboot(); + unsigned long millisec(); + void sleep(unsigned long ms); + bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms); + uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); + uint8_t readConfigByte(uint8_t pos); + void writeConfigByte(uint8_t pos, uint8_t value); + void readConfigBlock(void* buf, void * pos, size_t length); + void writeConfigBlock(void* pos, void* buf, size_t length); +#ifdef DEBUG + void debugPrint(bool isGW, const char *fmt, ... ); +#endif +private: +}; +#endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index c558e43..bb69787 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -37,16 +37,17 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } -MySensor::MySensor(MyTransport &_radio, MySigning &_signer) +MySensor::MySensor(MyTransport &_radio, MySigning &_signer, MyHw &_hw) : radio(_radio), - signer(_signer) + signer(_signer), + hw(_hw) { } void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { - Serial.begin(BAUD_RATE); + hw.init(); repeaterMode = _repeaterMode; msgCallback = _msgCallback; failedTransmissions = 0; @@ -62,11 +63,11 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b radio.init(); // Read settings from eeprom - eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + hw.readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM - eeprom_read_block((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + hw.readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); // Read out the signing requirements from EEPROM - eeprom_read_block((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); + hw.readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); if (isGateway) { nc.distance = 0; @@ -81,7 +82,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b if (!autoFindParent) { nc.parentNodeId = _parentNodeId; // Save static parent id in eeprom (used by bootloader) - eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); + hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); // We don't actually know the distance to gw here. Let's pretend it is 1. // If the current node is also repeater, be aware of this. nc.distance = 1; @@ -90,24 +91,26 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b findParentNode(); } - if (_nodeId != AUTO) { - // Set static id - nc.nodeId = _nodeId; - // Save static id in eeprom - eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, _nodeId); - } else if (isValidParent(nc.parentNodeId)) { - // Try to fetch node-id from gateway - requestNodeId(); + if (!isGateway) { + if (_nodeId != AUTO) { + // Set static id + nc.nodeId = _nodeId; + // Save static id in eeprom + if (_nodeId > 0) + hw.writeConfigByte(EEPROM_NODE_ID_ADDRESS, _nodeId); + } else if (isValidParent(nc.parentNodeId)) { + // Try to fetch node-id from gateway + requestNodeId(); + } } setupNode(); - debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), isGateway?"gateway":(repeaterMode?"repeater":"sensor"), nc.nodeId, nc.parentNodeId, nc.distance); } void MySensor::setupRepeaterMode(){ // childNodeTable = new uint8_t[256]; - eeprom_read_block((void*)childNodeTable, (void*)EEPROM_ROUTES_ADDRESS, 256); + hw.readConfigBlock((void*)childNodeTable, (void *)EEPROM_ROUTES_ADDRESS, 256); } uint8_t MySensor::getNodeId() { @@ -119,7 +122,7 @@ ControllerConfig MySensor::getConfig() { } void MySensor::requestNodeId() { - debug(PSTR("req node id\n")); + debug(PSTR("req id\n")); radio.setAddress(nc.nodeId); build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); sendWrite(nc.parentNodeId, msg); @@ -135,7 +138,7 @@ void MySensor::setupNode() { // Notify gateway (and possibly controller) about the signing preferences of this node sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); - // If we do require signing, wait for the gateway to tell us how it perfer us to transmit our messages + // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages if (signer.requestSignatures()) { wait(2000); } @@ -197,7 +200,7 @@ boolean MySensor::sendRoute(MyMessage &message) { message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { if (!sign(message)) { - debug(PSTR("Message signing failed\n")); + debug(PSTR("sign fail\n")); return false; } // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, @@ -312,6 +315,7 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { } boolean MySensor::process() { + hw.watchdogReset(); uint8_t to = 0; if (!radio.available(&to)) return false; @@ -328,11 +332,12 @@ boolean MySensor::process() { msg.type != I_ID_REQUEST && msg.type != I_ID_RESPONSE && msg.type != I_FIND_PARENT && msg.type != I_FIND_PARENT_RESPONSE))) { if (!mGetSigned(msg)) { - debug(PSTR("Got unsigned message that should have been signed\n")); + // Got unsigned message that should have been signed + debug(PSTR("no sign\n")); return false; } else if (!signer.verifyMsg(msg)) { - debug(PSTR("Message verification failed\n")); + debug(PSTR("verify fail\n")); return false; // This signed message has been tampered with! } } @@ -344,8 +349,7 @@ boolean MySensor::process() { mSetSigned(msg,0); // Clear the sign-flag now as verification (and debug printing) is completed if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { - debug(PSTR("version: %d\n"),mGetVersion(msg)); - debug(PSTR("version mismatch\n")); + debug(PSTR("ver mismatch\n")); return false; } @@ -388,9 +392,9 @@ boolean MySensor::process() { // Found a neighbor closer to GW than previously found nc.distance = distance; nc.parentNodeId = msg.sender; - eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); - eeprom_update_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance); - debug(PSTR("new parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); + hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); + hw.writeConfigByte(EEPROM_DISTANCE_ADDRESS, nc.distance); + debug(PSTR("parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); } } } @@ -409,7 +413,7 @@ boolean MySensor::process() { CLEAR_SIGN(msg.sender); } // Save updated table - eeprom_update_block((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); + hw.writeConfigBlock((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node @@ -428,8 +432,7 @@ boolean MySensor::process() { if (type == I_REBOOT) { // Requires MySensors or other bootloader with watchdogs enabled - wdt_enable(WDTO_15MS); - for (;;); + hw.reboot(); } else if (type == I_ID_RESPONSE) { if (nc.nodeId == AUTO) { nc.nodeId = msg.getByte(); @@ -440,7 +443,7 @@ boolean MySensor::process() { } setupNode(); // Write id to EEPROM - eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId); + hw.writeConfigByte(EEPROM_NODE_ID_ADDRESS, nc.nodeId); debug(PSTR("id=%d\n"), nc.nodeId); } } else if (type == I_CONFIG) { @@ -448,18 +451,18 @@ boolean MySensor::process() { // and store it in eeprom if changed isMetric = msg.getString()[0] == 'M' ; cc.isMetric = isMetric; - eeprom_update_byte((uint8_t*)EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); + hw.writeConfigByte(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); } else if (type == I_CHILDREN) { if (repeaterMode && msg.getString()[0] == 'C') { // Clears child relay data for this node - debug(PSTR("rd=clear\n")); + debug(PSTR("clear\n")); uint8_t i = 255; do { removeChildRoute(i); } while (i--); // Clear parent node id & distance to gw - eeprom_update_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); - eeprom_update_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, 0xFF); + hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); + hw.writeConfigByte(EEPROM_DISTANCE_ADDRESS, 0xFF); // Find parent node findParentNode(); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); @@ -484,7 +487,7 @@ boolean MySensor::process() { // Relaying nodes should always answer ping messages // Wait a random delay of 0-2 seconds to minimize collision // between ping ack messages from other relaying nodes - delay(millis() & 0x3ff); + wait(hw.millisec() & 0x3ff); sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); } } else if (to == nc.nodeId) { @@ -500,113 +503,48 @@ MyMessage& MySensor::getLastMessage() { } void MySensor::saveState(uint8_t pos, uint8_t value) { - eeprom_update_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos), value); + hw.writeConfigByte(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); } uint8_t MySensor::loadState(uint8_t pos) { - return eeprom_read_byte((uint8_t*)(EEPROM_LOCAL_CONFIG_ADDRESS+pos)); + return hw.readConfigByte(EEPROM_LOCAL_CONFIG_ADDRESS+pos); } void MySensor::addChildRoute(uint8_t childId, uint8_t route) { childNodeTable[childId] = route; - eeprom_update_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, route); + hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+childId, route); } void MySensor::removeChildRoute(uint8_t childId) { childNodeTable[childId] = 0xff; - eeprom_update_byte((uint8_t*)EEPROM_ROUTES_ADDRESS+childId, 0xff); + hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+childId, 0xff); } uint8_t MySensor::getChildRoute(uint8_t childId) { return childNodeTable[childId]; } -int8_t pinIntTrigger = 0; -void wakeUp() //place to send the interrupts -{ - pinIntTrigger = 1; -} -void wakeUp2() //place to send the second interrupts -{ - pinIntTrigger = 2; -} -void MySensor::internalSleep(unsigned long ms) { - while (!pinIntTrigger && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } - if (!pinIntTrigger && ms >= 4000) { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); ms -= 4000; } - if (!pinIntTrigger && ms >= 2000) { LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); ms -= 2000; } - if (!pinIntTrigger && ms >= 1000) { LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); ms -= 1000; } - if (!pinIntTrigger && ms >= 500) { LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); ms -= 500; } - if (!pinIntTrigger && ms >= 250) { LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); ms -= 250; } - if (!pinIntTrigger && ms >= 125) { LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF); ms -= 120; } - if (!pinIntTrigger && ms >= 64) { LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); ms -= 60; } - if (!pinIntTrigger && ms >= 32) { LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF); ms -= 30; } - if (!pinIntTrigger && ms >= 16) { LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); ms -= 15; } -} - -void MySensor::sleep(unsigned long ms) { - // Let serial prints finish (debug, log etc) - Serial.flush(); - radio.powerDown(); - pinIntTrigger = 0; - internalSleep(ms); -} void MySensor::wait(unsigned long ms) { - // Let serial prints finish (debug, log etc) - Serial.flush(); - unsigned long enter = millis(); - while (millis() - enter < ms) { - // reset watchdog - wdt_reset(); + unsigned long enter = hw.millisec(); + while (hw.millisec() - enter < ms) { process(); } } -bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - // Let serial prints finish (debug, log etc) - bool pinTriggeredWakeup = true; - Serial.flush(); +void MySensor::sleep(unsigned long ms) { radio.powerDown(); - attachInterrupt(interrupt, wakeUp, mode); - if (ms>0) { - pinIntTrigger = 0; - sleep(ms); - if (0 == pinIntTrigger) { - pinTriggeredWakeup = false; - } - } else { - Serial.flush(); - LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); - } - detachInterrupt(interrupt); - return pinTriggeredWakeup; + hw.sleep(ms); +} + +bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { + radio.powerDown(); + return hw.sleep(interrupt, mode, ms) ; } int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - int8_t retVal = 1; - Serial.flush(); // Let serial prints finish (debug, log etc) radio.powerDown(); - attachInterrupt(interrupt1, wakeUp, mode1); - attachInterrupt(interrupt2, wakeUp2, mode2); - if (ms>0) { - pinIntTrigger = 0; - sleep(ms); - if (0 == pinIntTrigger) { - retVal = -1; - } - } else { - Serial.flush(); - LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); - } - detachInterrupt(interrupt1); - detachInterrupt(interrupt2); - - if (1 == pinIntTrigger) { - retVal = (int8_t)interrupt1; - } else if (2 == pinIntTrigger) { - retVal = (int8_t)interrupt2; - } - return retVal; + return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ; } bool MySensor::sign(MyMessage &message) { @@ -615,9 +553,9 @@ bool MySensor::sign(MyMessage &message) { } else { // We have to wait for the nonce to arrive before we can sign our original message // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = millis(); + unsigned long enter = hw.millisec(); msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (millis() - enter < 5000) { + while (hw.millisec() - enter < 5000) { if (process()) { if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { // Proceed with signing if nonce has been received @@ -633,37 +571,3 @@ bool MySensor::sign(MyMessage &message) { return false; } -#ifdef DEBUG -void MySensor::debugPrint(const char *fmt, ... ) { - char fmtBuffer[300]; - if (isGateway) { - // prepend debug message to be handled correctly by gw (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); - Serial.print(fmtBuffer); - } - va_list args; - va_start (args, fmt ); - va_end (args); - if (isGateway) { - // Truncate message if this is gateway node - vsnprintf_P(fmtBuffer, 60, fmt, args); - fmtBuffer[59] = '\n'; - fmtBuffer[60] = '\0'; - } else { - vsnprintf_P(fmtBuffer, 299, fmt, args); - } - va_end (args); - Serial.print(fmtBuffer); - Serial.flush(); - - //Serial.write(freeRam()); -} -#endif - -#ifdef DEBUG -int MySensor::freeRam (void) { - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); -} -#endif diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index f9d75bb..5ccac1a 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -13,6 +13,8 @@ #define MySensor_h #include "Version.h" // Auto generated by bot +#include "MyHw.h" +#include "MyHwATMega328.h" #include "MyTransport.h" #include "MyTransportNRF24.h" #include "MyParser.h" @@ -21,24 +23,15 @@ #include "MyConfig.h" #include "MyMessage.h" #include -#include -#include -#include #include -#ifdef __cplusplus -#include -#include -#include "utility/LowPower.h" -#endif #ifdef DEBUG -#define debug(x,...) debugPrint(x, ##__VA_ARGS__) +#define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__) #else #define debug(x,...) #endif -#define BAUD_RATE 115200 // EEPROM start address for mysensors library data #define EEPROM_START 0 @@ -81,7 +74,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone()); + MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone(), MyHw &hw=*new MyHwATMega328()); /** * Begin operation of the MySensors library @@ -173,7 +166,7 @@ class MySensor * power cycles. * * You have 256 bytes to play with. Note that there is a limitation on the number - * of writes the EEPROM can handle (~100 000 cycles). + * of writes the EEPROM can handle (~100 000 cycles on ATMega328). * * @param pos The position to store value in (0-255) * @param Value to store in position @@ -193,11 +186,7 @@ class MySensor */ MyMessage& getLastMessage(void); - /** - * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer. - * @param ms Number of milliseconds to sleep. - */ - void sleep(unsigned long ms); + /** * Wait for a specified amount of time to pass. Keeps process()ing. @@ -209,7 +198,13 @@ class MySensor void wait(unsigned long ms); /** - * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer or pin change. + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. + * @param ms Number of milliseconds to sleep. + */ + void sleep(unsigned long ms); + + /** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 * @param interrupt Interrupt that should trigger the wakeup @@ -220,7 +215,7 @@ class MySensor bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); /** - * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer or pin change for two separate interrupts. + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 * @param interrupt1 First interrupt that should trigger the wakeup @@ -232,10 +227,6 @@ class MySensor */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); -#ifdef DEBUG - void debugPrint(const char *fmt, ... ); - int freeRam(); -#endif protected: NodeConfig nc; // Essential settings for node to work @@ -251,6 +242,7 @@ class MySensor MyTransport& radio; MySigning& signer; + MyHw& hw; void setupRepeaterMode(); boolean sendWrite(uint8_t dest, MyMessage &message); diff --git a/libraries/MySensors/MyTransport.h b/libraries/MySensors/MyTransport.h index 5c7b728..08ba0c6 100644 --- a/libraries/MySensors/MyTransport.h +++ b/libraries/MySensors/MyTransport.h @@ -17,7 +17,7 @@ #define BROADCAST_ADDRESS ((uint8_t)0xFF) class MyTransport -{ +{ public: // MyTransport constructor // different parameters would be needed depending on radio module (e.g. pins connected etc.) diff --git a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino index 407d92d..ddbaaba 100644 --- a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino +++ b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino @@ -6,12 +6,16 @@ #include #include +#include void setup() { + Serial.begin(BAUD_RATE); + Serial.println("Started clearing. Please wait..."); for (int i=0;i<512;i++) { EEPROM.write(i, 0xff); } + Serial.println("Clering done. You're ready to go!"); } void loop() diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 3f0e94f..2bb49ab 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -1,6 +1,9 @@ // Example sketch showing how to control physical relays. // This example will remember relay state even after power failure. +#include +#include +#include #include #include @@ -9,7 +12,14 @@ #define RELAY_ON 1 // GPIO value to write to turn on attached relay #define RELAY_OFF 0 // GPIO value to write to turn off attached relay -MySensor gw; +// NRFRF24L01 radio driver (set low transmit power by default) +MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +// Message signing driver (none default) +MySigningNone signer; +// Select AtMega328 hardware profile +MyHwATMega328 hw; +// Construct MySensors library +MySensor gw(radio, signer, hw); void setup() { From c5760f72c61db703b225a92422bc46a0b39b5ebf Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 12 Mar 2015 23:58:38 +0100 Subject: [PATCH 071/660] Remove EEPROM buffer for routing information --- libraries/MySensors/MySensor.cpp | 33 +++++--------------------------- libraries/MySensors/MySensor.h | 6 ------ 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index bb69787..32645a3 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -37,6 +37,7 @@ static inline bool isValidDistance( const uint8_t distance ) { return distance != DISTANCE_INVALID; } + MySensor::MySensor(MyTransport &_radio, MySigning &_signer, MyHw &_hw) : radio(_radio), @@ -55,10 +56,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b // Only gateway should use node id 0 isGateway = _nodeId == 0; - if (repeaterMode) { - setupRepeaterMode(); - } - // Setup radio radio.init(); @@ -108,10 +105,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), isGateway?"gateway":(repeaterMode?"repeater":"sensor"), nc.nodeId, nc.parentNodeId, nc.distance); } -void MySensor::setupRepeaterMode(){ -// childNodeTable = new uint8_t[256]; - hw.readConfigBlock((void*)childNodeTable, (void *)EEPROM_ROUTES_ADDRESS, 256); -} uint8_t MySensor::getNodeId() { return nc.nodeId; @@ -213,7 +206,7 @@ boolean MySensor::sendRoute(MyMessage &message) { ok = sendWrite(nc.parentNodeId, message); } else { // Relay the message - uint8_t route = getChildRoute(dest); + uint8_t route = hw.readConfigByte(EEPROM_ROUTES_ADDRESS+dest); if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { // This message should be forwarded to a child node. If we send message // to this nodes pipe then all children will receive it because the are @@ -251,7 +244,7 @@ boolean MySensor::sendRoute(MyMessage &message) { // This message should be routed back towards sensor net gateway ok = sendWrite(nc.parentNodeId, message); // Add this child to our "routing table" if it not already exist - addChildRoute(sender, last); + hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+sender, last); } } @@ -364,7 +357,7 @@ boolean MySensor::process() { if (repeaterMode && last != nc.parentNodeId) { // Message is from one of the child nodes. Add it to routing table. - addChildRoute(sender, last); + hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+sender, last); } // Check if sender requests an ack back. @@ -458,7 +451,7 @@ boolean MySensor::process() { debug(PSTR("clear\n")); uint8_t i = 255; do { - removeChildRoute(i); + hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+i, 0xff); } while (i--); // Clear parent node id & distance to gw hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); @@ -509,22 +502,6 @@ uint8_t MySensor::loadState(uint8_t pos) { return hw.readConfigByte(EEPROM_LOCAL_CONFIG_ADDRESS+pos); } -void MySensor::addChildRoute(uint8_t childId, uint8_t route) { - childNodeTable[childId] = route; - hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+childId, route); -} - -void MySensor::removeChildRoute(uint8_t childId) { - childNodeTable[childId] = 0xff; - hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+childId, 0xff); -} - -uint8_t MySensor::getChildRoute(uint8_t childId) { - return childNodeTable[childId]; -} - - - void MySensor::wait(unsigned long ms) { unsigned long enter = hw.millisec(); while (hw.millisec() - enter < ms) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 5ccac1a..a58d93a 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -244,7 +244,6 @@ class MySensor MySigning& signer; MyHw& hw; - void setupRepeaterMode(); boolean sendWrite(uint8_t dest, MyMessage &message); private: @@ -252,7 +251,6 @@ class MySensor char convBuf[MAX_PAYLOAD*2+1]; #endif uint8_t failedTransmissions; - uint8_t childNodeTable[256]; // In memory buffer for routing information to other nodes. also stored in EEPROM void (*timeCallback)(unsigned long); // Callback for requested time messages void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. @@ -260,10 +258,6 @@ class MySensor void setupNode(); void findParentNode(); uint8_t crc8Message(MyMessage &message); - uint8_t getChildRoute(uint8_t childId); - void addChildRoute(uint8_t childId, uint8_t route); - void removeChildRoute(uint8_t childId); - void internalSleep(unsigned long ms); bool sign(MyMessage &message); }; #endif From c1d5513578a809a2a2d8e68471964190d4d81073 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 12 Mar 2015 23:59:36 +0100 Subject: [PATCH 072/660] Remove LowPower dependency --- libraries/MySensors/MyHwATMega328.cpp | 70 +- libraries/MySensors/MyHwATMega328.h | 18 +- libraries/MySensors/utility/LowPower.cpp | 856 ----------------------- libraries/MySensors/utility/LowPower.h | 137 ---- 4 files changed, 73 insertions(+), 1008 deletions(-) delete mode 100644 libraries/MySensors/utility/LowPower.cpp delete mode 100644 libraries/MySensors/utility/LowPower.h diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index 3f42fc9..e5710cc 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -34,26 +34,69 @@ unsigned long MyHwATMega328::millisec() { } + +#define bodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +#if defined __AVR_ATmega328P__ +#define bodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +void powerDown(period_t period) { + + ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + #if defined __AVR_ATmega328P__ + bodOff(SLEEP_MODE_PWR_DOWN); + #else + bodOn(SLEEP_MODE_PWR_DOWN); + #endif + + ADCSRA |= (1 << ADEN); +} + void MyHwATMega328::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); pinIntTrigger = 0; - while (!pinIntTrigger && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } - if (!pinIntTrigger && ms >= 4000) { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); ms -= 4000; } - if (!pinIntTrigger && ms >= 2000) { LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); ms -= 2000; } - if (!pinIntTrigger && ms >= 1000) { LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); ms -= 1000; } - if (!pinIntTrigger && ms >= 500) { LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); ms -= 500; } - if (!pinIntTrigger && ms >= 250) { LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); ms -= 250; } - if (!pinIntTrigger && ms >= 125) { LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF); ms -= 120; } - if (!pinIntTrigger && ms >= 64) { LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); ms -= 60; } - if (!pinIntTrigger && ms >= 32) { LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF); ms -= 30; } - if (!pinIntTrigger && ms >= 16) { LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); ms -= 15; } + while (!pinIntTrigger && ms >= 8000) { powerDown(SLEEP_8S); ms -= 8000; } + if (!pinIntTrigger && ms >= 4000) { powerDown(SLEEP_4S); ms -= 4000; } + if (!pinIntTrigger && ms >= 2000) { powerDown(SLEEP_2S); ms -= 2000; } + if (!pinIntTrigger && ms >= 1000) { powerDown(SLEEP_1S); ms -= 1000; } + if (!pinIntTrigger && ms >= 500) { powerDown(SLEEP_500MS); ms -= 500; } + if (!pinIntTrigger && ms >= 250) { powerDown(SLEEP_250MS); ms -= 250; } + if (!pinIntTrigger && ms >= 125) { powerDown(SLEEP_120MS); ms -= 120; } + if (!pinIntTrigger && ms >= 64) { powerDown(SLEEP_60MS); ms -= 60; } + if (!pinIntTrigger && ms >= 32) { powerDown(SLEEP_30MS); ms -= 30; } + if (!pinIntTrigger && ms >= 16) { powerDown(SLEEP_15Ms); ms -= 15; } } bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; - Serial.flush(); attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; @@ -63,7 +106,7 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { } } else { Serial.flush(); - LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + powerDown(SLEEP_FOREVER); } detachInterrupt(interrupt); return pinTriggeredWakeup; @@ -71,7 +114,6 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; - Serial.flush(); // Let serial prints finish (debug, log etc) attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { @@ -82,7 +124,7 @@ uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrup } } else { Serial.flush(); - LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + powerDown(SLEEP_FOREVER); } detachInterrupt(interrupt1); detachInterrupt(interrupt2); diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 90e6e82..bd197c7 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -5,8 +5,10 @@ #include "MyMessage.h" #include #include +#include +#include +#include #include -#include "utility/LowPower.h" #include "MyHw.h" @@ -15,6 +17,20 @@ #include #endif +enum period_t +{ + SLEEP_15Ms, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; class MyHwATMega328 : public MyHw { diff --git a/libraries/MySensors/utility/LowPower.cpp b/libraries/MySensors/utility/LowPower.cpp deleted file mode 100644 index a72cc31..0000000 --- a/libraries/MySensors/utility/LowPower.cpp +++ /dev/null @@ -1,856 +0,0 @@ -/******************************************************************************* -* LowPower Library -* Version: 1.30 -* Date: 22-05-2013 -* Company: Rocket Scream Electronics -* Website: www.rocketscream.com -* -* This is a lightweight low power library for Arduino. Please check our wiki -* (www.rocketscream.com/wiki) for more information on using this piece of -* library. -* -* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 -* Unported License. -* -* Revision Description -* ======== =========== -* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. -* Tested to work with Arduino IDE 1.0.1 - 1.0.4. -* 1.20 Remove typo error in idle method for checking whether Timer 0 was -* turned off. -* Remove dependecy on WProgram.h which is not required. -* Tested to work with Arduino IDE 1.0. -* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future -* Arduino IDE release. -* 1.00 Initial public release. -*******************************************************************************/ -#include -#include -#include -#include -#include "LowPower.h" - -// Only Pico Power devices can change BOD settings through software -#if defined __AVR_ATmega328P__ -#ifndef sleep_bod_disable -#define sleep_bod_disable() \ -do { \ - unsigned char tempreg; \ - __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ - "ori %[tempreg], %[bods_bodse]" "\n\t" \ - "out %[mcucr], %[tempreg]" "\n\t" \ - "andi %[tempreg], %[not_bodse]" "\n\t" \ - "out %[mcucr], %[tempreg]" \ - : [tempreg] "=&d" (tempreg) \ - : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ - [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ - [not_bodse] "i" (~_BV(BODSE))); \ -} while (0) -#endif -#endif - -#define lowPowerBodOn(mode) \ -do { \ - set_sleep_mode(mode); \ - cli(); \ - sleep_enable(); \ - sei(); \ - sleep_cpu(); \ - sleep_disable(); \ - sei(); \ -} while (0); - -// Only Pico Power devices can change BOD settings through software -#if defined __AVR_ATmega328P__ -#define lowPowerBodOff(mode)\ -do { \ - set_sleep_mode(mode); \ - cli(); \ - sleep_enable(); \ - sleep_bod_disable(); \ - sei(); \ - sleep_cpu(); \ - sleep_disable(); \ - sei(); \ -} while (0); -#endif - -// Some macros is still missing from AVR GCC distribution for ATmega32U4 -#if defined __AVR_ATmega32U4__ - // Timer 4 PRR bit is currently not defined in iom32u4.h - #ifndef PRTIM4 - #define PRTIM4 4 - #endif - - // Timer 4 power reduction macro is not defined currently in power.h - #ifndef power_timer4_disable - #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) - #endif - - #ifndef power_timer4_enable - #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) - #endif -#endif - -/******************************************************************************* -* Name: idle -* Description: Putting ATmega328P/168 into idle state. Please make sure you -* understand the implication and result of disabling module. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control: -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. timer2 Timer 2 module disable control: -* (a) TIMER2_OFF - Turn off Timer 2 module -* (b) TIMER2_ON - Leave Timer 2 module in its default state -* -* 4. timer1 Timer 1 module disable control: -* (a) TIMER1_OFF - Turn off Timer 1 module -* (b) TIMER1_ON - Leave Timer 1 module in its default state -* -* 5. timer0 Timer 0 module disable control: -* (a) TIMER0_OFF - Turn off Timer 0 module -* (b) TIMER0_ON - Leave Timer 0 module in its default state -* -* 6. spi SPI module disable control: -* (a) SPI_OFF - Turn off SPI module -* (b) SPI_ON - Leave SPI module in its default state -* -* 7. usart0 USART0 module disable control: -* (a) USART0_OFF - Turn off USART0 module -* (b) USART0_ON - Leave USART0 module in its default state -* -* 8. twi TWI module disable control: -* (a) TWI_OFF - Turn off TWI module -* (b) TWI_ON - Leave TWI module in its default state -* -*******************************************************************************/ -#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) -void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, - timer1_t timer1, timer0_t timer0, - spi_t spi, usart0_t usart0, twi_t twi) -{ - // Temporary clock source variable - unsigned char clockSource = 0; - - if (timer2 == TIMER2_OFF) - { - if (TCCR2B & CS22) clockSource |= (1 << CS22); - if (TCCR2B & CS21) clockSource |= (1 << CS21); - if (TCCR2B & CS20) clockSource |= (1 << CS20); - - // Remove the clock source to shutdown Timer2 - TCCR2B &= ~(1 << CS22); - TCCR2B &= ~(1 << CS21); - TCCR2B &= ~(1 << CS20); - - power_timer2_disable(); - } - - if (adc == ADC_OFF) - { - ADCSRA &= ~(1 << ADEN); - power_adc_disable(); - } - - if (timer1 == TIMER1_OFF) power_timer1_disable(); - if (timer0 == TIMER0_OFF) power_timer0_disable(); - if (spi == SPI_OFF) power_spi_disable(); - if (usart0 == USART0_OFF) power_usart0_disable(); - if (twi == TWI_OFF) power_twi_disable(); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - lowPowerBodOn(SLEEP_MODE_IDLE); - - if (adc == ADC_OFF) - { - power_adc_enable(); - ADCSRA |= (1 << ADEN); - } - - if (timer2 == TIMER2_OFF) - { - if (clockSource & CS22) TCCR2B |= (1 << CS22); - if (clockSource & CS21) TCCR2B |= (1 << CS21); - if (clockSource & CS20) TCCR2B |= (1 << CS20); - - power_timer2_enable(); - } - - if (timer1 == TIMER1_OFF) power_timer1_enable(); - if (timer0 == TIMER0_OFF) power_timer0_enable(); - if (spi == SPI_OFF) power_spi_enable(); - if (usart0 == USART0_OFF) power_usart0_enable(); - if (twi == TWI_OFF) power_twi_enable(); -} -#endif - -/******************************************************************************* -* Name: idle -* Description: Putting ATmega32U4 into idle state. Please make sure you -* understand the implication and result of disabling module. -* Take note that Timer 2 is not available and USART0 -* is replaced with USART1 on ATmega32U4. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control: -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. timer4 Timer 4 module disable control: -* (a) TIMER4_OFF - Turn off Timer 4 module -* (b) TIMER4_ON - Leave Timer 4 module in its default state -* -* 4. timer3 Timer 3 module disable control: -* (a) TIMER3_OFF - Turn off Timer 3 module -* (b) TIMER3_ON - Leave Timer 3 module in its default state -* -* 5. timer1 Timer 1 module disable control: -* (a) TIMER1_OFF - Turn off Timer 1 module -* (b) TIMER1_ON - Leave Timer 1 module in its default state -* -* 6. timer0 Timer 0 module disable control: -* (a) TIMER0_OFF - Turn off Timer 0 module -* (b) TIMER0_ON - Leave Timer 0 module in its default state -* -* 7. spi SPI module disable control: -* (a) SPI_OFF - Turn off SPI module -* (b) SPI_ON - Leave SPI module in its default state -* -* 8. usart1 USART1 module disable control: -* (a) USART1_OFF - Turn off USART1 module -* (b) USART1_ON - Leave USART1 module in its default state -* -* 9. twi TWI module disable control: -* (a) TWI_OFF - Turn off TWI module -* (b) TWI_ON - Leave TWI module in its default state -* -* 10.usb USB module disable control: -* (a) USB_OFF - Turn off USB module -* (b) USB_ON - Leave USB module in its default state -*******************************************************************************/ -#if defined __AVR_ATmega32U4__ -void LowPowerClass::idle(period_t period, adc_t adc, - timer4_t timer4, timer3_t timer3, - timer1_t timer1, timer0_t timer0, - spi_t spi, usart1_t usart1, twi_t twi, usb_t usb) -{ - if (adc == ADC_OFF) - { - ADCSRA &= ~(1 << ADEN); - power_adc_disable(); - } - - if (timer4 == TIMER4_OFF) power_timer4_disable(); - if (timer3 == TIMER3_OFF) power_timer3_disable(); - if (timer1 == TIMER1_OFF) power_timer1_disable(); - if (timer0 == TIMER0_OFF) power_timer0_disable(); - if (spi == SPI_OFF) power_spi_disable(); - if (usart1 == USART1_OFF) power_usart1_disable(); - if (twi == TWI_OFF) power_twi_disable(); - if (usb == USB_OFF) power_usb_disable(); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - lowPowerBodOn(SLEEP_MODE_IDLE); - - if (adc == ADC_OFF) - { - power_adc_enable(); - ADCSRA |= (1 << ADEN); - } - - if (timer4 == TIMER4_OFF) power_timer4_enable(); - if (timer3 == TIMER3_OFF) power_timer3_enable(); - if (timer1 == TIMER1_OFF) power_timer1_enable(); - if (timer0 == TIMER0_OFF) power_timer0_enable(); - if (spi == SPI_OFF) power_spi_enable(); - if (usart1 == USART1_OFF) power_usart1_enable(); - if (twi == TWI_OFF) power_twi_enable(); - if (usb == USB_OFF) power_usb_enable(); -} -#endif - -/******************************************************************************* -* Name: idle -* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure -* you understand the implication and result of disabling module. -* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. -* Also take note that extra USART 3, 2, 1 compared to an -* ATmega328P/168. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control: -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. timer5 Timer 5 module disable control: -* (a) TIMER5_OFF - Turn off Timer 5 module -* (b) TIMER5_ON - Leave Timer 5 module in its default state -* -* 4. timer4 Timer 4 module disable control: -* (a) TIMER4_OFF - Turn off Timer 4 module -* (b) TIMER4_ON - Leave Timer 4 module in its default state -* -* 5. timer3 Timer 3 module disable control: -* (a) TIMER3_OFF - Turn off Timer 3 module -* (b) TIMER3_ON - Leave Timer 3 module in its default state -* -* 6. timer2 Timer 2 module disable control: -* (a) TIMER2_OFF - Turn off Timer 2 module -* (b) TIMER2_ON - Leave Timer 2 module in its default state -* -* 7. timer1 Timer 1 module disable control: -* (a) TIMER1_OFF - Turn off Timer 1 module -* (b) TIMER1_ON - Leave Timer 1 module in its default state -* -* 8. timer0 Timer 0 module disable control: -* (a) TIMER0_OFF - Turn off Timer 0 module -* (b) TIMER0_ON - Leave Timer 0 module in its default state -* -* 9. spi SPI module disable control: -* (a) SPI_OFF - Turn off SPI module -* (b) SPI_ON - Leave SPI module in its default state -* -* 10.usart3 USART3 module disable control: -* (a) USART3_OFF - Turn off USART3 module -* (b) USART3_ON - Leave USART3 module in its default state -* -* 11.usart2 USART2 module disable control: -* (a) USART2_OFF - Turn off USART2 module -* (b) USART2_ON - Leave USART2 module in its default state -* -* 12.usart1 USART1 module disable control: -* (a) USART1_OFF - Turn off USART1 module -* (b) USART1_ON - Leave USART1 module in its default state -* -* 13.usart0 USART0 module disable control: -* (a) USART0_OFF - Turn off USART0 module -* (b) USART0_ON - Leave USART0 module in its default state -* -* 14.twi TWI module disable control: -* (a) TWI_OFF - Turn off TWI module -* (b) TWI_ON - Leave TWI module in its default state -* -*******************************************************************************/ -#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) -void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, - timer4_t timer4, timer3_t timer3, timer2_t timer2, - timer1_t timer1, timer0_t timer0, spi_t spi, - usart3_t usart3, usart2_t usart2, usart1_t usart1, - usart0_t usart0, twi_t twi) -{ - // Temporary clock source variable - unsigned char clockSource = 0; - - if (timer2 == TIMER2_OFF) - { - if (TCCR2B & CS22) clockSource |= (1 << CS22); - if (TCCR2B & CS21) clockSource |= (1 << CS21); - if (TCCR2B & CS20) clockSource |= (1 << CS20); - - // Remove the clock source to shutdown Timer2 - TCCR2B &= ~(1 << CS22); - TCCR2B &= ~(1 << CS21); - TCCR2B &= ~(1 << CS20); - - power_timer2_disable(); - } - - if (adc == ADC_OFF) - { - ADCSRA &= ~(1 << ADEN); - power_adc_disable(); - } - - if (timer5 == TIMER5_OFF) power_timer5_disable(); - if (timer4 == TIMER4_OFF) power_timer4_disable(); - if (timer3 == TIMER3_OFF) power_timer3_disable(); - if (timer1 == TIMER1_OFF) power_timer1_disable(); - if (timer0 == TIMER0_OFF) power_timer0_disable(); - if (spi == SPI_OFF) power_spi_disable(); - if (usart3 == USART3_OFF) power_usart3_disable(); - if (usart2 == USART2_OFF) power_usart2_disable(); - if (usart1 == USART1_OFF) power_usart1_disable(); - if (usart0 == USART0_OFF) power_usart0_disable(); - if (twi == TWI_OFF) power_twi_disable(); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - lowPowerBodOn(SLEEP_MODE_IDLE); - - if (adc == ADC_OFF) - { - power_adc_enable(); - ADCSRA |= (1 << ADEN); - } - - if (timer2 == TIMER2_OFF) - { - if (clockSource & CS22) TCCR2B |= (1 << CS22); - if (clockSource & CS21) TCCR2B |= (1 << CS21); - if (clockSource & CS20) TCCR2B |= (1 << CS20); - - power_timer2_enable(); - } - - if (timer5 == TIMER5_OFF) power_timer5_enable(); - if (timer4 == TIMER4_OFF) power_timer4_enable(); - if (timer3 == TIMER3_OFF) power_timer3_enable(); - if (timer1 == TIMER1_OFF) power_timer1_enable(); - if (timer0 == TIMER0_OFF) power_timer0_enable(); - if (spi == SPI_OFF) power_spi_enable(); - if (usart3 == USART3_OFF) power_usart3_enable(); - if (usart2 == USART2_OFF) power_usart2_enable(); - if (usart1 == USART1_OFF) power_usart1_enable(); - if (usart0 == USART0_OFF) power_usart0_enable(); - if (twi == TWI_OFF) power_twi_enable(); -} -#endif - -/******************************************************************************* -* Name: adcNoiseReduction -* Description: Putting microcontroller into ADC noise reduction state. This is -* a very useful state when using the ADC to achieve best and low -* noise signal. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control. Turning off the ADC module is -* basically removing the purpose of this low power mode. -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. timer2 Timer 2 module disable control: -* (a) TIMER2_OFF - Turn off Timer 2 module -* (b) TIMER2_ON - Leave Timer 2 module in its default state -* -*******************************************************************************/ -void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, - timer2_t timer2) -{ - // Temporary clock source variable - unsigned char clockSource = 0; - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (TCCR2B & CS22) clockSource |= (1 << CS22); - if (TCCR2B & CS21) clockSource |= (1 << CS21); - if (TCCR2B & CS20) clockSource |= (1 << CS20); - - // Remove the clock source to shutdown Timer2 - TCCR2B &= ~(1 << CS22); - TCCR2B &= ~(1 << CS21); - TCCR2B &= ~(1 << CS20); - } - #endif - - if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - lowPowerBodOn(SLEEP_MODE_ADC); - - if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (clockSource & CS22) TCCR2B |= (1 << CS22); - if (clockSource & CS21) TCCR2B |= (1 << CS21); - if (clockSource & CS20) TCCR2B |= (1 << CS20); - - } - #endif -} - -/******************************************************************************* -* Name: powerDown -* Description: Putting microcontroller into power down state. This is -* the lowest current consumption state. Use this together with -* external pin interrupt to wake up through external event -* triggering (example: RTC clockout pin, SD card detect pin). -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control. Turning off the ADC module is -* basically removing the purpose of this low power mode. -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. bod Brown Out Detector (BOD) module disable control: -* (a) BOD_OFF - Turn off BOD module -* (b) BOD_ON - Leave BOD module in its default state -* -*******************************************************************************/ -void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod) -{ - if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - if (bod == BOD_OFF) - { - #if defined __AVR_ATmega328P__ - lowPowerBodOff(SLEEP_MODE_PWR_DOWN); - #else - lowPowerBodOn(SLEEP_MODE_PWR_DOWN); - #endif - } - else - { - lowPowerBodOn(SLEEP_MODE_PWR_DOWN); - } - - if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); -} - -/******************************************************************************* -* Name: powerSave -* Description: Putting microcontroller into power save state. This is -* the lowest current consumption state after power down. -* Use this state together with an external 32.768 kHz crystal (but -* 8/16 MHz crystal/resonator need to be removed) to provide an -* asynchronous clock source to Timer 2. Please take note that -* Timer 2 is also used by the Arduino core for PWM operation. -* Please refer to wiring.c for explanation. Removal of the external -* 8/16 MHz crystal/resonator requires the microcontroller to run -* on its internal RC oscillator which is not so accurate for time -* critical operation. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control. Turning off the ADC module is -* basically removing the purpose of this low power mode. -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. bod Brown Out Detector (BOD) module disable control: -* (a) BOD_OFF - Turn off BOD module -* (b) BOD_ON - Leave BOD module in its default state -* -* 4. timer2 Timer 2 module disable control: -* (a) TIMER2_OFF - Turn off Timer 2 module -* (b) TIMER2_ON - Leave Timer 2 module in its default state -* -*******************************************************************************/ -void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, - timer2_t timer2) -{ - // Temporary clock source variable - unsigned char clockSource = 0; - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (TCCR2B & CS22) clockSource |= (1 << CS22); - if (TCCR2B & CS21) clockSource |= (1 << CS21); - if (TCCR2B & CS20) clockSource |= (1 << CS20); - - // Remove the clock source to shutdown Timer2 - TCCR2B &= ~(1 << CS22); - TCCR2B &= ~(1 << CS21); - TCCR2B &= ~(1 << CS20); - } - #endif - - if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - if (bod == BOD_OFF) - { - #if defined __AVR_ATmega328P__ - lowPowerBodOff(SLEEP_MODE_PWR_SAVE); - #else - lowPowerBodOn(SLEEP_MODE_PWR_SAVE); - #endif - } - else - { - lowPowerBodOn(SLEEP_MODE_PWR_SAVE); - } - - if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (clockSource & CS22) TCCR2B |= (1 << CS22); - if (clockSource & CS21) TCCR2B |= (1 << CS21); - if (clockSource & CS20) TCCR2B |= (1 << CS20); - } - #endif -} - -/******************************************************************************* -* Name: powerStandby -* Description: Putting microcontroller into power standby state. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control. Turning off the ADC module is -* basically removing the purpose of this low power mode. -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. bod Brown Out Detector (BOD) module disable control: -* (a) BOD_OFF - Turn off BOD module -* (b) BOD_ON - Leave BOD module in its default state -* -*******************************************************************************/ -void LowPowerClass::powerStandby(period_t period, adc_t adc, bod_t bod) -{ - if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - - if (bod == BOD_OFF) - { - #if defined __AVR_ATmega328P__ - lowPowerBodOff(SLEEP_MODE_STANDBY); - #else - lowPowerBodOn(SLEEP_MODE_STANDBY); - #endif - } - else - { - lowPowerBodOn(SLEEP_MODE_STANDBY); - } - - if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); -} - -/******************************************************************************* -* Name: powerExtStandby -* Description: Putting microcontroller into power extended standby state. This -* is different from the power standby state as it has the -* capability to run Timer 2 asynchronously. -* -* Argument Description -* ========= =========== -* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake -* up resource: -* (a) SLEEP_15MS - 15 ms sleep -* (b) SLEEP_30MS - 30 ms sleep -* (c) SLEEP_60MS - 60 ms sleep -* (d) SLEEP_120MS - 120 ms sleep -* (e) SLEEP_250MS - 250 ms sleep -* (f) SLEEP_500MS - 500 ms sleep -* (g) SLEEP_1S - 1 s sleep -* (h) SLEEP_2S - 2 s sleep -* (i) SLEEP_4S - 4 s sleep -* (j) SLEEP_8S - 8 s sleep -* (k) SLEEP_FOREVER - Sleep without waking up through WDT -* -* 2. adc ADC module disable control. -* (a) ADC_OFF - Turn off ADC module -* (b) ADC_ON - Leave ADC module in its default state -* -* 3. bod Brown Out Detector (BOD) module disable control: -* (a) BOD_OFF - Turn off BOD module -* (b) BOD_ON - Leave BOD module in its default state -* -* 4. timer2 Timer 2 module disable control: -* (a) TIMER2_OFF - Turn off Timer 2 module -* (b) TIMER2_ON - Leave Timer 2 module in its default state -* -*******************************************************************************/ -void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, - timer2_t timer2) -{ - // Temporary clock source variable - unsigned char clockSource = 0; - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (TCCR2B & CS22) clockSource |= (1 << CS22); - if (TCCR2B & CS21) clockSource |= (1 << CS21); - if (TCCR2B & CS20) clockSource |= (1 << CS20); - - // Remove the clock source to shutdown Timer2 - TCCR2B &= ~(1 << CS22); - TCCR2B &= ~(1 << CS21); - TCCR2B &= ~(1 << CS20); - } - #endif - - if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); - - if (period != SLEEP_FOREVER) - { - wdt_enable(period); - WDTCSR |= (1 << WDIE); - } - if (bod == BOD_OFF) - { - #if defined __AVR_ATmega328P__ - lowPowerBodOff(SLEEP_MODE_EXT_STANDBY); - #else - lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); - #endif - } - else - { - lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); - } - - if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); - - #if !defined(__AVR_ATmega32U4__) - if (timer2 == TIMER2_OFF) - { - if (clockSource & CS22) TCCR2B |= (1 << CS22); - if (clockSource & CS21) TCCR2B |= (1 << CS21); - if (clockSource & CS20) TCCR2B |= (1 << CS20); - } - #endif -} - -/******************************************************************************* -* Name: ISR (WDT_vect) -* Description: Watchdog Timer interrupt service routine. This routine is -* required to allow automatic WDIF and WDIE bit clearance in -* hardware. -* -*******************************************************************************/ -ISR (WDT_vect) -{ - // WDIE & WDIF is cleared in hardware upon entering this ISR - wdt_disable(); -} - -LowPowerClass LowPower; \ No newline at end of file diff --git a/libraries/MySensors/utility/LowPower.h b/libraries/MySensors/utility/LowPower.h deleted file mode 100644 index ef05901..0000000 --- a/libraries/MySensors/utility/LowPower.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef LowPower_h -#define LowPower_h - -enum period_t -{ - SLEEP_15Ms, - SLEEP_30MS, - SLEEP_60MS, - SLEEP_120MS, - SLEEP_250MS, - SLEEP_500MS, - SLEEP_1S, - SLEEP_2S, - SLEEP_4S, - SLEEP_8S, - SLEEP_FOREVER -}; - -enum bod_t -{ - BOD_OFF, - BOD_ON -}; - -enum adc_t -{ - ADC_OFF, - ADC_ON -}; - -enum timer5_t -{ - TIMER5_OFF, - TIMER5_ON -}; - -enum timer4_t -{ - TIMER4_OFF, - TIMER4_ON -}; - -enum timer3_t -{ - TIMER3_OFF, - TIMER3_ON -}; - -enum timer2_t -{ - TIMER2_OFF, - TIMER2_ON -}; - -enum timer1_t -{ - TIMER1_OFF, - TIMER1_ON -}; - -enum timer0_t -{ - TIMER0_OFF, - TIMER0_ON -}; - -enum spi_t -{ - SPI_OFF, - SPI_ON -}; - -enum usart0_t -{ - USART0_OFF, - USART0_ON -}; - -enum usart1_t -{ - USART1_OFF, - USART1_ON -}; - -enum usart2_t -{ - USART2_OFF, - USART2_ON -}; - -enum usart3_t -{ - USART3_OFF, - USART3_ON -}; - -enum twi_t -{ - TWI_OFF, - TWI_ON -}; - -enum usb_t -{ - USB_OFF, - USB_ON -}; - -class LowPowerClass -{ - public: - #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) - void idle(period_t period, adc_t adc, timer2_t timer2, - timer1_t timer1, timer0_t timer0, spi_t spi, - usart0_t usart0, twi_t twi); - #elif defined __AVR_ATmega2560__ - void idle(period_t period, adc_t adc, timer5_t timer5, - timer4_t timer4, timer3_t timer3, timer2_t timer2, - timer1_t timer1, timer0_t timer0, spi_t spi, - usart3_t usart3, usart2_t usart2, usart1_t usart1, - usart0_t usart0, twi_t twi); - #elif defined __AVR_ATmega32U4__ - void idle(period_t period, adc_t adc, timer4_t timer4, timer3_t timer3, - timer1_t timer1, timer0_t timer0, spi_t spi, - usart1_t usart1, twi_t twi, usb_t usb); - #else - #error "Please ensure chosen MCU is either 328P, 32U4 or 2560." - #endif - void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2); - void powerDown(period_t period, adc_t adc, bod_t bod); - void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2); - void powerStandby(period_t period, adc_t adc, bod_t bod); - void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2); -}; - -extern LowPowerClass LowPower; -#endif \ No newline at end of file From d88e9175440627bd30a48456a393f979bad77ae9 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 13 Mar 2015 15:39:05 +0100 Subject: [PATCH 073/660] Simplify thinga a bit --- libraries/MySensors/MyHwATMega328.cpp | 67 ++++++++++++--------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index e5710cc..7b03cd7 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -16,50 +16,24 @@ MyHwATMega328::MyHwATMega328() : MyHw() } -void MyHwATMega328::init() { +inline void MyHwATMega328::init() { Serial.begin(BAUD_RATE); } -void MyHwATMega328::watchdogReset() { +inline void MyHwATMega328::watchdogReset() { wdt_reset(); } -void MyHwATMega328::reboot() { +inline void MyHwATMega328::reboot() { wdt_enable(WDTO_15MS); for (;;); } -unsigned long MyHwATMega328::millisec() { +inline unsigned long MyHwATMega328::millisec() { return millis(); } - -#define bodOn(mode) \ -do { \ - set_sleep_mode(mode); \ - cli(); \ - sleep_enable(); \ - sei(); \ - sleep_cpu(); \ - sleep_disable(); \ - sei(); \ -} while (0); - -#if defined __AVR_ATmega328P__ -#define bodOff(mode)\ -do { \ - set_sleep_mode(mode); \ - cli(); \ - sleep_enable(); \ - sleep_bod_disable(); \ - sei(); \ - sleep_cpu(); \ - sleep_disable(); \ - sei(); \ -} while (0); -#endif - void powerDown(period_t period) { ADCSRA &= ~(1 << ADEN); @@ -70,15 +44,32 @@ void powerDown(period_t period) { WDTCSR |= (1 << WDIE); } #if defined __AVR_ATmega328P__ - bodOff(SLEEP_MODE_PWR_DOWN); + do { + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + cli(); + sleep_enable(); + sleep_bod_disable(); + sei(); + sleep_cpu(); + sleep_disable(); + sei(); + } while (0); #else - bodOn(SLEEP_MODE_PWR_DOWN); + do { + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + cli(); + sleep_enable(); + sei(); + sleep_cpu(); + sleep_disable(); + sei(); + } while (0); #endif ADCSRA |= (1 << ADEN); } -void MyHwATMega328::sleep(unsigned long ms) { +inline void MyHwATMega328::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); pinIntTrigger = 0; @@ -112,7 +103,7 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { return pinTriggeredWakeup; } -uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { +inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); @@ -137,19 +128,19 @@ uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrup return retVal; } -uint8_t MyHwATMega328::readConfigByte(uint8_t pos) { +inline uint8_t MyHwATMega328::readConfigByte(uint8_t pos) { return eeprom_read_byte((uint8_t*)pos); } -void MyHwATMega328::writeConfigByte(uint8_t pos, uint8_t value) { +inline void MyHwATMega328::writeConfigByte(uint8_t pos, uint8_t value) { eeprom_update_byte((uint8_t*)pos, value); } -void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { +inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { eeprom_read_block(buf, (void*)pos, length); } -void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { +inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { eeprom_write_block((void*)pos, (void*)buf, length); } From 5ae55e5b8a54abdc30986e7665677977848a99a6 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 13 Mar 2015 16:09:09 -0300 Subject: [PATCH 074/660] add DigitalIO.h to MQTTGateway --- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index bb1ea20..169ad89 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -56,9 +56,11 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ +#include +#include + #include #include -#include #include #include #include From 73024ea4c98ed45308c3708ffc0479029cf524b2 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 16 Mar 2015 10:43:09 +0100 Subject: [PATCH 075/660] Weird compile error for Patrick --- libraries/MySensors/MyConfig.h | 10 ++++-- libraries/MySensors/MyHw.h | 11 +++--- libraries/MySensors/MyHwATMega328.cpp | 44 +++++++++++++---------- libraries/MySensors/MyHwATMega328.h | 25 +++++++++---- libraries/MySensors/MySensor.cpp | 52 +++++++++++++-------------- libraries/MySensors/MySensor.h | 5 ++- 6 files changed, 85 insertions(+), 62 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 3e09981..0b4d806 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -1,13 +1,17 @@ #ifndef MyConfig_h #define MyConfig_h #include -/********************************** -* Enable/Disable debug logging -***********************************/ + +// Enable debug flag for debug prints. This will add a lot to the size of the final sketch but good +// to see what is actually is happening when developing #define DEBUG +// Serial output baud rate #define BAUD_RATE 115200 +// Set the hardware driver to use (initialized by MySensor-class) +#include "MyHwATMega328.h" +typedef MyHwATMega328 MyHwDriver; /********************************** * Message Signing Settings diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/MyHw.h index a7ce870..95cf2a4 100644 --- a/libraries/MySensors/MyHw.h +++ b/libraries/MySensors/MyHw.h @@ -15,17 +15,18 @@ class MyHw public: // MyHw constructor MyHw(); - virtual void init() = 0; +/* // The following is defined as macros to save space + virtual void init() = 0; virtual void watchdogReset() = 0; virtual void reboot() = 0; virtual unsigned long millisec() = 0; + virtual uint8_t readConfig(uint8_t pos) = 0; + virtual void writeConfig(uint8_t pos, uint8_t value) = 0; + virtual void readConfigBlock(void* buf, void * pos, size_t length) = 0; + virtual void writeConfigBlock(void* pos, void* buf, uint16_t length) = 0; */ virtual void sleep(unsigned long ms) = 0; virtual bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) = 0; virtual uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) = 0; - virtual uint8_t readConfigByte(uint8_t pos) = 0; - virtual void writeConfigByte(uint8_t pos, uint8_t value) = 0; - virtual void readConfigBlock(void* buf, void * pos, size_t length) = 0; - virtual void writeConfigBlock(void* pos, void* buf, uint16_t length) = 0; #ifdef DEBUG virtual void debugPrint(bool isGW, const char *fmt, ... ) = 0; #endif diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index 7b03cd7..4f9d9a8 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -16,6 +16,27 @@ MyHwATMega328::MyHwATMega328() : MyHw() } +/* + +// The following was redifined as macros to save space + +inline uint8_t MyHwATMega328::readConfig(uint8_t pos) { + return eeprom_read_byte((uint8_t*)pos); +} + +inline void MyHwATMega328::writeConfig(uint8_t pos, uint8_t value) { + eeprom_update_byte((uint8_t*)pos, value); +} + +inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { + eeprom_read_block(buf, (void*)pos, length); +} + +inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { + eeprom_write_block((void*)pos, (void*)buf, length); +} + + inline void MyHwATMega328::init() { Serial.begin(BAUD_RATE); } @@ -25,13 +46,13 @@ inline void MyHwATMega328::watchdogReset() { } inline void MyHwATMega328::reboot() { - wdt_enable(WDTO_15MS); - for (;;); + wdt_enable(WDTO_15MS); for (;;); } -inline unsigned long MyHwATMega328::millisec() { - return millis(); +inline unsigned long MyHwATMega328::millis() { + return ::millis(); } +*/ void powerDown(period_t period) { @@ -128,21 +149,6 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i return retVal; } -inline uint8_t MyHwATMega328::readConfigByte(uint8_t pos) { - return eeprom_read_byte((uint8_t*)pos); -} - -inline void MyHwATMega328::writeConfigByte(uint8_t pos, uint8_t value) { - eeprom_update_byte((uint8_t*)pos, value); -} - -inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { - eeprom_read_block(buf, (void*)pos, length); -} - -inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { - eeprom_write_block((void*)pos, (void*)buf, length); -} #ifdef DEBUG diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index bd197c7..618a789 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -17,6 +17,18 @@ #include #endif +// Define these as macros to save valuable space +#define hw_init() Serial.begin(BAUD_RATE) +#define hw_watchdogReset() wdt_reset() +#define hw_reboot() wdt_enable(WDTO_15MS); for (;;) +#define hw_millis() millis() +#define hw_readConfig(__pos) eeprom_read_byte((uint8_t*)__pos) +#define hw_writeConfig(__pos, __value) eeprom_update_byte((uint8_t*)__pos, __value) +#define hw_readConfigBlock(__buf, __pos, __length) eeprom_read_block(buf, (void*)__pos, __length) +#define hw_writeConfigBlock(__pos, __buf, __length) eeprom_write_block((void*)__pos, (void*)__buf, __length) + + + enum period_t { SLEEP_15Ms, @@ -37,17 +49,18 @@ class MyHwATMega328 : public MyHw public: MyHwATMega328(); - void init(); +/* void init(); void watchdogReset(); void reboot(); - unsigned long millisec(); + unsigned long millis(); + uint8_t readConfig(uint8_t pos); + void writeConfig(uint8_t pos, uint8_t value); + void readConfigBlock(void* buf, void * pos, size_t length); + void writeConfigBlock(void* pos, void* buf, size_t length); */ + void sleep(unsigned long ms); bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms); uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); - uint8_t readConfigByte(uint8_t pos); - void writeConfigByte(uint8_t pos, uint8_t value); - void readConfigBlock(void* buf, void * pos, size_t length); - void writeConfigBlock(void* pos, void* buf, size_t length); #ifdef DEBUG void debugPrint(bool isGW, const char *fmt, ... ); #endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 32645a3..c058e2e 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -48,7 +48,7 @@ MySensor::MySensor(MyTransport &_radio, MySigning &_signer, MyHw &_hw) void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { - hw.init(); + hw_init(); repeaterMode = _repeaterMode; msgCallback = _msgCallback; failedTransmissions = 0; @@ -60,11 +60,11 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b radio.init(); // Read settings from eeprom - hw.readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM - hw.readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); // Read out the signing requirements from EEPROM - hw.readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); + hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); if (isGateway) { nc.distance = 0; @@ -79,7 +79,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b if (!autoFindParent) { nc.parentNodeId = _parentNodeId; // Save static parent id in eeprom (used by bootloader) - hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); + hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); // We don't actually know the distance to gw here. Let's pretend it is 1. // If the current node is also repeater, be aware of this. nc.distance = 1; @@ -94,7 +94,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b nc.nodeId = _nodeId; // Save static id in eeprom if (_nodeId > 0) - hw.writeConfigByte(EEPROM_NODE_ID_ADDRESS, _nodeId); + hw_writeConfig(EEPROM_NODE_ID_ADDRESS, _nodeId); } else if (isValidParent(nc.parentNodeId)) { // Try to fetch node-id from gateway requestNodeId(); @@ -206,7 +206,7 @@ boolean MySensor::sendRoute(MyMessage &message) { ok = sendWrite(nc.parentNodeId, message); } else { // Relay the message - uint8_t route = hw.readConfigByte(EEPROM_ROUTES_ADDRESS+dest); + uint8_t route = hw_readConfig(EEPROM_ROUTES_ADDRESS+dest); if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { // This message should be forwarded to a child node. If we send message // to this nodes pipe then all children will receive it because the are @@ -244,7 +244,7 @@ boolean MySensor::sendRoute(MyMessage &message) { // This message should be routed back towards sensor net gateway ok = sendWrite(nc.parentNodeId, message); // Add this child to our "routing table" if it not already exist - hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+sender, last); + hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); } } @@ -308,7 +308,7 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { } boolean MySensor::process() { - hw.watchdogReset(); + hw_watchdogReset(); uint8_t to = 0; if (!radio.available(&to)) return false; @@ -357,7 +357,7 @@ boolean MySensor::process() { if (repeaterMode && last != nc.parentNodeId) { // Message is from one of the child nodes. Add it to routing table. - hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+sender, last); + hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); } // Check if sender requests an ack back. @@ -385,8 +385,8 @@ boolean MySensor::process() { // Found a neighbor closer to GW than previously found nc.distance = distance; nc.parentNodeId = msg.sender; - hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); - hw.writeConfigByte(EEPROM_DISTANCE_ADDRESS, nc.distance); + hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); + hw_writeConfig(EEPROM_DISTANCE_ADDRESS, nc.distance); debug(PSTR("parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); } } @@ -406,7 +406,7 @@ boolean MySensor::process() { CLEAR_SIGN(msg.sender); } // Save updated table - hw.writeConfigBlock((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); + hw_writeConfigBlock((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node @@ -425,7 +425,7 @@ boolean MySensor::process() { if (type == I_REBOOT) { // Requires MySensors or other bootloader with watchdogs enabled - hw.reboot(); + hw_reboot(); } else if (type == I_ID_RESPONSE) { if (nc.nodeId == AUTO) { nc.nodeId = msg.getByte(); @@ -436,7 +436,7 @@ boolean MySensor::process() { } setupNode(); // Write id to EEPROM - hw.writeConfigByte(EEPROM_NODE_ID_ADDRESS, nc.nodeId); + hw_writeConfig(EEPROM_NODE_ID_ADDRESS, nc.nodeId); debug(PSTR("id=%d\n"), nc.nodeId); } } else if (type == I_CONFIG) { @@ -444,18 +444,18 @@ boolean MySensor::process() { // and store it in eeprom if changed isMetric = msg.getString()[0] == 'M' ; cc.isMetric = isMetric; - hw.writeConfigByte(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); + hw_writeConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); } else if (type == I_CHILDREN) { if (repeaterMode && msg.getString()[0] == 'C') { // Clears child relay data for this node debug(PSTR("clear\n")); uint8_t i = 255; do { - hw.writeConfigByte(EEPROM_ROUTES_ADDRESS+i, 0xff); + hw_writeConfig(EEPROM_ROUTES_ADDRESS+i, 0xff); } while (i--); // Clear parent node id & distance to gw - hw.writeConfigByte(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); - hw.writeConfigByte(EEPROM_DISTANCE_ADDRESS, 0xFF); + hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); + hw_writeConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); // Find parent node findParentNode(); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); @@ -480,7 +480,7 @@ boolean MySensor::process() { // Relaying nodes should always answer ping messages // Wait a random delay of 0-2 seconds to minimize collision // between ping ack messages from other relaying nodes - wait(hw.millisec() & 0x3ff); + wait(hw_millis() & 0x3ff); sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); } } else if (to == nc.nodeId) { @@ -496,15 +496,15 @@ MyMessage& MySensor::getLastMessage() { } void MySensor::saveState(uint8_t pos, uint8_t value) { - hw.writeConfigByte(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); + hw_writeConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); } uint8_t MySensor::loadState(uint8_t pos) { - return hw.readConfigByte(EEPROM_LOCAL_CONFIG_ADDRESS+pos); + return hw_readConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos); } void MySensor::wait(unsigned long ms) { - unsigned long enter = hw.millisec(); - while (hw.millisec() - enter < ms) { + unsigned long enter = hw_millis(); + while (hw_millis() - enter < ms) { process(); } } @@ -530,9 +530,9 @@ bool MySensor::sign(MyMessage &message) { } else { // We have to wait for the nonce to arrive before we can sign our original message // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hw.millisec(); + unsigned long enter = hw_millis(); msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (hw.millisec() - enter < 5000) { + while (hw_millis() - enter < 5000) { if (process()) { if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { // Proceed with signing if nonce has been received diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index a58d93a..9a2ec57 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -13,14 +13,13 @@ #define MySensor_h #include "Version.h" // Auto generated by bot +#include "MyConfig.h" #include "MyHw.h" -#include "MyHwATMega328.h" #include "MyTransport.h" #include "MyTransportNRF24.h" #include "MyParser.h" #include "MySigning.h" #include "MySigningNone.h" -#include "MyConfig.h" #include "MyMessage.h" #include #include @@ -74,7 +73,7 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone(), MyHw &hw=*new MyHwATMega328()); + MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone(), MyHw &hw=*new MyHwDriver()); /** * Begin operation of the MySensors library From cb5e3172bdbf5e8121284aa203d5f7c694ae0a96 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 16 Mar 2015 19:39:06 +0100 Subject: [PATCH 076/660] Fixed compile problem --- libraries/MySensors/MyHw.h | 2 -- libraries/MySensors/MyHwATMega328.h | 14 +++++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/MyHw.h index 95cf2a4..b73ec23 100644 --- a/libraries/MySensors/MyHw.h +++ b/libraries/MySensors/MyHw.h @@ -3,9 +3,7 @@ #include #include -#include "MyConfig.h" -//#include "MySensor.h" /** * The Hw contains all hardware specific details of the platform */ diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 618a789..5a63faf 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -1,7 +1,8 @@ #ifndef MyHwATMega328_h #define MyHwATMega328_h -#include "MyConfig.h" +#include "MyHw.h" +//#include "MyConfig.h" #include "MyMessage.h" #include #include @@ -10,7 +11,6 @@ #include #include -#include "MyHw.h" #ifdef __cplusplus #include @@ -20,12 +20,12 @@ // Define these as macros to save valuable space #define hw_init() Serial.begin(BAUD_RATE) #define hw_watchdogReset() wdt_reset() -#define hw_reboot() wdt_enable(WDTO_15MS); for (;;) +#define hw_reboot() wdt_enable(WDTO_15MS); while (1) #define hw_millis() millis() -#define hw_readConfig(__pos) eeprom_read_byte((uint8_t*)__pos) -#define hw_writeConfig(__pos, __value) eeprom_update_byte((uint8_t*)__pos, __value) -#define hw_readConfigBlock(__buf, __pos, __length) eeprom_read_block(buf, (void*)__pos, __length) -#define hw_writeConfigBlock(__pos, __buf, __length) eeprom_write_block((void*)__pos, (void*)__buf, __length) +#define hw_readConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) +#define hw_writeConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) +#define hw_readConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) +#define hw_writeConfigBlock(__pos, __buf, __length) (eeprom_write_block((void*)(__pos), (void*)__buf, (__length))) From 4c4c9a8b39332516a2196490bb749933e3d1df59 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 7 Mar 2015 14:47:06 +0100 Subject: [PATCH 077/660] Added SHA command to ATSHA204 backend driver The SHA command is available in ATSHA204A variants of the chip and can be used to calculate SHA256 digests of arbitrary data. This enables us to strengthen the quality of the signatures by salting signatures with node-specific data and improving the quality of random data. --- libraries/MySensors/MySigningAtsha204.cpp | 26 +++++++++++++++++++++++ libraries/MySensors/MySigningAtsha204.h | 3 ++- libraries/MySensors/utility/ATSHA204.cpp | 15 +++++++++---- libraries/MySensors/utility/ATSHA204.h | 16 +++++++++++++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 1effefc..146ce30 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -215,3 +215,29 @@ bool MySigningAtsha204::calculateSignature(MyMessage &msg) { DEBUG_ATSHA_PRINTBUF("HMAC:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return true; // We return with the signature in rx_buffer[SHA204_BUFFER_POS_DATA] } + +// Helper to calculate a generic SHA256 digest of provided buffer (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) (only supports one block) +uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { + // Initiate SHA256 calculator + if (atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, + SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to initiate sha256"); + return NULL; + } + + // Calculate a hash + memset(temp_message, 0x00, SHA_MSG_SIZE); + memcpy(temp_message, data, sz); + temp_message[sz] = 0x80; + // Write length data to the last bytes + temp_message[SHA_MSG_SIZE-2] = (sz >> 5); + temp_message[SHA_MSG_SIZE-1] = (sz << 3); + DEBUG_ATSHA_PRINTBUF("Data to hash (padded):", temp_message, SHA_MSG_SIZE); + if (atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, temp_message, + SHA_COUNT_LONG, tx_buffer, SHA_RSP_SIZE_LONG, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to calculate sha256"); + return NULL; + } + DEBUG_ATSHA_PRINTBUF("SHA:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); + return &rx_buffer[SHA204_BUFFER_POS_DATA]; +} diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/MySigningAtsha204.h index 8850b2c..d6b3465 100644 --- a/libraries/MySensors/MySigningAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -31,10 +31,11 @@ private: unsigned long timestamp; bool verification_ongoing; uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; - uint8_t temp_message[32]; + uint8_t temp_message[SHA_MSG_SIZE]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; bool calculateSignature(MyMessage &msg); + uint8_t* sha256(const uint8_t* data, size_t sz); }; #endif diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index da63668..21ad514 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -447,12 +447,19 @@ uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t response_size = RANDOM_RSP_SIZE; break; - case SHA204_WRITE: - poll_delay = WRITE_DELAY; - poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; - response_size = WRITE_RSP_SIZE; + case SHA204_SHA: + poll_delay = SHA_DELAY; + poll_timeout = SHA_EXEC_MAX - SHA_DELAY; + response_size = param1 == SHA_INIT + ? SHA_RSP_SIZE_SHORT : SHA_RSP_SIZE_LONG; break; + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + default: poll_delay = 0; poll_timeout = SHA204_COMMAND_EXEC_MAX; diff --git a/libraries/MySensors/utility/ATSHA204.h b/libraries/MySensors/utility/ATSHA204.h index cb2abc8..c2a057e 100644 --- a/libraries/MySensors/utility/ATSHA204.h +++ b/libraries/MySensors/utility/ATSHA204.h @@ -59,6 +59,7 @@ #define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code #define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code #define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_SHA ((uint8_t) 0x47) //!< SHA command op-code #define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code // packet size definitions @@ -122,6 +123,15 @@ #define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update #define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update +// SHA command definitions +#define SHA_MODE_IDX SHA204_PARAM1_IDX //!< SHA command index for mode +#define SHA_PARAM2_IDX SHA204_PARAM2_IDX //!< SHA command index for 2. parameter +#define SHA_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< SHA command packet size for init +#define SHA_COUNT_LONG (71) //!< SHA command packet size for calculation +#define SHA_MSG_SIZE (64) //!< SHA message data size +#define SHA_INIT ((uint8_t) 0x00) //!< SHA mode for init +#define SHA_CALC ((uint8_t) 0x01) //!< SHA mode for calculation + // Write command definitions #define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone #define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address @@ -142,6 +152,8 @@ #define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 #define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command #define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define SHA_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of SHA command with mode[0:1] = 0 +#define SHA_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of SHA command #define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command // command timing definitions for minimum execution times (ms) @@ -149,6 +161,7 @@ #define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define SHA_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) // command timing definitions for maximum execution times (ms) @@ -156,6 +169,7 @@ #define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define SHA_EXEC_MAX ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) /* from sha204_config.h */ @@ -172,7 +186,7 @@ #define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay #define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) -#define SHA204_CMD_SIZE_MAX ((uint8_t) NONCE_COUNT_LONG) //! maximum size of command packet (Nonce) +#define SHA204_CMD_SIZE_MAX ((uint8_t) SHA_COUNT_LONG) //! maximum size of command packet (SHA) #define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes #define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response #define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response From a1024cd2cd8607db078bd2a2391fdf6d575da23f Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 9 Mar 2015 21:37:16 +0100 Subject: [PATCH 078/660] Added support to read the serial number from ATSHA204 The serial number can be used for whitelisting of nodes that are considered "trusted". --- libraries/MySensors/utility/ATSHA204.cpp | 45 ++++++++++++++++++++++++ libraries/MySensors/utility/ATSHA204.h | 25 +++++++++++++ 2 files changed, 70 insertions(+) diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index 21ad514..9991335 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -18,6 +18,34 @@ atsha204Class::atsha204Class(uint8_t pin) device_port_IN = portInputRegister(port); } +uint8_t atsha204Class::getSerialNumber(uint8_t * response) +{ + uint8_t readCommand[READ_COUNT]; + uint8_t readResponse[READ_4_RSP_SIZE]; + + /* read from bytes 0->3 of config zone */ + uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + if (!returnCode) // should return 0 if successful + { + for (int i=0; i<4; i++) // store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + + /* read from bytes 8->11 of config zone */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + + for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + + if (!returnCode) + { /* Finally if last two reads were successful, read byte 8 of the SN */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE + } + } + + return returnCode; +} + /* SWI bit bang functions */ void atsha204Class::swi_set_signal_pin(uint8_t is_high) @@ -412,6 +440,23 @@ uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s /* Marshaling functions */ +uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +{ + uint8_t rx_size; + + address >>= 2; + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); +} + uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) { diff --git a/libraries/MySensors/utility/ATSHA204.h b/libraries/MySensors/utility/ATSHA204.h index c2a057e..d29f884 100644 --- a/libraries/MySensors/utility/ATSHA204.h +++ b/libraries/MySensors/utility/ATSHA204.h @@ -59,6 +59,7 @@ #define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code #define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code #define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code #define SHA204_SHA ((uint8_t) 0x47) //!< SHA command op-code #define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code @@ -123,6 +124,13 @@ #define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update #define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update +// Read command definitions +#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address +#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0. +#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes + // SHA command definitions #define SHA_MODE_IDX SHA204_PARAM1_IDX //!< SHA command index for mode #define SHA_PARAM2_IDX SHA204_PARAM2_IDX //!< SHA command index for 2. parameter @@ -152,6 +160,8 @@ #define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 #define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command #define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes +#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes #define SHA_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of SHA command with mode[0:1] = 0 #define SHA_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of SHA command #define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command @@ -161,6 +171,7 @@ #define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define SHA_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) #define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) @@ -169,6 +180,7 @@ #define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define SHA_EXEC_MAX ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) #define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) @@ -195,6 +207,17 @@ #define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error #define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error +/* EEPROM Addresses */ +/* Configuration Zone */ +#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone +#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum +#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone +#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE +#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status +#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204 +#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode +#define ADDRESS_SELECTOR 19 // Controls writability of Selector + class atsha204Class { private: @@ -207,6 +230,7 @@ private: uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); uint8_t swi_send_byte(uint8_t value); uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); + uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); public: atsha204Class(uint8_t pin); // Constructor uint8_t sha204c_wakeup(uint8_t *response); @@ -215,6 +239,7 @@ public: uint8_t sha204c_resync(uint8_t size, uint8_t *response); uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t getSerialNumber(uint8_t *response); }; #endif From e35a01766bc8da7bb7790528e2ae5a48f58a11de Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 8 Mar 2015 21:17:34 +0100 Subject: [PATCH 079/660] Implemented basic whitening of nonce A simple (for performanc reasons) whitening scheme has been implemented for the ATSHA204 backeds that strengthens the nonce "randomness". --- libraries/MySensors/MySigningAtsha204.cpp | 52 +++++++++++++------ libraries/MySensors/MySigningAtsha204Soft.cpp | 17 ++++-- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 146ce30..2a966fa 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -42,31 +42,43 @@ MySigningAtsha204::MySigningAtsha204(bool requestSignatures, uint8_t atshaPin) atsha204(atshaPin), verification_ongoing(false) { - // We set the part of the 32-byte nonce that does not fit into a message to 0xAA - memset(current_nonce, 0xAA, sizeof(current_nonce)); } bool MySigningAtsha204::getNonce(MyMessage &msg) { - // Wake device before starting operations - if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to wake device"); - return false; - } - // Generate random number for use as nonce - if (atsha204.sha204m_execute(SHA204_RANDOM, RANDOM_NO_SEED_UPDATE, 0, 0, NULL, - RANDOM_COUNT, tx_buffer, RANDOM_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to generate nonce"); - return false; + uint8_t* pRnd = NULL; + // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value + // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce + for (int i = 0; i < 32; i++) { + // Wake device before starting operations + if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to wake device"); + return false; + } + if (atsha204.sha204m_execute(SHA204_RANDOM, RANDOM_NO_SEED_UPDATE, 0, 0, NULL, + RANDOM_COUNT, tx_buffer, RANDOM_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to generate nonce"); + return false; + } + atsha204.sha204c_sleep(); + current_nonce[i] = rx_buffer[SHA204_BUFFER_POS_DATA]; } - - // We can put the device back to sleep as we will program the nonce once we do the verification + pRnd = sha256(current_nonce, 32); atsha204.sha204c_sleep(); - // Store nonce and replace the first byte in the nonce with our signing identifier - memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD); + if (!pRnd) { + DEBUG_ATSHA_PRINTLN("Failed to hash random value"); + return false; + } + + memcpy(current_nonce, pRnd, MAX_PAYLOAD); + + // We set the part of the 32-byte nonce that does not fit into a message to 0xAA + memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); + + // Replace the first byte in the nonce with our signing identifier current_nonce[0] = SIGNING_IDENTIFIER; - + // Transfer the first part of the nonce to the message msg.set(current_nonce, MAX_PAYLOAD); verification_ongoing = true; @@ -218,6 +230,12 @@ bool MySigningAtsha204::calculateSignature(MyMessage &msg) { // Helper to calculate a generic SHA256 digest of provided buffer (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) (only supports one block) uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { + // Wake device before starting operations + if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { + DEBUG_ATSHA_PRINTLN("Failed to wake device"); + return NULL; + } + // Initiate SHA256 calculator if (atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index 3ac6f38..465cd93 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -49,17 +49,24 @@ MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, uint8_t ran Sha256() { - // We set the part of the 32-byte nonce that does not fit into a message to 0xAA - memset(current_nonce, 0xAA, sizeof(current_nonce)); } bool MySigningAtsha204Soft::getNonce(MyMessage &msg) { // Set randomseed randomSeed(analogRead(rndPin)); - for (int i = 0; i < MAX_PAYLOAD; i++) - { - current_nonce[i] = random(255); + + // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value + // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce + Sha256.init(); + for (int i = 0; i < 32; i++) { + Sha256.write(random(255)); } + memcpy(current_nonce, Sha256.result(), MAX_PAYLOAD); + + // We set the part of the 32-byte nonce that does not fit into a message to 0xAA + memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); + + // Replace the first byte in the nonce with our signing identifier current_nonce[0] = SIGNING_IDENTIFIER; // Transfer the first part of the nonce to the message From cf31edcb810ff04b7a9c367d52fb91b07729086a Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 13 Mar 2015 18:52:47 +0100 Subject: [PATCH 080/660] New way of presenting ATSHA204 serial in personalizer The serial is now more copy+paste friendly for use in whitelists. --- .../Sha204Personalizer/Sha204Personalizer.ino | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino index 066c834..4b7017f 100644 --- a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino +++ b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino @@ -41,7 +41,7 @@ //#define SKIP_KEY_STORAGE // Uncomment this to skip key data storage (once configuration is locked, key -// will aways randomize ) +// will aways randomize) // Uncomment this to skip key generation and use 'user_key_data' as key instead. //#define USER_KEY_DATA @@ -703,6 +703,19 @@ void setup() else { Serial.print(F("Device serial: ")); + Serial.print('{'); + for (int i=0; i<9; i++) + { + Serial.print(F("0x")); + if (rx_buffer[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + if (i < 8) Serial.print(','); + } + Serial.print('}'); + Serial.println(); for (int i=0; i<9; i++) { if (rx_buffer[i] < 0x10) From f295ef2961809777247b86471b5438e3fed74611 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 13 Mar 2015 23:44:12 +0100 Subject: [PATCH 081/660] Whitelisting support in signing backend Whitelisting is enabled using MY_SECURE_NODE_WHITELISTING in MyConfig.h. The whitelist is provided in backend constructors. See the SecureActuator example for a typical usecase. --- libraries/MySensors/MyConfig.h | 12 ++++ libraries/MySensors/MySigningAtsha204.cpp | 68 +++++++++++++------ libraries/MySensors/MySigningAtsha204.h | 19 +++++- libraries/MySensors/MySigningAtsha204Soft.cpp | 53 +++++++++++++-- libraries/MySensors/MySigningAtsha204Soft.h | 21 +++++- .../SecureActuator/SecureActuator.ino | 37 ++++++++-- libraries/MySensors/utility/ATSHA204.h | 2 + 7 files changed, 177 insertions(+), 35 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 0b4d806..e68709a 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -21,11 +21,23 @@ typedef MyHwATMega328 MyHwDriver; // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. #define MY_VERIFICATION_TIMEOUT_MS 5000 +// Enable to turn on whitelisting +// When enabled, a signing node will salt the signature with it's unique signature and nodeId. +// The verifying node will look up the sender in a local table of trusted nodes and +// do the corresponding salting in order to verify the signature. +// For this reason, if whitelisting is enabled on one of the nodes in a sign-verify pair, both +// nodes have to implement whitelisting for this to work. +// Note that a node can still transmit a non-salted message (i.e. have whitelisting disabled) +// to a node that has whitelisting enabled (assuming the receiver does not have a matching entry +// for the sender in it's whitelist) +//#define MY_SECURE_NODE_WHITELISTING + // MySigningAtsha204 default setting #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached // MySigningAtsha204Soft default settings #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) + // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 2a966fa..e9fcd42 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -36,10 +36,18 @@ static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #endif -MySigningAtsha204::MySigningAtsha204(bool requestSignatures, uint8_t atshaPin) +MySigningAtsha204::MySigningAtsha204(bool requestSignatures, +#ifdef MY_SECURE_NODE_WHITELISTING + uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, +#endif + uint8_t atshaPin) : MySigning(requestSignatures), atsha204(atshaPin), +#ifdef MY_SECURE_NODE_WHITELISTING + whitelist(the_whitelist), + whitlist_sz(nof_whitelist_entries), +#endif verification_ongoing(false) { } @@ -50,21 +58,14 @@ bool MySigningAtsha204::getNonce(MyMessage &msg) { // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce for (int i = 0; i < 32; i++) { - // Wake device before starting operations - if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to wake device"); - return false; - } if (atsha204.sha204m_execute(SHA204_RANDOM, RANDOM_NO_SEED_UPDATE, 0, 0, NULL, RANDOM_COUNT, tx_buffer, RANDOM_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { DEBUG_ATSHA_PRINTLN("Failed to generate nonce"); return false; } - atsha204.sha204c_sleep(); current_nonce[i] = rx_buffer[SHA204_BUFFER_POS_DATA]; } pRnd = sha256(current_nonce, 32); - atsha204.sha204c_sleep(); if (!pRnd) { DEBUG_ATSHA_PRINTLN("Failed to hash random value"); @@ -134,6 +135,19 @@ bool MySigningAtsha204::signMsg(MyMessage &msg) { return false; } +#ifdef MY_SECURE_NODE_WHITELISTING + // Salt the signature with the senders nodeId and the unique serial of the ATSHA device + memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + current_nonce[32] = msg.sender; + (void)atsha204.getSerialNumber(¤t_nonce[33]); + (void)sha256(current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + DEBUG_ATSHA_PRINTLN("Signature salted"); +#endif + + // Overwrite the first byte in the signature with the signing identifier + rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; + // Transfer as much signature data as the remaining space in the message permits memcpy(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); @@ -166,9 +180,29 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { return false; } +#ifdef MY_SECURE_NODE_WHITELISTING + // Look up the senders nodeId in our whitelist and salt the signature with that data + for (int j=0; j < whitlist_sz; j++) { + if (whitelist[j].nodeId == msg.sender) { + DEBUG_ATSHA_PRINTLN("Sender found in whitelist"); + memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + current_nonce[32] = msg.sender; + memcpy(¤t_nonce[33], whitelist[j].serial, SHA204_SERIAL_SZ); + (void)sha256(current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + break; + } + } +#endif + + // Overwrite the first byte in the signature with the signing identifier + rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; + // Compare the caluclated signature with the provided signature if (memcmp(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { DEBUG_ATSHA_PRINTBUF("Signature bad. Calculated signature:", &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); +#ifdef MY_SECURE_NODE_WHITELISTING + DEBUG_ATSHA_PRINTLN("Is the sender whitelisted?"); +#endif return false; } else { DEBUG_ATSHA_PRINTLN("Signature ok"); @@ -182,9 +216,6 @@ bool MySigningAtsha204::calculateSignature(MyMessage &msg) { memset(temp_message, 0, 32); memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - // Wake device before starting operations - if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) return false; - // Program the data to sign into the ATSHA204 if (atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, temp_message, WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { @@ -221,21 +252,12 @@ bool MySigningAtsha204::calculateSignature(MyMessage &msg) { // Put device back to sleep atsha204.sha204c_sleep(); - // Overwrite the first byte in the signature with the signing identifier - rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; - DEBUG_ATSHA_PRINTBUF("HMAC:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return true; // We return with the signature in rx_buffer[SHA204_BUFFER_POS_DATA] } // Helper to calculate a generic SHA256 digest of provided buffer (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) (only supports one block) uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { - // Wake device before starting operations - if (atsha204.sha204c_wakeup(rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to wake device"); - return NULL; - } - // Initiate SHA256 calculator if (atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { @@ -250,12 +272,16 @@ uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { // Write length data to the last bytes temp_message[SHA_MSG_SIZE-2] = (sz >> 5); temp_message[SHA_MSG_SIZE-1] = (sz << 3); - DEBUG_ATSHA_PRINTBUF("Data to hash (padded):", temp_message, SHA_MSG_SIZE); + DEBUG_ATSHA_PRINTBUF("Data to hash:", temp_message, SHA_MSG_SIZE); if (atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, temp_message, SHA_COUNT_LONG, tx_buffer, SHA_RSP_SIZE_LONG, rx_buffer) != SHA204_SUCCESS) { DEBUG_ATSHA_PRINTLN("Failed to calculate sha256"); return NULL; } + + // Put device back to sleep + atsha204.sha204c_sleep(); + DEBUG_ATSHA_PRINTBUF("SHA:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return &rx_buffer[SHA204_BUFFER_POS_DATA]; } diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/MySigningAtsha204.h index d6b3465..b96386a 100644 --- a/libraries/MySensors/MySigningAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -14,13 +14,24 @@ #define SIGNING_IDENTIFIER (1) +#ifdef MY_SECURE_NODE_WHITELISTING +typedef struct { + uint8_t nodeId; + uint8_t serial[SHA204_SERIAL_SZ]; +} whitelist_entry_t; +#endif + // The ATSHA204 is capable of generating proper random numbers for nonce // and can calculate HMAC-SHA256 signatures. This is enterprise- // level of security and ought to implement the signing needs for anybody. class MySigningAtsha204 : public MySigning { public: - MySigningAtsha204(bool requestSignatures=true, uint8_t atshaPin = MY_ATSHA204_PIN); + MySigningAtsha204(bool requestSignatures=true, +#ifdef MY_SECURE_NODE_WHITELISTING + uint8_t nof_whitelist_entries=0, const whitelist_entry_t* the_whitelist=NULL, +#endif + uint8_t atshaPin=MY_ATSHA204_PIN); bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); @@ -30,12 +41,16 @@ private: atsha204Class atsha204; unsigned long timestamp; bool verification_ongoing; - uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; + uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1]; uint8_t temp_message[SHA_MSG_SIZE]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; bool calculateSignature(MyMessage &msg); uint8_t* sha256(const uint8_t* data, size_t sz); +#ifdef MY_SECURE_NODE_WHITELISTING + uint8_t whitlist_sz; + const whitelist_entry_t* whitelist; +#endif }; #endif diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index 465cd93..4d56cf1 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -40,11 +40,21 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) #define DEBUG_ATSHASOFT_PRINTBUF(str, buf, sz) #endif -MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, uint8_t randomseedPin) +MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, +#ifdef MY_SECURE_NODE_WHITELISTING + uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, + const uint8_t* the_serial, +#endif + uint8_t randomseedPin) : MySigning(requestSignatures), rndPin(randomseedPin), hmacKey({MY_HMAC_KEY}), +#ifdef MY_SECURE_NODE_WHITELISTING + whitlist_sz(nof_whitelist_entries), + whitelist(the_whitelist), + node_serial_info(the_serial), +#endif verification_ongoing(false), Sha256() @@ -124,6 +134,19 @@ bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { return false; } +#ifdef MY_SECURE_NODE_WHITELISTING + // Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided + Sha256.init(); + for (int i=0; i<32; i++) Sha256.write(hmac[i]); + Sha256.write(msg.sender); + for (int i=0; i +#define USE_SOFTWARE_ATSHA // Disable to use ATSHA204A circuit + #include +#include #include #include +#ifdef USE_SOFTWARE_ATSHA +#include +#else +#include +#endif #define LOCK_1 3 // Arduino Digital I/O pin number for first lock (second on pin+1 etc) #define NOF_LOCKS 1 // Total number of attached locks @@ -12,13 +19,35 @@ #define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock MyTransportNRF24 radio; // NRFRF24L01 radio driver +MyHwATMega328 hw; // Select AtMega328 hardware profile +#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef USE_SOFTWARE_ATSHA +// Change the soft_serial value to an arbitrary value for proper security +uint8_t soft_serial[SHA204_SERIAL_SZ] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}; +#endif +// We only use one whitelist entry (the gateway) +whitelist_entry_t node_whitelist[] = { + { .nodeId = GATEWAY_ADDRESS, + .serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01} } +}; +#ifdef USE_SOFTWARE_ATSHA MySigningAtsha204Soft signer; // Message signing driver -MySensor gw(radio, signer); +#else +MySigningAtsha204 signer(true, 1, node_whitelist); +#endif +#else +#ifdef USE_SOFTWARE_ATSHA +MySigningAtsha204Soft signer; +#else +MySigningAtsha204 signer; +#endif +#endif +MySensor gw(radio, hw, signer); void setup() -{ +{ // Initialize library and add callback for incoming messages (signing is required) - gw.begin(incomingMessage, AUTO, true, AUTO); + gw.begin(incomingMessage, AUTO); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Secure Lock", "1.0"); diff --git a/libraries/MySensors/utility/ATSHA204.h b/libraries/MySensors/utility/ATSHA204.h index d29f884..f4499b4 100644 --- a/libraries/MySensors/utility/ATSHA204.h +++ b/libraries/MySensors/utility/ATSHA204.h @@ -218,6 +218,8 @@ #define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode #define ADDRESS_SELECTOR 19 // Controls writability of Selector +#define SHA204_SERIAL_SZ 9 // The number of bytes the serial number consists of + class atsha204Class { private: From 611ba0cf442d7d30c40fbf261335280ee5891593 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 14 Mar 2015 12:20:02 +0100 Subject: [PATCH 082/660] Slimmed down memory footprint of signing backends --- libraries/MySensors/MySigningAtsha204.cpp | 136 ++++++------------ libraries/MySensors/MySigningAtsha204.h | 2 +- libraries/MySensors/MySigningAtsha204Soft.cpp | 62 ++++---- libraries/MySensors/MySigningAtsha204Soft.h | 2 +- libraries/MySensors/MySigningNone.cpp | 15 +- libraries/MySensors/utility/ATSHA204.cpp | 12 +- libraries/MySensors/utility/ATSHA204.h | 10 +- 7 files changed, 92 insertions(+), 147 deletions(-) diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index e9fcd42..07dca5f 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -8,18 +8,17 @@ #include "MySigningAtsha204.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) -//#define DEBUG_ATSHA_SIGNING +//#define DEBUG_SIGNING -#ifdef DEBUG_ATSHA_SIGNING -#define DEBUG_ATSHA_PRINTLN(args) Serial.println(args) +#ifdef DEBUG_SIGNING +#define DEBUG_SIGNING_PRINTLN(args) Serial.println(args) #else -#define DEBUG_ATSHA_PRINTLN(args) +#define DEBUG_SIGNING_PRINTLN(args) #endif -#ifdef DEBUG_ATSHA_SIGNING -static void DEBUG_ATSHA_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +#ifdef DEBUG_SIGNING +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { - int i; Serial.println(str); for (int i=0; i timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_ATSHA_PRINTLN("Verification timeout"); + DEBUG_SIGNING_PRINTLN(F("VT")); // VT = Verification timeout // Purge nonce - memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + memset(current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); verification_ongoing = false; return false; } @@ -105,44 +96,35 @@ bool MySigningAtsha204::checkTimer() { } bool MySigningAtsha204::putNonce(MyMessage &msg) { - if (mGetLength(msg) != MAX_PAYLOAD) { - DEBUG_ATSHA_PRINTLN("Incoming nonce with incorrect size"); - return false; // We require as big nonce as possible - } - if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { - DEBUG_ATSHA_PRINTLN("Incorrect signing identifier"); + DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier return false; } memcpy(current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); + // We set the part of the 32-byte nonce that does not fit into a message to 0xAA + memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); return true; } bool MySigningAtsha204::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { - DEBUG_ATSHA_PRINTLN("Cannot fit any signature to this message"); + DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit return false; } // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated - DEBUG_ATSHA_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - if (!calculateSignature(msg)) { - DEBUG_ATSHA_PRINTLN("Failed to calculate signature"); - mSetSigned(msg, 0); // make sure signing flag is truthful - return false; - } + calculateSignature(msg); #ifdef MY_SECURE_NODE_WHITELISTING // Salt the signature with the senders nodeId and the unique serial of the ATSHA device memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed current_nonce[32] = msg.sender; - (void)atsha204.getSerialNumber(¤t_nonce[33]); + atsha204.getSerialNumber(¤t_nonce[33]); (void)sha256(current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place - memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); - DEBUG_ATSHA_PRINTLN("Signature salted"); + DEBUG_SIGNING_PRINTLN(F("SWS")); // SWS = Signature whitelist salted #endif // Overwrite the first byte in the signature with the signing identifier @@ -156,7 +138,7 @@ bool MySigningAtsha204::signMsg(MyMessage &msg) { bool MySigningAtsha204::verifyMsg(MyMessage &msg) { if (!verification_ongoing) { - DEBUG_ATSHA_PRINTLN("No active verification session"); + DEBUG_SIGNING_PRINTLN(F("NAVS")); // NAVS = No active verification session return false; } else { // Make sure we have not expired @@ -167,24 +149,18 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { - DEBUG_ATSHA_PRINTLN("Incorrect signing identifier"); + DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier return false; } - DEBUG_ATSHA_PRINTBUF("Message to verify:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_ATSHA_PRINTBUF("Signature in message:", (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); - - // Get signature of message - if (!calculateSignature(msg)) { - DEBUG_ATSHA_PRINTLN("Failed to calculate signature"); - return false; - } + DEBUG_SIGNING_PRINTBUF(F("SIM:"), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); // SIM = Signature in message + calculateSignature(msg); // Get signature of message #ifdef MY_SECURE_NODE_WHITELISTING // Look up the senders nodeId in our whitelist and salt the signature with that data for (int j=0; j < whitlist_sz; j++) { if (whitelist[j].nodeId == msg.sender) { - DEBUG_ATSHA_PRINTLN("Sender found in whitelist"); + DEBUG_SIGNING_PRINTLN(F("SIW")); // SIW = Sender found in whitelist memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed current_nonce[32] = msg.sender; memcpy(¤t_nonce[33], whitelist[j].serial, SHA204_SERIAL_SZ); @@ -199,71 +175,56 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { // Compare the caluclated signature with the provided signature if (memcmp(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { - DEBUG_ATSHA_PRINTBUF("Signature bad. Calculated signature:", &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); + DEBUG_SIGNING_PRINTBUF(F("SNOK:"), &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); // SNOK = Signature bad #ifdef MY_SECURE_NODE_WHITELISTING - DEBUG_ATSHA_PRINTLN("Is the sender whitelisted?"); + DEBUG_SIGNING_PRINTLN(F("W?")); // W? = Is the sender whitelisted? #endif return false; } else { - DEBUG_ATSHA_PRINTLN("Signature ok"); + DEBUG_SIGNING_PRINTLN(F("SOK")); // SOK = Signature OK return true; } } } // Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) -bool MySigningAtsha204::calculateSignature(MyMessage &msg) { +void MySigningAtsha204::calculateSignature(MyMessage &msg) { memset(temp_message, 0, 32); memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // Program the data to sign into the ATSHA204 - if (atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, temp_message, - WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to program data"); - return false; - } + DEBUG_SIGNING_PRINTBUF(F("MSG:"), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // MSG = Message to sign + DEBUG_SIGNING_PRINTBUF(F("CNC:"), current_nonce, 32); // CNC = Current nonce + (void)atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, temp_message, + WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); // Program the nonce to use for the signature (has to be done just before GENDIG due to chip limitations) - if (atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, current_nonce, - NONCE_COUNT_LONG, tx_buffer, NONCE_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to program nonce"); - // Purge nonce when used - memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); - return false; - } + (void)atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, current_nonce, + NONCE_COUNT_LONG, tx_buffer, NONCE_RSP_SIZE_SHORT, rx_buffer); // Purge nonce when used - memset(current_nonce, 0xAA, NONCE_NUMIN_SIZE_PASSTHROUGH); + memset(current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); // Generate digest of data and nonce - if (atsha204.sha204m_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL, - GENDIG_COUNT_DATA, tx_buffer, GENDIG_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to generate digest"); - return false; - } + (void)atsha204.sha204m_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL, + GENDIG_COUNT_DATA, tx_buffer, GENDIG_RSP_SIZE, rx_buffer); // Calculate HMAC of message+nonce digest and secret key - if (atsha204.sha204m_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, - HMAC_COUNT, tx_buffer, HMAC_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to generate HMAC"); - return false; - } + (void)atsha204.sha204m_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, + HMAC_COUNT, tx_buffer, HMAC_RSP_SIZE, rx_buffer); // Put device back to sleep atsha204.sha204c_sleep(); - DEBUG_ATSHA_PRINTBUF("HMAC:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); - return true; // We return with the signature in rx_buffer[SHA204_BUFFER_POS_DATA] + DEBUG_SIGNING_PRINTBUF(F("HMAC:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); } -// Helper to calculate a generic SHA256 digest of provided buffer (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) (only supports one block) +// Helper to calculate a generic SHA256 digest of provided buffer (only supports one block) +// The pointer to the hash is returned, but the hash is also stored in rx_buffer[SHA204_BUFFER_POS_DATA]) uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { // Initiate SHA256 calculator - if (atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, - SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to initiate sha256"); - return NULL; - } + (void)atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, + SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer); // Calculate a hash memset(temp_message, 0x00, SHA_MSG_SIZE); @@ -272,16 +233,13 @@ uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { // Write length data to the last bytes temp_message[SHA_MSG_SIZE-2] = (sz >> 5); temp_message[SHA_MSG_SIZE-1] = (sz << 3); - DEBUG_ATSHA_PRINTBUF("Data to hash:", temp_message, SHA_MSG_SIZE); - if (atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, temp_message, - SHA_COUNT_LONG, tx_buffer, SHA_RSP_SIZE_LONG, rx_buffer) != SHA204_SUCCESS) { - DEBUG_ATSHA_PRINTLN("Failed to calculate sha256"); - return NULL; - } + DEBUG_SIGNING_PRINTBUF(F("DTH:"), temp_message, SHA_MSG_SIZE); // DTH = Data to hash + (void)atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, temp_message, + SHA_COUNT_LONG, tx_buffer, SHA_RSP_SIZE_LONG, rx_buffer); // Put device back to sleep atsha204.sha204c_sleep(); - DEBUG_ATSHA_PRINTBUF("SHA:", &rx_buffer[SHA204_BUFFER_POS_DATA], 32); + DEBUG_SIGNING_PRINTBUF(F("SHA:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return &rx_buffer[SHA204_BUFFER_POS_DATA]; } diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/MySigningAtsha204.h index b96386a..1ebf386 100644 --- a/libraries/MySensors/MySigningAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -45,7 +45,7 @@ private: uint8_t temp_message[SHA_MSG_SIZE]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - bool calculateSignature(MyMessage &msg); + void calculateSignature(MyMessage &msg); uint8_t* sha256(const uint8_t* data, size_t sz); #ifdef MY_SECURE_NODE_WHITELISTING uint8_t whitlist_sz; diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index 4d56cf1..d5aa8aa 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -13,16 +13,16 @@ #include "utility/sha256.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) -//#define DEBUG_ATSHASOFT_SIGNING +//#define DEBUG_SIGNING -#ifdef DEBUG_ATSHASOFT_SIGNING -#define DEBUG_ATSHASOFT_PRINTLN(args) Serial.println(args) +#ifdef DEBUG_SIGNING +#define DEBUG_SIGNING_PRINTLN(args) Serial.println(args) #else -#define DEBUG_ATSHASOFT_PRINTLN(args) +#define DEBUG_SIGNING_PRINTLN(args) #endif -#ifdef DEBUG_ATSHASOFT_SIGNING -static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +#ifdef DEBUG_SIGNING +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { int i; Serial.println(str); @@ -37,7 +37,7 @@ static void DEBUG_ATSHASOFT_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) Serial.println(); } #else -#define DEBUG_ATSHASOFT_PRINTBUF(str, buf, sz) +#define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, @@ -93,7 +93,7 @@ bool MySigningAtsha204Soft::getNonce(MyMessage &msg) { bool MySigningAtsha204Soft::checkTimer() { if (verification_ongoing) { if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { - DEBUG_ATSHASOFT_PRINTLN("Verification timeout"); + DEBUG_SIGNING_PRINTLN(F("VT")); // VT = Verification timeout // Purge nonce memset(current_nonce, 0xAA, 32); verification_ongoing = false; @@ -104,13 +104,8 @@ bool MySigningAtsha204Soft::checkTimer() { } bool MySigningAtsha204Soft::putNonce(MyMessage &msg) { - if (mGetLength(msg) != MAX_PAYLOAD) { - DEBUG_ATSHASOFT_PRINTLN("Incoming nonce with incorrect size"); - return false; // We require as big nonce as possible - } - if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { - DEBUG_ATSHASOFT_PRINTLN("Incorrect signing identifier"); + DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier return false; } @@ -121,18 +116,13 @@ bool MySigningAtsha204Soft::putNonce(MyMessage &msg) { bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { - DEBUG_ATSHASOFT_PRINTLN("Cannot fit any signature to this message"); + DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit return false; } // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated - DEBUG_ATSHASOFT_PRINTBUF("Message to sign:", (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - if (!calculateSignature(msg)) { - DEBUG_ATSHASOFT_PRINTLN("Failed to calculate signature"); - mSetSigned(msg, 0); // make sure signing flag is truthful - return false; - } + calculateSignature(msg); #ifdef MY_SECURE_NODE_WHITELISTING // Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided @@ -141,7 +131,7 @@ bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { Sha256.write(msg.sender); for (int i=0; i */ +#include "MyConfig.h" #include "MySigning.h" #include "MySigningNone.h" // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) -//#define DEBUG_NONE_SIGNING +//#define DEBUG_SIGNING -#ifdef DEBUG_NONE_SIGNING -#define DEBUG_NONE_PRINTLN(args) Serial.println(args) +#ifdef DEBUG_SIGNING +#define DEBUG_SIGNING_PRINTLN(args) Serial.println(args) #else -#define DEBUG_NONE_PRINTLN(args) +#define DEBUG_SIGNING_PRINTLN(args) #endif -#ifdef DEBUG_NONE_SIGNING -static void DEBUG_NONE_PRINTBUF(char* str, uint8_t* buf, uint8_t sz) +#ifdef DEBUG_SIGNING +static void DEBUG_NONE_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { int i; Serial.println(str); @@ -52,7 +53,7 @@ bool MySigningNone::putNonce(MyMessage &msg) { bool MySigningNone::signMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { - DEBUG_NONE_PRINTLN("Cannot fit any signature to this message"); + DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit return false; } mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index 9991335..c03ae7c 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -18,14 +18,14 @@ atsha204Class::atsha204Class(uint8_t pin) device_port_IN = portInputRegister(port); } -uint8_t atsha204Class::getSerialNumber(uint8_t * response) +void atsha204Class::getSerialNumber(uint8_t * response) { uint8_t readCommand[READ_COUNT]; uint8_t readResponse[READ_4_RSP_SIZE]; /* read from bytes 0->3 of config zone */ uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); - if (!returnCode) // should return 0 if successful + if (!returnCode) { for (int i=0; i<4; i++) // store bytes 0-3 into respones array response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; @@ -43,7 +43,7 @@ uint8_t atsha204Class::getSerialNumber(uint8_t * response) } } - return returnCode; + return; } /* SWI bit bang functions */ @@ -212,9 +212,9 @@ uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) /* Physical functions */ -uint8_t atsha204Class::sha204c_sleep() +void atsha204Class::sha204c_sleep() { - return swi_send_byte(SHA204_SWI_FLAG_SLEEP); + swi_send_byte(SHA204_SWI_FLAG_SLEEP); } uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) @@ -289,7 +289,7 @@ uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) // We lost communication. Send a Wake pulse and try // to receive a response (steps 2 and 3 of the // re-synchronization process). - (void) sha204c_sleep(); + sha204c_sleep(); ret_code = sha204c_wakeup(response); // Translate a return value of success into one diff --git a/libraries/MySensors/utility/ATSHA204.h b/libraries/MySensors/utility/ATSHA204.h index f4499b4..3864289 100644 --- a/libraries/MySensors/utility/ATSHA204.h +++ b/libraries/MySensors/utility/ATSHA204.h @@ -233,15 +233,15 @@ private: uint8_t swi_send_byte(uint8_t value); uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); + uint8_t sha204c_wakeup(uint8_t *response); + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); public: atsha204Class(uint8_t pin); // Constructor - uint8_t sha204c_wakeup(uint8_t *response); - uint8_t sha204c_sleep(); - uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); - uint8_t sha204c_resync(uint8_t size, uint8_t *response); + void sha204c_sleep(); uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); - uint8_t getSerialNumber(uint8_t *response); + void getSerialNumber(uint8_t *response); }; #endif From 2d2eb74e0a9a4476845e9880fd809b0af2332f64 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 14 Mar 2015 12:37:22 +0100 Subject: [PATCH 083/660] Fixed bug with storing signing table in EEPROM eeprom_updated_block() uses a non-string-standardised order of arguments. --- libraries/MySensors/MySensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index c058e2e..644b3e1 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -406,7 +406,7 @@ boolean MySensor::process() { CLEAR_SIGN(msg.sender); } // Save updated table - hw_writeConfigBlock((void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, (void*)doSign, sizeof(doSign)); + hw_writeConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node From 7a2a5dad81e0a3ec30e6167d673d0c9d84f8c5c2 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 14 Mar 2015 13:38:39 +0100 Subject: [PATCH 084/660] Message signing logic now integrated into sendRoute() --- libraries/MySensors/MySensor.cpp | 52 +++++++++++++++++--------------- libraries/MySensors/MySensor.h | 1 - 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 644b3e1..b92f118 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -192,7 +192,33 @@ boolean MySensor::sendRoute(MyMessage &message) { (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { - if (!sign(message)) { + bool signOk = false; + // Send nonce-request + if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + debug(PSTR("nonce tr err\n")); + return false; + } + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust process() takes care of them + unsigned long enter = hw_millis(); + msgSign = message; // Copy the message to sign since message buffer might be touched in process() + while (hw_millis() - enter < MY_VERIFICATION_TIMEOUT_MS) { + if (process()) { + if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) { + message = msgSign; // Write the signed message back + signOk = true; + } + break; + } + } + } + if (hw_millis() - enter > MY_VERIFICATION_TIMEOUT_MS) { + debug(PSTR("nonce tmo\n")); + return false; + } + if (!signOk) { debug(PSTR("sign fail\n")); return false; } @@ -524,27 +550,3 @@ int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, ui return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ; } -bool MySensor::sign(MyMessage &message) { - if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { - return false; - } else { - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hw_millis(); - msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (hw_millis() - enter < 5000) { - if (process()) { - if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) { - message = msgSign; // Write the signed message back - return true; - } - break; - } - } - } - } - return false; -} - diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 9a2ec57..9093183 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -257,7 +257,6 @@ class MySensor void setupNode(); void findParentNode(); uint8_t crc8Message(MyMessage &message); - bool sign(MyMessage &message); }; #endif From 70eac0423d0f8da9b1ba8b6eaa5c440d8cca4a60 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 14 Mar 2015 13:53:11 +0100 Subject: [PATCH 085/660] Added config flag MY_SIGNING_FEATURE in MyConfig.h By disabeling MY_SIGNING_FEATURE all signing logic in the library will be removed. --- libraries/MySensors/MyConfig.h | 3 +++ libraries/MySensors/MySensor.cpp | 24 +++++++++++++++++-- libraries/MySensors/MySensor.h | 14 ++++++++--- .../SecureActuator/SecureActuator.ino | 5 ++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index e68709a..61351af 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -16,6 +16,9 @@ typedef MyHwATMega328 MyHwDriver; /********************************** * Message Signing Settings ***********************************/ +// Disable to completly disable signing functionality in library +#define MY_SIGNING_FEATURE + // Define a suitable timeout for a signature verification session // Consider the turnaround from a nonce being generated to a signed message being received // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index b92f118..aa777d4 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -13,10 +13,12 @@ #define DISTANCE_INVALID (0xFF) +#ifdef MY_SIGNING_FEATURE // Macros for manipulating signing requirement table #define DO_SIGN(node) (node == 0 ? (~doSign[0]&1) : (~doSign[node>>4]&(node%16))) #define SET_SIGN(node) (node == 0 ? (doSign[0]&=~1) : (doSign[node>>4]&=~(node%16))) #define CLEAR_SIGN(node) (node == 0 ? (doSign[0]|=1) : (doSign[node>>4]|=(node%16))) +#endif // Inline function and macros static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { @@ -38,10 +40,16 @@ static inline bool isValidDistance( const uint8_t distance ) { } -MySensor::MySensor(MyTransport &_radio, MySigning &_signer, MyHw &_hw) +MySensor::MySensor(MyTransport &_radio, MyHw &_hw +#ifdef MY_SIGNING_FEATURE + , MySigning &_signer +#endif + ) : radio(_radio), +#ifdef MY_SIGNING_FEATURE signer(_signer), +#endif hw(_hw) { } @@ -63,8 +71,10 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); +#ifdef MY_SIGNING_FEATURE // Read out the signing requirements from EEPROM hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); +#endif if (isGateway) { nc.distance = 0; @@ -128,6 +138,7 @@ void MySensor::setupNode() { // Present node and request config if (!isGateway && nc.nodeId != AUTO) { +#ifdef MY_SIGNING_FEATURE // Notify gateway (and possibly controller) about the signing preferences of this node sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); @@ -135,6 +146,7 @@ void MySensor::setupNode() { if (signer.requestSignatures()) { wait(2000); } +#endif // Send presentation for this radio node (attach present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); @@ -186,6 +198,7 @@ boolean MySensor::sendRoute(MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); +#ifdef MY_SIGNING_FEATURE // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) && (mGetCommand(message) != C_INTERNAL || @@ -225,6 +238,7 @@ boolean MySensor::sendRoute(MyMessage &message) { // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, // or signature will become invalid and the message rejected by the receiver } else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned +#endif if (dest == GATEWAY_ADDRESS || !repeaterMode) { // If destination is the gateway or if we aren't a repeater, let @@ -339,10 +353,13 @@ boolean MySensor::process() { if (!radio.available(&to)) return false; +#ifdef MY_SIGNING_FEATURE (void)signer.checkTimer(); // Manage signing timeout - +#endif + uint8_t len = radio.receive((uint8_t *)&msg); +#ifdef MY_SIGNING_FEATURE // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && !mGetAck(msg) && @@ -360,6 +377,7 @@ boolean MySensor::process() { return false; // This signed message has been tampered with! } } +#endif // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; @@ -418,6 +436,7 @@ boolean MySensor::process() { } } return false; +#ifdef MY_SIGNING_FEATURE } else if (type == I_GET_NONCE) { if (signer.getNonce(msg)) { sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); @@ -446,6 +465,7 @@ boolean MySensor::process() { return false; // Signing request is an internal MySensor protocol message, no need to inform caller about this } else if (type == I_GET_NONCE_RESPONSE) { return true; // Just pass along nonce silently (no need to call callback for these) +#endif } else if (sender == GATEWAY_ADDRESS) { bool isMetric; diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 9093183..0d43da3 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -18,8 +18,10 @@ #include "MyTransport.h" #include "MyTransportNRF24.h" #include "MyParser.h" +#ifdef MY_SIGNING_FEATURE #include "MySigning.h" #include "MySigningNone.h" +#endif #include "MyMessage.h" #include #include @@ -73,7 +75,11 @@ class MySensor * Creates a new instance of Sensor class. * */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MySigning &signer=*new MySigningNone(), MyHw &hw=*new MyHwDriver()); + MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() +#ifdef MY_SIGNING_FEATURE + , MySigning &signer=*new MySigningNone() +#endif + ); /** * Begin operation of the MySensors library @@ -233,14 +239,16 @@ class MySensor bool repeaterMode; bool autoFindParent; bool isGateway; - uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication MyMessage msg; // Buffer for incoming messages. MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). +#ifdef MY_SIGNING_FEATURE + uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication MyMessage msgSign; // Buffer for message to sign. + MySigning& signer; +#endif MyTransport& radio; - MySigning& signer; MyHw& hw; boolean sendWrite(uint8_t dest, MyMessage &message); diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 297f6dd..a3ee2bc 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -20,6 +20,7 @@ MyTransportNRF24 radio; // NRFRF24L01 radio driver MyHwATMega328 hw; // Select AtMega328 hardware profile +#ifdef MY_SIGNING_FEATURE #ifdef MY_SECURE_NODE_WHITELISTING #ifdef USE_SOFTWARE_ATSHA // Change the soft_serial value to an arbitrary value for proper security @@ -43,6 +44,10 @@ MySigningAtsha204 signer; #endif #endif MySensor gw(radio, hw, signer); +#else +#error SecureActuator cannot possibly be secure without signing enabled +MySensor gw(radio, hw); +#endif void setup() { From 6fd26880a2ba06ec9d3b1da67358bacd405fab12 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 16 Mar 2015 22:45:39 +0100 Subject: [PATCH 086/660] Made "Inclusion started by button" a DEBUG message In other words, the message will only be printed if DEBUG flag is enabled. --- libraries/MySensors/examples/EthernetGateway/GatewayUtil.h | 2 ++ libraries/MySensors/examples/SerialGateway/GatewayUtil.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index d564ea6..6f006df 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -91,7 +91,9 @@ void checkButtonTriggeredInclusion() { if (buttonTriggeredInclusion) { // Ok, someone pressed the inclusion button on the gateway // start inclusion mode for 1 munute. +#ifdef DEBUG serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); +#endif buttonTriggeredInclusion = false; setInclusionMode(true); } diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index d564ea6..6f006df 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -91,7 +91,9 @@ void checkButtonTriggeredInclusion() { if (buttonTriggeredInclusion) { // Ok, someone pressed the inclusion button on the gateway // start inclusion mode for 1 munute. +#ifdef DEBUG serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); +#endif buttonTriggeredInclusion = false; setInclusionMode(true); } From 6fb726675272738a4fbb2f369ea7bbe73b82023a Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 16 Mar 2015 22:53:27 +0100 Subject: [PATCH 087/660] Removed 'new' from PinChangeInt library As a consequence, only one pin is currently suppored. AddPin will not really add a new pin, just replace the configuration of the existing pin. The motivation for this limitation is that 'new' costs a lot of program memory. --- libraries/PinChangeInt/PinChangeInt.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/PinChangeInt/PinChangeInt.h b/libraries/PinChangeInt/PinChangeInt.h index 19be5a6..807b20d 100644 --- a/libraries/PinChangeInt/PinChangeInt.h +++ b/libraries/PinChangeInt/PinChangeInt.h @@ -234,6 +234,7 @@ protected: volatile uint8_t portFallingPins; volatile uint8_t lastPinView; PCintPin* firstPin; + PCintPin thePin; }; #ifndef LIBCALL_PINCHANGEINT // LIBCALL_PINCHANGEINT *********************************************** @@ -388,8 +389,9 @@ int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t } while (true); } - // Create pin p: fill in the data. - PCintPin* p=new PCintPin; + // Create pin p: fill in the data. NOTE: MySensors only support one pin due to size constraints + // TODO: Figure out a better way to solve this without relying on new/malloc + PCintPin* p = &thePin; //PCintPin* p=new PCintPin; if (p == NULL) return(-1); p->arduinoPin=arduinoPin; p->mode = mode; From f8281302eb98daea26dc728a08c4a32eacb8d3bf Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 18 Mar 2015 22:31:14 +0100 Subject: [PATCH 088/660] Fixed software signing whitelisting example in SecureActuator The software serial is now provided to the backend as it should be. --- libraries/MySensors/examples/SecureActuator/SecureActuator.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index a3ee2bc..73bf57d 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -32,7 +32,7 @@ whitelist_entry_t node_whitelist[] = { .serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01} } }; #ifdef USE_SOFTWARE_ATSHA -MySigningAtsha204Soft signer; // Message signing driver +MySigningAtsha204Soft signer(true, 1, node_whitelist, soft_serial); // Message signing driver #else MySigningAtsha204 signer(true, 1, node_whitelist); #endif From aa3fd74139cc82b1f0a2f77a90a75df75a2e9d18 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 20 Mar 2015 09:52:36 +0100 Subject: [PATCH 089/660] Update to cope with disabled signing. --- libraries/MySensors/examples/RelayActuator/RelayActuator.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 2bb49ab..9a7e7c7 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -15,11 +15,11 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) -MySigningNone signer; +// MySigningNone signer; // Select AtMega328 hardware profile MyHwATMega328 hw; // Construct MySensors library -MySensor gw(radio, signer, hw); +MySensor gw(radio, hw); void setup() { From b72ac4b2776f7234207eabc626311688c0de7c20 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 20 Mar 2015 19:45:26 +0100 Subject: [PATCH 090/660] Fix crash when debug enabled. --- libraries/MySensors/MyConfig.h | 6 ++---- libraries/MySensors/MyHw.h | 1 + libraries/MySensors/MyHwATMega328.h | 2 +- libraries/MySensors/MySensor.h | 7 +++++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 61351af..a4f8a53 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -9,15 +9,13 @@ // Serial output baud rate #define BAUD_RATE 115200 -// Set the hardware driver to use (initialized by MySensor-class) -#include "MyHwATMega328.h" -typedef MyHwATMega328 MyHwDriver; + /********************************** * Message Signing Settings ***********************************/ // Disable to completly disable signing functionality in library -#define MY_SIGNING_FEATURE +//#define MY_SIGNING_FEATURE // Define a suitable timeout for a signature verification session // Consider the turnaround from a nonce being generated to a signed message being received diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/MyHw.h index b73ec23..14857c6 100644 --- a/libraries/MySensors/MyHw.h +++ b/libraries/MySensors/MyHw.h @@ -3,6 +3,7 @@ #include #include +#include "MyConfig.h" /** * The Hw contains all hardware specific details of the platform diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 5a63faf..684ef59 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -2,7 +2,7 @@ #define MyHwATMega328_h #include "MyHw.h" -//#include "MyConfig.h" +#include "MyConfig.h" #include "MyMessage.h" #include #include diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 0d43da3..df297cf 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -27,6 +27,13 @@ #include +// Set the hardware driver to use (initialized by MySensor-class) +#if defined __AVR_ATmega328P__ +#include "MyHwATMega328.h" +typedef MyHwATMega328 MyHwDriver; +#endif + + #ifdef DEBUG #define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__) #else From dbe06255fcc95a86ec09488d339c40b98c0a0071 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 20 Mar 2015 19:47:32 +0100 Subject: [PATCH 091/660] New data type V_ID used for sensors with id such as DS1820b --- libraries/MySensors/MyMessage.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 2616c32..c2698bc 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -39,7 +39,10 @@ typedef enum { V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF, V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME, V_LOCK_STATUS, - V_DUST_LEVEL, V_VOLTAGE, V_CURRENT, V_RGB, V_RGBW + V_DUST_LEVEL, V_VOLTAGE, V_CURRENT, + V_RGB, // Used for sending/receiving color information. Sent as ascii hex. RRGGBB (RR=red, GG=green, BB=blue component) + V_RGBW, // Used for sending/receiving color information. Sent as ascii hex. RRGGBBWW (WW=while component) + V_ID // Can be used for reporting ids for sensors such as DS1820b. } mysensor_data; // Type of internal messages (for internal messages) From adca8b5a4ce1d2cee8d854e919754bf1b42db56f Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 24 Mar 2015 10:58:28 +0100 Subject: [PATCH 092/660] Temporary OTA commit --- libraries/MySensors/MyConfig.h | 15 +- libraries/MySensors/MyHwATMega328.h | 2 + libraries/MySensors/MySensor.cpp | 30 +++ libraries/MySensors/MySensor.h | 41 +++ .../examples/RelayActuator/RelayActuator.ino | 4 +- libraries/MySensors/utility/SPIFlash.cpp | 246 ++++++++++++++++++ libraries/MySensors/utility/SPIFlash.h | 100 +++++++ 7 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 libraries/MySensors/utility/SPIFlash.cpp create mode 100644 libraries/MySensors/utility/SPIFlash.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index a4f8a53..5f6423f 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -6,10 +6,23 @@ // to see what is actually is happening when developing #define DEBUG -// Serial output baud rate +// Serial output baud rate (for debug prints and serial gateway) #define BAUD_RATE 115200 +/********************************** +* Over the air firmware updates +***********************************/ + +// The following define enables the safe over-the-air firmware update feature +// which requires external flash and the DualOptiBoot bootloader. +// Note: You can still have OTA FW updates without external flash but it +// requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE +#define MY_OTA_FIRMWARE_FEATURE + +// Slave select pin for external flash +#define MY_OTA_FLASH_SS 8 + /********************************** * Message Signing Settings diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 684ef59..b45a5b9 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -10,6 +10,8 @@ #include #include #include +#include + #ifdef __cplusplus diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index aa777d4..c8e118f 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -55,6 +55,30 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw } +#ifdef MY_OTA_FRIMWARE_FEATURE +// do a crc16 on the whole received firmware +static uint8_t MySensor::isValidFirmware() { + void* ptr = 0; + uint16_t crc = ~0; + int j; + + for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { + uint8_t a = pgm_read_byte((uint16_t) ptr + i); + crc ^= a; + for (j = 0; j < 8; ++j) + { + if (crc & 1) + crc = (crc >> 1) ^ 0xA001; + else + crc = (crc >> 1); + } + } + return crc == fc.crc; +} + +#endif + + void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { hw_init(); repeaterMode = _repeaterMode; @@ -71,6 +95,12 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); +#ifdef MY_OTA_FRIMWARE_FEATURE + // Read firmware config from EEPROM, i.e. type, version, CRC, blocks + hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); +#endif + + #ifdef MY_SIGNING_FEATURE // Read out the signing requirements from EEPROM hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index df297cf..bb68d01 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -61,6 +61,7 @@ typedef MyHwATMega328 MyHwDriver; // Search for a new parent node after this many transmission failures #define SEARCH_FAILURES 5 + struct NodeConfig { uint8_t nodeId; // Current node id @@ -72,6 +73,42 @@ struct ControllerConfig { uint8_t isMetric; }; + +// Size of each firmware block +#define FIRMWARE_BLOCK_SIZE 16 +// Number of times a firmware block should be requested before giving up +#define FIRMWARE_MAX_REQUESTS 5 + +// FW config structure, stored in eeprom +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; +} __attribute__((packed)) NodeFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; + uint16_t BLVersion; +} __attribute__((packed)) RequestFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; +} __attribute__((packed)) RequestFWBlock; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; + uint8_t data[FIRMWARE_BLOCK_SIZE]; +} __attribute__((packed)) ReplyFWBlock; + + #ifdef __cplusplus class MySensor { @@ -243,6 +280,10 @@ class MySensor protected: NodeConfig nc; // Essential settings for node to work ControllerConfig cc; // Configuration coming from controller +#ifdef MY_OTA_FIRMWARE_FEATURE + NodeFirmwareConfig fc; +#endif + bool repeaterMode; bool autoFindParent; bool isGateway; diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 9a7e7c7..615049d 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -3,6 +3,7 @@ #include #include +//#include #include #include #include @@ -14,8 +15,9 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRF69 radio; // Message signing driver (none default) -// MySigningNone signer; +//MySigningNone signer; // Select AtMega328 hardware profile MyHwATMega328 hw; // Construct MySensors library diff --git a/libraries/MySensors/utility/SPIFlash.cpp b/libraries/MySensors/utility/SPIFlash.cpp new file mode 100644 index 0000000..03d6a1a --- /dev/null +++ b/libraries/MySensors/utility/SPIFlash.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013 by Felix Rusu + * SPI Flash memory library for arduino/moteino. + * This works with 256byte/page SPI flash memory + * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * Minimal modifications should allow chips that have different page size but modifications + * DEPENDS ON: Arduino SPI library + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include + +byte SPIFlash::UNIQUEID[8]; + +/// IMPORTANT: NAND FLASH memory requires erase before write, because +/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s +/// See http://en.wikipedia.org/wiki/Flash_memory +/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command + +/// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response +/// get this from the datasheet of your flash chip +/// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) +/// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) +SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { + _slaveSelectPin = slaveSelectPin; + _jedecID = jedecID; +} + +/// Select the flash chip +void SPIFlash::select() { + noInterrupts(); + //save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + //set FLASH chip SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + SPI.begin(); + digitalWrite(_slaveSelectPin, LOW); +} + +/// UNselect the flash chip +void SPIFlash::unselect() { + digitalWrite(_slaveSelectPin, HIGH); + //restore SPI settings to what they were before talking to the FLASH chip + SPCR = _SPCR; + SPSR = _SPSR; + interrupts(); +} + +/// setup SPI, read device ID etc... +boolean SPIFlash::initialize() +{ + _SPCR = SPCR; + _SPSR = SPSR; + pinMode(_slaveSelectPin, OUTPUT); + unselect(); + wakeup(); + + if (_jedecID == 0 || readDeviceId() == _jedecID) { + command(SPIFLASH_STATUSWRITE, true); // Write Status Register + SPI.transfer(0); // Global Unprotect + unselect(); + return true; + } + return false; +} + +/// Get the manufacturer and device ID bytes (as a short word) +word SPIFlash::readDeviceId() +{ +#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo + command(SPIFLASH_IDREAD); // Read JEDEC ID +#else + select(); + SPI.transfer(SPIFLASH_IDREAD); +#endif + word jedecid = SPI.transfer(0) << 8; + jedecid |= SPI.transfer(0); + unselect(); + return jedecid; +} + +/// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize +/// Returns the byte pointer to the UNIQUEID byte array +/// Read UNIQUEID like this: +/// flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); } +/// or like this: +/// flash.readUniqueId(); byte* MAC = flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); } +byte* SPIFlash::readUniqueId() +{ + command(SPIFLASH_MACREAD); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + for (byte i=0;i<8;i++) + UNIQUEID[i] = SPI.transfer(0); + unselect(); + return UNIQUEID; +} + +/// read 1 byte from flash memory +byte SPIFlash::readByte(long addr) { + command(SPIFLASH_ARRAYREADLOWFREQ); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + byte result = SPI.transfer(0); + unselect(); + return result; +} + +/// read unlimited # of bytes +void SPIFlash::readBytes(long addr, void* buf, word len) { + command(SPIFLASH_ARRAYREAD); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(0); //"dont care" + for (word i = 0; i < len; ++i) + ((byte*) buf)[i] = SPI.transfer(0); + unselect(); +} + +/// Send a command to the flash chip, pass TRUE for isWrite when its a write command +void SPIFlash::command(byte cmd, boolean isWrite){ +#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo + DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH! + PORTB |= B00000001; +#endif + if (isWrite) + { + command(SPIFLASH_WRITEENABLE); // Write Enable + unselect(); + } + //wait for any write/erase to complete + // a time limit cannot really be added here without it being a very large safe limit + // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations + // a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the + // open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present + while(busy()); + select(); + SPI.transfer(cmd); +} + +/// check if the chip is busy erasing/writing +boolean SPIFlash::busy() +{ + /* + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + byte status = SPI.transfer(0); + unselect(); + return status & 1; + */ + return readStatus() & 1; +} + +/// return the STATUS register +byte SPIFlash::readStatus() +{ + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + byte status = SPI.transfer(0); + unselect(); + return status; +} + + +/// Write 1 byte to flash memory +/// WARNING: you can only write to previously erased memory locations (see datasheet) +/// use the block erase commands to first clear memory (write 0xFFs) +void SPIFlash::writeByte(long addr, uint8_t byt) { + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(byt); + unselect(); +} + +/// write 1-256 bytes to flash memory +/// WARNING: you can only write to previously erased memory locations (see datasheet) +/// use the block erase commands to first clear memory (write 0xFFs) +/// WARNING: if you write beyond a page boundary (or more than 256bytes), +/// the bytes will wrap around and start overwriting at the beginning of that same page +/// see datasheet for more details +void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + for (uint16_t i = 0; i < len; i++) + SPI.transfer(((byte*) buf)[i]); + unselect(); +} + +/// erase entire flash memory array +/// may take several seconds depending on size, but is non blocking +/// so you may wait for this to complete using busy() or continue doing +/// other things and later check if the chip is done with busy() +/// note that any command will first wait for chip to become available using busy() +/// so no need to do that twice +void SPIFlash::chipErase() { + command(SPIFLASH_CHIPERASE, true); + unselect(); +} + +/// erase a 4Kbyte block +void SPIFlash::blockErase4K(long addr) { + command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); +} + +/// erase a 32Kbyte block +void SPIFlash::blockErase32K(long addr) { + command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); +} + +void SPIFlash::sleep() { + command(SPIFLASH_SLEEP); + unselect(); +} + +void SPIFlash::wakeup() { + command(SPIFLASH_WAKE); + unselect(); +} + +/// cleanup +void SPIFlash::end() { + SPI.end(); +} \ No newline at end of file diff --git a/libraries/MySensors/utility/SPIFlash.h b/libraries/MySensors/utility/SPIFlash.h new file mode 100644 index 0000000..f0c071a --- /dev/null +++ b/libraries/MySensors/utility/SPIFlash.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013 by Felix Rusu + * SPI Flash memory library for arduino/moteino. + * This works with 256byte/page SPI flash memory + * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * Minimal modifications should allow chips that have different page size but modifications + * DEPENDS ON: Arduino SPI library + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPIFLASH_H_ +#define _SPIFLASH_H_ + +#if ARDUINO >= 100 +#include +#else +#include +#include "pins_arduino.h" +#endif + +#include + +/// IMPORTANT: NAND FLASH memory requires erase before write, because +/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s +/// See http://en.wikipedia.org/wiki/Flash_memory +/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command + +/// Standard SPI flash commands +/// Assuming the WP pin is pulled up (to disable hardware write protection) +/// To use any write commands the WEL bit in the status register must be set to 1. +/// This is accomplished by sending a 0x06 command before any such write/erase command. +/// The WEL bit in the status register resets to the logical “0” state after a +/// device power-up or reset. In addition, the WEL bit will be reset to the logical “0” state automatically under the following conditions: +/// • Write Disable operation completes successfully +/// • Write Status Register operation completes successfully or aborts +/// • Protect Sector operation completes successfully or aborts +/// • Unprotect Sector operation completes successfully or aborts +/// • Byte/Page Program operation completes successfully or aborts +/// • Sequential Program Mode reaches highest unprotected memory location +/// • Sequential Program Mode reaches the end of the memory array +/// • Sequential Program Mode aborts +/// • Block Erase operation completes successfully or aborts +/// • Chip Erase operation completes successfully or aborts +/// • Hold condition aborts +#define SPIFLASH_WRITEENABLE 0x06 // write enable +#define SPIFLASH_WRITEDISABLE 0x04 // write disable + +#define SPIFLASH_BLOCKERASE_4K 0x20 // erase one 4K block of flash memory +#define SPIFLASH_BLOCKERASE_32K 0x52 // erase one 32K block of flash memory +#define SPIFLASH_BLOCKERASE_64K 0xD8 // erase one 64K block of flash memory +#define SPIFLASH_CHIPERASE 0x60 // chip erase (may take several seconds depending on size) + // but no actual need to wait for completion (instead need to check the status register BUSY bit) +#define SPIFLASH_STATUSREAD 0x05 // read status register +#define SPIFLASH_STATUSWRITE 0x01 // write status register +#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy byte after 3 address bytes) +#define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) + +#define SPIFLASH_SLEEP 0xB9 // deep power down +#define SPIFLASH_WAKE 0xAB // deep power wake up +#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256bytes) +#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) + // Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) + // Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) +#define SPIFLASH_MACREAD 0x4B // read unique ID number (MAC) + +class SPIFlash { +public: + static byte UNIQUEID[8]; + SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + boolean initialize(); + void command(byte cmd, boolean isWrite=false); + byte readStatus(); + byte readByte(long addr); + void readBytes(long addr, void* buf, word len); + void writeByte(long addr, byte byt); + void writeBytes(long addr, const void* buf, uint16_t len); + boolean busy(); + void chipErase(); + void blockErase4K(long address); + void blockErase32K(long address); + word readDeviceId(); + byte* readUniqueId(); + + void sleep(); + void wakeup(); + void end(); +protected: + void select(); + void unselect(); + byte _slaveSelectPin; + uint16_t _jedecID; + byte _SPCR; + byte _SPSR; +}; + +#endif \ No newline at end of file From 663c0386ea72b9e49fb8b55736c4e02b2a1d6dd4 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 24 Mar 2015 11:05:48 +0100 Subject: [PATCH 093/660] Light Lux level data type added --- libraries/MySensors/MyMessage.h | 3 ++- libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index c2698bc..93edc74 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -42,7 +42,8 @@ typedef enum { V_DUST_LEVEL, V_VOLTAGE, V_CURRENT, V_RGB, // Used for sending/receiving color information. Sent as ascii hex. RRGGBB (RR=red, GG=green, BB=blue component) V_RGBW, // Used for sending/receiving color information. Sent as ascii hex. RRGGBBWW (WW=while component) - V_ID // Can be used for reporting ids for sensors such as DS1820b. + V_ID, // Can be used for reporting ids for sensors such as DS1820b. + V_LIGHT_LEVEL_LUX // Light level in lux } mysensor_data; // Type of internal messages (for internal messages) diff --git a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino index 441c65e..2896056 100644 --- a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino +++ b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino @@ -27,7 +27,7 @@ unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) BH1750 lightSensor; MySensor gw; -MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL); +MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL_LUX); uint16_t lastlux; void setup() From c1a9a53ab916f9d9c431af4d4b3c89726871f1d5 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 26 Mar 2015 14:30:07 +0100 Subject: [PATCH 094/660] WIP --- libraries/MySensors/MyConfig.h | 9 ++++++++- libraries/MySensors/MySensor.cpp | 29 ++++++++++++++++++++++++++++- libraries/MySensors/MySensor.h | 6 ++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 5f6423f..4e5b579 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -19,9 +19,16 @@ // Note: You can still have OTA FW updates without external flash but it // requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE #define MY_OTA_FIRMWARE_FEATURE - // Slave select pin for external flash #define MY_OTA_FLASH_SS 8 +// Number of times to request a fw block before giving up +#define MY_OTA_RETRY 5 +// Number of millisecons before re-request a fw block +#define MY_OTA_RETRY_DELAY 500 +// Bootloader version +#define MY_OTA_BOOTLOADER_MAJOR_VERSION 2 +#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 +#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) /********************************** diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index c8e118f..4be0330 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -57,7 +57,7 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_OTA_FRIMWARE_FEATURE // do a crc16 on the whole received firmware -static uint8_t MySensor::isValidFirmware() { +bool MySensor::isValidFirmware() { void* ptr = 0; uint16_t crc = ~0; int j; @@ -188,6 +188,33 @@ void MySensor::setupNode() { // Wait configuration reply. wait(2000); + +#ifdef MY_OTA_FRIMWARE_FEATURE + RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)msg.data; + mSetLength(msg, sizeof(RequestFirmwareConfig)); + mSetCommand(msg, C_STREAM); + mSetPayloadType(msg,P_CUSTOM); + // copy node settings to reqFWConfig + memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig)); + // add bootloader information + reqFWConfig->BLVersion = MYSBOOTLOADER_VERSION; + + // send node config and request FW config from controller + if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE)) { + startup(); + } + + NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data; + + // compare with current node configuration, if equal startup + if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + startup(); + } + + +#endif + + } } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index bb68d01..40e5cd4 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -309,6 +309,12 @@ class MySensor void (*timeCallback)(unsigned long); // Callback for requested time messages void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. +#ifdef MY_OTA_FRIMWARE_FEATURE +// do a crc16 on the whole received firmware + bool isValidFirmware(); +#endif + + void requestNodeId(); void setupNode(); void findParentNode(); From 6da96e7d40e785ded232450adfe41cfc120da6e1 Mon Sep 17 00:00:00 2001 From: tekka Date: Thu, 26 Mar 2015 14:33:44 +0100 Subject: [PATCH 095/660] adding back time handler was missing in dev branch --- libraries/MySensors/MySensor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index aa777d4..ebb69ef 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -506,6 +506,11 @@ boolean MySensor::process() { findParentNode(); sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } + } else if (type == I_TIME) { + if (timeCallback != NULL) { + // Deliver time to callback + timeCallback(msg.getULong()); + } } return false; } From 3a59929b8ed8e1fca9876031264db5d6626876ff Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 30 Mar 2015 10:28:57 +0200 Subject: [PATCH 096/660] Initial untested OTA feature --- libraries/MySensors/MyConfig.h | 10 +- libraries/MySensors/MyHwATMega328.h | 1 - libraries/MySensors/MySensor.cpp | 137 +++++++++++++++++++++++----- libraries/MySensors/MySensor.h | 21 ++++- 4 files changed, 136 insertions(+), 33 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 4e5b579..4b7b4f1 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -21,14 +21,8 @@ #define MY_OTA_FIRMWARE_FEATURE // Slave select pin for external flash #define MY_OTA_FLASH_SS 8 -// Number of times to request a fw block before giving up -#define MY_OTA_RETRY 5 -// Number of millisecons before re-request a fw block -#define MY_OTA_RETRY_DELAY 500 -// Bootloader version -#define MY_OTA_BOOTLOADER_MAJOR_VERSION 2 -#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 -#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) +// Flash jdecid +#define MY_OTA_FLASH_JDECID 0x1F65 /********************************** diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index b45a5b9..8610f1b 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -10,7 +10,6 @@ #include #include #include -#include diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 4be0330..c05df58 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -49,13 +49,16 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw radio(_radio), #ifdef MY_SIGNING_FEATURE signer(_signer), +#endif +#ifdef MY_OTA_FIRMWARE_FEATURE + flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID), #endif hw(_hw) { } -#ifdef MY_OTA_FRIMWARE_FEATURE +#ifdef MY_OTA_FIRMWARE_FEATURE // do a crc16 on the whole received firmware bool MySensor::isValidFirmware() { void* ptr = 0; @@ -63,7 +66,7 @@ bool MySensor::isValidFirmware() { int j; for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - uint8_t a = pgm_read_byte((uint16_t) ptr + i); + uint8_t a = flash.readByte((uint16_t) ptr + i + FIRMWARE_START_OFFSET); crc ^= a; for (j = 0; j < 8; ++j) { @@ -95,7 +98,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); -#ifdef MY_OTA_FRIMWARE_FEATURE +#ifdef MY_OTA_FIRMWARE_FEATURE // Read firmware config from EEPROM, i.e. type, version, CRC, blocks hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); #endif @@ -189,7 +192,7 @@ void MySensor::setupNode() { // Wait configuration reply. wait(2000); -#ifdef MY_OTA_FRIMWARE_FEATURE +#ifdef MY_OTA_FIRMWARE_FEATURE RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)msg.data; mSetLength(msg, sizeof(RequestFirmwareConfig)); mSetCommand(msg, C_STREAM); @@ -197,21 +200,9 @@ void MySensor::setupNode() { // copy node settings to reqFWConfig memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig)); // add bootloader information - reqFWConfig->BLVersion = MYSBOOTLOADER_VERSION; - - // send node config and request FW config from controller - if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE)) { - startup(); - } - - NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data; - - // compare with current node configuration, if equal startup - if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { - startup(); - } - - + reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; + fwUpdateOngoing = false; + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); #endif @@ -408,7 +399,29 @@ boolean MySensor::process() { hw_watchdogReset(); uint8_t to = 0; if (!radio.available(&to)) + { +#ifdef MY_OTA_FIRMWARE_FEATURE + unsigned long enter = hw_millis(); + if (fwUpdateOngoing && (enter - fwLastRequestTime > MY_OTA_RETRY_DELAY)) { + if (fwRetry == 0) { + debug(PSTR("fw upd fail\n")); + // Give up. We have requested MY_OTA_RETRY times without any packet in return. + fwUpdateOngoing = false; + return false; + } + fwRetry--; + fwLastRequestTime = enter; + // Time to (re-)request firmware block from controller + RequestFWBlock *firmwareRequest = (RequestFWBlock *)msg.data; + mSetLength(msg, sizeof(RequestFWBlock)); + firmwareRequest->type = fc.type; + firmwareRequest->version = fc.version; + firmwareRequest->block = (fwBlock - 1); + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); + } +#endif return false; + } #ifdef MY_SIGNING_FEATURE (void)signer.checkTimer(); // Manage signing timeout @@ -567,6 +580,55 @@ boolean MySensor::process() { return false; } } +#ifdef MY_OTA_FIRMWARE_FEATURE + else if (command == C_STREAM) { + if (type == ST_FIRMWARE_CONFIG_RESPONSE) { + NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)msg.data; + // compare with current node configuration, if they differ, start fw fetch process + if (memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + debug(PSTR("fw update\n")); + fwUpdateOngoing = true; + fwBlock = fc.blocks; + // copy new FW config + memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); + // Init flash + if (!flash.initialize()) { + debug(PSTR("flash init fail\n")); + } + + } + } else if (type == ST_FIRMWARE_RESPONSE) { + // Save block to eeprom + debug(PSTR("fw block %d\n"), fwBlock); + + ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data; + // write to flash + flash.writeBytes(((fwBlock-1)*FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + fwBlock--; + if (fwBlock == 0) { + // We're finished! Do a checksum and reboot. + if (isValidFirmware()) { + debug(PSTR("fw checksum ok\n")); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + uint16_t fwsize = FIRMWARE_BLOCK_SIZE*fc.blocks; + flash.writeBytes(0, "FLXIMG:", 7); + flash.writeByte(7, fwsize >> 8); + flash.writeByte(8, fwsize); + flash.writeByte(9, ':'); + // Write the new firmware config to eeprom + hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hw_reboot(); + } else { + debug(PSTR("fw checksum fail\n")); + } + } + } + // Make sure packet request occurs next time process() is called by timing out requestTime. + fwRetry = MY_OTA_RETRY+1; + fwLastRequestTime = 0; + return false; + } +#endif // Call incoming message callback if available if (msgCallback != NULL) { msgCallback(msg); @@ -613,17 +675,46 @@ void MySensor::wait(unsigned long ms) { } void MySensor::sleep(unsigned long ms) { - radio.powerDown(); - hw.sleep(ms); +#ifdef MY_OTA_FIRMWARE_FEATURE + if (fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + } else { +#endif + radio.powerDown(); + hw.sleep(ms); +#ifdef MY_OTA_FIRMWARE_FEATURE + } +#endif } bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { +#ifdef MY_OTA_FIRMWARE_FEATURE + if (fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + return false; + } else { +#endif radio.powerDown(); return hw.sleep(interrupt, mode, ms) ; +#ifdef MY_OTA_FIRMWARE_FEATURE + } +#endif } int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - radio.powerDown(); - return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ; +#ifdef MY_OTA_FIRMWARE_FEATURE + if (fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + return -1; + } else { +#endif + radio.powerDown(); + return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ; +#ifdef MY_OTA_FIRMWARE_FEATURE + } +#endif } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 40e5cd4..7873c22 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -23,6 +23,9 @@ #include "MySigningNone.h" #endif #include "MyMessage.h" +#ifdef MY_OTA_FIRMWARE_FEATURE +#include "utility/SPIFlash.h" +#endif #include #include @@ -78,6 +81,17 @@ struct ControllerConfig { #define FIRMWARE_BLOCK_SIZE 16 // Number of times a firmware block should be requested before giving up #define FIRMWARE_MAX_REQUESTS 5 +// Number of times to request a fw block before giving up +#define MY_OTA_RETRY 5 +// Number of millisecons before re-request a fw block +#define MY_OTA_RETRY_DELAY 500 +// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#define FIRMWARE_START_OFFSET 10 +// Bootloader version +#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 +#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 +#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) + // FW config structure, stored in eeprom typedef struct { @@ -282,6 +296,11 @@ class MySensor ControllerConfig cc; // Configuration coming from controller #ifdef MY_OTA_FIRMWARE_FEATURE NodeFirmwareConfig fc; + bool fwUpdateOngoing; + unsigned long fwLastRequestTime; + uint16_t fwBlock; + uint8_t fwRetry; + SPIFlash flash; #endif bool repeaterMode; @@ -309,7 +328,7 @@ class MySensor void (*timeCallback)(unsigned long); // Callback for requested time messages void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. -#ifdef MY_OTA_FRIMWARE_FEATURE +#ifdef MY_OTA_FIRMWARE_FEATURE // do a crc16 on the whole received firmware bool isValidFirmware(); #endif From 0373b71a03365cd0235c1b5c0093b7446fb18e02 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 30 Mar 2015 11:56:55 +0200 Subject: [PATCH 097/660] Fix Serial GW constructor --- .../MySensors/examples/SerialGateway/SerialGateway.ino | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 8dc5e26..d103407 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -23,8 +23,9 @@ #define NO_PORTB_PINCHANGES -#include #include +#include + #include #include #include @@ -43,9 +44,11 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Message signing driver (none default) -MySigningNone signer; +//MySigningNone signer; // Construct MySensors library -MySensor gw(radio, signer); +MyHwATMega328 hw; + +MySensor gw(radio, hw); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; From 44406c28351ed8d33875efd650342e0cf0490506 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 30 Mar 2015 22:44:10 +0200 Subject: [PATCH 098/660] Add driver-options to gateways. --- libraries/MySensors/MyConfig.h | 2 +- libraries/MySensors/MySensor.h | 4 ++-- .../EthernetGateway/EthernetGateway.ino | 24 +++++++++++++++---- .../examples/MQTTGateway/MQTTGateway.ino | 24 +++++++++++++++---- .../examples/SerialGateway/SerialGateway.ino | 19 +++++++++++---- 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 4b7b4f1..d4a0633 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -18,7 +18,7 @@ // which requires external flash and the DualOptiBoot bootloader. // Note: You can still have OTA FW updates without external flash but it // requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE -#define MY_OTA_FIRMWARE_FEATURE +//#define MY_OTA_FIRMWARE_FEATURE // Slave select pin for external flash #define MY_OTA_FLASH_SS 8 // Flash jdecid diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 7873c22..40b44bb 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -31,10 +31,10 @@ // Set the hardware driver to use (initialized by MySensor-class) -#if defined __AVR_ATmega328P__ +//#if defined __AVR_ATmega328P__ #include "MyHwATMega328.h" typedef MyHwATMega328 MyHwDriver; -#endif +//#endif #ifdef DEBUG diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index bde2cf1..81f65f6 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -44,7 +44,12 @@ #include #include +#include #include +#include +#include +#include + #include #include #include @@ -72,11 +77,20 @@ // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -// Message signing driver (none default) -MySigningNone signer; -// Construct MySensors library -MySensor gw(radio, signer); +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRF69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +//MySigningNone signer; +//MySigningAtsha204Soft signer; +//MySigningAtsha204 signer; + +// Hardware profile +MyHwATMega328 hw; + +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +MySensor gw(transport, hw /*, signer*/); + #define IP_PORT 5003 // The port you want to open IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later! diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 169ad89..4742331 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -60,7 +60,12 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include +#include #include +#include +#include +#include + #include #include #include @@ -94,11 +99,20 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You ////////////////////////////////////////////////////////////////// // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -// Message signing driver (none default) -MySigningNone signer; -// Construct MySensors library -MySensor gw(radio, signer); +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRF69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +//MySigningNone signer; +//MySigningAtsha204Soft signer; +//MySigningAtsha204 signer; + +// Hardware profile +MyHwATMega328 hw; + +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +MySensor gw(transport, hw /*, signer*/); + EthernetServer server = EthernetServer(TCP_PORT); MyMessage msg; diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index d103407..a1b01e4 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -23,8 +23,12 @@ #define NO_PORTB_PINCHANGES +#include +#include #include #include +#include +#include #include #include @@ -40,15 +44,20 @@ #define RADIO_RX_LED_PIN 6 // Receive led pin #define RADIO_TX_LED_PIN 5 // the PCB, on board LED - // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -// Message signing driver (none default) +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRF69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) //MySigningNone signer; -// Construct MySensors library +//MySigningAtsha204Soft signer; +//MySigningAtsha204 signer; + +// Hardware profile MyHwATMega328 hw; -MySensor gw(radio, hw); +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +MySensor gw(transport, hw /*, signer*/); char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; From 527b2332da1cfffd50e20484fc83badd6ce8ecea Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 31 Mar 2015 23:44:38 +0200 Subject: [PATCH 099/660] Correct initialization for gateway --- libraries/MySensors/MySensor.cpp | 63 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 91644e0..70d3680 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -88,56 +88,55 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b msgCallback = _msgCallback; failedTransmissions = 0; - // Only gateway should use node id 0 - isGateway = _nodeId == 0; + // Only gateway should use node id 0! + isGateway = _nodeId == GATEWAY_ADDRESS; // Setup radio radio.init(); - // Read settings from eeprom - hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); - // Read latest received controller configuration from EEPROM - hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); -#ifdef MY_OTA_FIRMWARE_FEATURE - // Read firmware config from EEPROM, i.e. type, version, CRC, blocks - hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); -#endif - - #ifdef MY_SIGNING_FEATURE // Read out the signing requirements from EEPROM hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); #endif if (isGateway) { + // Set configuration for gateway + nc.parentNodeId = 0; nc.distance = 0; - } + nc.nodeId = 0; + } else { + // Read settings from eeprom + hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + // Read latest received controller configuration from EEPROM + hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); +#ifdef MY_OTA_FIRMWARE_FEATURE + // Read firmware config from EEPROM, i.e. type, version, CRC, blocks + hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); +#endif - if (cc.isMetric == 0xff) { - // Eeprom empty, set default to metric - cc.isMetric = 0x01; - } + if (cc.isMetric == 0xff) { + // Eeprom empty, set default to metric + cc.isMetric = 0x01; + } - autoFindParent = _parentNodeId == AUTO; - if (!autoFindParent) { - nc.parentNodeId = _parentNodeId; - // Save static parent id in eeprom (used by bootloader) - hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); - // We don't actually know the distance to gw here. Let's pretend it is 1. - // If the current node is also repeater, be aware of this. - nc.distance = 1; - } else if (!isValidParent(nc.parentNodeId)) { - // Auto find parent, but parent in eeprom is invalid. Try find one. - findParentNode(); - } + autoFindParent = _parentNodeId == AUTO; + if (!autoFindParent) { + nc.parentNodeId = _parentNodeId; + // Save static parent id in eeprom (used by bootloader) + hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); + // We don't actually know the distance to gw here. Let's pretend it is 1. + // If the current node is also repeater, be aware of this. + nc.distance = 1; + } else if (!isValidParent(nc.parentNodeId)) { + // Auto find parent, but parent in eeprom is invalid. Try find one. + findParentNode(); + } - if (!isGateway) { if (_nodeId != AUTO) { // Set static id nc.nodeId = _nodeId; // Save static id in eeprom - if (_nodeId > 0) - hw_writeConfig(EEPROM_NODE_ID_ADDRESS, _nodeId); + hw_writeConfig(EEPROM_NODE_ID_ADDRESS, _nodeId); } else if (isValidParent(nc.parentNodeId)) { // Try to fetch node-id from gateway requestNodeId(); From 6165834038810e46e58f7c56dc890e90875cf861 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 31 Mar 2015 23:46:36 +0200 Subject: [PATCH 100/660] RFM69 cleanup Corrected initialization of radio Add constructor arguments for driver Add defaults to MyConfig Fix ack problems reported on forum. --- libraries/MySensors/MyConfig.h | 29 ++++++++-- libraries/MySensors/MyTransportRF69.cpp | 57 ------------------- libraries/MySensors/MyTransportRF69.h | 44 -------------- libraries/MySensors/MyTransportRFM69.cpp | 54 ++++++++++++++++++ libraries/MySensors/MyTransportRFM69.h | 29 ++++++++++ .../EthernetGateway/EthernetGateway.ino | 4 +- .../examples/MQTTGateway/MQTTGateway.ino | 4 +- .../examples/RelayActuator/RelayActuator.ino | 4 +- .../examples/SerialGateway/SerialGateway.ino | 4 +- 9 files changed, 116 insertions(+), 113 deletions(-) delete mode 100644 libraries/MySensors/MyTransportRF69.cpp delete mode 100644 libraries/MySensors/MyTransportRF69.h create mode 100644 libraries/MySensors/MyTransportRFM69.cpp create mode 100644 libraries/MySensors/MyTransportRFM69.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index d4a0633..d274fe0 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -65,11 +65,14 @@ #define RF24_CS_PIN 10 #define RF24_PA_LEVEL RF24_PA_MAX #define RF24_PA_LEVEL_GW RF24_PA_LOW -#define RF24_CHANNEL 76 //RF channel for the sensor net, 0-127 -#define RF24_DATARATE RF24_250KBPS //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps -#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. +// RF channel for the sensor net, 0-127 +#define RF24_CHANNEL 76 +//RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps +#define RF24_DATARATE RF24_250KBPS +// This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. +#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) -// Enable SOFTSPI for the W5100 Ethernet module +// Enable SOFTSPI for NRF24L01 when using the W5100 Ethernet module //#define SOFTSPI #ifdef SOFTSPI // Define the soft SPI pins used for NRF radio @@ -79,4 +82,22 @@ #endif +/********************************** +* RFM69 Driver Defaults +***********************************/ +// Default network id. Use the same for all nodes that will talk to each other +#define RFM69_NETWORKID 100 + +// Default frequency to use. This must match the hardware version of the RFM69 radio (uncomment one): +// #define RFM69_FREQUENCY RF69_433MHZ +#define RFM69_FREQUENCY RF69_868MHZ +//#define FREQUENCY RF69_915MHZ + +// Enable this for encryption of packets +//#define RFM69_ENABLE_ENCRYPTION +#define RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! + + + + #endif diff --git a/libraries/MySensors/MyTransportRF69.cpp b/libraries/MySensors/MyTransportRF69.cpp deleted file mode 100644 index b55ce14..0000000 --- a/libraries/MySensors/MyTransportRF69.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "MyTransport.h" -#include "MyTransportRF69.h" - -MyTransportRF69::MyTransportRF69() - : - MyTransport(), - radio() -{ -} - -void MyTransportRF69::init() { - // Start up the radio library - radio->initialize(FREQUENCY,_address,NETWORKID); -#ifdef IS_RFM69HW - radio->setHighPower(); //uncomment only for RFM69HW! -#endif - // radio->encrypt(ENCRYPTKEY); - -} - -void MyTransportRF69::setAddress(uint8_t address) { - _address = address; - radio->setAddress(address); -} - -uint8_t MyTransportRF69::getAddress() { - return _address; -} - -bool MyTransportRF69::send(uint8_t to, const void* data, uint8_t len) { - // Make sure radio has powered up - return radio->sendWithRetry(to,data,len); -} - -bool MyTransportRF69::available(uint8_t *to) { - if (radio->TARGETID == BROADCAST_ADDRESS) - *to = BROADCAST_ADDRESS; - else - *to = _address; - return radio->receiveDone(); -} - -uint8_t MyTransportRF69::receive(void* data) { - // for (byte i = 0; i < radio->DATALEN; i++){ - // data[i]= (void)radio->DATA[i]; - // } - memcpy(data,(const void *)radio->DATA, radio->DATALEN); - if (radio->ACKRequested()) - { - radio->sendACK(); - } - return radio->DATALEN; -} - -void MyTransportRF69::powerDown() { - radio->sleep(); -} diff --git a/libraries/MySensors/MyTransportRF69.h b/libraries/MySensors/MyTransportRF69.h deleted file mode 100644 index 687259d..0000000 --- a/libraries/MySensors/MyTransportRF69.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef MyTransportRF69_h -#define MyTransportRF69_h - -#include "MyConfig.h" -#include "MyTransport.h" -#include -#include "utility/RFM69.h" -#include - -#define NODEID 2 //unique for each node on same network -#define NETWORKID 100 //the same on all nodes that talk to each other -#define GATEWAYID 1 -//Match frequency to the hardware version of the radio on your Moteino (uncomment one): -// #define FREQUENCY RF69_433MHZ -#define FREQUENCY RF69_868MHZ -//#define FREQUENCY RF69_915MHZ -#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! -//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! -#define ACK_TIME 30 // max # of ms to wait for an ack -#ifdef __AVR_ATmega1284P__ - #define LED 15 // Moteino MEGAs have LEDs on D15 - #define FLASH_SS 23 // and FLASH SS on D23 -#else - #define LED 9 // Moteinos have LEDs on D9 - #define FLASH_SS 8 // and FLASH SS on D8 -#endif - -class MyTransportRF69 : public MyTransport -{ -public: - MyTransportRF69(); - void init(); - void setAddress(uint8_t address); - uint8_t getAddress(); - bool send(uint8_t to, const void* data, uint8_t len); - bool available(uint8_t *to); - uint8_t receive(void* data); - void powerDown(); -private: - RFM69 *radio; - uint8_t _address; -}; - -#endif diff --git a/libraries/MySensors/MyTransportRFM69.cpp b/libraries/MySensors/MyTransportRFM69.cpp new file mode 100644 index 0000000..c387816 --- /dev/null +++ b/libraries/MySensors/MyTransportRFM69.cpp @@ -0,0 +1,54 @@ +#include "MyTransport.h" +#include "MyTransportRFM69.h" + +MyTransportRFM69::MyTransportRFM69(uint8_t freqBand, uint8_t networkId, uint8_t slaveSelectPin, uint8_t interruptPin, bool isRFM69HW, uint8_t interruptNum) + : + MyTransport(), + radio(slaveSelectPin, interruptPin, isRFM69HW, interruptNum), + _freqBand(freqBand), + _networkId(networkId) +{ +} + +void MyTransportRFM69::init() { + // Start up the radio library (_address will be set later by the MySensors library) + radio.initialize(_freqBand, _address, _networkId); +#ifdef RFM69_ENABLE_ENCRYPTION + radio.encrypt(ENCRYPTKEY); +#endif + +} + +void MyTransportRFM69::setAddress(uint8_t address) { + _address = address; + radio.setAddress(address); +} + +uint8_t MyTransportRFM69::getAddress() { + return _address; +} + +bool MyTransportRFM69::send(uint8_t to, const void* data, uint8_t len) { + return radio.sendWithRetry(to,data,len); +} + +bool MyTransportRFM69::available(uint8_t *to) { + if (radio.TARGETID == BROADCAST_ADDRESS) + *to = BROADCAST_ADDRESS; + else + *to = _address; + return radio.receiveDone(); +} + +uint8_t MyTransportRFM69::receive(void* data) { + memcpy(data,(const void *)radio.DATA, radio.DATALEN); + // Send ack back if this message wasn't a broadcast + if (radio.TARGETID != RF69_BROADCAST_ADDR) + radio.ACKRequested(); + radio.sendACK(); + return radio.DATALEN; +} + +void MyTransportRFM69::powerDown() { + radio.sleep(); +} diff --git a/libraries/MySensors/MyTransportRFM69.h b/libraries/MySensors/MyTransportRFM69.h new file mode 100644 index 0000000..7b3821a --- /dev/null +++ b/libraries/MySensors/MyTransportRFM69.h @@ -0,0 +1,29 @@ +#ifndef MyTransportRF69_h +#define MyTransportRF69_h + +#include "MyConfig.h" +#include "MyTransport.h" +#include +#include "utility/RFM69.h" +#include + + +class MyTransportRFM69 : public MyTransport +{ +public: + MyTransportRFM69(uint8_t freqBand=RFM69_FREQUENCY, uint8_t networkId=RFM69_NETWORKID, uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM); + void init(); + void setAddress(uint8_t address); + uint8_t getAddress(); + bool send(uint8_t to, const void* data, uint8_t len); + bool available(uint8_t *to); + uint8_t receive(void* data); + void powerDown(); +private: + RFM69 radio; + uint8_t _address; + uint8_t _freqBand; + uint8_t _networkId; +}; + +#endif diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 81f65f6..c653ab4 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -44,7 +44,7 @@ #include #include -#include +#include #include #include #include @@ -78,7 +78,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRF69 transport; +//MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) //MySigningNone signer; diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 4742331..006a785 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -60,7 +60,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include -#include +#include #include #include #include @@ -100,7 +100,7 @@ uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRF69 transport; +//MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) //MySigningNone signer; diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 615049d..93e93c2 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -3,7 +3,7 @@ #include #include -//#include +#include #include #include #include @@ -15,7 +15,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRF69 radio; +//MyTransportRFM69 radio; // Message signing driver (none default) //MySigningNone signer; // Select AtMega328 hardware profile diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index a1b01e4..266fdb7 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -24,7 +24,7 @@ #define NO_PORTB_PINCHANGES #include -#include +#include #include #include #include @@ -46,7 +46,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRF69 transport; +//MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) //MySigningNone signer; From 410a8869cbdb59de7923a149d5a43efdc640fc31 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 1 Apr 2015 00:50:25 +0200 Subject: [PATCH 101/660] Add V_UNIT_PREFIX and started documenting variable and sensor types. --- libraries/MySensors/MyMessage.h | 91 ++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 93edc74..e552f13 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -34,16 +34,54 @@ typedef enum { // Type of sensor data (for set/req/ack messages) typedef enum { - V_TEMP,V_HUM, V_LIGHT, V_DIMMER, V_PRESSURE, V_FORECAST, V_RAIN, - V_RAINRATE, V_WIND, V_GUST, V_DIRECTION, V_UV, V_WEIGHT, V_DISTANCE, - V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF, - V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, - V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME, V_LOCK_STATUS, - V_DUST_LEVEL, V_VOLTAGE, V_CURRENT, - V_RGB, // Used for sending/receiving color information. Sent as ascii hex. RRGGBB (RR=red, GG=green, BB=blue component) - V_RGBW, // Used for sending/receiving color information. Sent as ascii hex. RRGGBBWW (WW=while component) - V_ID, // Can be used for reporting ids for sensors such as DS1820b. - V_LIGHT_LEVEL_LUX // Light level in lux + V_TEMP, // S_TEMP + V_HUM, // S_HUM + V_LIGHT, // S_LIGHT (Light level in uncalibrated percentage) + V_DIMMER, // S_DIMMER + V_PRESSURE, // S_BARO + V_FORECAST, // S_BARO + V_RAIN, // S_RAIN + V_RAINRATE, // S_RAIN + V_WIND, // S_WIND + V_GUST, // S_WIND + V_DIRECTION, // S_WIND + V_UV, // S_UV + V_WEIGHT, // S_WEIGHT + V_DISTANCE, // S_DISTANCE + V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT + V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, + V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, + V_WATT, // S_POWER + V_KWH, // S_POWER + V_SCENE_ON, // S_SCENE_CONTROLLER + V_SCENE_OFF, // S_SCENE_CONTROLLER + V_HEATER, // S_HEATER + V_HEATER_SW, // S_HEATER + V_LIGHT_LEVEL, // S_LIGHT_LEVEL + V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, + V_UP, // S_COVER + V_DOWN, // S_COVER + V_STOP, // S_COVER + V_IR_SEND, // S_IR + V_IR_RECEIVE, // S_IR + V_FLOW, // S_WATER + V_VOLUME, // S_WATER + V_LOCK_STATUS, // S_LOCK + V_DUST_LEVEL, // S_DUST + V_VOLTAGE, // S_MULTIMETER + V_CURRENT, // S_MULTIMETER + V_RGB, // S_RGB_LIGHT, S_COLOR_SENSOR. + // Used for sending color information for led lighting or color sensors. + // Sent as ascii hex. RRGGBB (RR=red, GG=green, BB=blue component) + V_RGBW, // S_RGB_LIGHT + // Used for sending color information to led lighting. + // Sent as ascii hex. RRGGBBWW (WW=while component) + V_ID, // S_TEMP + // Used for reporting the sensor internal ids (E.g. DS1820b). + V_LIGHT_LEVEL_LUX, // S_LIGHT, Light level in lux + V_UNIT_PREFIX // Allows sensors to send in a string representing the + // unit prefix to be displayed in GUI, not parsed! E.g. cm, m, km, inch. + // Can be used for S_DISTANCE } mysensor_data; // Type of internal messages (for internal messages) @@ -56,10 +94,35 @@ typedef enum { // Type of sensor (for presentation message) typedef enum { - S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, - S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, - S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER,S_COLOR, S_MULTIMETER + S_DOOR, + S_MOTION, + S_SMOKE, + S_LIGHT, + S_DIMMER, + S_COVER, + S_TEMP, + S_HUM, + S_BARO, + S_WIND, + S_RAIN, + S_UV, + S_WEIGHT, + S_POWER, + S_HEATER, + S_DISTANCE, + S_LIGHT_LEVEL, + S_ARDUINO_NODE, + S_ARDUINO_REPEATER_NODE, + S_LOCK, + S_IR, + S_WATER, + S_AIR_QUALITY, // V_VAR1 + S_CUSTOM, + S_DUST, // V_DUST_LEVEL + S_SCENE_CONTROLLER, // V_SCENE_ON, V_SCENE_OFF. + S_RGB_LIGHT, // Send data using V_RGB or V_RGBW + S_COLOR_SENSOR, // Send data using V_RGB + S_MULTIMETER // V_VOLTAGE, V_CURRENT, V_IMPEDANCE } mysensor_sensor; // Type of data stream (for streamed message) From be9cb8b1ffd6e57bf03c48fbec83b7aa59f899fc Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 2 Apr 2015 10:10:43 +0200 Subject: [PATCH 102/660] Watchdog Timer interrupt service routine added.Thanks @kolaf. --- libraries/MySensors/MyHwATMega328.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index 4f9d9a8..f7e58a4 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -11,6 +11,14 @@ void wakeUp2() //place to send the second interrupts pinIntTrigger = 2; } +// Watchdog Timer interrupt service routine. This routine is required +// to allow automatic WDIF and WDIE bit clearance in hardware. +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + MyHwATMega328::MyHwATMega328() : MyHw() { } From d2dacd8670c94827dfb7b102d9abfd1baa0f235f Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 2 Apr 2015 13:46:54 +0200 Subject: [PATCH 103/660] Fix id request problem at startup --- libraries/MySensors/MySensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 70d3680..a8e42ea 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -137,7 +137,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b nc.nodeId = _nodeId; // Save static id in eeprom hw_writeConfig(EEPROM_NODE_ID_ADDRESS, _nodeId); - } else if (isValidParent(nc.parentNodeId)) { + } else if (nc.nodeId == AUTO && isValidParent(nc.parentNodeId)) { // Try to fetch node-id from gateway requestNodeId(); } From caaadf44cf644b4d0432effaed9130957a75aec6 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 8 Apr 2015 21:14:52 +0200 Subject: [PATCH 104/660] Update file headers. --- libraries/MySensors/MyConfig.h | 20 +++ libraries/MySensors/MyHw.cpp | 19 +++ libraries/MySensors/MyHw.h | 19 +++ libraries/MySensors/MyHwATMega328.cpp | 19 +++ libraries/MySensors/MyHwATMega328.h | 19 +++ libraries/MySensors/MyMessage.cpp | 20 +++ libraries/MySensors/MyMessage.h | 27 ++-- libraries/MySensors/MyParser.cpp | 19 +++ libraries/MySensors/MyParser.h | 21 ++- libraries/MySensors/MyParserSerial.cpp | 19 +++ libraries/MySensors/MyParserSerial.h | 21 ++- libraries/MySensors/MySensor.cpp | 31 ++-- libraries/MySensors/MySensor.h | 27 ++-- libraries/MySensors/MySigning.cpp | 19 +++ libraries/MySensors/MySigning.h | 32 ++++- libraries/MySensors/MySigningAtsha204.cpp | 33 ++++- libraries/MySensors/MySigningAtsha204.h | 33 ++++- libraries/MySensors/MySigningAtsha204Soft.cpp | 39 ++++-- libraries/MySensors/MySigningAtsha204Soft.h | 39 ++++-- libraries/MySensors/MySigningNone.cpp | 32 ++++- libraries/MySensors/MySigningNone.h | 32 ++++- libraries/MySensors/MyTransport.cpp | 19 +++ libraries/MySensors/MyTransport.h | 19 +++ libraries/MySensors/MyTransportNRF24.cpp | 19 +++ libraries/MySensors/MyTransportNRF24.h | 19 +++ libraries/MySensors/MyTransportRFM69.cpp | 19 +++ libraries/MySensors/MyTransportRFM69.h | 19 +++ libraries/MySensors/Version.h | 4 +- .../AirQualitySensor/AirQualitySensor.ino | 52 ++++--- .../BatteryPoweredSensor.ino | 31 +++- .../BinarySwitchSensor/BinarySwitchSensor.ino | 31 +++- .../BinarySwitchSleepSensor.ino | 37 ++++- .../ClearEepromConfig/ClearEepromConfig.ino | 30 +++- .../DallasTemperatureSensor.ino | 27 +++- .../DimmableLEDActuator.ino | 32 +++-- .../examples/DimmableLight/DimmableLight.ino | 27 +++- .../DistanceSensor/DistanceSensor.ino | 28 ++++ .../examples/DustSensor/DustSensor.ino | 57 +++++--- .../EnergyMeterPulseSensor.ino | 43 ++++-- .../EthernetGateway/EthernetGateway.ino | 29 +++- .../examples/EthernetGateway/GatewayUtil.h | 3 +- .../HumiditySensor/HumiditySensor.ino | 29 ++++ .../MySensors/examples/IrSensor/IrSensor.ino | 38 ++++- .../LightLuxSensor/LightLuxSensor.ino | 55 +++++--- .../examples/LightSensor/LightSensor.ino | 28 ++++ .../MAX6875TemperatureSensor.ino | 47 +++++-- .../examples/MQTTGateway/MQTTGateway.ino | 132 ++++++++++-------- .../examples/MotionSensor/MotionSensor.ino | 29 ++++ .../examples/MysensorMicro/MysensorMicro.ino | 39 +++++- .../PressureSensor/PressureSensor.ino | 29 ++++ .../RF433MhzSensor/RF433MhzSensor.ino | 26 +++- .../RFIDLockSensor/RFIDLockSensor.ino | 67 ++++++--- .../RealTimeClockDisplaySensor.ino | 55 ++++++-- .../examples/RelayActuator/RelayActuator.ino | 30 +++- .../RelayWithButtonActuator.ino | 34 ++++- .../examples/RepeaterNode/RepeaterNode.ino | 33 ++++- .../SecretKnockSensor/SecretKnockSensor.ino | 76 ++++++---- .../SecureActuator/SecureActuator.ino | 30 +++- .../examples/SerialGateway/GatewayUtil.h | 24 +++- .../examples/SerialGateway/SerialGateway.ino | 27 +++- .../examples/ServoActuator/ServoActuator.ino | 38 ++++- .../Sha204Personalizer/Sha204Personalizer.ino | 63 ++++++--- .../SoilMoistSensor/SoilMoistSensor.ino | 28 ++++ .../TimeAwareSensor/TimeAwareSensor.ino | 28 +++- .../TouchDisplaySceneControllerSensor.ino | 27 +++- .../MySensors/examples/UVSensor/UVSensor.ino | 55 +++++--- .../WaterMeterPulseSensor.ino | 44 ++++-- 67 files changed, 1795 insertions(+), 401 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index d274fe0..437ef3e 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -1,3 +1,23 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + + #ifndef MyConfig_h #define MyConfig_h #include diff --git a/libraries/MySensors/MyHw.cpp b/libraries/MySensors/MyHw.cpp index 75f020d..3016a6b 100644 --- a/libraries/MySensors/MyHw.cpp +++ b/libraries/MySensors/MyHw.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyHw.h" MyHw::MyHw() { diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/MyHw.h index 14857c6..74ceb13 100644 --- a/libraries/MySensors/MyHw.h +++ b/libraries/MySensors/MyHw.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyHw_h #define MyHw_h diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index f7e58a4..2281e6c 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyHw.h" #include "MyHwATMega328.h" diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 8610f1b..ccb35ba 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyHwATMega328_h #define MyHwATMega328_h diff --git a/libraries/MySensors/MyMessage.cpp b/libraries/MySensors/MyMessage.cpp index 7143e9c..a0fab36 100755 --- a/libraries/MySensors/MyMessage.cpp +++ b/libraries/MySensors/MyMessage.cpp @@ -1,3 +1,23 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + + #include "MyMessage.h" #include #include diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index e552f13..c5b8612 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -1,14 +1,23 @@ -/* - The MySensors library adds a new layer on top of the RF24 library. - It handles radio network routing, relaying and ids. - - Created by Henrik Ekblad - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. */ + #ifndef MyMessage_h #define MyMessage_h diff --git a/libraries/MySensors/MyParser.cpp b/libraries/MySensors/MyParser.cpp index dacd32b..2011d16 100644 --- a/libraries/MySensors/MyParser.cpp +++ b/libraries/MySensors/MyParser.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyParser.h" MyParser::MyParser() { diff --git a/libraries/MySensors/MyParser.h b/libraries/MySensors/MyParser.h index e606a0d..39e2975 100644 --- a/libraries/MySensors/MyParser.h +++ b/libraries/MySensors/MyParser.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyParser_h #define MyParser_h @@ -13,4 +32,4 @@ public: // returns true if successfully parsed the input string virtual bool parse(MyMessage &message, char *inputString) = 0; }; -#endif \ No newline at end of file +#endif diff --git a/libraries/MySensors/MyParserSerial.cpp b/libraries/MySensors/MyParserSerial.cpp index 9c1aa88..e2ee52a 100644 --- a/libraries/MySensors/MyParserSerial.cpp +++ b/libraries/MySensors/MyParserSerial.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyParser.h" #include "MyParserSerial.h" #include "MyTransport.h" diff --git a/libraries/MySensors/MyParserSerial.h b/libraries/MySensors/MyParserSerial.h index e7baf9b..80d315d 100644 --- a/libraries/MySensors/MyParserSerial.h +++ b/libraries/MySensors/MyParserSerial.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyParserSerial_h #define MyParserSerial_h @@ -12,4 +31,4 @@ public: private: uint8_t h2i(char c); }; -#endif \ No newline at end of file +#endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index a8e42ea..2f98b9e 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -1,14 +1,23 @@ - /* - The MySensors library adds a new layer on top of the RF24 library. - It handles radio network routing, relaying and ids. - - Created by Henrik Ekblad - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. */ + #include "MySensor.h" #define DISTANCE_INVALID (0xFF) @@ -101,9 +110,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b if (isGateway) { // Set configuration for gateway - nc.parentNodeId = 0; + nc.parentNodeId = GATEWAY_ADDRESS; nc.distance = 0; - nc.nodeId = 0; + nc.nodeId = GATEWAY_ADDRESS; } else { // Read settings from eeprom hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 40b44bb..0081b90 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -1,13 +1,22 @@ -/* - The MySensors library adds a new layer on top of the RF24 library. - It handles radio network routing, relaying and ids. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ - Created by Henrik Ekblad - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. -*/ #ifndef MySensor_h #define MySensor_h diff --git a/libraries/MySensors/MySigning.cpp b/libraries/MySensors/MySigning.cpp index 835b947..03c3ee3 100644 --- a/libraries/MySensors/MySigning.cpp +++ b/libraries/MySensors/MySigning.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MySigning.h" MySigning::MySigning(bool requestSignatures) : _requestSignatures(requestSignatures) { diff --git a/libraries/MySensors/MySigning.h b/libraries/MySensors/MySigning.h index dc4407d..e65d546 100644 --- a/libraries/MySensors/MySigning.h +++ b/libraries/MySensors/MySigning.h @@ -1,9 +1,29 @@ -/* - The MySigning driver provides a generic API for various signing backends to offer - signing of MySensors messages. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * The MySigning driver provides a generic API for various signing backends to offer + * signing of MySensors messages. + * + */ #ifndef MySigning_h #define MySigning_h diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 07dca5f..2baa0dd 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -1,9 +1,30 @@ -/* - ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and - HMAC-SHA256 authentication with a readout-protected key. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and + * HMAC-SHA256 authentication with a readout-protected key. + * + */ + #include "MySigning.h" #include "MySigningAtsha204.h" diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/MySigningAtsha204.h index 1ebf386..56342e9 100644 --- a/libraries/MySensors/MySigningAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -1,9 +1,30 @@ -/* - ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and - HMAC-SHA256 authentication with a readout-protected key. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * ATSHA204 signing backend. The Atmel ATSHA204 offers true random number generation and + * HMAC-SHA256 authentication with a readout-protected key. + * + */ + #ifndef MySigningAtsha204_h #define MySigningAtsha204_h diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index d5aa8aa..d552c17 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -1,12 +1,33 @@ -/* - ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random - number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. - NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end - could compromise the key used in the signed message infrastructure if device is lost and its memory - dumped. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random + * number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. + * NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end + * could compromise the key used in the signed message infrastructure if device is lost and its memory + * dumped. + * + */ + #include "MyConfig.h" #include "MySigning.h" #include "MySigningAtsha204Soft.h" diff --git a/libraries/MySensors/MySigningAtsha204Soft.h b/libraries/MySensors/MySigningAtsha204Soft.h index fdc1371..e516618 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.h +++ b/libraries/MySensors/MySigningAtsha204Soft.h @@ -1,12 +1,33 @@ -/* - ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random - number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. - NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end - could compromise the key used in the signed message infrastructure if device is lost and its memory - dumped. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * ATSHA204 emulated signing backend. The emulated ATSHA204 implementation offers pseudo random + * number generation and HMAC-SHA256 authentication compatible with a "physical" ATSHA204. + * NOTE: Key is stored in clear text in the Arduino firmware. Therefore, the use of this back-end + * could compromise the key used in the signed message infrastructure if device is lost and its memory + * dumped. + * + */ + #ifndef MySigningHmac256Soft_h #define MySigningHmac256Soft_h diff --git a/libraries/MySensors/MySigningNone.cpp b/libraries/MySensors/MySigningNone.cpp index 93e2aa5..a73a375 100644 --- a/libraries/MySensors/MySigningNone.cpp +++ b/libraries/MySensors/MySigningNone.cpp @@ -1,8 +1,30 @@ -/* - Disabled signing backend. Does not provide any security measures. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * Disabled signing backend. Does not provide any security measures. + * + */ + + #include "MyConfig.h" #include "MySigning.h" #include "MySigningNone.h" diff --git a/libraries/MySensors/MySigningNone.h b/libraries/MySensors/MySigningNone.h index dd8f319..b024b41 100644 --- a/libraries/MySensors/MySigningNone.h +++ b/libraries/MySensors/MySigningNone.h @@ -1,8 +1,30 @@ -/* - Disabled signing backend. Does not provide any security measures. - - Created by Patrick "Anticimex" Fallberg -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * Signing support created by Patrick "Anticimex" Fallberg + * Disabled signing backend. Does not provide any security measures. + * + */ + + #ifndef MySigningNone_h #define MySigningNone_h diff --git a/libraries/MySensors/MyTransport.cpp b/libraries/MySensors/MyTransport.cpp index 56cfdf9..05627de 100644 --- a/libraries/MySensors/MyTransport.cpp +++ b/libraries/MySensors/MyTransport.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyTransport.h" MyTransport::MyTransport() { diff --git a/libraries/MySensors/MyTransport.h b/libraries/MySensors/MyTransport.h index 08ba0c6..839dbbd 100644 --- a/libraries/MySensors/MyTransport.h +++ b/libraries/MySensors/MyTransport.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyTransport_h #define MyTransport_h diff --git a/libraries/MySensors/MyTransportNRF24.cpp b/libraries/MySensors/MyTransportNRF24.cpp index 9cc63fb..5635e18 100644 --- a/libraries/MySensors/MyTransportNRF24.cpp +++ b/libraries/MySensors/MyTransportNRF24.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyTransport.h" #include "MyTransportNRF24.h" diff --git a/libraries/MySensors/MyTransportNRF24.h b/libraries/MySensors/MyTransportNRF24.h index c5ac75e..5f9b7b7 100644 --- a/libraries/MySensors/MyTransportNRF24.h +++ b/libraries/MySensors/MyTransportNRF24.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyTransportNRF24_h #define MyTransportNRF24_h diff --git a/libraries/MySensors/MyTransportRFM69.cpp b/libraries/MySensors/MyTransportRFM69.cpp index c387816..d9b4a9f 100644 --- a/libraries/MySensors/MyTransportRFM69.cpp +++ b/libraries/MySensors/MyTransportRFM69.cpp @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "MyTransport.h" #include "MyTransportRFM69.h" diff --git a/libraries/MySensors/MyTransportRFM69.h b/libraries/MySensors/MyTransportRFM69.h index 7b3821a..c564986 100644 --- a/libraries/MySensors/MyTransportRFM69.h +++ b/libraries/MySensors/MyTransportRFM69.h @@ -1,3 +1,22 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef MyTransportRF69_h #define MyTransportRF69_h diff --git a/libraries/MySensors/Version.h b/libraries/MySensors/Version.h index 82462b7..437cd2c 100644 --- a/libraries/MySensors/Version.h +++ b/libraries/MySensors/Version.h @@ -1,11 +1,11 @@ /*** * This file defines the Sensor library version number * Normally, contributors should not modify this directly - * as it is manaaged by the MySensors Bot. + * as it is managed by the MySensors Bot. */ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.4.1" +#define LIBRARY_VERSION "1.5 b1" #endif diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino index efe12f3..014ce3d 100644 --- a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino +++ b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino @@ -1,20 +1,38 @@ -/* - Vera Arduino MQ2 - - connect the MQ2 sensor as follows : - - A H A >>> 5V - B >>> A0 - H >>> GND - B >>> 10K ohm >>> GND - - Contribution: epierre - Based on http://sandboxelectronics.com/?p=165 - - License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) - - Modified by HEK to work in 1.4 -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Connect the MQ2 sensor as follows : + * + * A H A >>> 5V + * B >>> A0 + * H >>> GND + * B >>> 10K ohm >>> GND + * + * Contribution: epierre + * Based on http://sandboxelectronics.com/?p=165 + * License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) + * Modified by HEK to work in 1.4 + * + */ #include #include diff --git a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino index 97bc0c1..7dbd93b 100644 --- a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino +++ b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino @@ -1,6 +1,31 @@ -// This is an example that demonstrates how to report the battery level for a sensor -// Instructions for measuring battery capacity on A0 are available in the follwoing forum -// thread: http://forum.micasaverde.com/index.php/topic,20078.0.html +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * This is an example that demonstrates how to report the battery level for a sensor + * Instructions for measuring battery capacity on A0 are available here: + * http://www.mysensors.org/build/battery + * + */ + #include #include diff --git a/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino b/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino index 6ca5886..d22b629 100644 --- a/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino +++ b/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino @@ -1,6 +1,31 @@ -// Simple binary switch example -// Connect button or door/window reed switch between -// digitial I/O pin 3 (BUTTON_PIN below) and GND. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Simple binary switch example + * Connect button or door/window reed switch between + * digitial I/O pin 3 (BUTTON_PIN below) and GND. + * http://www.mysensors.org/build/binary + */ + #include #include diff --git a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino index ff8637a..34e0a17 100644 --- a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino +++ b/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino @@ -1,9 +1,34 @@ -// Interrupt driven binary switch example with dual interrupts -// Author: Patrick 'Anticimex' Fallberg -// Connect one button or door/window reed switch between -// digitial I/O pin 3 (BUTTON_PIN below) and GND and the other -// one in similar fashion on digital I/O pin 2. -// This example is designed to fit Arduino Nano/Pro Mini +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Interrupt driven binary switch example with dual interrupts + * Author: Patrick 'Anticimex' Fallberg + * Connect one button or door/window reed switch between + * digitial I/O pin 3 (BUTTON_PIN below) and GND and the other + * one in similar fashion on digital I/O pin 2. + * This example is designed to fit Arduino Nano/Pro Mini + * + */ + #include #include diff --git a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino index ddbaaba..ae8debf 100644 --- a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino +++ b/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino @@ -1,8 +1,28 @@ -/* -* -* This sketch clears radioId, relayId and routing info in EEPROM -* -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * This sketch clears radioId, relayId and other routing information in EEPROM back to factory default + * + */ #include #include diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 3c6c2c0..5ac41b4 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -1,4 +1,29 @@ -// Example sketch showing how to send in OneWire temperature readings +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Example sketch showing how to send in DS1820B OneWire temperature readings back to the controller + * http://www.mysensors.org/build/temp + */ + #include #include #include diff --git a/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino b/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino index 6c6a140..d0ecb92 100644 --- a/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino +++ b/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino @@ -1,8 +1,27 @@ -/*** +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. - * + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - February 15, 2014 - Bruce Lacey + * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek) + * * DESCRIPTION * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad * Vera Arduino Sensor project. @@ -13,12 +32,9 @@ * to the LED negative terminal and the MOSFET Source pin is connected to ground. * * This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit. - * - * REVISION HISTORY - * Version 1.0 - February 15, 2014 - Bruce Lacey - * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek) - * - ***/ + * http://www.mysensors.org/build/dimmer + */ + #define SN "DimmableLED" #define SV "1.1" diff --git a/libraries/MySensors/examples/DimmableLight/DimmableLight.ino b/libraries/MySensors/examples/DimmableLight/DimmableLight.ino index d396d37..d2e0812 100644 --- a/libraries/MySensors/examples/DimmableLight/DimmableLight.ino +++ b/libraries/MySensors/examples/DimmableLight/DimmableLight.ino @@ -1,7 +1,25 @@ -/*** +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - January 30, 2015 - Developed by GizMoCuz (Domoticz) * * DESCRIPTION * This sketch provides an example how to implement a Dimmable Light @@ -9,12 +27,7 @@ * It can be used as a base sketch for actual hardware. * Stores the last light state and level in eeprom. * - * Developed by GizMoCuz (Domoticz) - * - * REVISION HISTORY - * Version 1.0 - January 30, 2015 - * - ***/ + */ #include #include diff --git a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino index abd0530..a21e86a 100644 --- a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino +++ b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino @@ -1,3 +1,31 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * + * DESCRIPTION + * This sketch provides an example how to implement a distance sensor using HC-SR04 + * http://www.mysensors.org/build/distance + */ + #include #include #include diff --git a/libraries/MySensors/examples/DustSensor/DustSensor.ino b/libraries/MySensors/examples/DustSensor/DustSensor.ino index 4ebe804..38f6682 100644 --- a/libraries/MySensors/examples/DustSensor/DustSensor.ino +++ b/libraries/MySensors/examples/DustSensor/DustSensor.ino @@ -1,21 +1,42 @@ -/* - Arduino Dust Sensort - - connect the sensor as follows : - - VCC >>> 5V - A >>> A0 - GND >>> GND - - Based on: http://www.dfrobot.com/wiki/index.php/Sharp_GP2Y1010AU - Authors: Cyrille Médard de Chardon (serialC), Christophe Trefois (Trefex) - Contribution: epierre - COnverted to 1.4 by Henrik Ekblad - - The dust sensor used (see purchase guide for latest link): - http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=171259125886&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg - -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - epierre + * Converted to 1.4 by Henrik Ekblad + * + * DESCRIPTION + * Arduino Dust Sensort + * + * connect the sensor as follows : + * + * VCC >>> 5V + * A >>> A0 + * GND >>> GND + * + * Based on: http://www.dfrobot.com/wiki/index.php/Sharp_GP2Y1010AU + * Authors: Cyrille Médard de Chardon (serialC), Christophe Trefois (Trefex) + * + * http://www.mysensors.org/build/dust + * + */ #include #include diff --git a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 01f3e66..b146a3b 100644 --- a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -1,11 +1,38 @@ -// Use this sensor to measure KWH and Watt of your house meeter -// You need to set the correct pulsefactor of your meeter (blinks per KWH). -// The sensor starts by fetching current KWH value from gateway. -// Reports both KWH and Watt back to gateway. -// -// Unfortunately millis() won't increment when the Arduino is in -// sleepmode. So we cannot make this sensor sleep if we also want -// to calculate/report watt-number. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * + * DESCRIPTION + * This sketch provides an example how to implement a distance sensor using HC-SR04 + * Use this sensor to measure KWH and Watt of your house meeter + * You need to set the correct pulsefactor of your meeter (blinks per KWH). + * The sensor starts by fetching current KWH value from gateway. + * Reports both KWH and Watt back to gateway. + * + * Unfortunately millis() won't increment when the Arduino is in + * sleepmode. So we cannot make this sensor sleep if we also want + * to calculate/report watt-number. + * http://www.mysensors.org/build/pulse_power + */ #include #include diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index c653ab4..562b28d 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -1,13 +1,28 @@ - -/* - * Copyright (C) 2013 Henrik Ekblad - * - * Contribution by a-lurker and Anticimex, - * Contribution by Norbert Truchsess +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * Contribution by a-lurker and Anticimex, + * Contribution by Norbert Truchsess + * * * DESCRIPTION * The EthernetGateway sends data received from sensors to the ethernet link. @@ -35,7 +50,7 @@ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error * - * See http://www.mysensors.org/build/ethernet_gateway for wiring instructions. + * See http://www.mysensors.org/build/ethernet_gateway for wiring instructions. * */ #define NO_PORTB_PINCHANGES diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 6f006df..2c1b22c 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -133,7 +133,7 @@ void parseAndSend(MySensor gw, char *commandBuffer) { } void setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) + if (newMode != inclusionMode) { inclusionMode = newMode; // Send back mode change on serial line to ack command serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); @@ -141,6 +141,7 @@ void setInclusionMode(boolean newMode) { if (inclusionMode) { inclusionStartTime = millis(); } + } } diff --git a/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino b/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino index 54dc5eb..f5020cd 100644 --- a/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino +++ b/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino @@ -1,3 +1,32 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * + * DESCRIPTION + * This sketch provides an example how to implement a humidity/temperature + * sensor using DHT11/DHT-22 + * http://www.mysensors.org/build/humidity + */ + #include #include #include diff --git a/libraries/MySensors/examples/IrSensor/IrSensor.ino b/libraries/MySensors/examples/IrSensor/IrSensor.ino index e954fcd..6c8d87e 100644 --- a/libraries/MySensors/examples/IrSensor/IrSensor.ino +++ b/libraries/MySensors/examples/IrSensor/IrSensor.ino @@ -1,9 +1,35 @@ -// Example sketch showing how to control ir devices -// An IR LED must be connected to Arduino PWM pin 3. -// An optional ir receiver can be connected to PWM pin 8. -// All receied ir signals will be sent to gateway device stored in VAR_1. -// When binary light on is clicked - sketch will send volume up ir command -// When binary light off is clicked - sketch will send volume down ir command +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * + * DESCRIPTION + * Example sketch showing how to control ir devices + * An IR LED must be connected to Arduino PWM pin 3. + * An optional ir receiver can be connected to PWM pin 8. + * All receied ir signals will be sent to gateway device stored in VAR_1. + * When binary light on is clicked - sketch will send volume up ir command + * When binary light off is clicked - sketch will send volume down ir command + * http://www.mysensors.org/build/ir + */ #include #include diff --git a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino index 2896056..2b57de3 100644 --- a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino +++ b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino @@ -1,20 +1,41 @@ -/* - Vera Arduino BH1750FVI Light sensor - communicate using I2C Protocol - this library enable 2 slave device addresses - Main address 0x23 - secondary address 0x5C - connect the sensor as follows : - - VCC >>> 5V - Gnd >>> Gnd - ADDR >>> NC or GND - SCL >>> A5 - SDA >>> A4 - - Contribution: idefix - -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - idefix + * + * DESCRIPTION + * Arduino BH1750FVI Light sensor + * communicate using I2C Protocol + * this library enable 2 slave device addresses + * Main address 0x23 + * secondary address 0x5C + * connect the sensor as follows : + * + * VCC >>> 5V + * Gnd >>> Gnd + * ADDR >>> NC or GND + * SCL >>> A5 + * SDA >>> A4 + * http://www.mysensors.org/build/light + */ #include #include diff --git a/libraries/MySensors/examples/LightSensor/LightSensor.ino b/libraries/MySensors/examples/LightSensor/LightSensor.ino index 534f8bb..b63c96b 100644 --- a/libraries/MySensors/examples/LightSensor/LightSensor.ino +++ b/libraries/MySensors/examples/LightSensor/LightSensor.ino @@ -1,3 +1,31 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * + * DESCRIPTION + * Example sketch showing how to measue light level using a LM393 photo-resistor + * http://www.mysensors.org/build/light + */ + #include #include diff --git a/libraries/MySensors/examples/MAX6875TemperatureSensor/MAX6875TemperatureSensor.ino b/libraries/MySensors/examples/MAX6875TemperatureSensor/MAX6875TemperatureSensor.ino index 553b840..d153c24 100644 --- a/libraries/MySensors/examples/MAX6875TemperatureSensor/MAX6875TemperatureSensor.ino +++ b/libraries/MySensors/examples/MAX6875TemperatureSensor/MAX6875TemperatureSensor.ino @@ -1,14 +1,39 @@ -// MAX6875 Hight temperature sensor with range: -200 degC - +1300 degC -// Contribution by MrLynx -// http://forum.mysensors.org/topic/641/max6675 -// -// Connect: -// MAX6675 - Arduino -// CS0 - 4 -// SO - 3 -// SCLK - 5 -// VCC - 5V -// GND - GND +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - MrLynx + * + * DESCRIPTION + * MAX6875 High temperature sensor with range: -200 degC - +1300 degC + * http://forum.mysensors.org/topic/641/max6675 + * + * Connect MAX6675 - Arduino + * CS0 - 4 + * SO - 3 + * SCLK - 5 + * VCC - 5V + * GND - GND + * + */ + #include #include diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 24e25eb..867c8be 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -1,60 +1,78 @@ -/* MyMQTT Broker Gateway 0.1b - -Created by Daniel Wiegert -Based on MySensors Ethernet Gateway by Henrik Ekblad -http://www.mysensors.org - -Requires MySensors lib 1.4b - -* Change below; TCP_IP, TCP_PORT, TCP_MAC -This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also. -*1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges. - -*2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change - the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details. - http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5 - -* Don't forget to look at the definitions in libraries\MySensors\MyMQTT.h! - - define TCPDUMP and connect serial interface if you have problems, please write on - http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to - turn on DEBUG in libraries\MySensors\MyConfig.h also. - - MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition. - If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20. - To disable: set MQTT_FIRST_SENSORID to 255. - - MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like. - - MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes. - This can be useful if you want to send latest state back to the MQTT client. Just check if incoming - message has any length or not. - Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. - -* Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType] - NodeID and SensorID is uint8 (0-255) number. - Last segment is translation of the sensor type, look inside MyMQTT.cpp for the definitions. - User can change this to their needs. We have also left some space for custom types. - -Special: (sensor 255 reserved for special commands) -You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version) - -To-do: -Special commands : clear or set EEPROM Values, Send REBOOT and Receive reboot for MyMQTT itself. -Be able to send ACK so client returns the data being sent. -... Please come with ideas! -What to do with publish messages. - -Test in more MQTT clients, So far tested in openhab and MyMQTT for Android (Not my creation) -- http://www.openhab.org/ -- https://play.google.com/store/apps/details?id=at.tripwire.mqtt.client&hl=en -... Please notify me if you use this broker with other software. - - -* How to set-up Openhab and MQTTGateway: -http://forum.mysensors.org/topic/303/mqtt-broker-gateway - -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Created by Daniel Wiegert + * + * DESCRIPTION + * MyMQTT Broker Gateway 0.1b + * Latest instructions found here: + * http://www.mysensors.org/build/mqtt_gateway + * http://www.mysensors.org/build/ethernet_gateway + * + * Change below; TCP_IP, TCP_PORT, TCP_MAC + * This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also. + * 1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges. + * 2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change + * the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details. + * http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5 + * + * Don't forget to look at the definitions in MyMQTT.h! + * + * define TCPDUMP and connect serial interface if you have problems, please write on + * http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to + * turn on DEBUG in libraries\MySensors\MyConfig.h also. + * + * MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition. + * If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20. + * To disable: set MQTT_FIRST_SENSORID to 255. + * + * MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like. + * + * MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes. + * This can be useful if you want to send latest state back to the MQTT client. Just check if incoming + * message has any length or not. + * Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. + * + * (*) Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType] + * NodeID and SensorID is uint8 (0-255) number. + * Last segment is translation of the sensor type, look inside MyMQTT.cpp for the definitions. + * User can change this to their needs. We have also left some space for custom types. + * + * Special: (sensor 255 reserved for special commands) + * You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version) + * + * To-do: + * Special commands : clear or set EEPROM Values, Send REBOOT and Receive reboot for MyMQTT itself. + * Be able to send ACK so client returns the data being sent. + * ... Please come with ideas! + * What to do with publish messages. + * + * Test in more MQTT clients, So far tested in openhab and MyMQTT for Android (Not my creation) + * - http://www.openhab.org/ + * - https://play.google.com/store/apps/details?id=at.tripwire.mqtt.client&hl=en + * ... Please notify me if you use this broker with other software. + * + * How to set-up Openhab and MQTTGateway: + * http://forum.mysensors.org/topic/303/mqtt-broker-gateway + */ #include #include diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index db8373f..0c9179b 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -1,3 +1,32 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Motion Sensor example using HC-SR501 + * http://www.mysensors.org/build/motion + * + */ + #include #include diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index c25fac2..9f98b3e 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -1,9 +1,36 @@ -// Default sensor sketch for MySensor Micro module -// Act as a temperature / humidity sensor by default. -// -// If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals -// -// Battery voltage is repported as child sensorId 199, as well as battery percentage +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Thomas Bowman Mørch + * + * DESCRIPTION + * Default sensor sketch for MySensor Sensebender Micro module + * Act as a temperature / humidity sensor by default. + * + * If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals + * + * Battery voltage is repported as child sensorId 199, as well as battery percentage + * + */ + #include diff --git a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino index c5743e6..4c8ff9b 100644 --- a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino +++ b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino @@ -1,3 +1,32 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Pressure sensor example using BMP085 module + * http://www.mysensors.org/build/pressure + * + */ + #include #include #include diff --git a/libraries/MySensors/examples/RF433MhzSensor/RF433MhzSensor.ino b/libraries/MySensors/examples/RF433MhzSensor/RF433MhzSensor.ino index 682e4d7..ec21834 100644 --- a/libraries/MySensors/examples/RF433MhzSensor/RF433MhzSensor.ino +++ b/libraries/MySensors/examples/RF433MhzSensor/RF433MhzSensor.ino @@ -1,4 +1,27 @@ -/* +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION * This sketch demonstrates how to use InterruptChain to receive and * decode remote switches (old and new) and remote sensors. * @@ -15,7 +38,6 @@ * Setup: * - connect a 433MHz receiver on digital pin 2. * - * * MySensor note: This example has not yet been adopted but can be used as an example * of receiving 433Mhz stuff. * diff --git a/libraries/MySensors/examples/RFIDLockSensor/RFIDLockSensor.ino b/libraries/MySensors/examples/RFIDLockSensor/RFIDLockSensor.ino index ecb9756..7b0880c 100644 --- a/libraries/MySensors/examples/RFIDLockSensor/RFIDLockSensor.ino +++ b/libraries/MySensors/examples/RFIDLockSensor/RFIDLockSensor.ino @@ -1,26 +1,47 @@ -/* - RFID Lock sensor/actuator - - Henrik Ekblad - - Use RFID tag to lock/unlock a door or trigger a scene on your controller. - This example sketch allows you to add an optional relay or solenoid - which can be activated/opened by RFID or controller. - - Use the I2C wiring option for your RFID module and connect to the following Arduino pins. - - RFID Arduino - ----- ------- - GND -> GND - VCC -> +5V - SCL -> A5 - SDA -> A4 - - Use normal wiring for NRF24L01 radio - - Attach a optional relay or solonoid lock to pin 4 - -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * RFID Lock sensor/actuator + * + * Use RFID tag to lock/unlock a door or trigger a scene on your controller. + * This example sketch allows you to add an optional relay or solenoid + * which can be activated/opened by RFID or controller. + * + * Use the I2C wiring option for your RFID module and connect to the following Arduino pins. + * + * RFID Arduino + * ----- ------- + * GND -> GND + * VCC -> +5V + * SCL -> A5 + * SDA -> A4 + * + * Use normal wiring for NRF24L01 radio + * + * Attach a optional relay or solonoid lock to pin 4 + * http://www.mysensors.org/build/rfid + */ #include #include diff --git a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino index 32e17fa..a4c5944 100644 --- a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino +++ b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino @@ -1,18 +1,43 @@ - -// Example sketch showing how to request time from controller which is stored in RTC module -// The time and temperature (DS3231/DS3232) is shown on an attached Crystal LCD display -// -// Created by Henrik Ekblad -// Inspired by Gregl - -// Wiring (radio wiring on www.mysensors.org) -// ------------------------------------ -// Arduino RTC-Module I2C Display -// ------------------------------------ -// GND GND GND -// +5V VCC VCC -// A4 SDA SDA -// A5 SCL SCL +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch showing how to request time from controller which is stored in RTC module + * The time and temperature (DS3231/DS3232) is shown on an attached Crystal LCD display + * + * + * Wiring (radio wiring on www.mysensors.org) + * ------------------------------------ + * Arduino RTC-Module I2C Display + * ------------------------------------ + * GND GND GND + * +5V VCC VCC + * A4 SDA SDA + * A5 SCL SCL + * + * http://www.mysensors.org/build/display + * + */ #include diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index 93e93c2..db05836 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -1,5 +1,31 @@ -// Example sketch showing how to control physical relays. -// This example will remember relay state even after power failure. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch showing how to control physical relays. + * This example will remember relay state after power failure. + * http://www.mysensors.org/build/relay + */ #include #include diff --git a/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino b/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino index 7cc2a77..07781d6 100644 --- a/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino +++ b/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino @@ -1,7 +1,33 @@ -// Example sketch för a "light switch" where you can control light or something -// else from both vera and a local physical button (connected between digital -// pin 3 and GND). -// This node also works as a repeader for other nodes +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch for a "light switch" where you can control light or something + * else from both HA controller and a local physical button + * (connected between digital pin 3 and GND). + * This node also works as a repeader for other nodes + * http://www.mysensors.org/build/relay + */ #include #include diff --git a/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino b/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino index 8ada2de..223f29b 100644 --- a/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino +++ b/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino @@ -1,7 +1,32 @@ -// Example sketch showing how to create a node thay repeates messages -// from nodes far from gateway back to gateway. -// It is important that nodes that has enabled repeater mode calls -// gw.preocess() frequently. This node should never sleep. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch showing how to create a node thay repeates messages + * from nodes far from gateway back to gateway. + * It is important that nodes that has enabled repeater mode calls + * gw.process() frequently. Repeaters should never sleep. + */ #include #include diff --git a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino b/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino index 9f5f00f..ec2a4ef 100644 --- a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -1,28 +1,54 @@ -/* Secret Knock Sensor - - See original instructions here (note: The MySensors adopted code might differ in wiring. The instructions below is correct): - https://learn.adafruit.com/secret-knock-activated-drawer-lock/ - Version 13.10.31 Built with Arduino IDE 1.0.5 - - By Steve Hoefer http://grathio.com - Adapted to MySensors by Henrik Ekblad - - Licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0 - http://creativecommons.org/licenses/by-nc-sa/3.0/us/ - (In short: Do what you want, as long as you credit me, don't relicense it, and don't sell it or use it in anything you sell without contacting me.) - - ------Wiring------ - Pin 0: Program button used for recording a new Knock (connect Pin0 -> button -> GND) - Pin 1: Optional: Connect LED here (remember resisor in series) - Pin 2: Optional: Piezo element (for beeps). - Pin 5: A sound sensor (digital output) for sensing knocks. See MySensors purchase guide. I used this: http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=200941260251&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg - Pin 4: Connects to either 1. Relay which open door or lock or - 2. transistor that opens a solenoid lock when HIGH (see adafruit guide for this option). - - - Connect radio according as usual(you can skip IRQ pin) - http://www.mysensors.org/build/connect_radio -*/ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * + * Secret Knock Sensor + * http://www.mysensors.org/build/knock + * + * See original instructions here (note: The MySensors adopted code might differ in wiring. The instructions below is correct): + * https://learn.adafruit.com/secret-knock-activated-drawer-lock/ + * Version 13.10.31 Built with Arduino IDE 1.0.5 + * + * By Steve Hoefer http://grathio.com + * Adapted to MySensors by Henrik Ekblad + * + * Licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0 + * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ + * (In short: Do what you want, as long as you credit me, don't relicense it, and don't sell it or use it in anything you sell without contacting me.) + * + * ------Wiring------ + * Pin 0: Program button used for recording a new Knock (connect Pin0 -> button -> GND) + * Pin 1: Optional: Connect LED here (remember resisor in series) + * Pin 2: Optional: Piezo element (for beeps). + * Pin 5: A sound sensor (digital output) for sensing knocks. See MySensors purchase guide. I used this: http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=200941260251&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg + * Pin 4: Connects to either 1. Relay which open door or lock or + * 2. transistor that opens a solenoid lock when HIGH (see adafruit guide for this option). + * + * + * Connect radio according as usual(you can skip IRQ pin) + * http://www.mysensors.org/build/connect_radio + */ #include #include diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 73bf57d..cae4b81 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -1,5 +1,31 @@ -// Example sketch showing how to securely control locks. -// This example will remember lock state even after power failure. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Patrick "Anticimex" Fallberg + * + * DESCRIPTION + * Example sketch showing how to securely control locks. + * This example will remember lock state even after power failure. + */ + #define USE_SOFTWARE_ATSHA // Disable to use ATSHA204A circuit diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index 6f006df..532d9ca 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -1,3 +1,23 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + */ + #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ @@ -133,7 +153,7 @@ void parseAndSend(MySensor gw, char *commandBuffer) { } void setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) + if (newMode != inclusionMode) { inclusionMode = newMode; // Send back mode change on serial line to ack command serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); @@ -141,6 +161,7 @@ void setInclusionMode(boolean newMode) { if (inclusionMode) { inclusionStartTime = millis(); } + } } @@ -193,3 +214,4 @@ void errBlink(uint8_t cnt) { #endif // ARDUINO #endif + diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 266fdb7..9bfa910 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -1,10 +1,23 @@ - /* - * Copyright (C) 2013-2014 Henrik Ekblad - * +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. - * + * + ******************************* + * * DESCRIPTION * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on radio network. @@ -12,13 +25,14 @@ * The GW code is designed for Arduino Nano 328p / 16MHz * * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND + * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * */ #define NO_PORTB_PINCHANGES @@ -139,3 +153,4 @@ void serialEvent() { + diff --git a/libraries/MySensors/examples/ServoActuator/ServoActuator.ino b/libraries/MySensors/examples/ServoActuator/ServoActuator.ino index 561fc73..8092412 100644 --- a/libraries/MySensors/examples/ServoActuator/ServoActuator.ino +++ b/libraries/MySensors/examples/ServoActuator/ServoActuator.ino @@ -1,9 +1,35 @@ -// Example showing how to create an atuator for a servo. -// Connect red to +5V, Black or brown to GND and the last cable to Digital pin 3. -// The servo consumes much power and should probably have its own powersource.' -// The arduino might spontanally restart if too much power is used (happend -// to me when servo tried to pass the extreme positions = full load). -// Contribution by: Derek Macias +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * Contribution by: Derek Macias + * + * DESCRIPTION + * Example showing how to create an atuator for a servo. + * Connect red to +5V, Black or brown to GND and the last cable to Digital pin 3. + * The servo consumes much power and should probably have its own powersource.' + * The arduino might spontanally restart if too much power is used (happend + * to me when servo tried to pass the extreme positions = full load). + * http://www.mysensors.org/build/servo + */ #include diff --git a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino index 4b7017f..92acedf 100644 --- a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino +++ b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino @@ -1,24 +1,47 @@ -/* SHA204 personalization sketch - by: Patrick Fallberg - date: January 10, 2015 - - This sketch will write factory default settings to the configuration zone - and then lock it. - It will then either - a. Generate a random value to use as a key which will be stored in - slot 0. The key is printed on UART (115200) in clear text for the user to be - able to use it as a user-supplied key in other personalization executions - where the same key is needed. - b. Use a user-supplied value to use as a key which will be stored in - slot 0. - Finally it will lock the data zone. +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Patrick Fallberg, January 10, 2015 + * + * DESCRIPTION + * SHA204 personalization sketch + * + * This sketch will write factory default settings to the configuration zone + * and then lock it. + * It will then either + * a. Generate a random value to use as a key which will be stored in + * slot 0. The key is printed on UART (115200) in clear text for the user to be + * able to use it as a user-supplied key in other personalization executions + * where the same key is needed. + * b. Use a user-supplied value to use as a key which will be stored in + * slot 0. + * Finally it will lock the data zone. + * + * By default, no locking is performed. User have to manually enable the flags that + * turn on the locking. Furthermore, user have to send a SPACE character on serial + * console when prompted to do any locking. On boards that does not provide UART + * input it is possible to configure the sketch to skip this confirmation. + * Default settings use ATSHA204 on pin 17 (A3). + */ - By default, no locking is performed. User have to manually enable the flags that - turn on the locking. Furthermore, user have to send a SPACE character on serial - console when prompted to do any locking. On boards that does not provide UART - input it is possible to configure the sketch to skip this confirmation. - Default settings use ATSHA204 on pin 17 (A3). -*/ #include #include diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino index ca6249a..2a2a108 100644 --- a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -1,3 +1,31 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch sending soil moisture alarm to controller + * http://www.mysensors.org/build/moisture + */ + #include #include diff --git a/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino b/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino index ac3b0b3..7dfe1b0 100644 --- a/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino +++ b/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino @@ -1,6 +1,30 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Example sketch showing how to request time from controller. + */ -// Example sketch showing how to request time from controller. -// Created by Henrik Ekblad #include #include diff --git a/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino b/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino index 37ebf29..7a1946a 100644 --- a/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino +++ b/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino @@ -1,5 +1,28 @@ - -/* +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * http://www.mysensors.org/build/scene_controller * Touch Display Scene Controller build using a touch enabled tft display * attached to a ATMega 2560. This example fetches time from controller and sends * in scene commands to the controller. diff --git a/libraries/MySensors/examples/UVSensor/UVSensor.ino b/libraries/MySensors/examples/UVSensor/UVSensor.ino index 417ae43..a00ed7f 100644 --- a/libraries/MySensors/examples/UVSensor/UVSensor.ino +++ b/libraries/MySensors/examples/UVSensor/UVSensor.ino @@ -1,22 +1,43 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - epierre + * Contribution: bulldoglowell, gizmocuz + * + * DESCRIPTION + * Arduino UVM-30A + * Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html + * Because this table is pretty lineair, we can calculate a UVI with one decimal + * + * Connect sensor: + * + * + >>> 5V + * - >>> GND + * out >>> A0 + * + * License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) + */ + #include #include -/* - Arduino UVM-30A - - connect the sensor as follows : - - + >>> 5V - - >>> GND - out >>> A0 - - Contribution: epierre, bulldoglowell, gizmocuz - - Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html - Because this table is pretty lineair, we can calculate a UVI with one decimal - - License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) -*/ - #include #include diff --git a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 6e9c4ee..d676d6c 100644 --- a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -1,13 +1,37 @@ -// -// Use this sensor to measure volume and flow of your house watermeter. -// You need to set the correct pulsefactor of your meter (pulses per m3). -// The sensor starts by fetching current volume reading from gateway (VAR 1). -// Reports both volume and flow back to gateway. -// -// Unfortunately millis() won't increment when the Arduino is in -// sleepmode. So we cannot make this sensor sleep if we also want -// to calculate/report flow. -// +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik Ekblad + * + * DESCRIPTION + * Use this sensor to measure volume and flow of your house watermeter. + * You need to set the correct pulsefactor of your meter (pulses per m3). + * The sensor starts by fetching current volume reading from gateway (VAR 1). + * Reports both volume and flow back to gateway. + * + * Unfortunately millis() won't increment when the Arduino is in + * sleepmode. So we cannot make this sensor sleep if we also want + * to calculate/report flow. + * http://www.mysensors.org/build/pulse_water + */ #include #include From 20c2938d3dc883b17929d50d8ee105f3f27c8e1b Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sun, 12 Apr 2015 19:53:07 +0200 Subject: [PATCH 105/660] Remove the executable bit from source files Signed-off-by: Tomas Hozza --- libraries/MySensors/MyMessage.cpp | 0 libraries/MySensors/MySensor.cpp | 0 libraries/MySensors/utility/RF24.cpp | 0 libraries/MySensors/utility/RF24.h | 0 libraries/MySensors/utility/RF24_config.h | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 libraries/MySensors/MyMessage.cpp mode change 100755 => 100644 libraries/MySensors/MySensor.cpp mode change 100755 => 100644 libraries/MySensors/utility/RF24.cpp mode change 100755 => 100644 libraries/MySensors/utility/RF24.h mode change 100755 => 100644 libraries/MySensors/utility/RF24_config.h diff --git a/libraries/MySensors/MyMessage.cpp b/libraries/MySensors/MyMessage.cpp old mode 100755 new mode 100644 diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp old mode 100755 new mode 100644 diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp old mode 100755 new mode 100644 diff --git a/libraries/MySensors/utility/RF24.h b/libraries/MySensors/utility/RF24.h old mode 100755 new mode 100644 diff --git a/libraries/MySensors/utility/RF24_config.h b/libraries/MySensors/utility/RF24_config.h old mode 100755 new mode 100644 From 192ccf9896316fe51ad98512a2e60df1d7a88036 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sun, 12 Apr 2015 21:33:48 +0200 Subject: [PATCH 106/660] Fix logging of error if initialization of the radio fails Signed-off-by: Tomas Hozza --- libraries/MySensors/MySensor.cpp | 4 +++- libraries/MySensors/MyTransport.h | 8 +------- libraries/MySensors/MyTransportNRF24.cpp | 6 +++--- libraries/MySensors/MyTransportNRF24.h | 2 +- libraries/MySensors/MyTransportRFM69.cpp | 4 ++-- libraries/MySensors/MyTransportRFM69.h | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 2f98b9e..5e01826 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -101,7 +101,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b isGateway = _nodeId == GATEWAY_ADDRESS; // Setup radio - radio.init(); + if (!radio.init()) { + debug(PSTR("radio initialization failed!")); + } #ifdef MY_SIGNING_FEATURE // Read out the signing requirements from EEPROM diff --git a/libraries/MySensors/MyTransport.h b/libraries/MySensors/MyTransport.h index 839dbbd..aab12f3 100644 --- a/libraries/MySensors/MyTransport.h +++ b/libraries/MySensors/MyTransport.h @@ -22,12 +22,6 @@ #include -#ifdef DEBUG -#define debug(x,...) debugPrint(x, ##__VA_ARGS__) -#else -#define debug(x,...) -#endif - #define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. #define NODE_SENSOR_ID 0xFF // Node child id is always created for when a node @@ -45,7 +39,7 @@ public: // init() // different parameters would be needed depending on radio module (e.g. channel, power, crc, etc.) // keeping these parameters as #define's in MyConfig to streamline the driver interface - virtual void init() = 0; + virtual bool init() = 0; // setAddress(address) // set the node address and start listening to that address (and the broadcast address) virtual void setAddress(uint8_t address) = 0; diff --git a/libraries/MySensors/MyTransportNRF24.cpp b/libraries/MySensors/MyTransportNRF24.cpp index 5635e18..fee7dca 100644 --- a/libraries/MySensors/MyTransportNRF24.cpp +++ b/libraries/MySensors/MyTransportNRF24.cpp @@ -28,13 +28,12 @@ MyTransportNRF24::MyTransportNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) { } -void MyTransportNRF24::init() { +bool MyTransportNRF24::init() { // Start up the radio library rf24.begin(); if (!rf24.isPVariant()) { - debug(PSTR("check wires\n")); - while(1); + return false; } rf24.setAutoAck(1); rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast @@ -48,6 +47,7 @@ void MyTransportNRF24::init() { // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); + return true; } void MyTransportNRF24::setAddress(uint8_t address) { diff --git a/libraries/MySensors/MyTransportNRF24.h b/libraries/MySensors/MyTransportNRF24.h index 5f9b7b7..8c582fb 100644 --- a/libraries/MySensors/MyTransportNRF24.h +++ b/libraries/MySensors/MyTransportNRF24.h @@ -36,7 +36,7 @@ class MyTransportNRF24 : public MyTransport { public: MyTransportNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); - void init(); + bool init(); void setAddress(uint8_t address); uint8_t getAddress(); bool send(uint8_t to, const void* data, uint8_t len); diff --git a/libraries/MySensors/MyTransportRFM69.cpp b/libraries/MySensors/MyTransportRFM69.cpp index d9b4a9f..4ad8fb4 100644 --- a/libraries/MySensors/MyTransportRFM69.cpp +++ b/libraries/MySensors/MyTransportRFM69.cpp @@ -29,13 +29,13 @@ MyTransportRFM69::MyTransportRFM69(uint8_t freqBand, uint8_t networkId, uint8_t { } -void MyTransportRFM69::init() { +bool MyTransportRFM69::init() { // Start up the radio library (_address will be set later by the MySensors library) radio.initialize(_freqBand, _address, _networkId); #ifdef RFM69_ENABLE_ENCRYPTION radio.encrypt(ENCRYPTKEY); #endif - + return true; } void MyTransportRFM69::setAddress(uint8_t address) { diff --git a/libraries/MySensors/MyTransportRFM69.h b/libraries/MySensors/MyTransportRFM69.h index c564986..afb7643 100644 --- a/libraries/MySensors/MyTransportRFM69.h +++ b/libraries/MySensors/MyTransportRFM69.h @@ -31,7 +31,7 @@ class MyTransportRFM69 : public MyTransport { public: MyTransportRFM69(uint8_t freqBand=RFM69_FREQUENCY, uint8_t networkId=RFM69_NETWORKID, uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM); - void init(); + bool init(); void setAddress(uint8_t address); uint8_t getAddress(); bool send(uint8_t to, const void* data, uint8_t len); From a68350af283985d36bd8693bd5e6f00a616c6a6b Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 12 Apr 2015 22:03:09 +0200 Subject: [PATCH 107/660] Added a few new sensors --- libraries/MySensors/MyMessage.h | 61 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index c5b8612..ac9d4de 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -58,8 +58,8 @@ typedef enum { V_WEIGHT, // S_WEIGHT V_DISTANCE, // S_DISTANCE V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT - V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, - V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, + V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER + V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER V_WATT, // S_POWER V_KWH, // S_POWER V_SCENE_ON, // S_SCENE_CONTROLLER @@ -88,9 +88,13 @@ typedef enum { V_ID, // S_TEMP // Used for reporting the sensor internal ids (E.g. DS1820b). V_LIGHT_LEVEL_LUX, // S_LIGHT, Light level in lux - V_UNIT_PREFIX // Allows sensors to send in a string representing the - // unit prefix to be displayed in GUI, not parsed! E.g. cm, m, km, inch. - // Can be used for S_DISTANCE + V_UNIT_PREFIX, // Allows sensors to send in a string representing the + // unit prefix to be displayed in GUI, not parsed! E.g. cm, m, km, inch. + // Can be used for S_DISTANCE + V_SOUND_DB, // S_SOUND sound level in db + V_VIBRATION_HZ, // S_VIBRATION vibration i Hz + V_ENCODER_VALUE, // S_ROTARY_ENCODER. Rotary encoder value. + } mysensor_data; // Type of internal messages (for internal messages) @@ -103,35 +107,40 @@ typedef enum { // Type of sensor (for presentation message) typedef enum { - S_DOOR, - S_MOTION, - S_SMOKE, - S_LIGHT, - S_DIMMER, - S_COVER, - S_TEMP, - S_HUM, - S_BARO, - S_WIND, - S_RAIN, - S_UV, - S_WEIGHT, - S_POWER, - S_HEATER, - S_DISTANCE, - S_LIGHT_LEVEL, + S_DOOR, // V_TRIPPED, V_ARMED + S_MOTION, // V_TRIPPED, V_ARMED + S_SMOKE, // V_TRIPPED, V_ARMED + S_LIGHT, // V_LIGHT, V_WATT + S_DIMMER, // V_DIMMER, V_WATT + S_COVER, // V_UP, V_DOWN, V_STOP + S_TEMP, // V_TEMP + S_HUM, // V_HUM + S_BARO, // V_PRESSURE, V_FORECAST + S_WIND, // V_WIND, V_GUST + S_RAIN, // V_RAIN, V_RAINRATE + S_UV, // V_UV + S_WEIGHT, // V_WEIGHT, V_IMPEDANCE + S_POWER, // V_WATT, V_KWH + S_HEATER, // V_HEATER, V_HEATER_SW + S_DISTANCE, // V_DISTANCE + S_LIGHT_LEVEL, // V_LIGHT S_ARDUINO_NODE, S_ARDUINO_REPEATER_NODE, - S_LOCK, - S_IR, - S_WATER, + S_LOCK, // V_LOCK_STATUS + S_IR, // V_IR_SEND, V_IR_RECEIVE + S_WATER, // V_FLOW, V_VOLUME S_AIR_QUALITY, // V_VAR1 S_CUSTOM, S_DUST, // V_DUST_LEVEL S_SCENE_CONTROLLER, // V_SCENE_ON, V_SCENE_OFF. S_RGB_LIGHT, // Send data using V_RGB or V_RGBW S_COLOR_SENSOR, // Send data using V_RGB - S_MULTIMETER // V_VOLTAGE, V_CURRENT, V_IMPEDANCE + S_MULTIMETER, // V_VOLTAGE, V_CURRENT, V_IMPEDANCE + S_SPRINKLER, // V_TRIPPED, V_ARMED + S_WATER_LEAK, // V_TRIPPED, V_ARMED + S_SOUND, // V_TRIPPED, V_ARMED, V_SOUND_DB + S_VIBRATION, // V_TRIPPED, V_ARMED, V_VIBRATION_HZ + S_ROTARY_ENCODER, // V_ENCODER_VALUE } mysensor_sensor; // Type of data stream (for streamed message) From e30dea71ffa1ced9dbcb03480d80e8fc7a661fd7 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 18 Apr 2015 20:57:15 +0200 Subject: [PATCH 108/660] Fix sleep problem reported by Gary Stofer. --- libraries/MySensors/MyHwATMega328.cpp | 10 +++++++--- libraries/MySensors/MyHwATMega328.h | 1 + libraries/MySensors/MySensor.cpp | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index 2281e6c..a9e6de7 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -117,7 +117,7 @@ void powerDown(period_t period) { ADCSRA |= (1 << ADEN); } -inline void MyHwATMega328::sleep(unsigned long ms) { +void MyHwATMega328::internalSleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); pinIntTrigger = 0; @@ -133,13 +133,17 @@ inline void MyHwATMega328::sleep(unsigned long ms) { if (!pinIntTrigger && ms >= 16) { powerDown(SLEEP_15Ms); ms -= 15; } } +void MyHwATMega328::sleep(unsigned long ms) { + internalSleep(ms); +} + bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; - sleep(ms); + internalSleep(ms); if (0 == pinIntTrigger) { pinTriggeredWakeup = false; } @@ -157,7 +161,7 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { pinIntTrigger = 0; - sleep(ms); + internalSleep(ms); if (0 == pinIntTrigger) { retVal = -1; } diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index ccb35ba..17a4222 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -85,5 +85,6 @@ public: void debugPrint(bool isGW, const char *fmt, ... ); #endif private: + void internalSleep(unsigned long ms); }; #endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 5e01826..16764b6 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -711,8 +711,8 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { return false; } else { #endif - radio.powerDown(); - return hw.sleep(interrupt, mode, ms) ; + radio.powerDown(); + return hw.sleep(interrupt, mode, ms) ; #ifdef MY_OTA_FIRMWARE_FEATURE } #endif From 7bd79f598bdb114b7512b3053278a240d7ee6dbe Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 20 Apr 2015 23:15:41 +0200 Subject: [PATCH 109/660] Do nothing more after radio initialization fails. Thanks @thozza --- libraries/MySensors/MySensor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 16764b6..837ffd6 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -102,7 +102,8 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b // Setup radio if (!radio.init()) { - debug(PSTR("radio initialization failed!")); + debug(PSTR("radio init fail\n")); + while(1); // Nothing more we can do } #ifdef MY_SIGNING_FEATURE From f015fa1d917adf24798c206ac7b490a3b08ecc02 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 28 Apr 2015 22:28:26 +0200 Subject: [PATCH 110/660] Update MSTimer2 to support ATmega1284P. Thanks Tom. --- libraries/MsTimer2/MsTimer2.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/MsTimer2/MsTimer2.cpp b/libraries/MsTimer2/MsTimer2.cpp index ead0871..0b0c2dc 100644 --- a/libraries/MsTimer2/MsTimer2.cpp +++ b/libraries/MsTimer2/MsTimer2.cpp @@ -3,6 +3,8 @@ Javier Valencia History: + + 05Apr2015 TRL V0.6a added support for ATmega1284P 29/Dec/11 - V0.6 added support for ATmega32u4, AT90USB646, AT90USB1286 (paul@pjrc.com) some improvements added by Bill Perry note: uses timer4 on Atmega32u4 @@ -49,7 +51,7 @@ void MsTimer2::set(unsigned long ms, void (*f)()) { func = f; -#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) TIMSK2 &= ~(1< Date: Sun, 19 Apr 2015 20:51:48 +0200 Subject: [PATCH 111/660] Add LED blinking support into MySensor without any library dependency Signed-off-by: Tomas Hozza --- libraries/MySensors/MyConfig.h | 20 ++++++++ libraries/MySensors/MySensor.cpp | 86 ++++++++++++++++++++++++++++++++ libraries/MySensors/MySensor.h | 29 +++++++++++ 3 files changed, 135 insertions(+) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 437ef3e..c2148ab 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -45,6 +45,26 @@ #define MY_OTA_FLASH_JDECID 0x1F65 +/********************************** +* Information LEDs blinking +***********************************/ +// This feature enables LEDs blinking on message receive, transmit +// or if some error occured. This was commonly used only in gateways, +// but now can be used in any sensor node. Also the LEDs can now be +// disabled in the gateway. + +// #define WITH_LEDS_BLINKING + +// default LEDs blinking period in milliseconds +#define DEFAULT_LED_BLINK_PERIOD 300 +// The RX LED default pin +#define DEFAULT_RX_LED_PIN 8 +// The TX LED default pin +#define DEFAULT_TX_LED_PIN 9 +// The Error LED default pin +#define DEFAULT_ERR_LED_PIN 7 + + /********************************** * Message Signing Settings ***********************************/ diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 837ffd6..f059b9e 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -52,6 +52,9 @@ static inline bool isValidDistance( const uint8_t distance ) { MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_SIGNING_FEATURE , MySigning &_signer +#endif +#ifdef WITH_LEDS_BLINKING + , uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period #endif ) : @@ -59,6 +62,9 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_SIGNING_FEATURE signer(_signer), #endif +#ifdef WITH_LEDS_BLINKING + pinRx(_rx), pinTx(_tx), pinEr(_er), ledBlinkPeriod(_blink_period), +#endif #ifdef MY_OTA_FIRMWARE_FEATURE flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID), #endif @@ -90,6 +96,64 @@ bool MySensor::isValidFirmware() { #endif +#ifdef WITH_LEDS_BLINKING +void MySensor::handleLedsBlinking() { + static unsigned long next_time = hw_millis() + ledBlinkPeriod; + + // Just return if it is not the time... + // http://playground.arduino.cc/Code/TimingRollover + if ((long)(hw_millis() - next_time) < 0) + return; + else + next_time = hw_millis() + ledBlinkPeriod; + + // do the actual blinking + if(countRx && countRx != 255) { + // switch led on + digitalWrite(pinRx, LOW); + } + else if(!countRx) { + // switching off + digitalWrite(pinRx, HIGH); + } + if(countRx != 255) + --countRx; + + if(countTx && countTx != 255) { + // switch led on + digitalWrite(pinTx, LOW); + } + else if(!countTx) { + // switching off + digitalWrite(pinTx, HIGH); + } + if(countTx != 255) + --countTx; + + if(countErr && countErr != 255) { + // switch led on + digitalWrite(pinEr, LOW); + } + else if(!countErr) { + // switching off + digitalWrite(pinEr, HIGH); + } + if(countErr != 255) + --countErr; +} + +void MySensor::rxBlink(uint8_t cnt) { + if(countRx == 255) { countRx = cnt; } +} + +void MySensor::txBlink(uint8_t cnt) { + if(countTx == 255) { countTx = cnt; } +} + +void MySensor::errBlink(uint8_t cnt) { + if(countErr == 255) { countErr = cnt; } +} +#endif void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { hw_init(); @@ -111,6 +175,23 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); #endif +#ifdef WITH_LEDS_BLINKING + // Setup led pins + pinMode(pinRx, OUTPUT); + pinMode(pinTx, OUTPUT); + pinMode(pinEr, OUTPUT); + + // Set initial state of leds + digitalWrite(pinRx, HIGH); + digitalWrite(pinTx, HIGH); + digitalWrite(pinEr, HIGH); + + // initialize counters + countRx = 0; + countTx = 0; + countErr = 0; +#endif + if (isGateway) { // Set configuration for gateway nc.parentNodeId = GATEWAY_ADDRESS; @@ -408,6 +489,11 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { boolean MySensor::process() { hw_watchdogReset(); + +#ifdef WITH_LEDS_BLINKING + handleLedsBlinking(); +#endif + uint8_t to = 0; if (!radio.available(&to)) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 0081b90..9917b66 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -145,6 +145,12 @@ class MySensor MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() #ifdef MY_SIGNING_FEATURE , MySigning &signer=*new MySigningNone() +#endif +#ifdef WITH_LEDS_BLINKING + , uint8_t _rx=DEFAULT_RX_LED_PIN, + uint8_t _tx=DEFAULT_TX_LED_PIN, + uint8_t _er=DEFAULT_ERR_LED_PIN, + unsigned long _blink_period=DEFAULT_LED_BLINK_PERIOD #endif ); @@ -299,6 +305,15 @@ class MySensor */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); +#ifdef WITH_LEDS_BLINKING + /** + * Blink with LEDs + * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms + */ + void rxBlink(uint8_t cnt); + void txBlink(uint8_t cnt); + void errBlink(uint8_t cnt); +#endif protected: NodeConfig nc; // Essential settings for node to work @@ -324,6 +339,20 @@ class MySensor MySigning& signer; #endif +#ifdef WITH_LEDS_BLINKING + uint8_t pinRx; // Rx led pin + uint8_t pinTx; // Tx led pin + uint8_t pinEr; // Err led pin + + // these variables don't need to be volatile, since we are not using interrupts + uint8_t countRx; + uint8_t countTx; + uint8_t countErr; + + unsigned long ledBlinkPeriod; + void handleLedsBlinking(); // do the actual blinking +#endif + MyTransport& radio; MyHw& hw; From 24464a6255988819d8ed4f87b1163d25d9ff1495 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sun, 19 Apr 2015 21:07:03 +0200 Subject: [PATCH 112/660] Use LED blinking in MySensor where appropriate Signed-off-by: Tomas Hozza --- libraries/MySensors/MySensor.cpp | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index f059b9e..cb0e026 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -327,12 +327,18 @@ boolean MySensor::sendRoute(MyMessage &message) { // If we still don't have any parent id, re-request and skip this message. if (nc.parentNodeId == AUTO) { findParentNode(); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } // If we still don't have any node id, re-request and skip this message. if (nc.nodeId == AUTO) { requestNodeId(); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } @@ -369,10 +375,16 @@ boolean MySensor::sendRoute(MyMessage &message) { } if (hw_millis() - enter > MY_VERIFICATION_TIMEOUT_MS) { debug(PSTR("nonce tmo\n")); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } if (!signOk) { debug(PSTR("sign fail\n")); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, @@ -431,6 +443,9 @@ boolean MySensor::sendRoute(MyMessage &message) { if (!ok) { // Failure when sending to parent node. The parent node might be down and we // need to find another route to gateway. +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif failedTransmissions++; if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { findParentNode(); @@ -445,6 +460,9 @@ boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = nc.nodeId; +#ifdef WITH_LEDS_BLINKING + txBlink(1); +#endif bool ok = radio.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), @@ -504,6 +522,9 @@ boolean MySensor::process() { debug(PSTR("fw upd fail\n")); // Give up. We have requested MY_OTA_RETRY times without any packet in return. fwUpdateOngoing = false; +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } fwRetry--; @@ -525,6 +546,9 @@ boolean MySensor::process() { #endif uint8_t len = radio.receive((uint8_t *)&msg); +#ifdef WITH_LEDS_BLINKING + rxBlink(1); +#endif #ifdef MY_SIGNING_FEATURE // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) @@ -537,10 +561,16 @@ boolean MySensor::process() { if (!mGetSigned(msg)) { // Got unsigned message that should have been signed debug(PSTR("no sign\n")); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } else if (!signer.verifyMsg(msg)) { debug(PSTR("verify fail\n")); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; // This signed message has been tampered with! } } @@ -554,6 +584,9 @@ boolean MySensor::process() { if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { debug(PSTR("ver mismatch\n")); +#ifdef WITH_LEDS_BLINKING + errBlink(1); +#endif return false; } From 0d6da230c5236daacb6375b6d04b30a3e91b90dc Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 6 May 2015 21:30:49 +0200 Subject: [PATCH 113/660] SerialGateway: Use internal LEDs feature for blinking Signed-off-by: Tomas Hozza --- .../examples/SerialGateway/GatewayUtil.h | 97 +++---------------- .../examples/SerialGateway/SerialGateway.ino | 15 +-- 2 files changed, 21 insertions(+), 91 deletions(-) diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index 532d9ca..bf24038 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -27,9 +27,6 @@ #ifdef ARDUINO -uint8_t pinRx = 8; // Rx led pin -uint8_t pinTx = 9; // Tx led pin -uint8_t pinEr = 7; // Err led pin uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode @@ -37,56 +34,28 @@ uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode #define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller volatile boolean buttonTriggeredInclusion; -volatile uint8_t countRx; -volatile uint8_t countTx; -volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); MyParserSerial parser; void setInclusionMode(boolean newMode); -void txBlink(uint8_t cnt); -void rxBlink(uint8_t cnt); -void errBlink(uint8_t cnt); char convBuf[MAX_PAYLOAD*2+1]; char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera unsigned long inclusionStartTime; -void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { +void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { inclusionMode = 0; buttonTriggeredInclusion = false; serial = _serial; - pinRx = _rx; - pinTx = _tx; - pinEr = _er; pinInclusion = _inc; inclusionTime = _incTime; - countRx = 0; - countTx = 0; - countErr = 0; - - - // Setup led pins - pinMode(pinRx, OUTPUT); - pinMode(pinTx, OUTPUT); - pinMode(pinEr, OUTPUT); - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); - // Setup digital in that triggers inclusion mode pinMode(pinInclusion, INPUT); digitalWrite(pinInclusion, HIGH); - - // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); - } @@ -96,11 +65,11 @@ void startInclusionInterrupt() { } void incomingMessage(const MyMessage &message) { - if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { - rxBlink(3); - } else { - rxBlink(1); - } +// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { +// gw.rxBlink(3); +// } else { +// gw.rxBlink(1); +// } // Pass along the message from sensors to serial line serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); } @@ -126,7 +95,7 @@ void checkInclusionFinished() { } } -void parseAndSend(MySensor gw, char *commandBuffer) { +void parseAndSend(MySensor &gw, char *commandBuffer) { boolean ok; MyMessage &msg = gw.getLastMessage(); @@ -143,10 +112,14 @@ void parseAndSend(MySensor gw, char *commandBuffer) { setInclusionMode(atoi(msg.data) == 1); } } else { - txBlink(1); + #ifdef WITH_LEDS_BLINKING + gw.txBlink(1); + #endif ok = gw.sendRoute(msg); if (!ok) { - errBlink(1); + #ifdef WITH_LEDS_BLINKING + gw.errBlink(1); + #endif } } } @@ -165,50 +138,6 @@ void setInclusionMode(boolean newMode) { } - - -void ledTimersInterrupt() { - if(countRx && countRx != 255) { - // switch led on - digitalWrite(pinRx, LOW); - } else if(!countRx) { - // switching off - digitalWrite(pinRx, HIGH); - } - if(countRx != 255) { countRx--; } - - if(countTx && countTx != 255) { - // switch led on - digitalWrite(pinTx, LOW); - } else if(!countTx) { - // switching off - digitalWrite(pinTx, HIGH); - } - if(countTx != 255) { countTx--; } - else if(inclusionMode) { countTx = 8; } - - if(countErr && countErr != 255) { - // switch led on - digitalWrite(pinEr, LOW); - } else if(!countErr) { - // switching off - digitalWrite(pinEr, HIGH); - } - if(countErr != 255) { countErr--; } -} - -void rxBlink(uint8_t cnt) { - if(countRx == 255) { countRx = cnt; } -} -void txBlink(uint8_t cnt) { - if(countTx == 255 && !inclusionMode) { countTx = cnt; } -} -void errBlink(uint8_t cnt) { - if(countErr == 255) { countErr = cnt; } -} - - - #else #error This example is only for use on Arduino. #endif // ARDUINO diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 9bfa910..7478665 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -29,6 +29,7 @@ * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): + * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error @@ -48,7 +49,6 @@ #include #include #include -#include #include #include "GatewayUtil.h" @@ -59,7 +59,7 @@ #define RADIO_TX_LED_PIN 5 // the PCB, on board LED // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); //MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) @@ -71,7 +71,12 @@ MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); MyHwATMega328 hw; // Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +#ifdef WITH_LEDS_BLINKING +MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else MySensor gw(transport, hw /*, signer*/); +#endif char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface int inputPos = 0; @@ -92,11 +97,7 @@ void setup() { gw.begin(incomingMessage, 0, true, 0); - setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - - // Add led timer interrupt - MsTimer2::set(300, ledTimersInterrupt); - MsTimer2::start(); + setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); // Add interrupt for inclusion button to pin PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); From 29b86801fbffa7853ea68eeba8a86a31c0f8f81f Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 6 May 2015 21:41:54 +0200 Subject: [PATCH 114/660] EthernetGateway: Use internal LEDs feature for blinking Signed-off-by: Tomas Hozza --- .../EthernetGateway/EthernetGateway.ino | 12 ++- .../examples/EthernetGateway/GatewayUtil.h | 97 +++---------------- 2 files changed, 20 insertions(+), 89 deletions(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 562b28d..383cbdf 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -46,6 +46,7 @@ * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 * * LED purposes: + * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error @@ -68,7 +69,6 @@ #include #include #include -#include #include #include "GatewayUtil.h" @@ -104,7 +104,12 @@ MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); MyHwATMega328 hw; // Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +#ifdef WITH_LEDS_BLINKING +MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else MySensor gw(transport, hw /*, signer*/); +#endif #define IP_PORT 5003 // The port you want to open @@ -136,11 +141,8 @@ void output(const char *fmt, ... ) { void setup() { Ethernet.begin(mac, myIp); - setupGateway(RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN, INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - // Add led timer interrupt - MsTimer2::set(300, ledTimersInterrupt); - MsTimer2::start(); + setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); // Add interrupt for inclusion button to pin PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 2c1b22c..64730f2 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -7,9 +7,6 @@ #ifdef ARDUINO -uint8_t pinRx = 8; // Rx led pin -uint8_t pinTx = 9; // Tx led pin -uint8_t pinEr = 7; // Err led pin uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode @@ -17,56 +14,28 @@ uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode #define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller volatile boolean buttonTriggeredInclusion; -volatile uint8_t countRx; -volatile uint8_t countTx; -volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); MyParserSerial parser; void setInclusionMode(boolean newMode); -void txBlink(uint8_t cnt); -void rxBlink(uint8_t cnt); -void errBlink(uint8_t cnt); char convBuf[MAX_PAYLOAD*2+1]; char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera unsigned long inclusionStartTime; -void setupGateway(uint8_t _rx, uint8_t _tx, uint8_t _er, uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { +void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { inclusionMode = 0; buttonTriggeredInclusion = false; serial = _serial; - pinRx = _rx; - pinTx = _tx; - pinEr = _er; pinInclusion = _inc; inclusionTime = _incTime; - countRx = 0; - countTx = 0; - countErr = 0; - - - // Setup led pins - pinMode(pinRx, OUTPUT); - pinMode(pinTx, OUTPUT); - pinMode(pinEr, OUTPUT); - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); - // Setup digital in that triggers inclusion mode pinMode(pinInclusion, INPUT); digitalWrite(pinInclusion, HIGH); - - // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); - } @@ -76,11 +45,11 @@ void startInclusionInterrupt() { } void incomingMessage(const MyMessage &message) { - if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { - rxBlink(3); - } else { - rxBlink(1); - } +// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { +// gw.rxBlink(3); +// } else { +// gw.rxBlink(1); +// } // Pass along the message from sensors to serial line serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); } @@ -106,7 +75,7 @@ void checkInclusionFinished() { } } -void parseAndSend(MySensor gw, char *commandBuffer) { +void parseAndSend(MySensor &gw, char *commandBuffer) { boolean ok; MyMessage &msg = gw.getLastMessage(); @@ -123,10 +92,14 @@ void parseAndSend(MySensor gw, char *commandBuffer) { setInclusionMode(atoi(msg.data) == 1); } } else { - txBlink(1); + #ifdef WITH_LEDS_BLINKING + gw.txBlink(1); + #endif ok = gw.sendRoute(msg); if (!ok) { - errBlink(1); + #ifdef WITH_LEDS_BLINKING + gw.errBlink(1); + #endif } } } @@ -145,50 +118,6 @@ void setInclusionMode(boolean newMode) { } - - -void ledTimersInterrupt() { - if(countRx && countRx != 255) { - // switch led on - digitalWrite(pinRx, LOW); - } else if(!countRx) { - // switching off - digitalWrite(pinRx, HIGH); - } - if(countRx != 255) { countRx--; } - - if(countTx && countTx != 255) { - // switch led on - digitalWrite(pinTx, LOW); - } else if(!countTx) { - // switching off - digitalWrite(pinTx, HIGH); - } - if(countTx != 255) { countTx--; } - else if(inclusionMode) { countTx = 8; } - - if(countErr && countErr != 255) { - // switch led on - digitalWrite(pinEr, LOW); - } else if(!countErr) { - // switching off - digitalWrite(pinEr, HIGH); - } - if(countErr != 255) { countErr--; } -} - -void rxBlink(uint8_t cnt) { - if(countRx == 255) { countRx = cnt; } -} -void txBlink(uint8_t cnt) { - if(countTx == 255 && !inclusionMode) { countTx = cnt; } -} -void errBlink(uint8_t cnt) { - if(countErr == 255) { countErr = cnt; } -} - - - #else #error This example is only for use on Arduino. #endif // ARDUINO From 9469188e3226793f8718ea572f69bd84b961e116 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 12 May 2015 00:36:22 +0200 Subject: [PATCH 115/660] Work in progress --- libraries/MySensors/MyConfig.h | 8 +- libraries/MySensors/MyGateway.cpp | 99 +++++++++++++++++++ libraries/MySensors/MyGateway.h | 83 ++++++++++++++++ ...yParserSerial.h => MyGatewayTransport.cpp} | 17 +--- libraries/MySensors/MyGatewayTransport.h | 44 +++++++++ .../MySensors/MyGatewayTransportSerial.cpp | 66 +++++++++++++ .../MySensors/MyGatewayTransportSerial.h | 50 ++++++++++ .../{MyParser.cpp => MyProtocol.cpp} | 4 +- .../MySensors/{MyParser.h => MyProtocol.h} | 14 ++- ...ParserSerial.cpp => MyProtocolDefault.cpp} | 16 ++- libraries/MySensors/MyProtocolDefault.h | 42 ++++++++ libraries/MySensors/MySensor.cpp | 91 +++++++++-------- libraries/MySensors/MySensor.h | 16 +-- .../EthernetGateway/EthernetGateway.ino | 2 +- .../examples/EthernetGateway/GatewayUtil.h | 4 +- .../examples/SerialGateway/GatewayUtil.h | 4 +- .../examples/SerialGateway/SerialGateway.ino | 2 +- 17 files changed, 477 insertions(+), 85 deletions(-) create mode 100644 libraries/MySensors/MyGateway.cpp create mode 100644 libraries/MySensors/MyGateway.h rename libraries/MySensors/{MyParserSerial.h => MyGatewayTransport.cpp} (76%) create mode 100644 libraries/MySensors/MyGatewayTransport.h create mode 100644 libraries/MySensors/MyGatewayTransportSerial.cpp create mode 100644 libraries/MySensors/MyGatewayTransportSerial.h rename libraries/MySensors/{MyParser.cpp => MyProtocol.cpp} (94%) rename libraries/MySensors/{MyParser.h => MyProtocol.h} (84%) rename libraries/MySensors/{MyParserSerial.cpp => MyProtocolDefault.cpp} (83%) create mode 100644 libraries/MySensors/MyProtocolDefault.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index c2148ab..020092d 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -56,13 +56,13 @@ // #define WITH_LEDS_BLINKING // default LEDs blinking period in milliseconds -#define DEFAULT_LED_BLINK_PERIOD 300 +#define MY_DEFAULT_LED_BLINK_PERIOD 300 // The RX LED default pin -#define DEFAULT_RX_LED_PIN 8 +#define MY_DEFAULT_RX_LED_PIN 8 // The TX LED default pin -#define DEFAULT_TX_LED_PIN 9 +#define MY_DEFAULT_TX_LED_PIN 9 // The Error LED default pin -#define DEFAULT_ERR_LED_PIN 7 +#define MY_DEFAULT_ERR_LED_PIN 7 /********************************** diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp new file mode 100644 index 0000000..93e58be --- /dev/null +++ b/libraries/MySensors/MyGateway.cpp @@ -0,0 +1,99 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyGateway.h" + +// Inline function and macros +static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { + msg.sender = sender; + msg.destination = destination; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,enableAck); + mSetAck(msg,false); + return msg; +} + +MyGateway::MyGateway(MyGatewayTransport &_transport,MyTransport &_radio, MyHw &_hw +#ifdef MY_SIGNING_FEATURE + , MySigning &_signer +#endif +#ifdef WITH_LEDS_BLINKING + , uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period +#endif + ) : transport(_transport),MySensor(_radio, _hw +#ifdef MY_SIGNING_FEATURE + , _signer +#endif +#ifdef WITH_LEDS_BLINKING + , _rx, _tx, _er, _blink_period +#endif + ) +{ + +} + +boolean MyGateway::sendRoute(MyMessage &message) { + if (message.destination == GATEWAY_ADDRESS) { + // This is a message sent from a sensor attached on the gateway node. + // Pass it directly to the gateway transport layer. + transport.send(message); + } else { + MySensor::sendRoute(message); + } +} + + +boolean MyGateway::process() { + bool newMessage = false; + if (transport.available()) { + MyMessage &gmsg = transport.receive(); + if (msg.destination == GATEWAY_ADDRESS) { + // Check if sender requests an ack back. + if (mGetRequestAck(gmsg)) { + // Copy message + tmpMsg = gmsg; + mSetRequestAck(tmpMsg,false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(tmpMsg,true); + tmpMsg.sender = nc.nodeId; + tmpMsg.destination = msg.sender; + transport.send(tmpMsg); + } + if (mGetCommand(gmsg) == C_INTERNAL) { + if (msg.type == I_VERSION) { + // Request for version. Create the response + transport.send(build(msg, GATEWAY_ADDRESS, GATEWAY_ADDRESS, GATEWAY_ADDRESS, C_INTERNAL, I_VERSION, false).set(LIBRARY_VERSION)); + } else if (msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + //setInclusionMode(atoi(msg.data) == 1); + } else { + processInternalMessages(gmsg); + } + } else { + // Call incoming message callback if available + if (msgCallback != NULL) { + msgCallback(msg); + } + newMessage = true; + } + } + } + return MySensor::process() || newMessage; +} diff --git a/libraries/MySensors/MyGateway.h b/libraries/MySensors/MyGateway.h new file mode 100644 index 0000000..a7cc319 --- /dev/null +++ b/libraries/MySensors/MyGateway.h @@ -0,0 +1,83 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyGateway_h +#define MyGateway_h + + +#include "MyConfig.h" +#include "MySensor.h" +#include "MyHw.h" +#include "MyTransport.h" +#include "MyTransportNRF24.h" +#ifdef MY_SIGNING_FEATURE +#include "MySigning.h" +#include "MySigningNone.h" +#endif +#include "MyMessage.h" +#ifdef MY_OTA_FIRMWARE_FEATURE +#include "utility/SPIFlash.h" +#endif + +#include "MyProtocol.h" +#include "MyGatewayTransport.h" +#include "MyGatewayTransportSerial.h" + +#include +#include + + +class MyGateway : public MySensor +{ +public: + // MyProtocolSerial constructor + MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() +#ifdef MY_SIGNING_FEATURE + , MySigning &signer=*new MySigningNone() +#endif +#ifdef WITH_LEDS_BLINKING + , uint8_t _rx=MY_DEFAULT_RX_LED_PIN + , uint8_t _tx=MY_DEFAULT_TX_LED_PIN + , uint8_t _er=MY_DEFAULT_ERR_LED_PIN + , unsigned long _blink_period=MY_DEFAULT_LED_BLINK_PERIOD +#endif + ); + + + void enableInclusionModeFeature(uint8_t inclusionModeButtonPin, uint8_t inclusionModeDuration); + + /** + * See MySensor.h + * + * Overloaded to handle local sensor data sent to controller. + */ + boolean sendRoute(MyMessage &message); + + /** + * Processes incoming messages to this node. + * Returns true if there is a message addressed for this node was received. + * Preferred way of handling incoming messages is to use the callback defined in begin(). + */ + boolean process(); + +private: + MyGatewayTransport &transport; +}; + +#endif diff --git a/libraries/MySensors/MyParserSerial.h b/libraries/MySensors/MyGatewayTransport.cpp similarity index 76% rename from libraries/MySensors/MyParserSerial.h rename to libraries/MySensors/MyGatewayTransport.cpp index 80d315d..2306d5f 100644 --- a/libraries/MySensors/MyParserSerial.h +++ b/libraries/MySensors/MyGatewayTransport.cpp @@ -17,18 +17,9 @@ * version 2 as published by the Free Software Foundation. */ -#ifndef MyParserSerial_h -#define MyParserSerial_h +#include "MyGatewayTransport.h" -#include "MyConfig.h" -#include "MyParser.h" -class MyParserSerial : public MyParser -{ -public: - MyParserSerial(); - bool parse(MyMessage &message, char *inputString); -private: - uint8_t h2i(char c); -}; -#endif +MyGatewayTransport::MyGatewayTransport(MyProtocol &_protocol) : protocol(_protocol) { + +} diff --git a/libraries/MySensors/MyGatewayTransport.h b/libraries/MySensors/MyGatewayTransport.h new file mode 100644 index 0000000..d94006f --- /dev/null +++ b/libraries/MySensors/MyGatewayTransport.h @@ -0,0 +1,44 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyGatewayTransport_h +#define MyGatewayTransport_h + +#include "MyMessage.h" +#include "MyProtocol.h" +#include "MyProtocolDefault.h" + +class MyGatewayTransport +{ +public: + // MyProtocol constructor + MyGatewayTransport(MyProtocol &protocol = *new MyProtocolDefault()); + + // Send message to controller + virtual bool send(MyMessage &message) = 0; + + // Check if a new message is available from controller + virtual bool available() = 0; + + // Pick up last message received from controller + virtual MyMessage& receive() = 0; +protected: + MyProtocol& protocol; +}; +#endif diff --git a/libraries/MySensors/MyGatewayTransportSerial.cpp b/libraries/MySensors/MyGatewayTransportSerial.cpp new file mode 100644 index 0000000..e0f79bf --- /dev/null +++ b/libraries/MySensors/MyGatewayTransportSerial.cpp @@ -0,0 +1,66 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyGatewayTransportSerial.h" + + +MyGatewayTransportSerial::MyGatewayTransportSerial(MyProtocol &_protocol) : MyGatewayTransport(_protocol),inputPos(0) +{ + +} + +bool MyGatewayTransportSerial::send(MyMessage &message) { + Serial.print(protocol.format(message)); + // Serial print is always successful + return true; +} + +bool MyGatewayTransportSerial::available() { + bool available = false; + while (Serial.available()) { + // get the new byte: + char inChar = (char) Serial.read(); + // if the incoming character is a newline, set a flag + // so the main loop can do something about it: + if (inputPos < MAX_RECEIVE_LENGTH - 1 && !available) { + if (inChar == '\n') { + inputString[inputPos] = 0; + available = true; + } else { + // add it to the inputString: + inputString[inputPos] = inChar; + inputPos++; + } + } else { + // Incoming message too long. Throw away + inputPos = 0; + } + } + if (available) { + // Parse message and return parse result + available = protocol.parse(msg, inputString); + inputPos = 0; + } + return available; +} + +MyMessage & MyGatewayTransportSerial::receive() { + // Return the last parsed message + return msg; +} diff --git a/libraries/MySensors/MyGatewayTransportSerial.h b/libraries/MySensors/MyGatewayTransportSerial.h new file mode 100644 index 0000000..678e932 --- /dev/null +++ b/libraries/MySensors/MyGatewayTransportSerial.h @@ -0,0 +1,50 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyGatewayTransportSerial_h +#define MyGatewayTransportSerial_h + +#include "MyMessage.h" +#include "MyProtocol.h" +#include "MyGatewayTransport.h" +#include "MyProtocolDefault.h" + +#define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller + +class MyGatewayTransportSerial : public MyGatewayTransport +{ +public: + // MyGateway constructor + MyGatewayTransportSerial(MyProtocol &protocol = *new MyProtocolDefault()); + + // Send message to controller + bool send(MyMessage &message); + + // Check if a new message is available from controller + bool available(); + + // Pick up last message received from controller + MyMessage& receive(); +private: + char inputString[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface + int inputPos; + MyMessage msg; +}; + +#endif diff --git a/libraries/MySensors/MyParser.cpp b/libraries/MySensors/MyProtocol.cpp similarity index 94% rename from libraries/MySensors/MyParser.cpp rename to libraries/MySensors/MyProtocol.cpp index 2011d16..f0a473a 100644 --- a/libraries/MySensors/MyParser.cpp +++ b/libraries/MySensors/MyProtocol.cpp @@ -17,7 +17,7 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyParser.h" +#include "MyProtocol.h" -MyParser::MyParser() { +MyProtocol::MyProtocol() { } diff --git a/libraries/MySensors/MyParser.h b/libraries/MySensors/MyProtocol.h similarity index 84% rename from libraries/MySensors/MyParser.h rename to libraries/MySensors/MyProtocol.h index 39e2975..5b0298f 100644 --- a/libraries/MySensors/MyParser.h +++ b/libraries/MySensors/MyProtocol.h @@ -17,19 +17,23 @@ * version 2 as published by the Free Software Foundation. */ -#ifndef MyParser_h -#define MyParser_h +#ifndef MyProtocol_h +#define MyProtocol_h #include "MyMessage.h" -class MyParser +class MyProtocol { public: - // MyParser constructor - MyParser(); + // MyProtocol constructor + MyProtocol(); // parse(message, inputString) // parse a string into a message element // returns true if successfully parsed the input string virtual bool parse(MyMessage &message, char *inputString) = 0; + + // Format MyMessage to the protocol represenataion + virtual char *format(MyMessage &message) = 0; + }; #endif diff --git a/libraries/MySensors/MyParserSerial.cpp b/libraries/MySensors/MyProtocolDefault.cpp similarity index 83% rename from libraries/MySensors/MyParserSerial.cpp rename to libraries/MySensors/MyProtocolDefault.cpp index e2ee52a..f410abe 100644 --- a/libraries/MySensors/MyParserSerial.cpp +++ b/libraries/MySensors/MyProtocolDefault.cpp @@ -17,13 +17,13 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyParser.h" -#include "MyParserSerial.h" +#include "MyProtocol.h" +#include "MyProtocolDefault.h" #include "MyTransport.h" -MyParserSerial::MyParserSerial() : MyParser() {} +MyProtocolDefault::MyProtocolDefault() : MyProtocol() {} -bool MyParserSerial::parse(MyMessage &message, char *inputString) { +bool MyProtocolDefault::parse(MyMessage &message, char *inputString) { char *str, *p, *value=NULL; uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; @@ -89,7 +89,13 @@ bool MyParserSerial::parse(MyMessage &message, char *inputString) { return true; } -uint8_t MyParserSerial::h2i(char c) { +char * MyProtocolDefault::format(MyMessage &message) { + snprintf_P(fmtBuffer, MAX_FORMAT_BUFFER_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuffer)); + return fmtBuffer; +} + + +uint8_t MyProtocolDefault::h2i(char c) { uint8_t i = 0; if (c <= '9') i += c - '0'; diff --git a/libraries/MySensors/MyProtocolDefault.h b/libraries/MySensors/MyProtocolDefault.h new file mode 100644 index 0000000..8d35609 --- /dev/null +++ b/libraries/MySensors/MyProtocolDefault.h @@ -0,0 +1,42 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyProtocolDefault_h +#define MyProtocolDefault_h + +#include "MyConfig.h" +#include "MyProtocol.h" +#include "MyTransport.h" + +#define MAX_FORMAT_BUFFER_LENGTH 120 // Max buffersize when formatting messages + + +class MyProtocolDefault : public MyProtocol +{ +public: + MyProtocolDefault(); + bool parse(MyMessage &message, char *inputString); + char *format(MyMessage &message); +private: + char fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; + char convBuffer[MAX_PAYLOAD*2+1]; + + uint8_t h2i(char c); +}; +#endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index cb0e026..8929282 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -667,50 +667,19 @@ boolean MySensor::process() { return true; // Just pass along nonce silently (no need to call callback for these) #endif } else if (sender == GATEWAY_ADDRESS) { - bool isMetric; - - if (type == I_REBOOT) { - // Requires MySensors or other bootloader with watchdogs enabled - hw_reboot(); - } else if (type == I_ID_RESPONSE) { + if (type == I_ID_RESPONSE && nc.nodeId == AUTO) { + nc.nodeId = msg.getByte(); if (nc.nodeId == AUTO) { - nc.nodeId = msg.getByte(); - if (nc.nodeId == AUTO) { - // sensor net gateway will return max id if all sensor id are taken - debug(PSTR("full\n")); - while (1); // Wait here. Nothing else we can do... - } - setupNode(); - // Write id to EEPROM - hw_writeConfig(EEPROM_NODE_ID_ADDRESS, nc.nodeId); - debug(PSTR("id=%d\n"), nc.nodeId); - } - } else if (type == I_CONFIG) { - // Pick up configuration from controller (currently only metric/imperial) - // and store it in eeprom if changed - isMetric = msg.getString()[0] == 'M' ; - cc.isMetric = isMetric; - hw_writeConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); - } else if (type == I_CHILDREN) { - if (repeaterMode && msg.getString()[0] == 'C') { - // Clears child relay data for this node - debug(PSTR("clear\n")); - uint8_t i = 255; - do { - hw_writeConfig(EEPROM_ROUTES_ADDRESS+i, 0xff); - } while (i--); - // Clear parent node id & distance to gw - hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); - hw_writeConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); - // Find parent node - findParentNode(); - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); - } - } else if (type == I_TIME) { - if (timeCallback != NULL) { - // Deliver time to callback - timeCallback(msg.getULong()); + // sensor net gateway will return max id if all sensor id are taken + debug(PSTR("full\n")); + while (1); // Wait here. Nothing else we can do... } + setupNode(); + // Write id to EEPROM + hw_writeConfig(EEPROM_NODE_ID_ADDRESS, nc.nodeId); + debug(PSTR("id=%d\n"), nc.nodeId); + } else { + processInternalMessages(msg); } return false; } @@ -791,6 +760,44 @@ boolean MySensor::process() { return false; } + +void MySensor::processInternalMessages(MyMessage &msg) { + bool isMetric; + uint8_t type = msg.type; + + if (type == I_REBOOT) { + // Requires MySensors or other bootloader with watchdogs enabled + hw_reboot(); + } else if (type == I_CONFIG) { + // Pick up configuration from controller (currently only metric/imperial) + // and store it in eeprom if changed + isMetric = msg.getString()[0] == 'M' ; + cc.isMetric = isMetric; + hw_writeConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); + } else if (type == I_CHILDREN) { + if (repeaterMode && msg.getString()[0] == 'C') { + // Clears child relay data for this node + debug(PSTR("clear\n")); + uint8_t i = 255; + do { + hw_writeConfig(EEPROM_ROUTES_ADDRESS+i, 0xff); + } while (i--); + // Clear parent node id & distance to gw + hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); + hw_writeConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); + // Find parent node + findParentNode(); + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); + } + } else if (type == I_TIME) { + if (timeCallback != NULL) { + // Deliver time to callback + timeCallback(msg.getULong()); + } + } +} + + MyMessage& MySensor::getLastMessage() { return msg; } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 9917b66..dfc762c 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -26,7 +26,6 @@ #include "MyHw.h" #include "MyTransport.h" #include "MyTransportNRF24.h" -#include "MyParser.h" #ifdef MY_SIGNING_FEATURE #include "MySigning.h" #include "MySigningNone.h" @@ -147,10 +146,10 @@ class MySensor , MySigning &signer=*new MySigningNone() #endif #ifdef WITH_LEDS_BLINKING - , uint8_t _rx=DEFAULT_RX_LED_PIN, - uint8_t _tx=DEFAULT_TX_LED_PIN, - uint8_t _er=DEFAULT_ERR_LED_PIN, - unsigned long _blink_period=DEFAULT_LED_BLINK_PERIOD + , uint8_t _rx=MY_DEFAULT_RX_LED_PIN, + uint8_t _tx=MY_DEFAULT_TX_LED_PIN, + uint8_t _er=MY_DEFAULT_ERR_LED_PIN, + unsigned long _blink_period=MY_DEFAULT_LED_BLINK_PERIOD #endif ); @@ -199,7 +198,6 @@ class MySensor */ bool send(MyMessage &msg, bool ack=false); - boolean sendRoute(MyMessage &message); /** * Send this nodes battery level to gateway. @@ -315,6 +313,8 @@ class MySensor void errBlink(uint8_t cnt); #endif + boolean sendRoute(MyMessage &message); + protected: NodeConfig nc; // Essential settings for node to work ControllerConfig cc; // Configuration coming from controller @@ -357,8 +357,7 @@ class MySensor MyHw& hw; boolean sendWrite(uint8_t dest, MyMessage &message); - - private: + void processInternalMessages(MyMessage &msg); #ifdef DEBUG char convBuf[MAX_PAYLOAD*2+1]; #endif @@ -371,6 +370,7 @@ class MySensor bool isValidFirmware(); #endif + private: void requestNodeId(); void setupNode(); diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 383cbdf..dcbb32f 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -66,7 +66,7 @@ #include #include -#include +#include #include #include #include diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 64730f2..4547446 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -17,7 +17,7 @@ volatile boolean buttonTriggeredInclusion; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyParserSerial parser; +MyProtocolDefault protocol; void setInclusionMode(boolean newMode); @@ -79,7 +79,7 @@ void parseAndSend(MySensor &gw, char *commandBuffer) { boolean ok; MyMessage &msg = gw.getLastMessage(); - if (parser.parse(msg, commandBuffer)) { + if (protocol.parse(msg, commandBuffer)) { uint8_t command = mGetCommand(msg); if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h index bf24038..e3cb90a 100644 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h @@ -37,7 +37,7 @@ volatile boolean buttonTriggeredInclusion; boolean inclusionMode; // Keeps track on inclusion mode void (*serial)(const char *fmt, ... ); -MyParserSerial parser; +MyProtocolDefault protocol; void setInclusionMode(boolean newMode); @@ -99,7 +99,7 @@ void parseAndSend(MySensor &gw, char *commandBuffer) { boolean ok; MyMessage &msg = gw.getLastMessage(); - if (parser.parse(msg, commandBuffer)) { + if (protocol.parse(msg, commandBuffer)) { uint8_t command = mGetCommand(msg); if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 7478665..ad75280 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include #include From 01d13f0ca42b288fe4851fffdeb93ea2ec96881a Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 12 May 2015 23:28:49 +0200 Subject: [PATCH 116/660] Serial Gateway in a working state --- libraries/MySensors/MyConfig.h | 24 ++- libraries/MySensors/MyGateway.cpp | 109 ++++++++++--- libraries/MySensors/MyGateway.h | 35 ++++- libraries/MySensors/MySensor.cpp | 32 ++-- libraries/MySensors/MySensor.h | 6 +- .../EthernetGateway/EthernetGateway.ino | 4 +- .../examples/EthernetGateway/GatewayUtil.h | 4 +- .../examples/SerialGateway/GatewayUtil.h | 146 ------------------ .../examples/SerialGateway/SerialGateway.ino | 97 +++--------- 9 files changed, 185 insertions(+), 272 deletions(-) delete mode 100644 libraries/MySensors/examples/SerialGateway/GatewayUtil.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 020092d..0e07a5a 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -49,22 +49,36 @@ * Information LEDs blinking ***********************************/ // This feature enables LEDs blinking on message receive, transmit -// or if some error occured. This was commonly used only in gateways, +// or if some error occurred. This was commonly used only in gateways, // but now can be used in any sensor node. Also the LEDs can now be // disabled in the gateway. -// #define WITH_LEDS_BLINKING +// #define MY_LEDS_BLINKING_FEATURE // default LEDs blinking period in milliseconds #define MY_DEFAULT_LED_BLINK_PERIOD 300 // The RX LED default pin -#define MY_DEFAULT_RX_LED_PIN 8 +#define MY_DEFAULT_RX_LED_PIN 6 // The TX LED default pin -#define MY_DEFAULT_TX_LED_PIN 9 +#define MY_DEFAULT_TX_LED_PIN 5 // The Error LED default pin -#define MY_DEFAULT_ERR_LED_PIN 7 +#define MY_DEFAULT_ERR_LED_PIN 4 +/********************************************** +* Gateway inclusion button/mode configuration +**********************************************/ +// Enabled inclusion mode feature +#define MY_INCLUSION_MODE_FEATURE + +// Enables inclusion-mode button feature on the gateway device +#define MY_INCLUSION_BUTTON_FEATURE + +// The default input pin used for the inclusion mode button +#define MY_INCLUSION_MODE_BUTTON_PIN 3 +// Number of seconds (default one minute) inclusion mode should be enabled +#define MY_INCLUSION_MODE_DURATION 60 + /********************************** * Message Signing Settings ***********************************/ diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index 93e58be..db4e4ee 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -20,33 +20,64 @@ #include "MyGateway.h" // Inline function and macros -static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { - msg.sender = sender; - msg.destination = destination; - msg.sensor = sensor; +static inline MyMessage& build(MyMessage &msg, uint8_t type) { + msg.sender = GATEWAY_ADDRESS; + msg.destination = GATEWAY_ADDRESS; + msg.sensor = 0; msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,enableAck); - mSetAck(msg,false); + mSetCommand(msg, C_INTERNAL); + mSetRequestAck(msg, false); + mSetAck(msg, false); return msg; } -MyGateway::MyGateway(MyGatewayTransport &_transport,MyTransport &_radio, MyHw &_hw +MyGateway::MyGateway(MyGatewayTransport &_transport, MyTransport &_radio, + MyHw &_hw #ifdef MY_SIGNING_FEATURE - , MySigning &_signer + , MySigning &_signer #endif -#ifdef WITH_LEDS_BLINKING - , uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period +#ifdef MY_LEDS_BLINKING_FEATURE + , uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period #endif - ) : transport(_transport),MySensor(_radio, _hw + ) : + transport(_transport), MySensor(_radio, _hw #ifdef MY_SIGNING_FEATURE - , _signer + , _signer #endif -#ifdef WITH_LEDS_BLINKING - , _rx, _tx, _er, _blink_period +#ifdef MY_LEDS_BLINKING_FEATURE + , _rx, _tx, _er, _blink_period #endif ) { +#ifdef MY_INCLUSION_MODE_FEATURE + inclusionMode = false; +#endif +} + +void MyGateway::begin(void (*_msgCallback)(const MyMessage &) +#ifdef MY_INCLUSION_MODE_FEATURE + , int _inclusionModeDuration +#ifdef MY_INCLUSION_BUTTON_FEATURE + , uint8_t _inclusionModeButtonPin +#endif +#endif + +) { + // Setup digital in that triggers inclusion mode +#ifdef MY_INCLUSION_MODE_FEATURE + inclusionDuration = _inclusionModeDuration*1000; +#ifdef MY_INCLUSION_BUTTON_FEATURE + inclusionButtonPin = _inclusionModeButtonPin; + pinMode(inclusionButtonPin, INPUT); + digitalWrite(inclusionButtonPin, HIGH); +#endif +#endif + + // Start MySensors in repeater mode + MySensor::begin(_msgCallback, GATEWAY_ADDRESS, true, GATEWAY_ADDRESS); + + // Startup complete + transport.send(build(msg, I_GATEWAY_READY).set("Gateway startup complete.")); } @@ -60,8 +91,8 @@ boolean MyGateway::sendRoute(MyMessage &message) { } } - boolean MyGateway::process() { + checkInclusionMode(); bool newMessage = false; if (transport.available()) { MyMessage &gmsg = transport.receive(); @@ -70,8 +101,8 @@ boolean MyGateway::process() { if (mGetRequestAck(gmsg)) { // Copy message tmpMsg = gmsg; - mSetRequestAck(tmpMsg,false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(tmpMsg,true); + mSetRequestAck(tmpMsg, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(tmpMsg, true); tmpMsg.sender = nc.nodeId; tmpMsg.destination = msg.sender; transport.send(tmpMsg); @@ -79,10 +110,12 @@ boolean MyGateway::process() { if (mGetCommand(gmsg) == C_INTERNAL) { if (msg.type == I_VERSION) { // Request for version. Create the response - transport.send(build(msg, GATEWAY_ADDRESS, GATEWAY_ADDRESS, GATEWAY_ADDRESS, C_INTERNAL, I_VERSION, false).set(LIBRARY_VERSION)); + transport.send(build(msg, I_VERSION).set(LIBRARY_VERSION)); +#ifdef MY_INCLUSION_MODE_FEATURE } else if (msg.type == I_INCLUSION_MODE) { // Request to change inclusion mode - //setInclusionMode(atoi(msg.data) == 1); + setInclusionMode(atoi(msg.data) == 1); +#endif } else { processInternalMessages(gmsg); } @@ -97,3 +130,39 @@ boolean MyGateway::process() { } return MySensor::process() || newMessage; } + +#ifdef MY_INCLUSION_MODE_FEATURE +void MyGateway::setInclusionMode(boolean newMode) { + if (newMode != inclusionMode) { + inclusionMode = newMode; + // Send back mode change to controller + transport.send(build(msg, I_INCLUSION_MODE).set(inclusionMode?1:0)); + if (inclusionMode) { + + inclusionStartTime = hw_millis(); + Serial.println(inclusionStartTime); + Serial.println(inclusionDuration); + + } + } +} + +void MyGateway::checkInclusionMode() { + + #ifdef MY_INCLUSION_BUTTON_FEATURE + if (!inclusionMode && digitalRead(inclusionButtonPin) == LOW) { + // Start inclusion mode + setInclusionMode(true); + } + #endif + + if (inclusionMode && hw_millis()-inclusionStartTime>inclusionDuration) { + // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode + setInclusionMode(false); + } +} + + +#endif + + diff --git a/libraries/MySensors/MyGateway.h b/libraries/MySensors/MyGateway.h index a7cc319..7ec55dc 100644 --- a/libraries/MySensors/MyGateway.h +++ b/libraries/MySensors/MyGateway.h @@ -51,7 +51,7 @@ public: #ifdef MY_SIGNING_FEATURE , MySigning &signer=*new MySigningNone() #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE , uint8_t _rx=MY_DEFAULT_RX_LED_PIN , uint8_t _tx=MY_DEFAULT_TX_LED_PIN , uint8_t _er=MY_DEFAULT_ERR_LED_PIN @@ -60,7 +60,24 @@ public: ); - void enableInclusionModeFeature(uint8_t inclusionModeButtonPin, uint8_t inclusionModeDuration); + /** + * Begin operation of the MySensors library + * + * Call this in setup(), before calling any other sensor net library methods. + * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. + * @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled + * @param inclusionModeButtonPin Button pin used for enabling inclusion mode + */ + + void begin(void (* msgCallback)(const MyMessage &)=NULL +#ifdef MY_INCLUSION_MODE_FEATURE + , int inclusionModeDuration=MY_INCLUSION_MODE_DURATION +#ifdef MY_INCLUSION_BUTTON_FEATURE + , uint8_t inclusionModeButtonPin=MY_INCLUSION_MODE_BUTTON_PIN +#endif +#endif + ); + /** * See MySensor.h @@ -77,7 +94,21 @@ public: boolean process(); private: + MyGatewayTransport &transport; + +#ifdef MY_INCLUSION_MODE_FEATURE + + void setInclusionMode(bool newMode); + void checkInclusionMode(); + unsigned long inclusionStartTime; + bool inclusionMode; + unsigned long inclusionDuration; + + #ifdef MY_INCLUSION_BUTTON_FEATURE + uint8_t inclusionButtonPin; + #endif +#endif }; #endif diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 8929282..0a35016 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -53,7 +53,7 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_SIGNING_FEATURE , MySigning &_signer #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE , uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period #endif ) @@ -62,7 +62,7 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_SIGNING_FEATURE signer(_signer), #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE pinRx(_rx), pinTx(_tx), pinEr(_er), ledBlinkPeriod(_blink_period), #endif #ifdef MY_OTA_FIRMWARE_FEATURE @@ -96,7 +96,7 @@ bool MySensor::isValidFirmware() { #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE void MySensor::handleLedsBlinking() { static unsigned long next_time = hw_millis() + ledBlinkPeriod; @@ -175,7 +175,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE // Setup led pins pinMode(pinRx, OUTPUT); pinMode(pinTx, OUTPUT); @@ -327,7 +327,7 @@ boolean MySensor::sendRoute(MyMessage &message) { // If we still don't have any parent id, re-request and skip this message. if (nc.parentNodeId == AUTO) { findParentNode(); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; @@ -336,7 +336,7 @@ boolean MySensor::sendRoute(MyMessage &message) { // If we still don't have any node id, re-request and skip this message. if (nc.nodeId == AUTO) { requestNodeId(); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; @@ -375,14 +375,14 @@ boolean MySensor::sendRoute(MyMessage &message) { } if (hw_millis() - enter > MY_VERIFICATION_TIMEOUT_MS) { debug(PSTR("nonce tmo\n")); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; } if (!signOk) { debug(PSTR("sign fail\n")); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; @@ -443,7 +443,7 @@ boolean MySensor::sendRoute(MyMessage &message) { if (!ok) { // Failure when sending to parent node. The parent node might be down and we // need to find another route to gateway. -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif failedTransmissions++; @@ -460,7 +460,7 @@ boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = nc.nodeId; -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE txBlink(1); #endif bool ok = radio.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); @@ -508,7 +508,7 @@ void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { boolean MySensor::process() { hw_watchdogReset(); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE handleLedsBlinking(); #endif @@ -522,7 +522,7 @@ boolean MySensor::process() { debug(PSTR("fw upd fail\n")); // Give up. We have requested MY_OTA_RETRY times without any packet in return. fwUpdateOngoing = false; -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; @@ -546,7 +546,7 @@ boolean MySensor::process() { #endif uint8_t len = radio.receive((uint8_t *)&msg); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE rxBlink(1); #endif @@ -561,14 +561,14 @@ boolean MySensor::process() { if (!mGetSigned(msg)) { // Got unsigned message that should have been signed debug(PSTR("no sign\n")); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; } else if (!signer.verifyMsg(msg)) { debug(PSTR("verify fail\n")); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; // This signed message has been tampered with! @@ -584,7 +584,7 @@ boolean MySensor::process() { if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { debug(PSTR("ver mismatch\n")); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE errBlink(1); #endif return false; diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index dfc762c..ad8e8f8 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -145,7 +145,7 @@ class MySensor #ifdef MY_SIGNING_FEATURE , MySigning &signer=*new MySigningNone() #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE , uint8_t _rx=MY_DEFAULT_RX_LED_PIN, uint8_t _tx=MY_DEFAULT_TX_LED_PIN, uint8_t _er=MY_DEFAULT_ERR_LED_PIN, @@ -303,7 +303,7 @@ class MySensor */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE /** * Blink with LEDs * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms @@ -339,7 +339,7 @@ class MySensor MySigning& signer; #endif -#ifdef WITH_LEDS_BLINKING +#ifdef MY_LEDS_BLINKING_FEATURE uint8_t pinRx; // Rx led pin uint8_t pinTx; // Tx led pin uint8_t pinEr; // Err led pin diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index dcbb32f..dbfdcd6 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -104,8 +104,8 @@ MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); MyHwATMega328 hw; // Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h -#ifdef WITH_LEDS_BLINKING +// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h +#ifdef MY_WITH_LEDS_BLINKING MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); #else MySensor gw(transport, hw /*, signer*/); diff --git a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h index 4547446..b0aea73 100644 --- a/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h +++ b/libraries/MySensors/examples/EthernetGateway/GatewayUtil.h @@ -92,12 +92,12 @@ void parseAndSend(MySensor &gw, char *commandBuffer) { setInclusionMode(atoi(msg.data) == 1); } } else { - #ifdef WITH_LEDS_BLINKING + #ifdef MY_LEDS_BLINKING_FEATURE gw.txBlink(1); #endif ok = gw.sendRoute(msg); if (!ok) { - #ifdef WITH_LEDS_BLINKING + #ifdef MY_LEDS_BLINKING_FEATURE gw.errBlink(1); #endif } diff --git a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h b/libraries/MySensors/examples/SerialGateway/GatewayUtil.h deleted file mode 100644 index e3cb90a..0000000 --- a/libraries/MySensors/examples/SerialGateway/GatewayUtil.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - */ - -#ifndef __GATEWAYUTIL_H__ -#define __GATEWAYUTIL_H__ - -#include - - -#ifdef ARDUINO - - -uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled -uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode - -#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller -#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller - -volatile boolean buttonTriggeredInclusion; -boolean inclusionMode; // Keeps track on inclusion mode -void (*serial)(const char *fmt, ... ); - -MyProtocolDefault protocol; - -void setInclusionMode(boolean newMode); - -char convBuf[MAX_PAYLOAD*2+1]; -char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera -unsigned long inclusionStartTime; - -void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { - inclusionMode = 0; - buttonTriggeredInclusion = false; - serial = _serial; - - pinInclusion = _inc; - inclusionTime = _incTime; - - // Setup digital in that triggers inclusion mode - pinMode(pinInclusion, INPUT); - digitalWrite(pinInclusion, HIGH); -} - - - -void startInclusionInterrupt() { - buttonTriggeredInclusion = true; -} - -void incomingMessage(const MyMessage &message) { -// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { -// gw.rxBlink(3); -// } else { -// gw.rxBlink(1); -// } - // Pass along the message from sensors to serial line - serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); -} - - - -void checkButtonTriggeredInclusion() { - if (buttonTriggeredInclusion) { - // Ok, someone pressed the inclusion button on the gateway - // start inclusion mode for 1 munute. -#ifdef DEBUG - serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); -#endif - buttonTriggeredInclusion = false; - setInclusionMode(true); - } -} - -void checkInclusionFinished() { - if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { - // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode - setInclusionMode(false); - } -} - -void parseAndSend(MySensor &gw, char *commandBuffer) { - boolean ok; - MyMessage &msg = gw.getLastMessage(); - - if (protocol.parse(msg, commandBuffer)) { - uint8_t command = mGetCommand(msg); - - if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { - // Handle messages directed to gateway - if (msg.type == I_VERSION) { - // Request for version - serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); - } else if (msg.type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(msg.data) == 1); - } - } else { - #ifdef WITH_LEDS_BLINKING - gw.txBlink(1); - #endif - ok = gw.sendRoute(msg); - if (!ok) { - #ifdef WITH_LEDS_BLINKING - gw.errBlink(1); - #endif - } - } - } -} - -void setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) { - inclusionMode = newMode; - // Send back mode change on serial line to ack command - serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); - - if (inclusionMode) { - inclusionStartTime = millis(); - } - } -} - - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif - diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index ad75280..cbf52d7 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -29,15 +29,13 @@ * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): - * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h + * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error * */ -#define NO_PORTB_PINCHANGES - #include #include #include @@ -46,13 +44,11 @@ #include #include +#include #include -#include -#include -#include -#include "GatewayUtil.h" +#include -#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled +#define INCLUSION_MODE_TIME 60 // Number of seconds inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button #define RADIO_ERROR_LED_PIN 4 // Error led pin #define RADIO_RX_LED_PIN 6 // Receive led pin @@ -70,88 +66,37 @@ MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); // Hardware profile MyHwATMega328 hw; +// Controller Transport profile +MyProtocolDefault protocol; +MyGatewayTransportSerial ctrlTransport(protocol); + // Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h -#ifdef WITH_LEDS_BLINKING -MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h +#ifdef MY_LEDS_BLINKING_FEATURE +MyGateway gw(ctrlTransport, transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); #else -MySensor gw(transport, hw /*, signer*/); +MyGateway gw(ctrlTransport, transport, hw /*, signer*/); #endif -char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface -int inputPos = 0; -boolean commandComplete = false; // whether the string is complete - -void parseAndSend(char *commandBuffer); - -void output(const char *fmt, ... ) { - va_list args; - va_start (args, fmt ); - vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); - va_end (args); - Serial.print(serialBuffer); -} - - void setup() { - gw.begin(incomingMessage, 0, true, 0); + gw.begin(NULL + #ifdef MY_INCLUSION_MODE_FEATURE + , INCLUSION_MODE_TIME + #ifdef MY_INCLUSION_BUTTON_FEATURE + , INCLUSION_MODE_PIN + #endif + #endif + ); - setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - - // Add interrupt for inclusion button to pin - PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); - - - // Send startup log message on serial - serial(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); } void loop() { gw.process(); - - checkButtonTriggeredInclusion(); - checkInclusionFinished(); - - if (commandComplete) { - // A command wass issued from serial interface - // We will now try to send it to the actuator - parseAndSend(gw, inputString); - commandComplete = false; - inputPos = 0; - } -} - - -/* - SerialEvent occurs whenever a new data comes in the - hardware serial RX. This routine is run between each - time loop() runs, so using delay inside loop can delay - response. Multiple bytes of data may be available. - */ -void serialEvent() { - while (Serial.available()) { - // get the new byte: - char inChar = (char)Serial.read(); - // if the incoming character is a newline, set a flag - // so the main loop can do something about it: - if (inputPos Date: Thu, 14 May 2015 21:12:35 +0200 Subject: [PATCH 117/660] Added GW device to MySensors HW profile (not complete yet!) --- hardware/MySensors/avr/boards.txt | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt index 349cf25..2a3c638 100644 --- a/hardware/MySensors/avr/boards.txt +++ b/hardware/MySensors/avr/boards.txt @@ -1,5 +1,8 @@ menu.cpu=Processor +###################################### +## Sensebender Micro + MysensorsMicro.name=Sensebender Micro MysensorsMicro.upload.tool=arduino:avrdude @@ -26,4 +29,29 @@ MysensorsMicro.menu.cpu.8Mhz=Atmega328 8Mhz MysensorsMicro.menu.cpu.8Mhz.build.f_cpu=8000000L MysensorsMicro.menu.cpu.1Mhz=Atmega328 1Mhz -MysensorsMicro.menu.cpu.1Mhz.build.f_cpu=1000000L \ No newline at end of file +MysensorsMicro.menu.cpu.1Mhz.build.f_cpu=1000000L + + +######################################## +## Gateway settings + +MysensorsGW.name=Sensebender Gateway +MysensorsGW.build.core=arduino:arduino +MysensorsGW.build.variant=GW +MysensorsGW.build.board=AVR_1284 +MysensorsGW.build.mcu=atmega1284p +MysensorsGW.build.f_cpu=20000000L + +MysensorsGW.upload.tool=arduino:avrdude +MysensorsGW.upload.protocol=arduino +MysensorsGW.upload.maximum_size=123720 +MysensorsGW.upload.maximum_data_size=16384 +MysensorsGW.upload.speed=115200 + +MysensorsGW.bootloader.tool=arduino:avrdude +MysensorsGW.bootloader.unlock_bits=0x3F +MysensorsGW.bootloader.lock_bits=0x0F +MysensorsGW.bootloader.low_fuses=0xE2 +MysensorsGW.bootloader.high_fuses=0xD2 +MysensorsGW.bootloader.extended_fuses=0xFE +MysensorsGW.bootloader.file=DualOptiboot/optiboot_atmega1284.hex From 2bfe5cc650043bb3171380beb17fdce6f663f049 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sat, 23 May 2015 21:41:53 +0200 Subject: [PATCH 118/660] Add begin function to the GatewayTransport class Signed-off-by: Tomas Hozza --- libraries/MySensors/MyGateway.cpp | 6 ++++++ libraries/MySensors/MyGatewayTransport.h | 3 +++ libraries/MySensors/MyGatewayTransportSerial.cpp | 4 ++++ libraries/MySensors/MyGatewayTransportSerial.h | 3 +++ 4 files changed, 16 insertions(+) diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index db4e4ee..404b5b4 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -73,6 +73,12 @@ void MyGateway::begin(void (*_msgCallback)(const MyMessage &) #endif #endif + // initialize the transport driver + if (!transport.begin()) { + debug(PSTR("transport driver init fail\n")); + while(1); // Nothing more we can do + } + // Start MySensors in repeater mode MySensor::begin(_msgCallback, GATEWAY_ADDRESS, true, GATEWAY_ADDRESS); diff --git a/libraries/MySensors/MyGatewayTransport.h b/libraries/MySensors/MyGatewayTransport.h index d94006f..da03ff5 100644 --- a/libraries/MySensors/MyGatewayTransport.h +++ b/libraries/MySensors/MyGatewayTransport.h @@ -30,6 +30,9 @@ public: // MyProtocol constructor MyGatewayTransport(MyProtocol &protocol = *new MyProtocolDefault()); + // initialize the transport driver + virtual bool begin() = 0; + // Send message to controller virtual bool send(MyMessage &message) = 0; diff --git a/libraries/MySensors/MyGatewayTransportSerial.cpp b/libraries/MySensors/MyGatewayTransportSerial.cpp index e0f79bf..f5acbed 100644 --- a/libraries/MySensors/MyGatewayTransportSerial.cpp +++ b/libraries/MySensors/MyGatewayTransportSerial.cpp @@ -25,6 +25,10 @@ MyGatewayTransportSerial::MyGatewayTransportSerial(MyProtocol &_protocol) : MyGa } +bool MyGatewayTransportSerial::begin() { + return true; +} + bool MyGatewayTransportSerial::send(MyMessage &message) { Serial.print(protocol.format(message)); // Serial print is always successful diff --git a/libraries/MySensors/MyGatewayTransportSerial.h b/libraries/MySensors/MyGatewayTransportSerial.h index 678e932..44434cf 100644 --- a/libraries/MySensors/MyGatewayTransportSerial.h +++ b/libraries/MySensors/MyGatewayTransportSerial.h @@ -33,6 +33,9 @@ public: // MyGateway constructor MyGatewayTransportSerial(MyProtocol &protocol = *new MyProtocolDefault()); + // initialize the transport driver + bool begin(); + // Send message to controller bool send(MyMessage &message); From 0c9b2b738d295f56a36097a4bfa564ea0060b960 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sat, 23 May 2015 22:20:03 +0200 Subject: [PATCH 119/660] Don't call checkInclusionMode() if the feature is not turned on Signed-off-by: Tomas Hozza --- libraries/MySensors/MyGateway.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index 404b5b4..906823b 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -98,7 +98,9 @@ boolean MyGateway::sendRoute(MyMessage &message) { } boolean MyGateway::process() { +#ifdef MY_INCLUSION_MODE_FEATURE checkInclusionMode(); +#endif bool newMessage = false; if (transport.available()) { MyMessage &gmsg = transport.receive(); From cc47409f1aecd3fa7eefca33647e2bca0d46b089 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sat, 23 May 2015 22:40:10 +0200 Subject: [PATCH 120/660] Send messages from sensor nodes using the GatewayTransport driver Signed-off-by: Tomas Hozza --- libraries/MySensors/MyGateway.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index 906823b..2eeb039 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -136,7 +136,15 @@ boolean MyGateway::process() { } } } - return MySensor::process() || newMessage; + + // new message from sensor node + if (MySensor::process()) { + MyMessage &msg = MySensor::getLastMessage(); + newMessage = true; + transport.send(msg); + } + + return newMessage; } #ifdef MY_INCLUSION_MODE_FEATURE From ceb8f5969fbe97b20ffe5fa9a7cbc264ead7a1e2 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sat, 23 May 2015 23:15:03 +0200 Subject: [PATCH 121/660] Add tested draft of MyGatewayTransportEthernet working as client Signed-off-by: Tomas Hozza --- libraries/MySensors/MyConfig.h | 12 ++ .../MySensors/MyGatewayTransportEthernet.cpp | 189 ++++++++++++++++++ .../MySensors/MyGatewayTransportEthernet.h | 100 +++++++++ 3 files changed, 301 insertions(+) create mode 100644 libraries/MySensors/MyGatewayTransportEthernet.cpp create mode 100644 libraries/MySensors/MyGatewayTransportEthernet.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 0e07a5a..871e269 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -74,6 +74,11 @@ // Enables inclusion-mode button feature on the gateway device #define MY_INCLUSION_BUTTON_FEATURE +// Disable inclusion mode button if inclusion mode feature is not enabled +#ifndef MY_INCLUSION_MODE_FEATURE +#undef MY_INCLUSION_BUTTON_FEATURE +#endif + // The default input pin used for the inclusion mode button #define MY_INCLUSION_MODE_BUTTON_PIN 3 // Number of seconds (default one minute) inclusion mode should be enabled @@ -152,6 +157,13 @@ #define RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +/************************************** +* Gateway Transport Ethernet Defaults +***************************************/ +// Enable to use DHCP for getting IP address. If not defined, static IP is expected +//#define IP_ADDRESS_DHCP +// Enable to use UDP instead of plain Ethernet +#define USE_UDP #endif diff --git a/libraries/MySensors/MyGatewayTransportEthernet.cpp b/libraries/MySensors/MyGatewayTransportEthernet.cpp new file mode 100644 index 0000000..7d5e948 --- /dev/null +++ b/libraries/MySensors/MyGatewayTransportEthernet.cpp @@ -0,0 +1,189 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Tomas Hozza + * Copyright (C) 2015 Tomas Hozza + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyGatewayTransportEthernet.h" + +MyGatewayTransportEthernet::MyGatewayTransportEthernet( + MyProtocol &protocol, + uint8_t *gw_mac +#ifndef IP_ADDRESS_DHCP + , IPAddress gw_ip +#endif /* not IP_ADDRESS_DHCP */ + , uint16_t gw_port +#ifdef IP_ADDRESS_DHCP + , unsigned long ip_renew_interval +#endif /* IP_ADDRESS_DHCP */ + , IPAddress controller_IP + , uint16_t controller_port) : + MyGatewayTransport(protocol), + gatewayMAC(gw_mac), +#ifndef IP_ADDRESS_DHCP + gatewayIP(gw_ip), +#endif /* not IP_ADDRESS_DHCP */ + gatewayPort(gw_port), +#ifdef IP_ADDRESS_DHCP + ip_renewal_period(ip_renew_interval), +#endif /* IP_ADDRESS_DHCP */ + controllerIP(controller_IP), + controllerPort(controller_port) +{ + ; +} + +bool MyGatewayTransportEthernet::begin() { +#ifdef IP_ADDRESS_DHCP + // Get IP address from DHCP + Ethernet.begin(gatewayMAC); +#else + Ethernet.begin(gatewayMAC, gatewayIP); +#endif /* IP_ADDRESS_DHCP */ + + // give the Ethernet interface a second to initialize + // TODO: use HW delay + delay(1000); + +#ifdef USE_UDP + server = new EthernetUDP(); + server->begin(gatewayPort); +#else + // we have to use pointers due to the constructor of EthernetServer + server = new EthernetServer(gatewayPort); + server->begin(); +#endif /* USE_UDP */ +} + +bool MyGatewayTransportEthernet::send(MyMessage &message) +{ + char *msg = NULL; + + if (controllerIP == INADDR_NONE) { + // no controller IP address set! + return false; + } + else { + msg = protocol.format(message); +#ifdef USE_UDP + server->beginPacket(controllerIP, controllerPort); + server->write(msg, strlen(msg)); + // returns 1 if the packet was sent successfully + return server->endPacket(); +#else + EthernetClient client; + if (client.connect(controllerIP, controllerPort)) { + client.write(msg, strlen(msg)); + client.stop(); + return true; + } + else { + // connecting to the server failed! + return false; + } +#endif /* USE_UDP */ + } +} + +bool MyGatewayTransportEthernet::available() +{ + bool available = false; + +#ifdef IP_ADDRESS_DHCP + // renew IP address using DHCP + renewIP(); +#endif + +#ifdef USE_UDP + int packet_size = server->parsePacket(); + + if (server->available()) { + server->read(inputBuffer, MAX_RECEIVE_LENGTH); + available = true; + } +#else + // if an incoming client connects, there will be + // bytes available to read via the client object + EthernetClient client = server->available(); + + if (client) { + while (client.available()) { + // read the bytes incoming from the client + char inChar = client.read(); + + if (inputPos < MAX_RECEIVE_LENGTH - 1) { + // if newline then command is complete + if (inChar == '\n') { + inputBuffer[inputPos] = 0; + available = true; + } else { + inputBuffer[inputPos] = inChar; + inputPos++; + } + } + } + } + inputPos = 0; +#endif + + if (available) { + // Parse message and return parse result + available = protocol.parse(msg, inputBuffer); + } + + return available; +} + +MyMessage& MyGatewayTransportEthernet::receive() +{ + // Return the last parsed message + return msg; +} + +void MyGatewayTransportEthernet::setControllerIPPort(const IPAddress& addr, const uint16_t port) { + controllerIP = addr; + + /* set the port if some legal value passed */ + if (port > 0) + controllerPort = port; +} + +#ifdef IP_ADDRESS_DHCP +void MyGatewayTransportEthernet::renewIP() +{ + /* renew/rebind IP address + 0 - nothing happened + 1 - renew failed + 2 - renew success + 3 - rebinf failed + 4 - rebind success + */ + // TODO: Use millis from MyHw ?? + static unsigned long next_time = millis() + ip_renewal_period; + unsigned long now = millis(); + + // http://playground.arduino.cc/Code/TimingRollover + if ((long)(now - next_time) < 0) + return; + + if (Ethernet.maintain() & ~(0x06)) { + /* Error occured -> IP was not renewed */ + return; + } + + next_time = now + ip_renewal_period; +} +#endif /* IP_ADDRESS_DHCP */ diff --git a/libraries/MySensors/MyGatewayTransportEthernet.h b/libraries/MySensors/MyGatewayTransportEthernet.h new file mode 100644 index 0000000..fefda1c --- /dev/null +++ b/libraries/MySensors/MyGatewayTransportEthernet.h @@ -0,0 +1,100 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Tomas Hozza + * Copyright (C) 2015 Tomas Hozza + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyGatewayTransportEthernet_h +#define MyGatewayTransportEthernet_h + +#include "MyConfig.h" +#include "MyMessage.h" +#include "MyProtocol.h" +#include "MyGatewayTransport.h" +#include "MyProtocolDefault.h" + +#include + +// Use this if you have attached a Ethernet ENC28J60 shields +//#include + +// Use this fo WizNET W5100 module and Arduino Ethernet Shield +#include + +#ifdef USE_UDP +#include +#endif /* USE_UDP */ + +#define CONTROLLER_PORT 5003 +#define IP_RENEWAL_INTERVAL 60000 // in milliseconds +#define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller + + +class MyGatewayTransportEthernet : public MyGatewayTransport +{ + public: + MyGatewayTransportEthernet(MyProtocol &protocol, + uint8_t *gw_mac +#ifndef IP_ADDRESS_DHCP + , IPAddress gw_ip +#endif /* not IP_ADDRESS_DHCP */ + , uint16_t gw_port +#ifdef IP_ADDRESS_DHCP + , unsigned long ip_renew_interval +#endif /* IP_ADDRESS_DHCP */ + , IPAddress controller_IP + , uint16_t controller_port + ); + + // initialize the driver + bool begin(); + + // Send message to controller + bool send(MyMessage &message); + + // Check if a new message is available from controller + bool available(); + + // Pick up last message received from controller + MyMessage& receive(); + + // Set the controller IP and Port + void setControllerIPPort(const IPAddress& addr, const uint16_t port); + +protected: + IPAddress controllerIP; + uint16_t controllerPort; + +#ifdef IP_ADDRESS_DHCP + void renewIP(); + unsigned long ip_renewal_period; +#endif /* IP_ADDRESS_DHCP */ + uint8_t *gatewayMAC; + IPAddress gatewayIP; + uint16_t gatewayPort; + +#ifndef USE_UDP + EthernetServer *server; + uint8_t inputPos; +#else + EthernetUDP *server; +#endif + + char inputBuffer[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface + MyMessage msg; +}; + +#endif /* MyGatewayTransportEthernet_h */ From e16cb028e97986dd0c5d77200fda733c975f74a6 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Sat, 23 May 2015 23:16:24 +0200 Subject: [PATCH 122/660] Rework Ethernet Gateway to use MyGatewayTransportEthernet Signed-off-by: Tomas Hozza --- .../EthernetGateway/EthernetGateway.ino | 184 ++++++------------ .../examples/EthernetGateway/GatewayUtil.h | 125 ------------ 2 files changed, 57 insertions(+), 252 deletions(-) delete mode 100644 libraries/MySensors/examples/EthernetGateway/GatewayUtil.h diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index dbfdcd6..6b38f89 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -20,67 +20,60 @@ * * REVISION HISTORY * Version 1.0 - Henrik EKblad - * Contribution by a-lurker and Anticimex, + * Contribution by a-lurker and Anticimex, * Contribution by Norbert Truchsess + * Contribution by Tomas Hozza + * * - * * DESCRIPTION - * The EthernetGateway sends data received from sensors to the ethernet link. + * The EthernetGateway sends data received from sensors to the ethernet link. * The gateway also accepts input on ethernet interface, which is then sent out to the radio network. * * The GW code is designed for Arduino 328p / 16MHz. ATmega168 does not have enough memory to run this program. - * + * * * COMPILING WIZNET (W5100) ETHERNET MODULE * > Edit MyConfig.h in (libraries\MySensors\) to enable softspi (remove // before "#define SOFTSPI"). * * COMPILING ENC28J60 ETHERNET MODULE - * > Use Arduino IDE 1.5.7 (or later) - * > Disable DEBUG in Sensor.h before compiling this sketch. Othervise the sketch will probably not fit in program space when downloading. - * > Remove Ethernet.h include below and include UIPEthernet.h - * > Remove DigitalIO include + * > Use Arduino IDE 1.5.7 (or later) + * > Disable DEBUG in Sensor.h before compiling this sketch. Othervise the sketch will probably not fit in program space when downloading. + * > Remove Ethernet.h include below and include UIPEthernet.h + * > Remove DigitalIO include * Note that I had to disable UDP and DHCP support in uipethernet-conf.h to reduce space. (which means you have to choose a static IP for that module) * * VERA CONFIGURATION: - * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. + * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 * * LED purposes: * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * * See http://www.mysensors.org/build/ethernet_gateway for wiring instructions. * */ -#define NO_PORTB_PINCHANGES #include // This include can be removed when using UIPEthernet module -#include +#include #include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include "GatewayUtil.h" +#include +#include +#include +// needed due to Arduino IDE +#include -// Use this if you have attached a Ethernet ENC28J60 shields -// #include - -// Use this for WizNET W5100 module and Arduino Ethernet Shield -#include - - -#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled +#define INCLUSION_MODE_TIME 60 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button #define RADIO_CE_PIN 5 // radio chip enable @@ -90,6 +83,11 @@ #define RADIO_RX_LED_PIN 8 // Receive led pin #define RADIO_TX_LED_PIN 9 // the PCB, on board LED +#define IP_PORT 5003 // The port you want to open +#ifndef IP_ADDRESS_DHCP +// Gateway IP address if not using DHCP +IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later! +#endif /* IP_ADDRESS_DHCP */ // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); @@ -100,117 +98,49 @@ MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); //MySigningAtsha204Soft signer; //MySigningAtsha204 signer; -// Hardware profile +// Hardware profile MyHwATMega328 hw; -// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h -#ifdef MY_WITH_LEDS_BLINKING -MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); -#else -MySensor gw(transport, hw /*, signer*/); -#endif - - -#define IP_PORT 5003 // The port you want to open -IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later! +// Controller protocol +MyProtocolDefault protocol; // The MAC address can be anything you want but should be unique on your network. // Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. // Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // DEAD BEEF FEED -// a R/W server on the port -EthernetServer server = EthernetServer(IP_PORT); -// handle to open connection -EthernetClient client = EthernetClient(); +// Controller IP +IPAddress controllerIP = IPAddress(192, 168, 178, 254); -char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface -int inputPos = 0; -bool sentReady = false; +// Gateway transport driver +#ifdef IP_ADDRESS_DHCP +MyGatewayTransportEthernet ctrlTransport(protocol, mac, /* gw port */ CONTROLLER_PORT, IP_RENEWAL_INTERVAL, controllerIP, CONTROLLER_PORT); +#else +MyGatewayTransportEthernet ctrlTransport(protocol, mac, myIp, /* gw port */ CONTROLLER_PORT, controllerIP, CONTROLLER_PORT); +#endif -void output(const char *fmt, ... ) { - va_list args; - va_start (args, fmt ); - vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); - va_end (args); - Serial.print(serialBuffer); - client.write(serialBuffer); + +// Construct MyGateway library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h +#ifdef MY_WITH_LEDS_BLINKING +MyGateway gw(ctrlTransport, transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else +MyGateway gw(ctrlTransport, transport, hw /*, signer*/); +#endif + +void setup() +{ + gw.begin(NULL +#ifdef MY_INCLUSION_MODE_FEATURE + , INCLUSION_MODE_TIME +#ifdef MY_INCLUSION_BUTTON_FEATURE + , INCLUSION_MODE_PIN +#endif +#endif + ); } -void setup() -{ - Ethernet.begin(mac, myIp); - - setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - - // Add interrupt for inclusion button to pin - PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); - - // give the Ethernet interface a second to initialize - delay(1000); - - // Initialize gateway at maximum PA level, channel 70 and callback for write operations - gw.begin(incomingMessage, 0, true, 0); - - - // start listening for clients - server.begin(); - -} - - void loop() { - gw.process(); - - checkButtonTriggeredInclusion(); - checkInclusionFinished(); - - // if an incoming client connects, there will be - // bytes available to read via the client object - EthernetClient newclient = server.available(); - // if a new client connects make sure to dispose any previous existing sockets - if (newclient) { - if (client != newclient) { - client.stop(); - client = newclient; - output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); - } - } - - if (client) { - if (!client.connected()) { - client.stop(); - } else if (client.available()) { - // read the bytes incoming from the client - char inChar = client.read(); - if (inputPos - - -#ifdef ARDUINO - - -uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled -uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode - -#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller -#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller - -volatile boolean buttonTriggeredInclusion; -boolean inclusionMode; // Keeps track on inclusion mode -void (*serial)(const char *fmt, ... ); - -MyProtocolDefault protocol; - -void setInclusionMode(boolean newMode); - -char convBuf[MAX_PAYLOAD*2+1]; -char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera -unsigned long inclusionStartTime; - -void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { - inclusionMode = 0; - buttonTriggeredInclusion = false; - serial = _serial; - - pinInclusion = _inc; - inclusionTime = _incTime; - - // Setup digital in that triggers inclusion mode - pinMode(pinInclusion, INPUT); - digitalWrite(pinInclusion, HIGH); -} - - - -void startInclusionInterrupt() { - buttonTriggeredInclusion = true; -} - -void incomingMessage(const MyMessage &message) { -// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { -// gw.rxBlink(3); -// } else { -// gw.rxBlink(1); -// } - // Pass along the message from sensors to serial line - serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); -} - - - -void checkButtonTriggeredInclusion() { - if (buttonTriggeredInclusion) { - // Ok, someone pressed the inclusion button on the gateway - // start inclusion mode for 1 munute. -#ifdef DEBUG - serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); -#endif - buttonTriggeredInclusion = false; - setInclusionMode(true); - } -} - -void checkInclusionFinished() { - if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { - // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode - setInclusionMode(false); - } -} - -void parseAndSend(MySensor &gw, char *commandBuffer) { - boolean ok; - MyMessage &msg = gw.getLastMessage(); - - if (protocol.parse(msg, commandBuffer)) { - uint8_t command = mGetCommand(msg); - - if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { - // Handle messages directed to gateway - if (msg.type == I_VERSION) { - // Request for version - serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); - } else if (msg.type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(msg.data) == 1); - } - } else { - #ifdef MY_LEDS_BLINKING_FEATURE - gw.txBlink(1); - #endif - ok = gw.sendRoute(msg); - if (!ok) { - #ifdef MY_LEDS_BLINKING_FEATURE - gw.errBlink(1); - #endif - } - } - } -} - -void setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) { - inclusionMode = newMode; - // Send back mode change on serial line to ack command - serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); - - if (inclusionMode) { - inclusionStartTime = millis(); - } - } -} - - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif From 17848db33db6a5941866814271bb2e30765d5353 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 6 Jun 2015 10:26:04 +0200 Subject: [PATCH 123/660] Fix compile error of LiquidCrystal library in Arduino IDE 1.6.x --- libraries/LiquidCrystal/LCD.cpp | 2 +- libraries/LiquidCrystal/LCD.h | 2 +- .../examples/IrrigationController/IrrigationController.ino | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/LiquidCrystal/LCD.cpp b/libraries/LiquidCrystal/LCD.cpp index f0e3068..77c0fb3 100644 --- a/libraries/LiquidCrystal/LCD.cpp +++ b/libraries/LiquidCrystal/LCD.cpp @@ -304,7 +304,7 @@ void LCD::createChar(uint8_t location, uint8_t charmap[]) } #ifdef __AVR__ -void LCD::createChar(uint8_t location, const prog_uchar charmap[]) +void LCD::createChar(uint8_t location, const unsigned char charmap[]) { location &= 0x7; // we only have 8 memory locations 0-7 diff --git a/libraries/LiquidCrystal/LCD.h b/libraries/LiquidCrystal/LCD.h index 126b935..1df775b 100644 --- a/libraries/LiquidCrystal/LCD.h +++ b/libraries/LiquidCrystal/LCD.h @@ -418,7 +418,7 @@ public: (0 to 7) @param charmap[in] the bitmap array representing each row of the character. */ - void createChar(uint8_t location, const prog_uchar charmap[]); + void createChar(uint8_t location, const unsigned char charmap[]); #endif // __AVR__ /*! diff --git a/libraries/MySensors/examples/IrrigationController/IrrigationController.ino b/libraries/MySensors/examples/IrrigationController/IrrigationController.ino index 9e9ddc6..bcbff1d 100644 --- a/libraries/MySensors/examples/IrrigationController/IrrigationController.ino +++ b/libraries/MySensors/examples/IrrigationController/IrrigationController.ino @@ -84,7 +84,10 @@ Contributed by Jim (BulldogLowell@gmail.com) with much contribution from Pete (p #include #include #include +#include #include + + // #define NUMBER_OF_VALVES 8 // Change this to set your valve count up to 16. #define VALVE_RESET_TIME 7500UL // Change this (in milliseconds) for the time you need your valves to hydraulically reset and change state From 6288c8997ea5fb6a907cf124e9886d66f94ed687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 7 Jun 2015 20:49:21 +0200 Subject: [PATCH 124/660] Added possibility to add battery voltage measurements as sensor value (to log battery voltages) --- .../SensebenderMicro/SensebenderMicro.ino | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index acc92ba..1cb0c7a 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -3,7 +3,7 @@ // // If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals // -// Battery voltage is repported as child sensorId 199, as well as battery percentage (Internal message) +// Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below) #include @@ -20,6 +20,9 @@ // Define a static node address, remove if you want auto address assignment //#define NODE_ADDRESS 3 +// Uncomment the line below, to transmit battery voltage as a normal sensor value +//#define BATT_SENSOR 199 + #define RELEASE "1.2" #define AVERAGES 2 @@ -54,6 +57,10 @@ MySensor gw; MyMessage msgHum(CHILD_ID_HUM, V_HUM); MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); +#ifdef BATT_SENSOR +MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE); +#endif + // Global settings int measureCount = 0; int sendBattery = 0; @@ -112,6 +119,10 @@ void setup() { gw.present(CHILD_ID_TEMP,S_TEMP); gw.present(CHILD_ID_HUM,S_HUM); +#ifdef BATT_SENSOR + gw.present(BATT_SENSOR, S_POWER); +#endif + isMetric = gw.getConfig().isMetric; Serial.print(F("isMetric: ")); Serial.println(isMetric); raHum.clear(); @@ -171,18 +182,18 @@ void sendTempHumidityMeasurements(bool force) float oldAvgTemp = raTemp.getAverage(); float oldAvgHum = raHum.getAverage(); - raTemp.addValue(data.celsiusHundredths / 100); + raTemp.addValue(data.celsiusHundredths); raHum.addValue(data.humidityPercent); - float diffTemp = abs(oldAvgTemp - raTemp.getAverage()); + float diffTemp = abs(lastTemperature - data.celsiusHundredths/100); float diffHum = abs(oldAvgHum - raHum.getAverage()); - Serial.println(diffTemp); - Serial.println(diffHum); + Serial.print(F("TempDiff :"));Serial.println(diffTemp); + Serial.print(F("HumDiff :"));Serial.println(diffHum); if (isnan(diffTemp)) tx = true; - if (diffTemp > 0.2) tx = true; - if (diffHum > 0.5) tx = true; + if (diffTemp > 0.3) tx = true; + if (diffHum >= 0.5) tx = true; if (tx) { measureCount = 0; @@ -213,6 +224,11 @@ void sendBattLevel(bool force) long vcc = readVcc(); if (vcc != lastBattery) { lastBattery = vcc; + +#ifdef BATT_SENSOR + gw.send(msgBatt.set(vcc)); +#endif + // Calculate percentage vcc = vcc - 1900; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at From 387aaba46e255f033b76d5fe4bc39a9866871e4f Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 8 Jun 2015 21:58:40 +0200 Subject: [PATCH 125/660] Fix error in V/S comments --- libraries/MySensors/MyMessage.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index ac9d4de..471bf49 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -45,7 +45,7 @@ typedef enum { typedef enum { V_TEMP, // S_TEMP V_HUM, // S_HUM - V_LIGHT, // S_LIGHT (Light level in uncalibrated percentage) + V_LIGHT, // S_LIGHT, S_DIMMER V_DIMMER, // S_DIMMER V_PRESSURE, // S_BARO V_FORECAST, // S_BARO @@ -60,13 +60,13 @@ typedef enum { V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER - V_WATT, // S_POWER + V_WATT, // S_POWER, S_LIGHT, S_DIMMER V_KWH, // S_POWER V_SCENE_ON, // S_SCENE_CONTROLLER V_SCENE_OFF, // S_SCENE_CONTROLLER V_HEATER, // S_HEATER V_HEATER_SW, // S_HEATER - V_LIGHT_LEVEL, // S_LIGHT_LEVEL + V_LIGHT_LEVEL, // S_LIGHT_LEVEL (light level in uncalibrated percentage) V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, V_UP, // S_COVER V_DOWN, // S_COVER @@ -111,7 +111,7 @@ typedef enum { S_MOTION, // V_TRIPPED, V_ARMED S_SMOKE, // V_TRIPPED, V_ARMED S_LIGHT, // V_LIGHT, V_WATT - S_DIMMER, // V_DIMMER, V_WATT + S_DIMMER, // V_LIGHT, V_DIMMER, V_WATT S_COVER, // V_UP, V_DOWN, V_STOP S_TEMP, // V_TEMP S_HUM, // V_HUM @@ -123,7 +123,7 @@ typedef enum { S_POWER, // V_WATT, V_KWH S_HEATER, // V_HEATER, V_HEATER_SW S_DISTANCE, // V_DISTANCE - S_LIGHT_LEVEL, // V_LIGHT + S_LIGHT_LEVEL, // V_LIGHT_LEVEL S_ARDUINO_NODE, S_ARDUINO_REPEATER_NODE, S_LOCK, // V_LOCK_STATUS From f642ec8bf6bea4545cf181bfba53236da888d212 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Jun 2015 23:05:45 +0200 Subject: [PATCH 126/660] Added optional description when presenting sensors. --- libraries/MySensors/MySensor.cpp | 4 ++-- libraries/MySensors/MySensor.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index cb0e026..184317a 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -483,8 +483,8 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } -void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(LIBRARY_VERSION)); +void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck, const char*description) { + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(description)); } void MySensor::sendSketchInfo(const char *name, const char *version, bool enableAck) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 9917b66..5798ac7 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -178,8 +178,9 @@ class MySensor * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. * @param sensorType The sensor type. See sensor typedef in MyMessage.h. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * @param description A textual description of the sensor. Defaults to library version. */ - void present(uint8_t sensorId, uint8_t sensorType, bool ack=false); + void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=LIBRARY_VERSION); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. From e111d64c3186a2691d8e66d72f7f715c09c8544e Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Jun 2015 23:47:44 +0200 Subject: [PATCH 127/660] Fix: Default to empty sensor description --- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 184317a..b953fd7 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -484,7 +484,7 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { } void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck, const char*description) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(description)); + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } void MySensor::sendSketchInfo(const char *name, const char *version, bool enableAck) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 5798ac7..0c89604 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -180,7 +180,7 @@ class MySensor * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. * @param description A textual description of the sensor. Defaults to library version. */ - void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=LIBRARY_VERSION); + void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=""); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. From b3bdc5213926ee5c2138183457a1e7fe6a9d2601 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Jun 2015 23:57:04 +0200 Subject: [PATCH 128/660] Added optionl sensor description on presentation --- libraries/MySensors/MySensor.cpp | 4 ++-- libraries/MySensors/MySensor.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 1af6a1b..3c18b79 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -235,8 +235,8 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } -void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(LIBRARY_VERSION)); +void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck, const char *description) { + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } void MySensor::sendSketchInfo(const char *name, const char *version, bool enableAck) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 27d4777..35e90b3 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -120,8 +120,9 @@ class MySensor : public RF24 * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. * @param sensorType The sensor type. See sensor typedef in MyMessage.h. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * @param description A textual description of the sensor. */ - void present(uint8_t sensorId, uint8_t sensorType, bool ack=false); + void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=""); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. From 52916cb8fe3b0bdddca63f37346bcca1acb214bd Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 9 Jun 2015 23:58:16 +0200 Subject: [PATCH 129/660] Fix comment for presentation --- libraries/MySensors/MySensor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 0c89604..1cda7d1 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -178,7 +178,7 @@ class MySensor * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. * @param sensorType The sensor type. See sensor typedef in MyMessage.h. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * @param description A textual description of the sensor. Defaults to library version. + * @param description A textual description of the sensor. */ void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=""); From b482a8eb7a09fe46f8b58d38fb5944f5d651892a Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 10 Jun 2015 23:43:04 +0200 Subject: [PATCH 130/660] Change argument order for presentation description --- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 3c18b79..47a9b5a 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -235,7 +235,7 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } -void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck, const char *description) { +void MySensor::present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 35e90b3..844e531 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -122,7 +122,7 @@ class MySensor : public RF24 * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. * @param description A textual description of the sensor. */ - void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=""); + void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. From 51d22c6936707e5f594786c473da0b32789f8bcc Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 10 Jun 2015 23:56:40 +0200 Subject: [PATCH 131/660] Change argument order in presentation --- libraries/MySensors/MySensor.cpp | 2 +- libraries/MySensors/MySensor.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index b953fd7..010cd19 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -483,7 +483,7 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } -void MySensor::present(uint8_t childSensorId, uint8_t sensorType, bool enableAck, const char*description) { +void MySensor::present(uint8_t childSensorId, uint8_t sensorType, const char*description, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 1cda7d1..8842a6f 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -177,10 +177,10 @@ class MySensor * * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. * @param sensorType The sensor type. See sensor typedef in MyMessage.h. - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. * @param description A textual description of the sensor. + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. */ - void present(uint8_t sensorId, uint8_t sensorType, bool ack=false, const char *description=""); + void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. From 938ade88232b12e364368e6004e2cf4d31008154 Mon Sep 17 00:00:00 2001 From: Kolbi Date: Wed, 17 Jun 2015 14:33:37 +0200 Subject: [PATCH 132/660] Update DallasTemperatureSensor.ino Small code improvements --- .../DallasTemperatureSensor.ino | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 5ac41b4..0c2878b 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -32,8 +32,8 @@ #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 16 unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) -OneWire oneWire(ONE_WIRE_BUS); -DallasTemperature sensors(&oneWire); +OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature. MySensor gw; float lastTemperature[MAX_ATTACHED_DS18B20]; int numSensors=0; @@ -44,8 +44,8 @@ MyMessage msg(0,V_TEMP); void setup() { - // Startup OneWire - sensors.begin(); + // Startup up the OneWire library + sensors.begin(); // Startup and initialize MySensors library. Set callback for incoming messages. gw.begin(); @@ -78,10 +78,11 @@ void loop() float temperature = static_cast(static_cast((gw.getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.; // Only send data if temperature has changed and no error - if (lastTemperature[i] != temperature && temperature != -127.00) { + if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) { // Send in the new temperature gw.send(msg.setSensor(i).set(temperature,1)); + // Save new temperatures for next compare lastTemperature[i]=temperature; } } From 8d7d63dfd9322a91bdf743fef6aeff39f78933cc Mon Sep 17 00:00:00 2001 From: Kolbi Date: Wed, 17 Jun 2015 14:34:43 +0200 Subject: [PATCH 133/660] Update DallasTemperatureSensor.ino --- .../DallasTemperatureSensor/DallasTemperatureSensor.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 0c2878b..05da63e 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -33,7 +33,7 @@ #define MAX_ATTACHED_DS18B20 16 unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) -DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. MySensor gw; float lastTemperature[MAX_ATTACHED_DS18B20]; int numSensors=0; @@ -45,10 +45,10 @@ MyMessage msg(0,V_TEMP); void setup() { // Startup up the OneWire library - sensors.begin(); + sensors.begin(); // Startup and initialize MySensors library. Set callback for incoming messages. - gw.begin(); + gw.begin(); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Temperature Sensor", "1.0"); From d90e2d9aac642604f89960845fd4fbca744de72b Mon Sep 17 00:00:00 2001 From: Kolbi Date: Wed, 17 Jun 2015 14:59:37 +0200 Subject: [PATCH 134/660] Update DallasTemperatureSensor.ino Updated version number to 1.1 since minor changes... --- .../DallasTemperatureSensor/DallasTemperatureSensor.ino | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 05da63e..dd74739 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -29,6 +29,8 @@ #include #include +#define COMPARE_TEMP 1 // Send temperature only if changed? 1 = Yes 0 = No + #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 16 unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) @@ -51,7 +53,7 @@ void setup() gw.begin(); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Temperature Sensor", "1.0"); + gw.sendSketchInfo("Temperature Sensor", "1.1"); // Fetch the number of attached temperature sensors numSensors = sensors.getDeviceCount(); @@ -78,7 +80,11 @@ void loop() float temperature = static_cast(static_cast((gw.getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.; // Only send data if temperature has changed and no error + #if COMPARE_TEMP == 1 if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) { + #else + if (temperature != -127.00 && temperature != 85.00) { + #endif // Send in the new temperature gw.send(msg.setSensor(i).set(temperature,1)); From ed939e7efd3be3bfad8ac72778da844f5962a165 Mon Sep 17 00:00:00 2001 From: Kolbi Date: Wed, 17 Jun 2015 15:42:50 +0200 Subject: [PATCH 135/660] Update BatteryPoweredSensor.ino Made debugging informations (Serial Print) optionally through setting --- .../examples/BatteryPoweredSensor/BatteryPoweredSensor.ino | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino index 7dbd93b..40c51da 100644 --- a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino +++ b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino @@ -30,6 +30,8 @@ #include #include +#define DEBUG 1 // Debug enables Serial.print 1 = Yes 0 = No + int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point MySensor gw; @@ -50,7 +52,9 @@ void loop() { // get the battery Voltage int sensorValue = analogRead(BATTERY_SENSE_PIN); + #if DEBUG > 0 Serial.println(sensorValue); + #endif // 1M, 470K divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point @@ -59,6 +63,7 @@ void loop() float batteryV = sensorValue * 0.003363075; int batteryPcnt = sensorValue / 10; + #if DEBUG > 0 Serial.print("Battery Voltage: "); Serial.print(batteryV); Serial.println(" V"); @@ -66,6 +71,7 @@ void loop() Serial.print("Battery percent: "); Serial.print(batteryPcnt); Serial.println(" %"); + #endif if (oldBatteryPcnt != batteryPcnt) { // Power up radio after sleep From 1049246a88bf91484ed44f0be878c2fa379d0600 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 20 Jun 2015 13:39:30 +0200 Subject: [PATCH 136/660] Make sure SPI backend is initialized in SPIFlash driver In some cases, SPIFlash driver hangs during initialization because it reads data from the SPI backend. But if SPI backend has not been initialized, this fails. --- libraries/MySensors/utility/SPIFlash.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/MySensors/utility/SPIFlash.cpp b/libraries/MySensors/utility/SPIFlash.cpp index 03d6a1a..ee6e1b0 100644 --- a/libraries/MySensors/utility/SPIFlash.cpp +++ b/libraries/MySensors/utility/SPIFlash.cpp @@ -56,6 +56,7 @@ void SPIFlash::unselect() { /// setup SPI, read device ID etc... boolean SPIFlash::initialize() { + SPI.begin(); _SPCR = SPCR; _SPSR = SPSR; pinMode(_slaveSelectPin, OUTPUT); From 872f694edeb40fb9c37a3d87a96571ff1b320f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Tue, 23 Jun 2015 21:03:37 +0200 Subject: [PATCH 137/660] Updated sensebender Micro sketch, for better transmition handling (implemented thresholds on temperature / humidity measurements) --- .../SensebenderMicro/SensebenderMicro.ino | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 1cb0c7a..74b5d94 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -40,6 +40,11 @@ // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes. // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement +// HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with +// TEMP_TRANSMIT_THRESHOLD for temperature threshold. +#define HUMI_TRANSMIT_THRESHOLD 0.5 +#define TEMP_TRANSMIT_THRESHOLD 0.5 + // Pin definitions #define TEST_PIN A0 #define LED_PIN A2 @@ -73,7 +78,6 @@ int lastHumidity = -100; long lastBattery = -100; RunningAverage raHum(AVERAGES); -RunningAverage raTemp(AVERAGES); /**************************************************** * @@ -109,6 +113,20 @@ void setup() { gw.begin(NULL,AUTO,false); #endif +// --- following code will heat up the sensor element, and wait until the temperature is +// within 0.3 degrees celcius of the initial temperature (measured at startup). +// This is to try and burn away residue humidity from manufacturing process. + int temperature = humiditySensor.getCelsiusHundredths(); + + humiditySensor.setHeater(true); + delay(500); + humiditySensor.setHeater(false); + + int t = 0; + do { + t = humiditySensor.getCelsiusHundredths() - temperature; + } while (abs(t) >30); +// --- digitalWrite(LED_PIN, LOW); humiditySensor.begin(); @@ -123,10 +141,10 @@ void setup() { gw.present(BATT_SENSOR, S_POWER); #endif + isMetric = gw.getConfig().isMetric; Serial.print(F("isMetric: ")); Serial.println(isMetric); raHum.clear(); - raTemp.clear(); sendTempHumidityMeasurements(false); sendBattLevel(false); } @@ -179,10 +197,8 @@ void sendTempHumidityMeasurements(bool force) bool tx = force; si7021_env data = humiditySensor.getHumidityAndTemperature(); - float oldAvgTemp = raTemp.getAverage(); float oldAvgHum = raHum.getAverage(); - raTemp.addValue(data.celsiusHundredths); raHum.addValue(data.humidityPercent); float diffTemp = abs(lastTemperature - data.celsiusHundredths/100); @@ -192,8 +208,8 @@ void sendTempHumidityMeasurements(bool force) Serial.print(F("HumDiff :"));Serial.println(diffHum); if (isnan(diffTemp)) tx = true; - if (diffTemp > 0.3) tx = true; - if (diffHum >= 0.5) tx = true; + if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true; + if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true; if (tx) { measureCount = 0; From f47ef2c248a20551eadf830141f2413fe267372f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Tue, 23 Jun 2015 22:03:56 +0200 Subject: [PATCH 138/660] Corrected a celcius/fahrenheit conversion, for the code that determines if it should transmit --- .../MySensors/examples/SensebenderMicro/SensebenderMicro.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 74b5d94..72467ab 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -201,13 +201,13 @@ void sendTempHumidityMeasurements(bool force) raHum.addValue(data.humidityPercent); - float diffTemp = abs(lastTemperature - data.celsiusHundredths/100); + float diffTemp = abs(lastTemperature - (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths)/100); float diffHum = abs(oldAvgHum - raHum.getAverage()); Serial.print(F("TempDiff :"));Serial.println(diffTemp); Serial.print(F("HumDiff :"));Serial.println(diffHum); - if (isnan(diffTemp)) tx = true; + if (isnan(diffHum)) tx = true; if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true; if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true; From e23baf9d5d16c1620aedbec266a9ef28accd72d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Tue, 23 Jun 2015 23:20:03 +0200 Subject: [PATCH 139/660] Removed "sensor conditioning code" as it made one of my sensors go haywire, so not the right thing to try and heat the sensor momentarily.. --- .../SensebenderMicro/SensebenderMicro.ino | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 72467ab..1dc3e77 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -113,23 +113,10 @@ void setup() { gw.begin(NULL,AUTO,false); #endif -// --- following code will heat up the sensor element, and wait until the temperature is -// within 0.3 degrees celcius of the initial temperature (measured at startup). -// This is to try and burn away residue humidity from manufacturing process. - int temperature = humiditySensor.getCelsiusHundredths(); - - humiditySensor.setHeater(true); - delay(500); - humiditySensor.setHeater(false); - - int t = 0; - do { - t = humiditySensor.getCelsiusHundredths() - temperature; - } while (abs(t) >30); -// --- + humiditySensor.begin(); + digitalWrite(LED_PIN, LOW); - humiditySensor.begin(); Serial.flush(); Serial.println(F(" - Online!")); gw.sendSketchInfo("Sensebender Micro", RELEASE); From 0300df686ec15ea09e6fa70ada36263fb62283f1 Mon Sep 17 00:00:00 2001 From: Robo Print Date: Sat, 27 Jun 2015 22:50:24 +0200 Subject: [PATCH 140/660] Updated versions of DallasTemperature and OneWire libraries --- .../DallasTemperature/DallasTemperature.cpp | 874 ++++++++++-------- .../DallasTemperature/DallasTemperature.h | 112 ++- .../DallasTemperature/{README => README.md} | 27 +- libraries/DallasTemperature/change.txt | 85 ++ .../examples/Alarm/Alarm.pde | 2 +- .../examples/AlarmHandler/AlarmHandler.pde | 3 +- .../examples/Multiple/Multiple.pde | 6 +- .../examples/Single/Single.pde | 2 +- .../examples/Tester/Tester.pde | 6 +- .../WaitForConversion/WaitForConversion.pde | 66 ++ .../WaitForConversion2/WaitForConversion2.pde | 80 ++ libraries/DallasTemperature/keywords.txt | 15 +- libraries/DallasTemperature/library.json | 39 + libraries/OneWire/OneWire.cpp | 64 +- libraries/OneWire/OneWire.h | 55 +- .../DS18x20_Temperature.pde | 25 +- 16 files changed, 1001 insertions(+), 460 deletions(-) rename libraries/DallasTemperature/{README => README.md} (84%) create mode 100644 libraries/DallasTemperature/change.txt create mode 100644 libraries/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde create mode 100644 libraries/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde create mode 100644 libraries/DallasTemperature/library.json diff --git a/libraries/DallasTemperature/DallasTemperature.cpp b/libraries/DallasTemperature/DallasTemperature.cpp index ea5b1e5..8cf7515 100644 --- a/libraries/DallasTemperature/DallasTemperature.cpp +++ b/libraries/DallasTemperature/DallasTemperature.cpp @@ -3,369 +3,491 @@ // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. +// Version 3.7.2 modified on Dec 6, 2011 to support Arduino 1.0 +// See Includes... +// Modified by Jordan Hochenbaum + #include "DallasTemperature.h" +#if ARDUINO >= 100 +#include "Arduino.h" +#else extern "C" { - #include "Arduino.h" +#include "WConstants.h" } +#endif DallasTemperature::DallasTemperature(OneWire* _oneWire) - #if REQUIRESALARMS - : _AlarmHandler(&defaultAlarmHandler) - #endif +#if REQUIRESALARMS + : _AlarmHandler(&defaultAlarmHandler) +#endif { - _wire = _oneWire; - devices = 0; - parasite = false; - conversionDelay = TEMP_9_BIT; + _wire = _oneWire; + devices = 0; + parasite = false; + bitResolution = 9; + waitForConversion = true; + checkForConversion = true; } -// initialize the bus +// initialise the bus void DallasTemperature::begin(void) { - DeviceAddress deviceAddress; + DeviceAddress deviceAddress; - _wire->reset_search(); - devices = 0; // Reset the number of devices when we enumerate wire devices + _wire->reset_search(); + devices = 0; // Reset the number of devices when we enumerate wire devices - while (_wire->search(deviceAddress)) - { - if (validAddress(deviceAddress)) + while (_wire->search(deviceAddress)) { - if (!parasite && readPowerSupply(deviceAddress)) parasite = true; + if (validAddress(deviceAddress)) + { + if (!parasite && readPowerSupply(deviceAddress)) parasite = true; - ScratchPad scratchPad; + ScratchPad scratchPad; - readScratchPad(deviceAddress, scratchPad); + readScratchPad(deviceAddress, scratchPad); - if (deviceAddress[0] == DS18S20MODEL) conversionDelay = TEMP_12_BIT; // 750 ms - else if (scratchPad[CONFIGURATION] > conversionDelay) conversionDelay = scratchPad[CONFIGURATION]; + bitResolution = max(bitResolution, getResolution(deviceAddress)); - devices++; + devices++; + } } - } } // returns the number of devices found on the bus uint8_t DallasTemperature::getDeviceCount(void) { - return devices; + return devices; } // returns true if address is valid -bool DallasTemperature::validAddress(uint8_t* deviceAddress) +bool DallasTemperature::validAddress(const uint8_t* deviceAddress) { - return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]); + return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]); } // finds an address at a given index on the bus // returns true if the device was found bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) { - uint8_t depth = 0; + uint8_t depth = 0; - _wire->reset_search(); + _wire->reset_search(); - while (depth <= index && _wire->search(deviceAddress)) - { - if (depth == index && validAddress(deviceAddress)) return true; - depth++; - } + while (depth <= index && _wire->search(deviceAddress)) + { + if (depth == index && validAddress(deviceAddress)) return true; + depth++; + } - return false; + return false; } // attempt to determine if the device at the given address is connected to the bus -bool DallasTemperature::isConnected(uint8_t* deviceAddress) +bool DallasTemperature::isConnected(const uint8_t* deviceAddress) { - ScratchPad scratchPad; - return isConnected(deviceAddress, scratchPad); + ScratchPad scratchPad; + return isConnected(deviceAddress, scratchPad); } // attempt to determine if the device at the given address is connected to the bus // also allows for updating the read scratchpad -bool DallasTemperature::isConnected(uint8_t* deviceAddress, uint8_t* scratchPad) +bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) { - readScratchPad(deviceAddress, scratchPad); - return (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); + readScratchPad(deviceAddress, scratchPad); + return (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); } // read device's scratch pad -void DallasTemperature::readScratchPad(uint8_t* deviceAddress, uint8_t* scratchPad) +void DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad) { - // send the command - _wire->reset(); - _wire->select(deviceAddress); - _wire->write(READSCRATCH); + // send the command + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READSCRATCH); - // read the response + // TODO => collect all comments & use simple loop + // byte 0: temperature LSB + // byte 1: temperature MSB + // byte 2: high alarm temp + // byte 3: low alarm temp + // byte 4: DS18S20: store for crc + // DS18B20 & DS1822: configuration register + // byte 5: internal use & crc + // byte 6: DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + // byte 7: DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + // byte 8: SCRATCHPAD_CRC + // + // for(int i=0; i<9; i++) + // { + // scratchPad[i] = _wire->read(); + // } - // byte 0: temperature LSB - scratchPad[TEMP_LSB] = _wire->read(); - // byte 1: temperature MSB - scratchPad[TEMP_MSB] = _wire->read(); + // read the response - // byte 2: high alarm temp - scratchPad[HIGH_ALARM_TEMP] = _wire->read(); + // byte 0: temperature LSB + scratchPad[TEMP_LSB] = _wire->read(); - // byte 3: low alarm temp - scratchPad[LOW_ALARM_TEMP] = _wire->read(); + // byte 1: temperature MSB + scratchPad[TEMP_MSB] = _wire->read(); - // byte 4: - // DS18S20: store for crc - // DS18B20 & DS1822: configuration register - scratchPad[CONFIGURATION] = _wire->read(); + // byte 2: high alarm temp + scratchPad[HIGH_ALARM_TEMP] = _wire->read(); - // byte 5: - // internal use & crc - scratchPad[INTERNAL_BYTE] = _wire->read(); + // byte 3: low alarm temp + scratchPad[LOW_ALARM_TEMP] = _wire->read(); - // byte 6: - // DS18S20: COUNT_REMAIN - // DS18B20 & DS1822: store for crc - scratchPad[COUNT_REMAIN] = _wire->read(); + // byte 4: + // DS18S20: store for crc + // DS18B20 & DS1822: configuration register + scratchPad[CONFIGURATION] = _wire->read(); - // byte 7: - // DS18S20: COUNT_PER_C - // DS18B20 & DS1822: store for crc - scratchPad[COUNT_PER_C] = _wire->read(); + // byte 5: + // internal use & crc + scratchPad[INTERNAL_BYTE] = _wire->read(); - // byte 8: - // SCTRACHPAD_CRC - scratchPad[SCRATCHPAD_CRC] = _wire->read(); + // byte 6: + // DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + scratchPad[COUNT_REMAIN] = _wire->read(); - _wire->reset(); + // byte 7: + // DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + scratchPad[COUNT_PER_C] = _wire->read(); + + // byte 8: + // SCTRACHPAD_CRC + scratchPad[SCRATCHPAD_CRC] = _wire->read(); + + _wire->reset(); } // writes device's scratch pad -void DallasTemperature::writeScratchPad(uint8_t* deviceAddress, const uint8_t* scratchPad) +void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad) { - _wire->reset(); - _wire->select(deviceAddress); - _wire->write(WRITESCRATCH); - _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp - _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp - // DS18S20 does not use the configuration register - if (deviceAddress[0] != DS18S20MODEL) _wire->write(scratchPad[CONFIGURATION]); // configuration - _wire->reset(); - // save the newly written values to eeprom - _wire->write(COPYSCRATCH, parasite); - if (parasite) delay(10); // 10ms delay - _wire->reset(); + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(WRITESCRATCH); + _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp + _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp + // DS1820 and DS18S20 have no configuration register + if (deviceAddress[0] != DS18S20MODEL) _wire->write(scratchPad[CONFIGURATION]); // configuration + _wire->reset(); + _wire->select(deviceAddress); //<--this line was missing + // save the newly written values to eeprom + _wire->write(COPYSCRATCH, parasite); + delay(20); // <--- added 20ms delay to allow 10ms long EEPROM write operation (as specified by datasheet) + if (parasite) delay(10); // 10ms delay + _wire->reset(); } // reads the device's power requirements -bool DallasTemperature::readPowerSupply(uint8_t* deviceAddress) +bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) { - bool ret = false; - _wire->reset(); - _wire->select(deviceAddress); - _wire->write(READPOWERSUPPLY); - if (_wire->read_bit() == 0) ret = true; - _wire->reset(); - return ret; + bool ret = false; + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READPOWERSUPPLY); + if (_wire->read_bit() == 0) ret = true; + _wire->reset(); + return ret; } -// returns the current resolution, 9-12 -uint8_t DallasTemperature::getResolution(uint8_t* deviceAddress) -{ - if (deviceAddress[0] == DS18S20MODEL) return 9; // this model has a fixed resolution - ScratchPad scratchPad; - readScratchPad(deviceAddress, scratchPad); - switch (scratchPad[CONFIGURATION]) - { - case TEMP_12_BIT: - return 12; - break; - case TEMP_11_BIT: - return 11; - break; - case TEMP_10_BIT: - return 10; - break; - case TEMP_9_BIT: - return 9; - break; - } +// set resolution of all devices to 9, 10, 11, or 12 bits +// if new resolution is out of range, it is constrained. +void DallasTemperature::setResolution(uint8_t newResolution) +{ + bitResolution = constrain(newResolution, 9, 12); + DeviceAddress deviceAddress; + for (int i=0; ireset(); - _wire->skip(); - _wire->write(STARTCONVO, parasite); + return bitResolution; +} - switch (conversionDelay) - { - case TEMP_9_BIT: - delay(94); - break; - case TEMP_10_BIT: - delay(188); - break; - case TEMP_11_BIT: - delay(375); - break; - case TEMP_12_BIT: - default: - delay(750); - break; - } +// returns the current resolution of the device, 9-12 +// returns 0 if device not found +uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) +{ + // DS1820 and DS18S20 have no resolution configuration register + if (deviceAddress[0] == DS18S20MODEL) return 12; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + switch (scratchPad[CONFIGURATION]) + { + case TEMP_12_BIT: + return 12; + + case TEMP_11_BIT: + return 11; + + case TEMP_10_BIT: + return 10; + + case TEMP_9_BIT: + return 9; + } + } + return 0; +} + + +// sets the value of the waitForConversion flag +// TRUE : function requestTemperature() etc returns when conversion is ready +// FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!) +// (1) programmer has to check if the needed delay has passed +// (2) but the application can do meaningful things in that time +void DallasTemperature::setWaitForConversion(bool flag) +{ + waitForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getWaitForConversion() +{ + return waitForConversion; +} + + +// sets the value of the checkForConversion flag +// TRUE : function requestTemperature() etc will 'listen' to an IC to determine whether a conversion is complete +// FALSE: function requestTemperature() etc will wait a set time (worst case scenario) for a conversion to complete +void DallasTemperature::setCheckForConversion(bool flag) +{ + checkForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getCheckForConversion() +{ + return checkForConversion; +} + +bool DallasTemperature::isConversionAvailable(const uint8_t* deviceAddress) +{ + // Check if the clock has been raised indicating the conversion is complete + ScratchPad scratchPad; + readScratchPad(deviceAddress, scratchPad); + return scratchPad[0]; +} + + +// sends command for all devices on the bus to perform a temperature conversion +void DallasTemperature::requestTemperatures() +{ + _wire->reset(); + _wire->skip(); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) return; + blockTillConversionComplete(bitResolution, NULL); } // sends command for one device to perform a temperature by address -void DallasTemperature::requestTemperaturesByAddress(uint8_t* deviceAddress) +// returns FALSE if device is disconnected +// returns TRUE otherwise +bool DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress) { - _wire->reset(); - _wire->select(deviceAddress); - _wire->write(STARTCONVO, parasite); + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(STARTCONVO, parasite); - switch (conversionDelay) - { - case TEMP_9_BIT: - delay(94); - break; - case TEMP_10_BIT: - delay(188); - break; - case TEMP_11_BIT: - delay(375); - break; - case TEMP_12_BIT: + // check device + ScratchPad scratchPad; + if (!isConnected(deviceAddress, scratchPad)) return false; + + // ASYNC mode? + if (!waitForConversion) return true; + blockTillConversionComplete(getResolution(deviceAddress), deviceAddress); + + return true; +} + +// returns number of milliseconds to wait till conversion is complete (based on IC datasheet) +int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) +{ + switch (bitResolution) + { + case 9: + return 94; + case 10: + return 188; + case 11: + return 375; default: - delay(750); - break; - } + return 750; + } +} + +// Continue to check if the IC has responded with a temperature +void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, const uint8_t* deviceAddress) +{ + int delms = millisToWaitForConversion(bitResolution); + if (deviceAddress != NULL && checkForConversion && !parasite) + { + unsigned long timend = millis() + delms; + while(!isConversionAvailable(deviceAddress) && (millis() < timend)); + } + else + { + delay(delms); + } } // sends command for one device to perform a temp conversion by index -void DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) +bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) { - DeviceAddress deviceAddress; - getAddress(deviceAddress, deviceIndex); - requestTemperaturesByAddress(deviceAddress); + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + return requestTemperaturesByAddress(deviceAddress); } - // Fetch temperature for device index float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) { - DeviceAddress deviceAddress; - getAddress(deviceAddress, deviceIndex); - return getTempC((uint8_t*)deviceAddress); + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)) + return DEVICE_DISCONNECTED_C; + return getTempC((uint8_t*)deviceAddress); } // Fetch temperature for device index float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) { - return DallasTemperature::toFahrenheit(getTempCByIndex(deviceIndex)); + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)) + return DEVICE_DISCONNECTED_F; + return getTempF((uint8_t*)deviceAddress); } -// reads scratchpad and returns the temperature in degrees C -float DallasTemperature::calculateTemperature(uint8_t* deviceAddress, uint8_t* scratchPad) +// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 +int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad) { - int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB]; + int16_t fpTemperature = + (((int16_t) scratchPad[TEMP_MSB]) << 11) | + (((int16_t) scratchPad[TEMP_LSB]) << 3); - switch (deviceAddress[0]) - { - case DS18B20MODEL: - case DS1822MODEL: - switch (scratchPad[CONFIGURATION]) - { - case TEMP_12_BIT: - return (float)rawTemperature * 0.0625; - break; - case TEMP_11_BIT: - return (float)(rawTemperature >> 1) * 0.125; - break; - case TEMP_10_BIT: - return (float)(rawTemperature >> 2) * 0.25; - break; - case TEMP_9_BIT: - return (float)(rawTemperature >> 3) * 0.5; - break; - } - break; - case DS18S20MODEL: - /* + /* + DS1820 and DS18S20 have a 9-bit temperature register. - Resolutions greater than 9 bits can be calculated using the data from - the temperature, COUNT REMAIN and COUNT PER °C registers in the - scratchpad. Note that the COUNT PER °C register is hard-wired to 16 - (10h). After reading the scratchpad, the TEMP_READ value is obtained - by truncating the 0.5°C bit (bit 0) from the temperature data. The - extended resolution temperature can then be calculated using the - following equation: + Resolutions greater than 9-bit can be calculated using the data from + the temperature, and COUNT REMAIN and COUNT PER °C registers in the + scratchpad. The resolution of the calculation depends on the model. - COUNT_PER_C - COUNT_REMAIN - TEMPERATURE = TEMP_READ - 0.25 + -------------------------- - COUNT_PER_C - */ + While the COUNT PER °C register is hard-wired to 16 (10h) in a + DS18S20, it changes with temperature in DS1820. - // Good spot. Thanks Nic Johns for your contribution - return (float)(rawTemperature >> 1) - 0.25 +((float)(scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) / (float)scratchPad[COUNT_PER_C] ); - break; - } + After reading the scratchpad, the TEMP_READ value is obtained by + truncating the 0.5°C bit (bit 0) from the temperature data. The + extended resolution temperature can then be calculated using the + following equation: + + COUNT_PER_C - COUNT_REMAIN + TEMPERATURE = TEMP_READ - 0.25 + -------------------------- + COUNT_PER_C + + Hagai Shatz simplified this to integer arithmetic for a 12 bits + value for a DS18S20, and James Cameron added legacy DS1820 support. + + See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html + */ + + if (deviceAddress[0] == DS18S20MODEL) + fpTemperature = ((fpTemperature & 0xfff0) << 3) - 16 + + ( + ((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7) / + scratchPad[COUNT_PER_C] + ); + + return fpTemperature; } -// returns temperature in degrees C or DEVICE_DISCONNECTED if the + +// returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the // device's scratch pad cannot be read successfully. -// the numeric value of DEVICE_DISCONNECTED is defined in -// DallasTemperature.h. it is a large negative number outside the +// the numeric value of DEVICE_DISCONNECTED_RAW is defined in +// DallasTemperature.h. It is a large negative number outside the // operating range of the device -float DallasTemperature::getTempC(uint8_t* deviceAddress) +int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress) { - // TODO: Multiple devices (up to 64) on the same bus may take some time to negotiate a response - // What happens in case of collision? - - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) return calculateTemperature(deviceAddress, scratchPad); - return DEVICE_DISCONNECTED; + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return calculateTemperature(deviceAddress, scratchPad); + return DEVICE_DISCONNECTED_RAW; } -// returns temperature in degrees F -float DallasTemperature::getTempF(uint8_t* deviceAddress) +// returns temperature in degrees C or DEVICE_DISCONNECTED_C if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_C is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempC(const uint8_t* deviceAddress) { - return toFahrenheit(getTempC(deviceAddress)); + return rawToCelsius(getTemp(deviceAddress)); +} + +// returns temperature in degrees F or DEVICE_DISCONNECTED_F if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_F is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempF(const uint8_t* deviceAddress) +{ + return rawToFahrenheit(getTemp(deviceAddress)); } // returns true if the bus requires parasite power bool DallasTemperature::isParasitePowerMode(void) { - return parasite; + return parasite; } #if REQUIRESALARMS @@ -390,65 +512,65 @@ the next temperature conversion. */ -// sets the high alarm temperature for a device in degrees celsius +// sets the high alarm temperature for a device in degrees Celsius // accepts a float, but the alarm resolution will ignore anything // after a decimal point. valid range is -55C - 125C -void DallasTemperature::setHighAlarmTemp(uint8_t* deviceAddress, char celsius) +void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, char celsius) { - // make sure the alarm temperature is within the device's range - if (celsius > 125) celsius = 125; - else if (celsius < -55) celsius = -55; + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) - { - scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius; - writeScratchPad(deviceAddress, scratchPad); - } + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } } -// sets the low alarm temperature for a device in degreed celsius +// sets the low alarm temperature for a device in degrees Celsius // accepts a float, but the alarm resolution will ignore anything // after a decimal point. valid range is -55C - 125C -void DallasTemperature::setLowAlarmTemp(uint8_t* deviceAddress, char celsius) +void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, char celsius) { - // make sure the alarm temperature is within the device's range - if (celsius > 125) celsius = 125; - else if (celsius < -55) celsius = -55; + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) - { - scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius; - writeScratchPad(deviceAddress, scratchPad); - } + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } } // returns a char with the current high alarm temperature or // DEVICE_DISCONNECTED for an address -char DallasTemperature::getHighAlarmTemp(uint8_t* deviceAddress) +char DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) { - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; - return DEVICE_DISCONNECTED; + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; } // returns a char with the current low alarm temperature or // DEVICE_DISCONNECTED for an address -char DallasTemperature::getLowAlarmTemp(uint8_t* deviceAddress) +char DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) { - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; - return DEVICE_DISCONNECTED; + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; } // resets internal variables used for the alarm search void DallasTemperature::resetAlarmSearch() { - alarmSearchJunction = -1; - alarmSearchExhausted = 0; - for(uint8_t i = 0; i < 7; i++) - alarmSearchAddress[i] = 0; + alarmSearchJunction = -1; + alarmSearchExhausted = 0; + for(uint8_t i = 0; i < 7; i++) + alarmSearchAddress[i] = 0; } // This is a modified version of the OneWire::search method. @@ -465,132 +587,152 @@ void DallasTemperature::resetAlarmSearch() // DallasTemperature::resetAlarmSearch() to start over. bool DallasTemperature::alarmSearch(uint8_t* newAddr) { - uint8_t i; - char lastJunction = -1; - uint8_t done = 1; + uint8_t i; + char lastJunction = -1; + uint8_t done = 1; - if (alarmSearchExhausted) return false; - if (!_wire->reset()) return false; + if (alarmSearchExhausted) return false; + if (!_wire->reset()) return false; - // send the alarm search command - _wire->write(0xEC, 0); + // send the alarm search command + _wire->write(0xEC, 0); - for(i = 0; i < 64; i++) - { - uint8_t a = _wire->read_bit( ); - uint8_t nota = _wire->read_bit( ); - uint8_t ibyte = i / 8; - uint8_t ibit = 1 << (i & 7); - - // I don't think this should happen, this means nothing responded, but maybe if - // something vanishes during the search it will come up. - if (a && nota) return false; - - if (!a && !nota) + for(i = 0; i < 64; i++) { - if (i == alarmSearchJunction) - { - // this is our time to decide differently, we went zero last time, go one. - a = 1; - alarmSearchJunction = lastJunction; - } - else if (i < alarmSearchJunction) - { - // take whatever we took last time, look in address - if (alarmSearchAddress[ibyte] & ibit) a = 1; - else + uint8_t a = _wire->read_bit( ); + uint8_t nota = _wire->read_bit( ); + uint8_t ibyte = i / 8; + uint8_t ibit = 1 << (i & 7); + + // I don't think this should happen, this means nothing responded, but maybe if + // something vanishes during the search it will come up. + if (a && nota) return false; + + if (!a && !nota) { - // Only 0s count as pending junctions, we've already exhasuted the 0 side of 1s - a = 0; - done = 0; - lastJunction = i; + if (i == alarmSearchJunction) + { + // this is our time to decide differently, we went zero last time, go one. + a = 1; + alarmSearchJunction = lastJunction; + } + else if (i < alarmSearchJunction) + { + // take whatever we took last time, look in address + if (alarmSearchAddress[ibyte] & ibit) a = 1; + else + { + // Only 0s count as pending junctions, we've already exhausted the 0 side of 1s + a = 0; + done = 0; + lastJunction = i; + } + } + else + { + // we are blazing new tree, take the 0 + a = 0; + alarmSearchJunction = i; + done = 0; + } + // OneWire search fix + // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 } - } - else - { - // we are blazing new tree, take the 0 - a = 0; - alarmSearchJunction = i; - done = 0; - } - // OneWire search fix - // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 + + if (a) alarmSearchAddress[ibyte] |= ibit; + else alarmSearchAddress[ibyte] &= ~ibit; + + _wire->write_bit(a); } - if (a) alarmSearchAddress[ibyte] |= ibit; - else alarmSearchAddress[ibyte] &= ~ibit; - - _wire->write_bit(a); - } - - if (done) alarmSearchExhausted = 1; - for (i = 0; i < 8; i++) newAddr[i] = alarmSearchAddress[i]; - return true; + if (done) alarmSearchExhausted = 1; + for (i = 0; i < 8; i++) newAddr[i] = alarmSearchAddress[i]; + return true; } -// returns true if device address has an alarm condition -bool DallasTemperature::hasAlarm(uint8_t* deviceAddress) +// returns true if device address might have an alarm condition +// (only an alarm search can verify this) +bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) { - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) - { - float temp = calculateTemperature(deviceAddress, scratchPad); + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + char temp = calculateTemperature(deviceAddress, scratchPad) >> 7; - // check low alarm - if ((char)temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; + // check low alarm + if (temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; - // check high alarm - if ((char)temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; - } + // check high alarm + if (temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; + } - // no alarm - return false; + // no alarm + return false; } // returns true if any device is reporting an alarm condition on the bus bool DallasTemperature::hasAlarm(void) { - DeviceAddress deviceAddress; - resetAlarmSearch(); - return alarmSearch(deviceAddress); + DeviceAddress deviceAddress; + resetAlarmSearch(); + return alarmSearch(deviceAddress); } // runs the alarm handler for all devices returned by alarmSearch() void DallasTemperature::processAlarms(void) { - resetAlarmSearch(); - DeviceAddress alarmAddr; + resetAlarmSearch(); + DeviceAddress alarmAddr; - while (alarmSearch(alarmAddr)) - { - if (validAddress(alarmAddr)) - _AlarmHandler(alarmAddr); - } + while (alarmSearch(alarmAddr)) + { + if (validAddress(alarmAddr)) + _AlarmHandler(alarmAddr); + } } // sets the alarm handler void DallasTemperature::setAlarmHandler(AlarmHandler *handler) { - _AlarmHandler = handler; + _AlarmHandler = handler; } // The default alarm handler -void DallasTemperature::defaultAlarmHandler(uint8_t* deviceAddress) +void DallasTemperature::defaultAlarmHandler(const uint8_t* deviceAddress) { } #endif -// Convert float celsius to fahrenheit +// Convert float Celsius to Fahrenheit float DallasTemperature::toFahrenheit(float celsius) { - return (celsius * 1.8) + 32; + return (celsius * 1.8) + 32; } -// Convert float fahrenheit to celsius +// Convert float Fahrenheit to Celsius float DallasTemperature::toCelsius(float fahrenheit) { - return (fahrenheit - 32) / 1.8; + return (fahrenheit - 32) * 0.555555556; +} + +// convert from raw to Celsius +float DallasTemperature::rawToCelsius(int16_t raw) +{ + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_C; + // C = RAW/128 + return (float)raw * 0.0078125; +} + +// convert from raw to Fahrenheit +float DallasTemperature::rawToFahrenheit(int16_t raw) +{ + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_F; + // C = RAW/128 + // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 + return ((float)raw * 0.0140625) + 32; } #if REQUIRESNEW @@ -598,21 +740,21 @@ float DallasTemperature::toCelsius(float fahrenheit) // MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object void* DallasTemperature::operator new(unsigned int size) // Implicit NSS obj size { - void * p; // void pointer - p = malloc(size); // Allocate memory - memset((DallasTemperature*)p,0,size); // Initalise memory + void * p; // void pointer + p = malloc(size); // Allocate memory + memset((DallasTemperature*)p,0,size); // Initialise memory - //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method - return (DallasTemperature*) p; // Cast blank region to NSS pointer + //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method + return (DallasTemperature*) p; // Cast blank region to NSS pointer } -// MnetCS 2009 - Unallocates the memory used by this instance +// MnetCS 2009 - Free the memory used by this instance void DallasTemperature::operator delete(void* p) { - DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer - pNss->~DallasTemperature(); // Destruct the object + DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer + pNss->~DallasTemperature(); // Destruct the object - free(p); // Free the memory + free(p); // Free the memory } #endif diff --git a/libraries/DallasTemperature/DallasTemperature.h b/libraries/DallasTemperature/DallasTemperature.h index daf4ad1..93d9713 100644 --- a/libraries/DallasTemperature/DallasTemperature.h +++ b/libraries/DallasTemperature/DallasTemperature.h @@ -1,6 +1,8 @@ #ifndef DallasTemperature_h #define DallasTemperature_h +#define DALLASTEMPLIBVERSION "3.7.2" + // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either @@ -20,9 +22,10 @@ #include // Model IDs -#define DS18S20MODEL 0x10 +#define DS18S20MODEL 0x10 // also DS1820 #define DS18B20MODEL 0x28 #define DS1822MODEL 0x22 +#define DS1825MODEL 0x3B // OneWire commands #define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad @@ -51,7 +54,9 @@ #define TEMP_12_BIT 0x7F // 12 bit // Error Codes -#define DEVICE_DISCONNECTED -127 +#define DEVICE_DISCONNECTED_C -127 +#define DEVICE_DISCONNECTED_F -196.6 +#define DEVICE_DISCONNECTED_RAW -7040 typedef uint8_t DeviceAddress[8]; @@ -61,54 +66,71 @@ class DallasTemperature DallasTemperature(OneWire*); - // initalize bus + // initialise bus void begin(void); // returns the number of devices found on the bus uint8_t getDeviceCount(void); // returns true if address is valid - bool validAddress(uint8_t*); + bool validAddress(const uint8_t*); // finds an address at a given index on the bus - bool getAddress(uint8_t*, const uint8_t); + bool getAddress(uint8_t*, uint8_t); // attempt to determine if the device at the given address is connected to the bus - bool isConnected(uint8_t*); + bool isConnected(const uint8_t*); // attempt to determine if the device at the given address is connected to the bus // also allows for updating the read scratchpad - bool isConnected(uint8_t*, uint8_t*); + bool isConnected(const uint8_t*, uint8_t*); // read device's scratchpad - void readScratchPad(uint8_t*, uint8_t*); + void readScratchPad(const uint8_t*, uint8_t*); // write device's scratchpad - void writeScratchPad(uint8_t*, const uint8_t*); + void writeScratchPad(const uint8_t*, const uint8_t*); // read device's power requirements - bool readPowerSupply(uint8_t*); + bool readPowerSupply(const uint8_t*); - // returns the current resolution, 9-12 - uint8_t getResolution(uint8_t*); + // get global resolution + uint8_t getResolution(); + + // set global resolution to 9, 10, 11, or 12 bits + void setResolution(uint8_t); + + // returns the device resolution: 9, 10, 11, or 12 bits + uint8_t getResolution(const uint8_t*); // set resolution of a device to 9, 10, 11, or 12 bits - void setResolution(uint8_t*, uint8_t); - - // sends command for all devices on the bus to perform a temperature conversion + bool setResolution(const uint8_t*, uint8_t); + + // sets/gets the waitForConversion flag + void setWaitForConversion(bool); + bool getWaitForConversion(void); + + // sets/gets the checkForConversion flag + void setCheckForConversion(bool); + bool getCheckForConversion(void); + + // sends command for all devices on the bus to perform a temperature conversion void requestTemperatures(void); // sends command for one device to perform a temperature conversion by address - void requestTemperaturesByAddress(uint8_t*); + bool requestTemperaturesByAddress(const uint8_t*); // sends command for one device to perform a temperature conversion by index - void requestTemperaturesByIndex(uint8_t); + bool requestTemperaturesByIndex(uint8_t); + + // returns temperature raw value (12 bit integer of 1/16 degrees C) + int16_t getTemp(const uint8_t*); // returns temperature in degrees C - float getTempC(uint8_t*); + float getTempC(const uint8_t*); // returns temperature in degrees F - float getTempF(uint8_t*); + float getTempF(const uint8_t*); // Get temperature for device index (slow) float getTempCByIndex(uint8_t); @@ -118,26 +140,28 @@ class DallasTemperature // returns true if the bus requires parasite power bool isParasitePowerMode(void); + + bool isConversionAvailable(const uint8_t*); #if REQUIRESALARMS - typedef void AlarmHandler(uint8_t*); + typedef void AlarmHandler(const uint8_t*); // sets the high alarm temperature for a device // accepts a char. valid range is -55C - 125C - void setHighAlarmTemp(uint8_t*, const char); + void setHighAlarmTemp(const uint8_t*, char); // sets the low alarm temperature for a device // accepts a char. valid range is -55C - 125C - void setLowAlarmTemp(uint8_t*, const char); + void setLowAlarmTemp(const uint8_t*, char); // returns a signed char with the current high alarm temperature for a device // in the range -55C - 125C - char getHighAlarmTemp(uint8_t*); + char getHighAlarmTemp(const uint8_t*); // returns a signed char with the current low alarm temperature for a device // in the range -55C - 125C - char getLowAlarmTemp(uint8_t*); + char getLowAlarmTemp(const uint8_t*); // resets internal variables used for the alarm search void resetAlarmSearch(void); @@ -146,7 +170,7 @@ class DallasTemperature bool alarmSearch(uint8_t*); // returns true if ia specific device has an alarm - bool hasAlarm(uint8_t*); + bool hasAlarm(const uint8_t*); // returns true if any device is reporting an alarm on the bus bool hasAlarm(void); @@ -155,22 +179,28 @@ class DallasTemperature void processAlarms(void); // sets the alarm handler - void setAlarmHandler(AlarmHandler *); + void setAlarmHandler(const AlarmHandler *); // The default alarm handler - static void defaultAlarmHandler(uint8_t*); + static void defaultAlarmHandler(const uint8_t*); #endif - // convert from celcius to farenheit - static float toFahrenheit(const float); + // convert from Celsius to Fahrenheit + static float toFahrenheit(float); - // convert from farenheit to celsius - static float toCelsius(const float); + // convert from Fahrenheit to Celsius + static float toCelsius(float); + + // convert from raw to Celsius + static float rawToCelsius(int16_t); + + // convert from raw to Fahrenheit + static float rawToFahrenheit(int16_t); #if REQUIRESNEW - // initalize memory area + // initialize memory area void* operator new (unsigned int); // delete memory reference @@ -186,16 +216,26 @@ class DallasTemperature // used to determine the delay amount needed to allow for the // temperature conversion to take place - int conversionDelay; - + uint8_t bitResolution; + + // used to requestTemperature with or without delay + bool waitForConversion; + + // used to requestTemperature to dynamically check if a conversion is complete + bool checkForConversion; + // count of devices on the bus uint8_t devices; // Take a pointer to one wire instance OneWire* _wire; - // reads scratchpad and returns the temperature in degrees C - float calculateTemperature(uint8_t*, uint8_t*); + // reads scratchpad and returns the raw temperature + int16_t calculateTemperature(const uint8_t*, uint8_t*); + + int16_t millisToWaitForConversion(uint8_t); + + void blockTillConversionComplete(uint8_t, const uint8_t*); #if REQUIRESALARMS diff --git a/libraries/DallasTemperature/README b/libraries/DallasTemperature/README.md similarity index 84% rename from libraries/DallasTemperature/README rename to libraries/DallasTemperature/README.md index 829d266..b4ca8c2 100644 --- a/libraries/DallasTemperature/README +++ b/libraries/DallasTemperature/README.md @@ -4,10 +4,14 @@ Arduino Library for Dallas Temperature ICs Usage ----- -This library supports the following devices: - DS18B20 - DS18S20 - Please note there appears to be an issue with this series. - DS1822 +This library supports the following devices : + + +* DS18B20 +* DS18S20 - Please note there appears to be an issue with this series. +* DS1822 +* DS1820 + You will need a pull-up resistor of about 5 KOhm between the 1-Wire data line and your 5V power. If you are using the DS18B20, ground pins 1 and 3. The @@ -15,7 +19,18 @@ centre pin is the data line '1-wire'. We have included a "REQUIRESNEW" and "REQUIRESALARMS" definition. If you want to slim down the code feel free to use either of these by including -#define REQUIRESNEW or #define REQUIRESALARMS a the top of DallasTemperature.h + + + + #define REQUIRESNEW + +or + + #define REQUIRESALARMS + + +at the top of DallasTemperature.h + Credits ------- @@ -26,6 +41,8 @@ Miles Burton originally developed this library. Tim Newsome added support for multiple sensors on the same bus. Guil Barros [gfbarros@bappos.com] added getTempByAddress (v3.5) +Rob Tillaart [rob.tillaart@gmail.com] added async modus (v3.7.0) + Website ------- diff --git a/libraries/DallasTemperature/change.txt b/libraries/DallasTemperature/change.txt new file mode 100644 index 0000000..42564ca --- /dev/null +++ b/libraries/DallasTemperature/change.txt @@ -0,0 +1,85 @@ + +This file contains the change history of the Dallas Temperature Control Library. + +VERSION 3.7.2 BETA +=================== +DATE: 6 DEC 2011 + +- Jordan Hochenbaum [jhochenbaum@gmail.com] updated library for compatibility with Arduino 1.0. + +VERSION 3.7.0 BETA +=================== +DATE: 11 JAN 2011 + +- Rob Tillaart [rob.tillaart@gmail.com] added async modus (v3.7.0) + The library is backwards compatible with version 3.6.0 + + MAJOR: async modus + ------------------ +- Added - private bool waitForConversion. +This boolean is default set to true in the Constructor to keep the library backwards compatible. If this flag is true calls to requestTemperatures(), requestTemperaturesByAddress() et al, will be blocking with the appropiate time specified (in datasheet) for the resolution used. If the flag is set to false, requestTemperatures() et al, will return immediately after the conversion command is send over the 1-wire interface. The programmer is responsible to wait long enough before reading the temperature values. This enables the application to do other things while waiting for a new reading, like calculations, update LCD, read/write other IO lines etc. See examples. + +- Added - void setWaitForConversion(bool); +To set the flag to true or false, depending on the modus needed. + +- Added - bool getWaitForConversion(void); +To get the current value of the flag. + +- Changed - void requestTemperatures(void); +Added a test (false == waitForConversion) to return immediately after the conversion command instead of waiting until the conversion is ready. + +- Changed - bool requestTemperaturesByAddress(uint8_t*); +Added a test (false == waitForConversion) to return immediately after the conversion command instead of waiting until the conversion is ready. + + + MINOR version number + -------------------- +- Added - #define DALLASTEMPLIBVERSION "3.7.0" +To indicate the version number in .h file + + + MINOR internal var bitResolution + ---------------------------- +- Changed - private int conversionDelay - is renamed to - private int bitResolution +As this variable holds the resolution. The delay for the conversion is derived from it. + +- Changed - uint8_t getResolution(uint8_t* deviceAddress); +If the device is not connected, it returns 0, otherwise it returns the resolution of the device. + +- Changed - bool setResolution(uint8_t* deviceAddress, uint8_t newResolution); +If the device is not connected, it returns FALSE (fail), otherwise it returns TRUE (succes). + +- Added - uint8_t getResolution(); +Returns bitResolution. + +- Added - void setResolution(uint8_t newResolution) +Sets the internal variable bitResolution, and all devices to this value + + + MINOR check connected state + ---------------------------- +- Changed - bool requestTemperaturesByIndex(deviceIndex) +Changed return type from void to bool. The function returns false if the device identified with [deviceIndex] is not found on the bus and true otherwise. + +- Changed - bool requestTemperaturesByAddress(deviceAddress) +Changed return type from void to bool. The function returns false if the device identified with [deviceAddress] is not found on the bus and true otherwise. +Added code to handle the DS18S20 which has a 9 bit resolution separately. +Changed code so the blocking delay matches the bitResolution set in the device with deviceAddress. + +- Changed - bool requestTemperaturesByIndex(uint8_t deviceIndex) +Changed return type from void to bool. The function returns false if the device identified with [deviceIndex] is not found on the bus and true otherwise. + + + +VERSION 3.6.0 +============== +DATE: 2010-10-10 + +- no detailed change history known except: + +- The OneWire code has been derived from +http://www.arduino.cc/playground/Learning/OneWire. +- Miles Burton originally developed this library. +- Tim Newsome added support for multiple sensors on +the same bus. +- Guil Barros [gfbarros@bappos.com] added getTempByAddress (v3.5) diff --git a/libraries/DallasTemperature/examples/Alarm/Alarm.pde b/libraries/DallasTemperature/examples/Alarm/Alarm.pde index bd8af00..2aab5f5 100644 --- a/libraries/DallasTemperature/examples/Alarm/Alarm.pde +++ b/libraries/DallasTemperature/examples/Alarm/Alarm.pde @@ -2,7 +2,7 @@ #include // Data wire is plugged into port 2 on the Arduino -#define ONE_WIRE_BUS 3 +#define ONE_WIRE_BUS 2 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); diff --git a/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde b/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde index 05b3a5f..606c5df 100644 --- a/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde +++ b/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde @@ -2,8 +2,7 @@ #include // Data wire is plugged into port 2 on the Arduino -#define ONE_WIRE_BUS 3 -#define TEMPERATURE_PRECISION 9 +#define ONE_WIRE_BUS 2 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); diff --git a/libraries/DallasTemperature/examples/Multiple/Multiple.pde b/libraries/DallasTemperature/examples/Multiple/Multiple.pde index 86cc47d..9e7d6a8 100644 --- a/libraries/DallasTemperature/examples/Multiple/Multiple.pde +++ b/libraries/DallasTemperature/examples/Multiple/Multiple.pde @@ -2,7 +2,7 @@ #include // Data wire is plugged into port 2 on the Arduino -#define ONE_WIRE_BUS 3 +#define ONE_WIRE_BUS 2 #define TEMPERATURE_PRECISION 9 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) @@ -74,8 +74,8 @@ void setup(void) Serial.println(); // set the resolution to 9 bit - sensors.setResolution(insideThermometer, 9); - sensors.setResolution(outsideThermometer, 9); + sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION); + sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION); Serial.print("Device 0 Resolution: "); Serial.print(sensors.getResolution(insideThermometer), DEC); diff --git a/libraries/DallasTemperature/examples/Single/Single.pde b/libraries/DallasTemperature/examples/Single/Single.pde index 61cfcd0..784eb7a 100644 --- a/libraries/DallasTemperature/examples/Single/Single.pde +++ b/libraries/DallasTemperature/examples/Single/Single.pde @@ -2,7 +2,7 @@ #include // Data wire is plugged into port 2 on the Arduino -#define ONE_WIRE_BUS 3 +#define ONE_WIRE_BUS 2 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); diff --git a/libraries/DallasTemperature/examples/Tester/Tester.pde b/libraries/DallasTemperature/examples/Tester/Tester.pde index 8da0722..4f75839 100644 --- a/libraries/DallasTemperature/examples/Tester/Tester.pde +++ b/libraries/DallasTemperature/examples/Tester/Tester.pde @@ -2,7 +2,7 @@ #include // Data wire is plugged into port 2 on the Arduino -#define ONE_WIRE_BUS 3 +#define ONE_WIRE_BUS 2 #define TEMPERATURE_PRECISION 9 // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) @@ -52,9 +52,9 @@ void setup(void) Serial.println(); Serial.print("Setting resolution to "); - Serial.println(TEMPERATURE_PRECISION,DEC); + Serial.println(TEMPERATURE_PRECISION, DEC); - // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions) + // set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions) sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION); Serial.print("Resolution actually set to: "); diff --git a/libraries/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde b/libraries/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde new file mode 100644 index 0000000..52c30be --- /dev/null +++ b/libraries/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde @@ -0,0 +1,66 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +void setup(void) +{ + // start serial port + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.println("\nDemo shows the difference in length of the call\n\n"); + + // Start up the library + sensors.begin(); +} + +void loop(void) +{ + // Request temperature conversion (traditional) + Serial.println("Before blocking requestForConversion"); + unsigned long start = millis(); + + sensors.requestTemperatures(); + + unsigned long stop = millis(); + Serial.println("After blocking requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n"); + + // Request temperature conversion - non-blocking / async + Serial.println("Before NON-blocking/async requestForConversion"); + start = millis(); + sensors.setWaitForConversion(false); // makes it async + sensors.requestTemperatures(); + sensors.setWaitForConversion(true); + stop = millis(); + Serial.println("After NON-blocking/async requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + + // 9 bit resolution by default + // Note the programmer is responsible for the right delay + // we could do something usefull here instead of the delay + int resolution = 9; + delay(750/ (1 << (12-resolution))); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n\n\n\n"); + + delay(5000); +} diff --git a/libraries/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde b/libraries/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde new file mode 100644 index 0000000..f8e7700 --- /dev/null +++ b/libraries/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde @@ -0,0 +1,80 @@ +// +// Sample of using Async reading of Dallas Temperature Sensors +// +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +DeviceAddress tempDeviceAddress; + +int resolution = 12; +unsigned long lastTempRequest = 0; +int delayInMillis = 0; +float temperature = 0.0; +int idle = 0; +// +// SETUP +// +void setup(void) +{ + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.print("Library Version: "); + Serial.println(DALLASTEMPLIBVERSION); + Serial.println("\n"); + + sensors.begin(); + sensors.getAddress(tempDeviceAddress, 0); + sensors.setResolution(tempDeviceAddress, resolution); + + sensors.setWaitForConversion(false); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + + pinMode(13, OUTPUT); +} + +void loop(void) +{ + + if (millis() - lastTempRequest >= delayInMillis) // waited long enough?? + { + digitalWrite(13, LOW); + Serial.print(" Temperature: "); + temperature = sensors.getTempCByIndex(0); + Serial.println(temperature, resolution - 8); + Serial.print(" Resolution: "); + Serial.println(resolution); + Serial.print("Idle counter: "); + Serial.println(idle); + Serial.println(); + + idle = 0; + + // immediately after fetching the temperature we request a new sample + // in the async modus + // for the demo we let the resolution change to show differences + resolution++; + if (resolution > 12) resolution = 9; + + sensors.setResolution(tempDeviceAddress, resolution); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + } + + digitalWrite(13, HIGH); + // we can do usefull things here + // for the demo we just count the idle time in millis + delay(1); + idle++; +} diff --git a/libraries/DallasTemperature/keywords.txt b/libraries/DallasTemperature/keywords.txt index a143d76..b80a269 100644 --- a/libraries/DallasTemperature/keywords.txt +++ b/libraries/DallasTemperature/keywords.txt @@ -7,8 +7,8 @@ ####################################### DallasTemperature KEYWORD1 OneWire KEYWORD1 -AlarmHandler KEYWORD1 -DeviceAddress KEYWORD1 +AlarmHandler KEYWORD1 +DeviceAddress KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -20,12 +20,14 @@ getTempC KEYWORD2 toFahrenheit KEYWORD2 getTempF KEYWORD2 getTempCByIndex KEYWORD2 -getTempFByIndex KEYWORD2 +getTempFByIndex KEYWORD2 +setWaitForConversion KEYWORD2 +getWaitForConversion KEYWORD2 requestTemperatures KEYWORD2 -requestTemperaturesByAddress KEYWORD2 -requestTemperaturesByIndex KEYWORD2 +requestTemperaturesByAddress KEYWORD2 +requestTemperaturesByIndex KEYWORD2 isParasitePowerMode KEYWORD2 -begin KEYWORD2 +begin KEYWORD2 getDeviceCount KEYWORD2 getAddress KEYWORD2 validAddress KEYWORD2 @@ -45,6 +47,7 @@ processAlarmss KEYWORD2 setAlarmHandlers KEYWORD2 defaultAlarmHandler KEYWORD2 calculateTemperature KEYWORD2 +millisToWaitForConversion KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/libraries/DallasTemperature/library.json b/libraries/DallasTemperature/library.json new file mode 100644 index 0000000..2222135 --- /dev/null +++ b/libraries/DallasTemperature/library.json @@ -0,0 +1,39 @@ +{ + "name": "DallasTemperature", + "keywords": "onewire, 1-wire, bus, sensor, temperature", + "description": "Arduino Library for Dallas Temperature ICs (DS18B20, DS18S20, DS1822, DS1820)", + "repository": + { + "type": "git", + "url": "https://github.com/milesburton/Arduino-Temperature-Control-Library.git" + }, + "authors": + [ + { + "name": "Miles Burton", + "email": "miles@mnetcs.com", + "url": "http://www.milesburton.com", + "maintainer": true + }, + { + "name": "Tim Newsome", + "email": "nuisance@casualhacker.net" + }, + { + "name": "Guil Barros", + "email": "gfbarros@bappos.com" + }, + { + "name": "Rob Tillaart", + "email": "rob.tillaart@gmail.com" + } + ], + "dependencies": + { + "name": "OneWire", + "authors": "Paul Stoffregen", + "frameworks": "arduino" + }, + "frameworks": "arduino", + "platforms": "atmelavr" +} diff --git a/libraries/OneWire/OneWire.cpp b/libraries/OneWire/OneWire.cpp index 5c3561a..631813f 100644 --- a/libraries/OneWire/OneWire.cpp +++ b/libraries/OneWire/OneWire.cpp @@ -4,6 +4,24 @@ Copyright (c) 2007, Jim Studt (original old version - many contributors since) The latest version of this library may be found at: http://www.pjrc.com/teensy/td_libs_OneWire.html +OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since +January 2010. At the time, it was in need of many bug fixes, but had +been abandoned the original author (Jim Studt). None of the known +contributors were interested in maintaining OneWire. Paul typically +works on OneWire every 6 to 12 months. Patches usually wait that +long. If anyone is interested in more actively maintaining OneWire, +please contact Paul. + +Version 2.2: + Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com + Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030 + Fix DS18B20 example negative temperature + Fix DS18B20 example's low res modes, Ken Butcher + Improve reset timing, Mark Tillotson + Add const qualifiers, Bertrik Sikken + Add initial value input to crc16, Bertrik Sikken + Add target_search() function, Scott Roberts + Version 2.1: Arduino 1.0 compatibility, Paul Stoffregen Improve temperature example, Paul Stoffregen @@ -136,13 +154,13 @@ uint8_t OneWire::reset(void) DIRECT_WRITE_LOW(reg, mask); DIRECT_MODE_OUTPUT(reg, mask); // drive output low interrupts(); - delayMicroseconds(500); + delayMicroseconds(480); noInterrupts(); DIRECT_MODE_INPUT(reg, mask); // allow it to float - delayMicroseconds(80); + delayMicroseconds(70); r = !DIRECT_READ(reg, mask); interrupts(); - delayMicroseconds(420); + delayMicroseconds(410); return r; } @@ -249,13 +267,13 @@ void OneWire::read_bytes(uint8_t *buf, uint16_t count) { // // Do a ROM select // -void OneWire::select( uint8_t rom[8]) +void OneWire::select(const uint8_t rom[8]) { - int i; + uint8_t i; write(0x55); // Choose ROM - for( i = 0; i < 8; i++) write(rom[i]); + for (i = 0; i < 8; i++) write(rom[i]); } // @@ -280,17 +298,30 @@ void OneWire::depower() // You do not need to do it for the first search, though you could. // void OneWire::reset_search() - { +{ // reset the search state LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; - for(int i = 7; ; i--) - { + for(int i = 7; ; i--) { ROM_NO[i] = 0; if ( i == 0) break; - } } +} + +// Setup the search to find the device type 'family_code' on the next call +// to search(*newAddr) if it is present. +// +void OneWire::target_search(uint8_t family_code) +{ + // set the search state to find SearchFamily type devices + ROM_NO[0] = family_code; + for (uint8_t i = 1; i < 8; i++) + ROM_NO[i] = 0; + LastDiscrepancy = 64; + LastFamilyDiscrepancy = 0; + LastDeviceFlag = FALSE; +} // // Perform a search. If this function returns a '1' then it has @@ -461,7 +492,7 @@ static const uint8_t PROGMEM dscrc_table[] = { // compared to all those delayMicrosecond() calls. But I got // confused, so I use this table from the examples.) // -uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) { uint8_t crc = 0; @@ -475,7 +506,7 @@ uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) // Compute a Dallas Semiconductor 8 bit CRC directly. // this is much slower, but much smaller, than the lookup table. // -uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) { uint8_t crc = 0; @@ -493,23 +524,22 @@ uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) #endif #if ONEWIRE_CRC16 -bool OneWire::check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc) +bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc) { - uint16_t crc = ~crc16(input, len); + crc = ~crc16(input, len, crc); return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1]; } -uint16_t OneWire::crc16(uint8_t* input, uint16_t len) +uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) { static const uint8_t oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; - uint16_t crc = 0; // Starting seed is zero. for (uint16_t i = 0 ; i < len ; i++) { // Even though we're just copying a byte from the input, // we'll be doing 16-bit computation with it. uint16_t cdata = input[i]; - cdata = (cdata ^ (crc & 0xff)) & 0xff; + cdata = (cdata ^ crc) & 0xff; crc >>= 8; if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) diff --git a/libraries/OneWire/OneWire.h b/libraries/OneWire/OneWire.h index 2737b27..916c529 100644 --- a/libraries/OneWire/OneWire.h +++ b/libraries/OneWire/OneWire.h @@ -56,13 +56,44 @@ #define IO_REG_TYPE uint8_t #define IO_REG_ASM asm("r30") #define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) -#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask)) -#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask)) -#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask)) -#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask)) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) + +#elif defined(__MK20DX128__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (1) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (*((base)+512)) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1) + +#elif defined(__SAM3X8E__) +// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due. +// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268 +// If you have trouble with OneWire on Arduino Due, please check the +// status of delayMicroseconds() before reporting a bug in OneWire! +#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask)) +#ifndef PROGMEM +#define PROGMEM +#endif +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const uint8_t *)(addr)) +#endif #elif defined(__PIC32MX__) -#include // is this necessary? #define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) #define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) #define IO_REG_TYPE uint32_t @@ -101,7 +132,7 @@ class OneWire uint8_t reset(void); // Issue a 1-Wire rom select command, you do the reset first. - void select( uint8_t rom[8]); + void select(const uint8_t rom[8]); // Issue a 1-Wire rom skip command, to address all on bus. void skip(void); @@ -137,6 +168,10 @@ class OneWire // Clear the search state so that if will start from the beginning again. void reset_search(); + // Setup the search to find the device type 'family_code' on the next call + // to search(*newAddr) if it is present. + void target_search(uint8_t family_code); + // Look for the next device. Returns 1 if a new address has been // returned. A zero might mean that the bus is shorted, there are // no devices, or you have already retrieved all of them. It @@ -149,7 +184,7 @@ class OneWire #if ONEWIRE_CRC // Compute a Dallas Semiconductor 8 bit CRC, these are used in the // ROM and scratchpad registers. - static uint8_t crc8( uint8_t *addr, uint8_t len); + static uint8_t crc8(const uint8_t *addr, uint8_t len); #if ONEWIRE_CRC16 // Compute the 1-Wire CRC16 and compare it against the received CRC. @@ -170,8 +205,9 @@ class OneWire // @param inverted_crc - The two CRC16 bytes in the received data. // This should just point into the received data, // *not* at a 16-bit integer. + // @param crc - The crc starting value (optional) // @return True, iff the CRC matches. - static bool check_crc16(uint8_t* input, uint16_t len, uint8_t* inverted_crc); + static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); // Compute a Dallas Semiconductor 16 bit CRC. This is required to check // the integrity of data received from many 1-Wire devices. Note that the @@ -183,8 +219,9 @@ class OneWire // byte order than the two bytes you get from 1-Wire. // @param input - Array of bytes to checksum. // @param len - How many bytes to use. + // @param crc - The crc starting value (optional) // @return The CRC16, as defined by Dallas Semiconductor. - static uint16_t crc16(uint8_t* input, uint16_t len); + static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); #endif #endif }; diff --git a/libraries/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.pde b/libraries/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.pde index 1d632ca..68ca194 100644 --- a/libraries/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.pde +++ b/libraries/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.pde @@ -7,7 +7,7 @@ // The DallasTemperature library can do all this work for you! // http://milesburton.com/Dallas_Temperature_Control_Library -OneWire ds(10); // on pin 10 +OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) void setup(void) { Serial.begin(9600); @@ -62,7 +62,7 @@ void loop(void) { ds.reset(); ds.select(addr); - ds.write(0x44,1); // start conversion, with parasite power on at the end + ds.write(0x44, 1); // start conversion, with parasite power on at the end delay(1000); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. @@ -72,7 +72,7 @@ void loop(void) { ds.write(0xBE); // Read Scratchpad Serial.print(" Data = "); - Serial.print(present,HEX); + Serial.print(present, HEX); Serial.print(" "); for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); @@ -83,21 +83,24 @@ void loop(void) { Serial.print(OneWire::crc8(data, 8), HEX); Serial.println(); - // convert the data to actual temperature - - unsigned int raw = (data[1] << 8) | data[0]; + // Convert the data to actual temperature + // because the result is a 16 bit signed integer, it should + // be stored to an "int16_t" type, which is always 16 bits + // even when compiled on a 32 bit processor. + int16_t raw = (data[1] << 8) | data[0]; if (type_s) { raw = raw << 3; // 9 bit resolution default if (data[7] == 0x10) { - // count remain gives full 12 bit resolution + // "count remain" gives full 12 bit resolution raw = (raw & 0xFFF0) + 12 - data[6]; } } else { byte cfg = (data[4] & 0x60); - if (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms - else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms - else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms - // default is 12 bit resolution, 750 ms conversion time + // at lower res, the low bits are undefined, so let's zero them + if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms + else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms + else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms + //// default is 12 bit resolution, 750 ms conversion time } celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; From e47e596075282b122ac5d266ec6ad5c60ca8c978 Mon Sep 17 00:00:00 2001 From: Robo Print Date: Sat, 27 Jun 2015 23:00:37 +0200 Subject: [PATCH 141/660] Make DallasTemperature::millisToWaitForConversion() publicly available --- libraries/DallasTemperature/DallasTemperature.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/DallasTemperature/DallasTemperature.h b/libraries/DallasTemperature/DallasTemperature.h index 93d9713..189fc6b 100644 --- a/libraries/DallasTemperature/DallasTemperature.h +++ b/libraries/DallasTemperature/DallasTemperature.h @@ -116,7 +116,10 @@ class DallasTemperature // sends command for all devices on the bus to perform a temperature conversion void requestTemperatures(void); - + + // returns time to wait for a temperature conversion based on given resolution + int16_t millisToWaitForConversion(uint8_t); + // sends command for one device to perform a temperature conversion by address bool requestTemperaturesByAddress(const uint8_t*); @@ -233,8 +236,6 @@ class DallasTemperature // reads scratchpad and returns the raw temperature int16_t calculateTemperature(const uint8_t*, uint8_t*); - int16_t millisToWaitForConversion(uint8_t); - void blockTillConversionComplete(uint8_t, const uint8_t*); #if REQUIRESALARMS From dffec694626b8fc0a70eb97368a1bdc440b5bdc4 Mon Sep 17 00:00:00 2001 From: Robo Print Date: Sat, 27 Jun 2015 23:27:35 +0200 Subject: [PATCH 142/660] Non-blocking Dallas sensors temperature conversion => lower power usage --- .../DallasTemperatureSensor.ino | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index 3c6c2c0..ade4edd 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -21,6 +21,8 @@ void setup() { // Startup OneWire sensors.begin(); + // requestTemperatures() will not block current thread + sensors.setWaitForConversion(false); // Startup and initialize MySensors library. Set callback for incoming messages. gw.begin(); @@ -44,7 +46,12 @@ void loop() gw.process(); // Fetch temperatures from Dallas sensors - sensors.requestTemperatures(); + sensors.requestTemperatures(); + + // query conversion time and sleep until conversion completed + int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution()); + // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater) + gw.sleep(conversionTime); // Read temperatures and send them to controller for (int i=0; i Date: Sat, 4 Jul 2015 18:17:09 -0600 Subject: [PATCH 143/660] Example sketch for PWF Lightning Sensor --- .../LightningSensor/LightningSensor.ino | 121 +++++ .../PWF_Lightning_Sensor.txt | 10 + .../PWFusion_AS3935.cpp | 421 ++++++++++++++++++ .../PWFusion_AS3935.h | 96 ++++ 4 files changed, 648 insertions(+) create mode 100644 libraries/MySensors/examples/LightningSensor/LightningSensor.ino create mode 100644 libraries/PWF_AS3935_Lightning_Sensor/PWF_Lightning_Sensor.txt create mode 100644 libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp create mode 100644 libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.h diff --git a/libraries/MySensors/examples/LightningSensor/LightningSensor.ino b/libraries/MySensors/examples/LightningSensor/LightningSensor.ino new file mode 100644 index 0000000..8d2bace --- /dev/null +++ b/libraries/MySensors/examples/LightningSensor/LightningSensor.ino @@ -0,0 +1,121 @@ +// This sketch is to integrate the Playing With Fusion AXS3935 Lightning Sensor Breakout Board +// with the MySensors environment and is based on a sketch provided by Playing With Fusion +// http://playingwithfusion.com/productview.php?pdid=22&catid=1001 +// +#include "MySensor.h" +// the lightning sensor can communicate via SPI or I2C. This sketch uses the SPI interface +#include "SPI.h" +// include Playing With Fusion AXS3935 libraries +#include "PWFusion_AS3935.h" + +// setup CS pins used for the connection with the lightning sensor +// other connections are controlled by the SPI library) +int8_t CS_PIN = 8; +int8_t SI_PIN = 7; +int8_t IRQ_PIN = 3; +volatile int8_t AS3935_ISR_Trig = 0; + +// #defines +#define AS3935_INDOORS 1 +#define AS3935_OUTDOORS 0 +#define AS3935_DIST_DIS 0 +#define AS3935_DIST_EN 1 +#define AS3935_CAPACITANCE 96 // <-- SET THIS VALUE TO THE NUMBER LISTED ON YOUR BOARD +// prototypes +void AS3935_ISR(); + +PWF_AS3935 lightning0(CS_PIN, IRQ_PIN, SI_PIN); + +#define CHILD_ID_DISTANCE 1 +#define CHILD_ID_INTENSITY 2 +MySensor gw; +MyMessage msgDist(CHILD_ID_DISTANCE, V_DISTANCE); +MyMessage msgInt(CHILD_ID_INTENSITY, V_VAR1); + +void setup() +{ + gw.begin(); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("Lightning Sensor", "1.1"); + + // Register all sensors to gw (they will be created as child devices) + gw.present(CHILD_ID_DISTANCE, S_DISTANCE); + gw.present(CHILD_ID_INTENSITY, S_CUSTOM); + boolean metric = gw.getConfig().isMetric; + + Serial.begin(115200); + Serial.println("Playing With Fusion: AS3935 Lightning Sensor, SEN-39001"); + Serial.println("beginning boot procedure...."); + + // setup for the the SPI library: + SPI.begin(); // begin SPI + SPI.setClockDivider(SPI_CLOCK_DIV4); // SPI speed to SPI_CLOCK_DIV16/1MHz (max 2MHz, NEVER 500kHz!) + SPI.setDataMode(SPI_MODE1); // MAX31855 is a Mode 1 device + // --> clock starts low, read on rising edge + SPI.setBitOrder(MSBFIRST); // data sent to chip MSb first + + lightning0.AS3935_DefInit(); // set registers to default + // now update sensor cal for your application and power up chip + lightning0.AS3935_ManualCal(AS3935_CAPACITANCE, AS3935_OUTDOORS, AS3935_DIST_EN); + // AS3935_ManualCal Parameters: + // --> capacitance, in pF (marked on package) + // --> indoors/outdoors (AS3935_INDOORS:0 / AS3935_OUTDOORS:1) + // --> disturbers (AS3935_DIST_EN:1 / AS3935_DIST_DIS:2) + // function also powers up the chip + + // enable interrupt (hook IRQ pin to Arduino Uno/Mega interrupt input: 1 -> pin 3 ) + attachInterrupt(1, AS3935_ISR, RISING); + // dump the registry data to the serial port for troubleshooting purposes + lightning0.AS3935_PrintAllRegs(); + + // delay execution to allow chip to stabilize. + delay(1000); + +} + +void loop() +{ + + // This program only handles an AS3935 lightning sensor. It does nothing until + // an interrupt is detected on the IRQ pin. + while(0 == AS3935_ISR_Trig){} + + // reset interrupt flag + AS3935_ISR_Trig = 0; + + // now get interrupt source + uint8_t int_src = lightning0.AS3935_GetInterruptSrc(); + if(0 == int_src) + { + Serial.println("Unknown interrupt source"); + } + else if(1 == int_src) + { + uint8_t lightning_dist_km = lightning0.AS3935_GetLightningDistKm(); + uint32_t lightning_intensity = lightning0.AS3935_GetStrikeEnergyRaw(); + + Serial.print("Lightning detected! Distance to strike: "); + Serial.print(lightning_dist_km); + Serial.println(" kilometers"); + Serial.print("Lightning detected! Lightning Intensity: "); + Serial.println(lightning_intensity); + gw.send(msgDist.set(lightning_dist_km)); + gw.send(msgInt.set(lightning_intensity)); + } + else if(2 == int_src) + { + Serial.println("Disturber detected"); + } + else if(3 == int_src) + { + Serial.println("Noise level too high"); + } +} + +// this is irq handler for AS3935 interrupts, has to return void and take no arguments +// always make code in interrupt handlers fast and short +void AS3935_ISR() +{ + AS3935_ISR_Trig = 1; +} \ No newline at end of file diff --git a/libraries/PWF_AS3935_Lightning_Sensor/PWF_Lightning_Sensor.txt b/libraries/PWF_AS3935_Lightning_Sensor/PWF_Lightning_Sensor.txt new file mode 100644 index 0000000..ed26e7e --- /dev/null +++ b/libraries/PWF_AS3935_Lightning_Sensor/PWF_Lightning_Sensor.txt @@ -0,0 +1,10 @@ +Notes from AS3935 datasheet: +Register Map: Page 11, detailed version on Page 12 + +Max clock freq for SPI = 2MHz + +SPI command Structure: Page14 +To activate this SPI, the CS has to be set to low. A SPI command consists of two bytes serial command and the data are sampled on the falling +edge of SCLK (CPHA=1). The next table shows command structure, from the MSB (B15) to LSB (B0). The command stream has to be sent to +the SPI from the MSB (B15) to the LSB (B0). + diff --git a/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp new file mode 100644 index 0000000..1d2b8a0 --- /dev/null +++ b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp @@ -0,0 +1,421 @@ +/*************************************************************************** +* File Name: PWFusion_AS3935.h +* Processor/Platform: Arduino Uno R3 (tested) +* Development Environment: Arduino 1.0.5 +* +* Designed for use with with Playing With Fusion AS3935 Lightning Sensor +* Breakout: SEN-39001. +* +* SEN-39001 (universal applications) +* ---> http://www.playingwithfusion.com/productview.php?pdid=22 +* +* Copyright © 2014 Playing With Fusion, Inc. +* SOFTWARE LICENSE AGREEMENT: This code is released under the MIT License. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* ************************************************************************** +* REVISION HISTORY: +* Author Date Comments +* J. Steinlage 2014Aug20 Original version +* +* Playing With Fusion, Inc. invests time and resources developing open-source +* code. Please support Playing With Fusion and continued open-source +* development by buying products from Playing With Fusion! +* +* ************************************************************************** +* ADDITIONAL NOTES: +* This file contains functions to interface with the AS3935 Franklin +* Lightning Sensor manufactured by AMS. Originally designed for application +* on the Arduino Uno platform. +**************************************************************************/ +#include "PWFusion_AS3935.h" + +PWF_AS3935::PWF_AS3935(int8_t CSx, int8_t IRQx, int8_t SIx) +{ + _cs = CSx; + _si = SIx; + _irq = IRQx; + + // initalize the chip select pins + pinMode(_cs, OUTPUT); + pinMode(_si, OUTPUT); + pinMode(_irq, INPUT); + + digitalWrite(_cs, HIGH); // set pin high to initialize/clear SPI bus + digitalWrite(_si, LOW); // set pin low for SPI mode + +} + +uint8_t PWF_AS3935::_sing_reg_read(uint8_t RegAdd) +{ + digitalWrite(_cs, LOW); // set pin low to start talking to IC + // next pack command byte, send AS3935.... structure is shown below + // MODE Register Address/Direct Cmd + // B15-14 B13------------------8 + // 15 is always 0; B14, 0: Write/Direct Command, 1: Read + SPI.transfer((RegAdd & 0x3F) | 0x40); // simple write, nothing to read back + uint8_t RegData = SPI.transfer(0x00); // read register data from IC + digitalWrite(_cs, HIGH); // set pin high to end SPI session + + return RegData; +} + +void PWF_AS3935::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData) +{ + // start by reading original register data (only modifying what we need to) + uint8_t OrigRegData = _sing_reg_read(RegAdd); + + // calculate new register data... 'delete' old targeted data, replace with new data + // note: 'DataMask' must be bits targeted for replacement + // add'l note: this function does NOT shift values into the proper place... they need to be there already + uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask)); + + // now configure and write the updated register value + digitalWrite(_cs, LOW); // set pin low to start talking to IC + // next pack command byte, send AS3935.... structure is shown below + // MODE Register Address/Direct Cmd + // B15-14 B13------------------8 + // 15 is always 0; B14, 0: Write/Direct Command, 1: Read + SPI.transfer((RegAdd & 0x3F)); // simple write, nothing to read back + SPI.transfer(RegData); // write register data to IC + digitalWrite(_cs, HIGH); // set pin high to end SPI session +} + +void PWF_AS3935::AS3935_DefInit() +{ + _AS3935_Reset(); // reset registers to default +} + +void PWF_AS3935::_AS3935_Reset() +{ + // run PRESET_DEFAULT Direct Command to set all registers in default state + digitalWrite(_cs, LOW); // begin transfer + SPI.transfer(0x3C); // send first byte (write, PRESET_DEFAULT register) + SPI.transfer(0x96); // send second byte (direct command) + digitalWrite(_cs, HIGH); // end transfer + delay(2); // wait 2ms to complete +} + +void PWF_AS3935::_CalRCO() +{ + // run ALIB_RCO Direct Command to cal internal RCO + digitalWrite(_cs, LOW); // begin transfer + SPI.transfer(0x3D); // send first byte (write, CALIB_RCO register) + SPI.transfer(0x96); // send second byte (direct command) + digitalWrite(_cs, HIGH); // end transfer + delay(3); // wait 3ms to complete +} + +void PWF_AS3935::AS3935_PowerUp(void) +{ + // power-up sequence based on datasheet, pg 23/27 + // register 0x00, PWD bit: 0 (clears PWD) + _sing_reg_write(0x00, 0x01, 0x00); + _CalRCO(); // run RCO cal cmd + _sing_reg_write(0x08, 0x20, 0x20); // set DISP_SRCO to 1 + delay(2); + _sing_reg_write(0x08, 0x20, 0x00); // set DISP_SRCO to 0 + +} + +void PWF_AS3935::AS3935_PowerDown(void) +{ + // register 0x00, PWD bit: 0 (sets PWD) + _sing_reg_write(0x00, 0x01, 0x01); + Serial.println("AS3935 powered down"); +} + +void PWF_AS3935::AS3935_DisturberEn(void) +{ + // register 0x03, PWD bit: 5 (sets MASK_DIST) + _sing_reg_write(0x03, 0x20, 0x00); + Serial.println("disturber detection enabled"); +} + +void PWF_AS3935::AS3935_DisturberDis(void) +{ + // register 0x03, PWD bit: 5 (sets MASK_DIST) + _sing_reg_write(0x03, 0x20, 0x20); +} + +void PWF_AS3935::AS3935_SetIRQ_Output_Source(uint8_t irq_select) +{ + // set interrupt source - what to displlay on IRQ pin + // reg 0x08, bits 5 (TRCO), 6 (SRCO), 7 (LCO) + // only one should be set at once, I think + // 0 = NONE, 1 = TRCO, 2 = SRCO, 3 = LCO + + if(1 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x20); // set only TRCO bit + } + else if(2 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x40); // set only SRCO bit + } + else if(3 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x80); // set only LCO bit + } + else // assume 0 + { + _sing_reg_write(0x08, 0xE0, 0x00); // clear IRQ pin display bits + } + +} + +void PWF_AS3935::AS3935_SetTuningCaps(uint8_t cap_val) +{ + // Assume only numbers divisible by 8 (because that's all the chip supports) + if(120 < cap_val) // cap_value out of range, assume highest capacitance + { + _sing_reg_write(0x08, 0x0F, 0x0F); // set capacitance bits to maximum + } + else + { + _sing_reg_write(0x08, 0x0F, (cap_val>>3)); // set capacitance bits + } + Serial.print("capacitance set to 8x"); + Serial.println((_sing_reg_read(0x08) & 0x0F)); +} + +uint8_t PWF_AS3935::AS3935_GetInterruptSrc(void) +{ + // definition of interrupt data on table 18 of datasheet + // for this function: + // 0 = unknown src, 1 = lightning detected, 2 = disturber, 3 = Noise level too high + delay(10); // wait 10ms before reading (2ms per pg 22 of datasheet) + uint8_t int_src = (_sing_reg_read(0x03) & 0x0F); // read register, get rid of non-interrupt data + if(0x08 == int_src) + { + return 1; // lightning caused interrupt + } + else if(0x04 == int_src) + { + return 2; // disturber detected + } + else if(0x01 == int_src) + { + return 3; // Noise level too high + } + else{return 0;} // interrupt result not expected + +} + +uint8_t PWF_AS3935::AS3935_GetLightningDistKm(void) +{ + uint8_t strike_dist = (_sing_reg_read(0x07) & 0x3F); // read register, get rid of non-distance data + return strike_dist; +} + +uint32_t PWF_AS3935::AS3935_GetStrikeEnergyRaw(void) +{ + uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB + nrgy_raw |= _sing_reg_read(0x05); // read MSB + nrgy_raw <= 8; // shift 8 bits left, make room for LSB + nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others + + return nrgy_raw; +} + +uint8_t PWF_AS3935::AS3935_SetMinStrikes(uint8_t min_strk) +{ + // This function sets min strikes to the closest available number, rounding to the floor, + // where necessary, then returns the physical value that was set. Options are 1, 5, 9 or 16 strikes. + // see pg 22 of the datasheet for more info (#strikes in 17 min) + if(5 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x00); + return 1; + } + else if(9 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x10); + return 5; + } + else if(16 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x20); + return 9; + } + else + { + _sing_reg_write(0x02, 0x30, 0x30); + return 16; + } +} + +void PWF_AS3935::AS3935_SetIndoors(void) +{ + // AFE settings addres 0x00, bits 5:1 (10010, based on datasheet, pg 19, table 15) + // this is the default setting at power-up (AS3935 datasheet, table 9) + _sing_reg_write(0x00, 0x3E, 0x24); + Serial.println("set up for indoor operation"); +} + +void PWF_AS3935::AS3935_SetOutdoors(void) +{ + // AFE settings addres 0x00, bits 5:1 (01110, based on datasheet, pg 19, table 15) + _sing_reg_write(0x00, 0x3E, 0x1C); + Serial.println("set up for outdoor operation"); +} + +void PWF_AS3935::AS3935_ClearStatistics(void) +{ + // clear is accomplished by toggling CL_STAT bit 'high-low-high' (then set low to move on) + _sing_reg_write(0x02, 0x40, 0x40); // high + _sing_reg_write(0x02, 0x40, 0x00); // low + _sing_reg_write(0x02, 0x40, 0x40); // high +} + +uint8_t PWF_AS3935::AS3935_GetNoiseFloorLvl(void) +{ + // NF settings addres 0x01, bits 6:4 + // default setting of 010 at startup (datasheet, table 9) + uint8_t reg_raw = _sing_reg_read(0x01); // read register 0x01 + return ((reg_raw & 0x70)>>4); // should return value from 0-7, see table 16 for info +} + +void PWF_AS3935::AS3935_SetNoiseFloorLvl(uint8_t nf_sel) +{ + // NF settings addres 0x01, bits 6:4 + // default setting of 010 at startup (datasheet, table 9) + if(7 >= nf_sel) // nf_sel within expected range + { + _sing_reg_write(0x01, 0x70, ((nf_sel & 0x07)<<4)); + } + else + { // out of range, set to default (power-up value 010) + _sing_reg_write(0x01, 0x70, 0x20); + } +} + +uint8_t PWF_AS3935::AS3935_GetWatchdogThreshold(void) +{ + // This function is used to read WDTH. It is used to increase robustness to disturbers, + // though will make detection less efficient (see page 19, Fig 20 of datasheet) + // WDTH register: add 0x01, bits 3:0 + // default value of 0001 + // values should only be between 0x00 and 0x0F (0 and 7) + uint8_t reg_raw = _sing_reg_read(0x01); + return (reg_raw & 0x0F); +} + +void PWF_AS3935::AS3935_SetWatchdogThreshold(uint8_t wdth) +{ + // This function is used to modify WDTH. It is used to increase robustness to disturbers, + // though will make detection less efficient (see page 19, Fig 20 of datasheet) + // WDTH register: add 0x01, bits 3:0 + // default value of 0001 + // values should only be between 0x00 and 0x0F (0 and 7) + _sing_reg_write(0x01, 0x0F, (wdth & 0x0F)); +} + +uint8_t PWF_AS3935::AS3935_GetSpikeRejection(void) +{ + // This function is used to read SREJ (spike rejection). Similar to the Watchdog threshold, + // it is used to make the system more robust to disturbers, though will make general detection + // less efficient (see page 20-21, especially Fig 21 of datasheet) + // SREJ register: add 0x02, bits 3:0 + // default value of 0010 + // values should only be between 0x00 and 0x0F (0 and 7) + uint8_t reg_raw = _sing_reg_read(0x02); + return (reg_raw & 0x0F); +} + +void PWF_AS3935::AS3935_SetSpikeRejection(uint8_t srej) +{ + // This function is used to modify SREJ (spike rejection). Similar to the Watchdog threshold, + // it is used to make the system more robust to disturbers, though will make general detection + // less efficient (see page 20-21, especially Fig 21 of datasheet) + // WDTH register: add 0x02, bits 3:0 + // default value of 0010 + // values should only be between 0x00 and 0x0F (0 and 7) + _sing_reg_write(0x02, 0x0F, (srej & 0x0F)); +} + +void PWF_AS3935::AS3935_SetLCO_FDIV(uint8_t fdiv) +{ + // This function sets LCO_FDIV register. This is useful in the tuning of the antenna + // LCO_FDIV register: add 0x03, bits 7:6 + // default value: 00 + // set 0, 1, 2 or 3 for ratios of 16, 32, 64 and 128, respectively. + // See pg 23, Table 20 for more info. + _sing_reg_write(0x03, 0xC0, ((fdiv & 0x03) << 5)); +} + +void PWF_AS3935::AS3935_PrintAllRegs(void) +{ + Serial.print("Reg 0x00: "); + Serial.println(_sing_reg_read(0x00)); + Serial.print("Reg 0x01: "); + Serial.println(_sing_reg_read(0x01)); + Serial.print("Reg 0x02: "); + Serial.println(_sing_reg_read(0x02)); + Serial.print("Reg 0x03: "); + Serial.println(_sing_reg_read(0x03)); + Serial.print("Reg 0x04: "); + Serial.println(_sing_reg_read(0x04)); + Serial.print("Reg 0x05: "); + Serial.println(_sing_reg_read(0x05)); + Serial.print("Reg 0x06: "); + Serial.println(_sing_reg_read(0x06)); + Serial.print("Reg 0x07: "); + Serial.println(_sing_reg_read(0x07)); + Serial.print("Reg 0x08: "); + Serial.println(_sing_reg_read(0x08)); + uint32_t nrgy_val = AS3935_GetStrikeEnergyRaw(); + Serial.println(nrgy_val); +} + +void PWF_AS3935::AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber) +{ + // start by powering up + AS3935_PowerUp(); + + // indoors/outdoors next... + if(1 == location) // set outdoors if 1 + { + AS3935_SetOutdoors(); + } + else // set indoors if anything but 1 + { + AS3935_SetIndoors(); + } + + // disturber cal + if(0 == disturber) // disabled if 0 + { + AS3935_DisturberDis(); + } + else // enabled if anything but 0 + { + AS3935_DisturberEn(); + } + + AS3935_SetIRQ_Output_Source(0); + + delay(500); + // capacitance first... directly write value here + AS3935_SetTuningCaps(capacitance); + + Serial.println("AS3935 manual cal complete"); +} +// a nice function would be to read the last 'x' strike data values.... + diff --git a/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.h b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.h new file mode 100644 index 0000000..4f62f07 --- /dev/null +++ b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.h @@ -0,0 +1,96 @@ +/*************************************************************************** +* File Name: PWFusion_AS3935.h +* Processor/Platform: Arduino Uno R3 (tested) +* Development Environment: Arduino 1.0.5 +* +* Designed for use with with Playing With Fusion AS3935 Lightning Sensor +* Breakout: SEN-39001. +* +* SEN-39001 (universal applications) +* ---> http://www.playingwithfusion.com/productview.php?pdid=22 +* +* Copyright © 2014 Playing With Fusion, Inc. +* SOFTWARE LICENSE AGREEMENT: This code is released under the MIT License. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* ************************************************************************** +* REVISION HISTORY: +* Author Date Comments +* J. Steinlage 2014Aug20 Original version +* +* Playing With Fusion, Inc. invests time and resources developing open-source +* code. Please support Playing With Fusion and continued open-source +* development by buying products from Playing With Fusion! +* +* ************************************************************************** +* ADDITIONAL NOTES: +* This file contains functions to interface with the AS3935 Franklin +* Lightning Sensor manufactured by AMS. Originally designed for application +* on the Arduino Uno platform. +**************************************************************************/ +#ifndef PWF_AS3935_h +#define PWF_AS3935_h + +#include "Arduino.h" +#include "avr/pgmspace.h" +#include "util/delay.h" +#include "stdlib.h" +#include "SPI.h" + +class PWF_AS3935 +{ + public: + PWF_AS3935(int8_t CSx, int8_t IRQx, int8_t SIx); + void AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber); + void AS3935_DefInit(void); + void AS3935_PowerUp(void); + void AS3935_PowerDown(void); + void AS3935_DisturberEn(void); + void AS3935_DisturberDis(void); + void AS3935_SetIRQ_Output_Source(uint8_t irq_select); + void AS3935_SetTuningCaps(uint8_t cap_val); + uint8_t AS3935_GetInterruptSrc(void); + uint8_t AS3935_GetLightningDistKm(void); + uint32_t AS3935_GetStrikeEnergyRaw(void); + uint8_t AS3935_SetMinStrikes(uint8_t min_strk); + void AS3935_ClearStatistics(void); + void AS3935_SetIndoors(void); + void AS3935_SetOutdoors(void); + uint8_t AS3935_GetNoiseFloorLvl(void); + void AS3935_SetNoiseFloorLvl(uint8_t nf_sel); + uint8_t AS3935_GetWatchdogThreshold(void); + void AS3935_SetWatchdogThreshold(uint8_t wdth); + uint8_t AS3935_GetSpikeRejection(void); + void AS3935_SetSpikeRejection(uint8_t srej); + void AS3935_SetLCO_FDIV(uint8_t fdiv); + void AS3935_PrintAllRegs(void); + + private: + int8_t _cs, _irq, _si; + uint8_t _sing_reg_read(uint8_t RegAdd); + void _sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData); + void _AS3935_Reset(void); + void _CalRCO(void); +}; + +#endif + + + + From 5d7fe779e0615a9c45cbbc3d128737627ec7d4d1 Mon Sep 17 00:00:00 2001 From: windkh Date: Wed, 8 Jul 2015 22:37:38 +0200 Subject: [PATCH 144/660] Refactored forecast algorithm - reduced footprint by storing only the last few samples instead of all 180 - fixed wrong calculation: 65/1023 factor replaced with a conversion factor hPa to kPa - fixed error when 180 minutes were reached: sketch started at 5 min instead of 6 triggering a wrong average calculation Cleaned up code - removed unused variable - fixed unit Pa to hPa in serial print - introduced constants and enum for better readability Signed-off-by: windkh I agree to the CLA! --- .../PressureSensor/PressureSensor.ino | 351 ++++++++++-------- 1 file changed, 194 insertions(+), 157 deletions(-) diff --git a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino index 8911e74..dc4c213 100644 --- a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino +++ b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino @@ -6,7 +6,21 @@ #define BARO_CHILD 0 #define TEMP_CHILD 1 -unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in seconds) +const float ALTITUDE = 688; // <-- adapt this value to your own location's altitude. + +// Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute. +const unsigned long SLEEP_TIME = 60000; + +const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" }; +enum FORECAST +{ + STABLE = 0, // "Stable Weather Pattern" + SUNNY = 1, // "Slowly rising Good Weather", "Clear/Sunny " + CLOUDY = 2, // "Slowly falling L-Pressure ", "Cloudy/Rain " + UNSTABLE = 3, // "Quickly rising H-Press", "Not Stable" + THUNDERSTORM = 4, // "Quickly falling L-Press", "Thunderstorm" + UNKNOWN = 5 // "Unknown (More Time needed) +}; Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor MySensor gw; @@ -14,206 +28,229 @@ MySensor gw; float lastPressure = -1; float lastTemp = -1; int lastForecast = -1; -const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; -int minutes; -float pressureSamples[7][6]; + +const int LAST_SAMPLES_COUNT = 5; +float lastPressureSamples[LAST_SAMPLES_COUNT]; + +// this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm +// get kPa/h be dividing hPa by 10 +#define CONVERSION_FACTOR (1.0/10.0) + int minuteCount = 0; bool firstRound = true; float pressureAvg[7]; + float dP_dt; -boolean metric; +boolean metric; MyMessage tempMsg(TEMP_CHILD, V_TEMP); MyMessage pressureMsg(BARO_CHILD, V_PRESSURE); MyMessage forecastMsg(BARO_CHILD, V_FORECAST); -void setup() { - gw.begin(); - // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Pressure Sensor", "1.0"); +void setup() +{ + gw.begin(); - if (!bmp.begin()) { - Serial.println("Could not find a valid BMP085 sensor, check wiring!"); - while (1) { } - } + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("Pressure Sensor", "1.1"); - // Register sensors to gw (they will be created as child devices) - gw.present(BARO_CHILD, S_BARO); - gw.present(TEMP_CHILD, S_TEMP); - metric = gw.getConfig().isMetric; + if (!bmp.begin()) + { + Serial.println("Could not find a valid BMP085 sensor, check wiring!"); + while (1) {} + } + + // Register sensors to gw (they will be created as child devices) + gw.present(BARO_CHILD, S_BARO); + gw.present(TEMP_CHILD, S_TEMP); + metric = gw.getConfig().isMetric; } -void loop() { - float pressure = bmp.readSealevelPressure(205)/100.0; // 205 meters above sealevel - float temperature = bmp.readTemperature(); - - if (!metric) { - // Convert to fahrenheit - temperature = temperature * 9.0 / 5.0 + 32.0; - } - - int forecast = sample(pressure); +void loop() +{ + float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0; + float temperature = bmp.readTemperature(); - Serial.print("Temperature = "); - Serial.print(temperature); - Serial.println(metric?" *C":" *F"); - Serial.print("Pressure = "); - Serial.print(pressure); - Serial.println(" Pa"); - Serial.println(weather[forecast]); + if (!metric) + { + // Convert to fahrenheit + temperature = temperature * 9.0 / 5.0 + 32.0; + } + + int forecast = sample(pressure); + + Serial.print("Temperature = "); + Serial.print(temperature); + Serial.println(metric ? " *C" : " *F"); + Serial.print("Pressure = "); + Serial.print(pressure); + Serial.println(" hPa"); + Serial.print("Forecast = "); + Serial.println(weather[forecast]); - if (temperature != lastTemp) { - gw.send(tempMsg.set(temperature,1)); - lastTemp = temperature; - } + if (temperature != lastTemp) + { + gw.send(tempMsg.set(temperature, 1)); + lastTemp = temperature; + } - if (pressure != lastPressure) { - gw.send(pressureMsg.set(pressure, 0)); - lastPressure = pressure; - } + if (pressure != lastPressure) + { + gw.send(pressureMsg.set(pressure, 0)); + lastPressure = pressure; + } - if (forecast != lastForecast) { - gw.send(forecastMsg.set(weather[forecast])); - lastForecast = forecast; - } - - /* - DP/Dt explanation + if (forecast != lastForecast) + { + gw.send(forecastMsg.set(weather[forecast])); + lastForecast = forecast; + } - 0 = "Stable Weather Pattern" - 1 = "Slowly rising Good Weather", "Clear/Sunny " - 2 = "Slowly falling L-Pressure ", "Cloudy/Rain " - 3 = "Quickly rising H-Press", "Not Stable" - 4 = "Quickly falling L-Press", "Thunderstorm" - 5 = "Unknown (More Time needed) - */ - - gw.sleep(SLEEP_TIME); + gw.sleep(SLEEP_TIME); } -int sample(float pressure) { - // Algorithm found here - // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf - if (minuteCount == 180) - minuteCount = 5; - - //From 0 to 5 min. - if (minuteCount <= 5){ - pressureSamples[0][minuteCount] = pressure; - } - //From 30 to 35 min. - if ((minuteCount <= 30) && (minuteCount >= 35)){ - pressureSamples[1][minuteCount - 30] = pressure; - } - //From 55 to 60 min. - if ((minuteCount <= 55) && (minuteCount >= 60)){ - pressureSamples[2][minuteCount - 55] = pressure; - } - //From 90 to 95 min. - if ((minuteCount <= 90) && (minuteCount >= 95)){ - pressureSamples[3][minuteCount - 90] = pressure; - } - //From 115 to 119 min. - if ((minuteCount <= 115) && (minuteCount >= 120)){ - pressureSamples[4][minuteCount - 115] = pressure; - } - //From 150 to 155 min. - if ((minuteCount <= 150) && (minuteCount >= 155)){ - pressureSamples[5][minuteCount - 150] = pressure; - } - //From 175 to 180 min. - if ((minuteCount <= 175) && (minuteCount >= 180)){ - pressureSamples[6][minuteCount - 175] = pressure; - } - +float getLastPressureSamplesAverage() +{ + float lastPressureSamplesAverage = 0; + for (int i = 0; i < LAST_SAMPLES_COUNT; i++) + { + lastPressureSamplesAverage += lastPressureSamples[i]; + } + lastPressureSamplesAverage /= LAST_SAMPLES_COUNT; + + return lastPressureSamplesAverage; +} + +// Algorithm found here +// http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf +// Pressure in hPa --> forecast done by calculating kPa/h +int sample(float pressure) +{ + // Calculate the average of the last n minutes. + int index = minuteCount % LAST_SAMPLES_COUNT; + lastPressureSamples[index] = pressure; minuteCount++; + if (minuteCount > 185) + { + minuteCount = 6; + } - if (minuteCount == 5) { - // Avg pressure in first 5 min, value averaged from 0 to 5 min. - pressureAvg[0] = ((pressureSamples[0][0] + pressureSamples[0][1] - + pressureSamples[0][2] + pressureSamples[0][3] - + pressureSamples[0][4] + pressureSamples[0][5]) / 6); - } else if (minuteCount == 35) { - // Avg pressure in 30 min, value averaged from 0 to 5 min. - pressureAvg[1] = ((pressureSamples[1][0] + pressureSamples[1][1] - + pressureSamples[1][2] + pressureSamples[1][3] - + pressureSamples[1][4] + pressureSamples[1][5]) / 6); - float change = (pressureAvg[1] - pressureAvg[0]); + if (minuteCount == 5) + { + pressureAvg[0] = getLastPressureSamplesAverage(); + } + else if (minuteCount == 35) + { + pressureAvg[1] = getLastPressureSamplesAverage(); + float change = (pressureAvg[1] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour - dP_dt = ((65.0 / 1023.0) * 2 * change); // note this is for t = 0.5hour + { + dP_dt = change * 2; // note this is for t = 0.5hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 1.5); // divide by 1.5 as this is the difference in time from 0 value. - } else if (minuteCount == 60) { - // Avg pressure at end of the hour, value averaged from 0 to 5 min. - pressureAvg[2] = ((pressureSamples[2][0] + pressureSamples[2][1] - + pressureSamples[2][2] + pressureSamples[2][3] - + pressureSamples[2][4] + pressureSamples[2][5]) / 6); - float change = (pressureAvg[2] - pressureAvg[0]); + { + dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value. + } + } + else if (minuteCount == 65) + { + pressureAvg[2] = getLastPressureSamplesAverage(); + float change = (pressureAvg[2] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) //first time initial 3 hour - dP_dt = ((65.0 / 1023.0) * change); //note this is for t = 1 hour + { + dP_dt = change; //note this is for t = 1 hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 2); //divide by 2 as this is the difference in time from 0 value - } else if (minuteCount == 95) { - // Avg pressure at end of the hour, value averaged from 0 to 5 min. - pressureAvg[3] = ((pressureSamples[3][0] + pressureSamples[3][1] - + pressureSamples[3][2] + pressureSamples[3][3] - + pressureSamples[3][4] + pressureSamples[3][5]) / 6); - float change = (pressureAvg[3] - pressureAvg[0]); + { + dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value + } + } + else if (minuteCount == 95) + { + pressureAvg[3] = getLastPressureSamplesAverage(); + float change = (pressureAvg[3] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour - dP_dt = (((65.0 / 1023.0) * change) / 1.5); // note this is for t = 1.5 hour + { + dP_dt = change / 1.5; // note this is for t = 1.5 hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 2.5); // divide by 2.5 as this is the difference in time from 0 value - } else if (minuteCount == 120) { - // Avg pressure at end of the hour, value averaged from 0 to 5 min. - pressureAvg[4] = ((pressureSamples[4][0] + pressureSamples[4][1] - + pressureSamples[4][2] + pressureSamples[4][3] - + pressureSamples[4][4] + pressureSamples[4][5]) / 6); - float change = (pressureAvg[4] - pressureAvg[0]); + { + dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value + } + } + else if (minuteCount == 125) + { + pressureAvg[4] = getLastPressureSamplesAverage(); + float change = (pressureAvg[4] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour - dP_dt = (((65.0 / 1023.0) * change) / 2); // note this is for t = 2 hour + { + dP_dt = change / 2; // note this is for t = 2 hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 3); // divide by 3 as this is the difference in time from 0 value - } else if (minuteCount == 155) { - // Avg pressure at end of the hour, value averaged from 0 to 5 min. - pressureAvg[5] = ((pressureSamples[5][0] + pressureSamples[5][1] - + pressureSamples[5][2] + pressureSamples[5][3] - + pressureSamples[5][4] + pressureSamples[5][5]) / 6); - float change = (pressureAvg[5] - pressureAvg[0]); + { + dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value + } + } + else if (minuteCount == 155) + { + pressureAvg[5] = getLastPressureSamplesAverage(); + float change = (pressureAvg[5] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour - dP_dt = (((65.0 / 1023.0) * change) / 2.5); // note this is for t = 2.5 hour + { + dP_dt = change / 2.5; // note this is for t = 2.5 hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 3.5); // divide by 3.5 as this is the difference in time from 0 value - } else if (minuteCount == 180) { - // Avg pressure at end of the hour, value averaged from 0 to 5 min. - pressureAvg[6] = ((pressureSamples[6][0] + pressureSamples[6][1] - + pressureSamples[6][2] + pressureSamples[6][3] - + pressureSamples[6][4] + pressureSamples[6][5]) / 6); - float change = (pressureAvg[6] - pressureAvg[0]); + { + dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value + } + } + else if (minuteCount == 185) + { + pressureAvg[6] = getLastPressureSamplesAverage(); + float change = (pressureAvg[6] - pressureAvg[0]) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour - dP_dt = (((65.0 / 1023.0) * change) / 3); // note this is for t = 3 hour + { + dP_dt = change / 3; // note this is for t = 3 hour + } else - dP_dt = (((65.0 / 1023.0) * change) / 4); // divide by 4 as this is the difference in time from 0 value + { + dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value + } pressureAvg[0] = pressureAvg[5]; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past. firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop. } + int forecast = UNKNOWN; if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval. - return 5; // Unknown, more time needed + { + forecast = UNKNOWN; + } else if (dP_dt < (-0.25)) - return 4; // Quickly falling LP, Thunderstorm, not stable + { + forecast = THUNDERSTORM; + } else if (dP_dt > 0.25) - return 3; // Quickly rising HP, not stable weather + { + forecast = UNSTABLE; + } else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05))) - return 2; // Slowly falling Low Pressure System, stable rainy weather + { + forecast = CLOUDY; + } else if ((dP_dt > 0.05) && (dP_dt < 0.25)) - return 1; // Slowly rising HP stable good weather - else if ((dP_dt > (-0.05)) && (dP_dt < 0.05)) - return 0; // Stable weather + { + forecast = SUNNY; + } + else if ((dP_dt >(-0.05)) && (dP_dt < 0.05)) + { + forecast = STABLE; + } else - return 5; // Unknown + { + forecast = UNKNOWN; + } + + return forecast; } - - - From fcb92436d9abd3a86c9b74d6732a3c26c620e856 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 9 Jul 2015 14:19:57 -0300 Subject: [PATCH 145/660] fix repeater loop for I_FIND_PARENT A repeater calls findParentNode() inside process() when receives a I_FIND_PARENT and nc.distance is invalid, this could cause a loop --- libraries/MySensors/MySensor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 2e2d70e..099a927 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -302,6 +302,12 @@ void MySensor::setupNode() { } void MySensor::findParentNode() { + static boolean findingParentNode = false; + + if (findingParentNode) + return; + findingParentNode = true; + failedTransmissions = 0; // Set distance to max @@ -316,6 +322,7 @@ void MySensor::findParentNode() { // Wait for ping response. wait(2000); + findingParentNode = false; } boolean MySensor::sendRoute(MyMessage &message) { From 616b7d8b09e83aacf8821814765576204d85eaa7 Mon Sep 17 00:00:00 2001 From: "Bruce B. Lacey" Date: Sat, 11 Jul 2015 09:09:14 -0700 Subject: [PATCH 146/660] Changed the extended_fuses from 0xFE to 0x06 (set unused bits 3-7 to 0 instead of F) to improve compatibility with a broader range of programmers (e.g. ATMEL Dragon and USBTiny ISP v3). --- hardware/MySensors/avr/boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt index 2a3c638..7fc0ec8 100644 --- a/hardware/MySensors/avr/boards.txt +++ b/hardware/MySensors/avr/boards.txt @@ -16,7 +16,7 @@ MysensorsMicro.bootloader.unlock_bits=0x3F MysensorsMicro.bootloader.lock_bits=0x0F MysensorsMicro.bootloader.low_fuses=0xE2 MysensorsMicro.bootloader.high_fuses=0xD2 -MysensorsMicro.bootloader.extended_fuses=0xFE +MysensorsMicro.bootloader.extended_fuses=0x06 MysensorsMicro.bootloader.file=DualOptiboot/optiboot_atmega328_pro_8MHz.hex MysensorsMicro.build.board=AVR_MICRO8 From 4abaa6ded34d22e3f3dd98d33d3d12450a537706 Mon Sep 17 00:00:00 2001 From: "Bruce B. Lacey" Date: Sat, 11 Jul 2015 09:31:30 -0700 Subject: [PATCH 147/660] Changed WITH_LEDS_BLINKING option to use the default LED pins as described on http://www.mysensors.org/build/advanced_gateway for consistency and backwards compatibility. Also corrected the LED on/off state to HIGH/LOW from LOW/HIGH respectively. --- libraries/MySensors/MyConfig.h | 6 +++--- libraries/MySensors/MySensor.cpp | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index c2148ab..11c8af1 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -58,11 +58,11 @@ // default LEDs blinking period in milliseconds #define DEFAULT_LED_BLINK_PERIOD 300 // The RX LED default pin -#define DEFAULT_RX_LED_PIN 8 +#define DEFAULT_RX_LED_PIN 6 // The TX LED default pin -#define DEFAULT_TX_LED_PIN 9 +#define DEFAULT_TX_LED_PIN 5 // The Error LED default pin -#define DEFAULT_ERR_LED_PIN 7 +#define DEFAULT_ERR_LED_PIN 4 /********************************** diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 2e2d70e..c32e44b 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -110,33 +110,33 @@ void MySensor::handleLedsBlinking() { // do the actual blinking if(countRx && countRx != 255) { // switch led on - digitalWrite(pinRx, LOW); + digitalWrite(pinRx, HIGH); } else if(!countRx) { // switching off - digitalWrite(pinRx, HIGH); + digitalWrite(pinRx, LOW); } if(countRx != 255) --countRx; if(countTx && countTx != 255) { // switch led on - digitalWrite(pinTx, LOW); + digitalWrite(pinTx, HIGH); } else if(!countTx) { // switching off - digitalWrite(pinTx, HIGH); + digitalWrite(pinTx, LOW); } if(countTx != 255) --countTx; if(countErr && countErr != 255) { // switch led on - digitalWrite(pinEr, LOW); + digitalWrite(pinEr, HIGH); } else if(!countErr) { // switching off - digitalWrite(pinEr, HIGH); + digitalWrite(pinEr, LOW); } if(countErr != 255) --countErr; @@ -182,9 +182,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b pinMode(pinEr, OUTPUT); // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); + digitalWrite(pinRx, LOW); + digitalWrite(pinTx, LOW); + digitalWrite(pinEr, LOW); // initialize counters countRx = 0; From 99917b43acac4c19ac90a9773821a769c85953c8 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 16 Jul 2015 20:16:10 +0200 Subject: [PATCH 148/660] Allow disabling of LED/Inclusion pins LED/inclusion pins will always be controlled, even when not configured to use them. This fix will ignore pins when a negative pin number is passed. --- libraries/MySensors/MyGateway.cpp | 113 +++++++++++++++++------------- libraries/MySensors/MyGateway.h | 12 ++-- 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index c65978f..63ce970 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -14,17 +14,20 @@ #include "utility/PinChangeInt.h" -uint8_t pinRx; -uint8_t pinTx; -uint8_t pinEr; +int8_t pinRx; +int8_t pinTx; +int8_t pinEr; boolean buttonTriggeredInclusion; volatile uint8_t countRx; volatile uint8_t countTx; volatile uint8_t countErr; boolean inclusionMode; // Keeps track on inclusion mode +#define LED_ON (LOW) +#define LED_OFF (HIGH) -MyGateway::MyGateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time, uint8_t _inclusion_pin, uint8_t _rx, uint8_t _tx, uint8_t _er) : MySensor(_cepin, _cspin) { + +MyGateway::MyGateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time, int8_t _inclusion_pin, int8_t _rx, int8_t _tx, int8_t _er) : MySensor(_cepin, _cspin) { pinInclusion = _inclusion_pin; inclusionTime = _inclusion_time; pinRx = _rx; @@ -56,23 +59,29 @@ void MyGateway::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e da countTx = 0; countErr = 0; - // Setup led pins - pinMode(pinRx, OUTPUT); - pinMode(pinTx, OUTPUT); - pinMode(pinEr, OUTPUT); - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); - + // Setup led pins & set initial state of leds + if (pinRx >= 0) + { + digitalWrite(pinRx, LED_OFF); + pinMode(pinRx, OUTPUT); + } + if (pinTx >= 0) + { + digitalWrite(pinTx, LED_OFF); + pinMode(pinTx, OUTPUT); + } + if (pinEr >= 0) + { + digitalWrite(pinEr, LED_OFF); + pinMode(pinEr, OUTPUT); + } // Setup digital in that triggers inclusion mode - pinMode(pinInclusion, INPUT); - digitalWrite(pinInclusion, HIGH); - - // Set initial state of leds - digitalWrite(pinRx, HIGH); - digitalWrite(pinTx, HIGH); - digitalWrite(pinEr, HIGH); - + if (pinInclusion >= 0) + { + pinMode(pinInclusion, INPUT); + // Add interrupt for inclusion button to pin + PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); + } // Start up the radio library setupRadio(paLevel, channel, dataRate); @@ -84,9 +93,6 @@ void MyGateway::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e da MsTimer2::set(300, ledTimersInterrupt); MsTimer2::start(); - // Add interrupt for inclusion button to pin - PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); - // Send startup log message on serial serial(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); } @@ -257,34 +263,42 @@ void MyGateway::serial(MyMessage &msg) { void ledTimersInterrupt() { - if(countRx && countRx != 255) { - // switch led on - digitalWrite(pinRx, LOW); - } else if(!countRx) { - // switching off - digitalWrite(pinRx, HIGH); - } - if(countRx != 255) { countRx--; } + if (pinRx >= 0) + { + if(countRx && countRx != 255) { + // switch led on + digitalWrite(pinRx, LED_ON); + } else if(!countRx) { + // switching off + digitalWrite(pinRx, LED_OFF); + } + } + if(countRx != 255) { countRx--; } - if(countTx && countTx != 255) { - // switch led on - digitalWrite(pinTx, LOW); - } else if(!countTx) { - // switching off - digitalWrite(pinTx, HIGH); - } - if(countTx != 255) { countTx--; } - else if(inclusionMode) { countTx = 8; } - - if(countErr && countErr != 255) { - // switch led on - digitalWrite(pinEr, LOW); - } else if(!countErr) { - // switching off - digitalWrite(pinEr, HIGH); - } - if(countErr != 255) { countErr--; } + if (pinTx >= 0) + { + if(countTx && countTx != 255) { + // switch led on + digitalWrite(pinTx, LED_ON); + } else if(!countTx) { + // switching off + digitalWrite(pinTx, LED_OFF); + } + } + if(countTx != 255) { countTx--; } + else if(inclusionMode) { countTx = 8; } + if (pinEr >= 0) + { + if(countErr && countErr != 255) { + // switch led on + digitalWrite(pinEr, LED_ON); + } else if(!countErr) { + // switching off + digitalWrite(pinEr, LED_OFF); + } + } + if(countErr != 255) { countErr--; } } void MyGateway::rxBlink(uint8_t cnt) { @@ -296,4 +310,3 @@ void MyGateway::txBlink(uint8_t cnt) { void MyGateway::errBlink(uint8_t cnt) { if(countErr == 255) { countErr = cnt; } } - diff --git a/libraries/MySensors/MyGateway.h b/libraries/MySensors/MyGateway.h index 21a93d6..772154f 100644 --- a/libraries/MySensors/MyGateway.h +++ b/libraries/MySensors/MyGateway.h @@ -30,13 +30,13 @@ class MyGateway : public MySensor * @param _cepin The pin attached to RF24 Chip Enable on the RF module (default 9) * @param _cspin The pin attached to RF24 Chip Select (defualt 10) * @param _inclusion_time Time of inclusion mode (in minutes, default 1) - * @param _inclusion_pin Digital pin that triggers inclusion mode - * @param _rx Digital pin for receive led - * @param _tx Digital pin for transfer led - * @param _er Digital pin for error led + * @param _inclusion_pin Digital pin that triggers inclusion mode, negative value disables functionality. + * @param _rx Digital pin for receive led, negative value disables functionality. + * @param _tx Digital pin for transfer led, negative value disables functionality. + * @param _er Digital pin for error led, negative value disables functionality. * */ - MyGateway(uint8_t _cepin=DEFAULT_CE_PIN, uint8_t _cspin=DEFAULT_CS_PIN, uint8_t _inclusion_time = 1, uint8_t _inclusion_pin = 3, uint8_t _rx=6, uint8_t _tx=5, uint8_t _er=4); + MyGateway(uint8_t _cepin=DEFAULT_CE_PIN, uint8_t _cspin=DEFAULT_CS_PIN, uint8_t _inclusion_time = 1, int8_t _inclusion_pin=-1, int8_t _rx=-1, int8_t _tx=-1, int8_t _er=-1); /* Use this and pass a function that should be called when you want to process commands that arrive from radio network */ void begin(rf24_pa_dbm_e paLevel=RF24_PA_LEVEL_GW, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE, void (*dataCallback)(char *)=NULL); @@ -50,7 +50,7 @@ class MyGateway : public MySensor unsigned long inclusionStartTime; boolean useWriteCallback; void (*dataCallback)(char *); - uint8_t pinInclusion; + int8_t pinInclusion; uint8_t inclusionTime; uint8_t h2i(char c); From d72e20047b6fdce7d0e9edb445fd13fd4bc73336 Mon Sep 17 00:00:00 2001 From: windkh Date: Thu, 16 Jul 2015 21:48:08 +0200 Subject: [PATCH 149/660] Bugfix: new reference value is the average after 120min instead of average after 150min. Reduced footprint. I agree to the CLA. Signed-off-by: windkh --- .../PressureSensor/PressureSensor.ino | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino index dc4c213..e8ed9cb 100644 --- a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino +++ b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino @@ -38,7 +38,10 @@ float lastPressureSamples[LAST_SAMPLES_COUNT]; int minuteCount = 0; bool firstRound = true; -float pressureAvg[7]; +// average value is used in forecast algorithm. +float pressureAvg; +// average after 2 hours is used as reference value for the next iteration. +float pressureAvg2; float dP_dt; boolean metric; @@ -122,6 +125,8 @@ float getLastPressureSamplesAverage() return lastPressureSamplesAverage; } + + // Algorithm found here // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf // Pressure in hPa --> forecast done by calculating kPa/h @@ -139,12 +144,12 @@ int sample(float pressure) if (minuteCount == 5) { - pressureAvg[0] = getLastPressureSamplesAverage(); + pressureAvg = getLastPressureSamplesAverage(); } else if (minuteCount == 35) { - pressureAvg[1] = getLastPressureSamplesAverage(); - float change = (pressureAvg[1] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour { dP_dt = change * 2; // note this is for t = 0.5hour @@ -156,8 +161,8 @@ int sample(float pressure) } else if (minuteCount == 65) { - pressureAvg[2] = getLastPressureSamplesAverage(); - float change = (pressureAvg[2] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) //first time initial 3 hour { dP_dt = change; //note this is for t = 1 hour @@ -169,8 +174,8 @@ int sample(float pressure) } else if (minuteCount == 95) { - pressureAvg[3] = getLastPressureSamplesAverage(); - float change = (pressureAvg[3] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour { dP_dt = change / 1.5; // note this is for t = 1.5 hour @@ -182,8 +187,9 @@ int sample(float pressure) } else if (minuteCount == 125) { - pressureAvg[4] = getLastPressureSamplesAverage(); - float change = (pressureAvg[4] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + pressureAvg2 = lastPressureAvg; // store for later use. + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour { dP_dt = change / 2; // note this is for t = 2 hour @@ -195,8 +201,8 @@ int sample(float pressure) } else if (minuteCount == 155) { - pressureAvg[5] = getLastPressureSamplesAverage(); - float change = (pressureAvg[5] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour { dP_dt = change / 2.5; // note this is for t = 2.5 hour @@ -208,8 +214,8 @@ int sample(float pressure) } else if (minuteCount == 185) { - pressureAvg[6] = getLastPressureSamplesAverage(); - float change = (pressureAvg[6] - pressureAvg[0]) * CONVERSION_FACTOR; + float lastPressureAvg = getLastPressureSamplesAverage(); + float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR; if (firstRound) // first time initial 3 hour { dP_dt = change / 3; // note this is for t = 3 hour @@ -218,7 +224,7 @@ int sample(float pressure) { dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value } - pressureAvg[0] = pressureAvg[5]; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past. + pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past. firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop. } @@ -252,5 +258,13 @@ int sample(float pressure) forecast = UNKNOWN; } + // uncomment when debugging + //Serial.print(F("Forecast at minute ")); + //Serial.print(minuteCount); + //Serial.print(F(" dP/dt = ")); + //Serial.print(dP_dt); + //Serial.print(F("kPa/h --> ")); + //Serial.println(weather[forecast]); + return forecast; } From 76493ff6a71771c47c0aae4e01d89a9aa088becb Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 21 Jul 2015 17:39:51 +0200 Subject: [PATCH 150/660] Sensebender OTA fix - fix OTA updates - update flash driver --- libraries/MySensors/MySensor.cpp | 60 ++++++---- libraries/MySensors/utility/SPIFlash.cpp | 142 +++++++++++++++-------- libraries/MySensors/utility/SPIFlash.h | 105 ++++++++++------- 3 files changed, 194 insertions(+), 113 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index c32e44b..b065d7c 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -74,24 +74,21 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw #ifdef MY_OTA_FIRMWARE_FEATURE -// do a crc16 on the whole received firmware -bool MySensor::isValidFirmware() { - void* ptr = 0; - uint16_t crc = ~0; - int j; +// do a crc16 on the whole received firmware +bool MySensor::isValidFirmware() { + // init crc + uint16_t crc = ~0; for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - uint8_t a = flash.readByte((uint16_t) ptr + i + FIRMWARE_START_OFFSET); - crc ^= a; - for (j = 0; j < 8; ++j) - { + crc ^= flash.readByte(i + FIRMWARE_START_OFFSET); + for (int8_t j = 0; j < 8; ++j) { if (crc & 1) crc = (crc >> 1) ^ 0xA001; else crc = (crc >> 1); } - } - return crc == fc.crc; + } + return crc == fc.crc; } #endif @@ -722,46 +719,61 @@ boolean MySensor::process() { // compare with current node configuration, if they differ, start fw fetch process if (memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { debug(PSTR("fw update\n")); - fwUpdateOngoing = true; - fwBlock = fc.blocks; // copy new FW config memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); // Init flash if (!flash.initialize()) { debug(PSTR("flash init fail\n")); + fwUpdateOngoing = false; + } else { + // erase lower 32K -> max flash size for ATMEGA328 + flash.blockErase32K(0); + // wait until flash erased + while ( flash.busy() ); + fwBlock = fc.blocks; + fwUpdateOngoing = true; + // reset flags + fwRetry = MY_OTA_RETRY+1; + fwLastRequestTime = 0; } - - } + return false; + } else debug(PSTR("fw update skipped\n")); } else if (type == ST_FIRMWARE_RESPONSE) { - // Save block to eeprom + // Save block to flash debug(PSTR("fw block %d\n"), fwBlock); - + // extract FW block ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data; // write to flash - flash.writeBytes(((fwBlock-1)*FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + flash.writeBytes( ((fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + // wait until flash written + while ( flash.busy() ); fwBlock--; - if (fwBlock == 0) { + if (!fwBlock) { // We're finished! Do a checksum and reboot. if (isValidFirmware()) { debug(PSTR("fw checksum ok\n")); // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - uint16_t fwsize = FIRMWARE_BLOCK_SIZE*fc.blocks; flash.writeBytes(0, "FLXIMG:", 7); + // FW size in flash + uint16_t fwsize = FIRMWARE_BLOCK_SIZE * fc.blocks; flash.writeByte(7, fwsize >> 8); flash.writeByte(8, fwsize); + // end of header flash.writeByte(9, ':'); // Write the new firmware config to eeprom hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); hw_reboot(); } else { debug(PSTR("fw checksum fail\n")); + fwUpdateOngoing = false; } } + // reset flags + fwRetry = MY_OTA_RETRY+1; + fwLastRequestTime = 0; + return false; } - // Make sure packet request occurs next time process() is called by timing out requestTime. - fwRetry = MY_OTA_RETRY+1; - fwLastRequestTime = 0; - return false; + } #endif // Call incoming message callback if available diff --git a/libraries/MySensors/utility/SPIFlash.cpp b/libraries/MySensors/utility/SPIFlash.cpp index ee6e1b0..e250c17 100644 --- a/libraries/MySensors/utility/SPIFlash.cpp +++ b/libraries/MySensors/utility/SPIFlash.cpp @@ -1,20 +1,40 @@ -/* - * Copyright (c) 2013 by Felix Rusu - * SPI Flash memory library for arduino/moteino. - * This works with 256byte/page SPI flash memory - * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) - * Minimal modifications should allow chips that have different page size but modifications - * DEPENDS ON: Arduino SPI library - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ +// Copyright (c) 2013-2015 by Felix Rusu, LowPowerLab.com +// SPI Flash memory library for arduino/moteino. +// This works with 256byte/page SPI flash memory +// For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) +// Minimal modifications should allow chips that have different page size but modifications +// DEPENDS ON: Arduino SPI library +// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. +// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) +// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4 +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code #include -byte SPIFlash::UNIQUEID[8]; +uint8_t SPIFlash::UNIQUEID[8]; /// IMPORTANT: NAND FLASH memory requires erase before write, because /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s @@ -32,15 +52,22 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { /// Select the flash chip void SPIFlash::select() { - noInterrupts(); //save current SPI settings +#ifndef SPI_HAS_TRANSACTION + noInterrupts(); +#endif _SPCR = SPCR; _SPSR = SPSR; - //set FLASH chip SPI settings + +#ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); +#else + // set FLASH SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present SPI.begin(); +#endif digitalWrite(_slaveSelectPin, LOW); } @@ -48,18 +75,25 @@ void SPIFlash::select() { void SPIFlash::unselect() { digitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to the FLASH chip +#ifdef SPI_HAS_TRANSACTION + SPI.endTransaction(); +#else + interrupts(); +#endif SPCR = _SPCR; SPSR = _SPSR; - interrupts(); } /// setup SPI, read device ID etc... boolean SPIFlash::initialize() { - SPI.begin(); _SPCR = SPCR; _SPSR = SPSR; pinMode(_slaveSelectPin, OUTPUT); +#ifdef SPI_HAS_TRANSACTION + _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); +#endif + unselect(); wakeup(); @@ -73,7 +107,7 @@ boolean SPIFlash::initialize() } /// Get the manufacturer and device ID bytes (as a short word) -word SPIFlash::readDeviceId() +uint16_t SPIFlash::readDeviceId() { #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo command(SPIFLASH_IDREAD); // Read JEDEC ID @@ -81,7 +115,7 @@ word SPIFlash::readDeviceId() select(); SPI.transfer(SPIFLASH_IDREAD); #endif - word jedecid = SPI.transfer(0) << 8; + uint16_t jedecid = SPI.transfer(0) << 8; jedecid |= SPI.transfer(0); unselect(); return jedecid; @@ -90,47 +124,47 @@ word SPIFlash::readDeviceId() /// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize /// Returns the byte pointer to the UNIQUEID byte array /// Read UNIQUEID like this: -/// flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); } +/// flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); } /// or like this: -/// flash.readUniqueId(); byte* MAC = flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); } -byte* SPIFlash::readUniqueId() +/// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); } +uint8_t* SPIFlash::readUniqueId() { command(SPIFLASH_MACREAD); SPI.transfer(0); SPI.transfer(0); SPI.transfer(0); SPI.transfer(0); - for (byte i=0;i<8;i++) + for (uint8_t i=0;i<8;i++) UNIQUEID[i] = SPI.transfer(0); unselect(); return UNIQUEID; } /// read 1 byte from flash memory -byte SPIFlash::readByte(long addr) { +uint8_t SPIFlash::readByte(uint32_t addr) { command(SPIFLASH_ARRAYREADLOWFREQ); SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); SPI.transfer(addr); - byte result = SPI.transfer(0); + uint8_t result = SPI.transfer(0); unselect(); return result; } /// read unlimited # of bytes -void SPIFlash::readBytes(long addr, void* buf, word len) { +void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) { command(SPIFLASH_ARRAYREAD); SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); SPI.transfer(addr); SPI.transfer(0); //"dont care" - for (word i = 0; i < len; ++i) - ((byte*) buf)[i] = SPI.transfer(0); + for (uint16_t i = 0; i < len; ++i) + ((uint8_t*) buf)[i] = SPI.transfer(0); unselect(); } /// Send a command to the flash chip, pass TRUE for isWrite when its a write command -void SPIFlash::command(byte cmd, boolean isWrite){ +void SPIFlash::command(uint8_t cmd, boolean isWrite){ #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH! PORTB |= B00000001; @@ -156,7 +190,7 @@ boolean SPIFlash::busy() /* select(); SPI.transfer(SPIFLASH_STATUSREAD); - byte status = SPI.transfer(0); + uint8_t status = SPI.transfer(0); unselect(); return status & 1; */ @@ -164,11 +198,11 @@ boolean SPIFlash::busy() } /// return the STATUS register -byte SPIFlash::readStatus() +uint8_t SPIFlash::readStatus() { select(); SPI.transfer(SPIFLASH_STATUSREAD); - byte status = SPI.transfer(0); + uint8_t status = SPI.transfer(0); unselect(); return status; } @@ -177,7 +211,7 @@ byte SPIFlash::readStatus() /// Write 1 byte to flash memory /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -void SPIFlash::writeByte(long addr, uint8_t byt) { +void SPIFlash::writeByte(uint32_t addr, uint8_t byt) { command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); @@ -186,20 +220,32 @@ void SPIFlash::writeByte(long addr, uint8_t byt) { unselect(); } -/// write 1-256 bytes to flash memory +/// write multiple bytes to flash memory (up to 64K) /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -/// WARNING: if you write beyond a page boundary (or more than 256bytes), -/// the bytes will wrap around and start overwriting at the beginning of that same page -/// see datasheet for more details -void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - for (uint16_t i = 0; i < len; i++) - SPI.transfer(((byte*) buf)[i]); - unselect(); +/// This version handles both page alignment and data blocks larger than 256 bytes. +/// +void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { + uint16_t n; + uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page + uint16_t offset = 0; + while (len>0) + { + n = (len<=maxBytes) ? len : maxBytes; + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + + for (uint16_t i = 0; i < n; i++) + SPI.transfer(((uint8_t*) buf)[offset + i]); + unselect(); + + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. + offset +=n; + len -= n; + maxBytes = 256; // now we can do up to 256 bytes per loop + } } /// erase entire flash memory array @@ -214,7 +260,7 @@ void SPIFlash::chipErase() { } /// erase a 4Kbyte block -void SPIFlash::blockErase4K(long addr) { +void SPIFlash::blockErase4K(uint32_t addr) { command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); @@ -223,7 +269,7 @@ void SPIFlash::blockErase4K(long addr) { } /// erase a 32Kbyte block -void SPIFlash::blockErase32K(long addr) { +void SPIFlash::blockErase32K(uint32_t addr) { command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); diff --git a/libraries/MySensors/utility/SPIFlash.h b/libraries/MySensors/utility/SPIFlash.h index f0c071a..a308760 100644 --- a/libraries/MySensors/utility/SPIFlash.h +++ b/libraries/MySensors/utility/SPIFlash.h @@ -1,16 +1,36 @@ -/* - * Copyright (c) 2013 by Felix Rusu - * SPI Flash memory library for arduino/moteino. - * This works with 256byte/page SPI flash memory - * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) - * Minimal modifications should allow chips that have different page size but modifications - * DEPENDS ON: Arduino SPI library - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either the GNU General Public License version 2 - * or the GNU Lesser General Public License version 2.1, both as - * published by the Free Software Foundation. - */ +// Copyright (c) 2013-2015 by Felix Rusu, LowPowerLab.com +// SPI Flash memory library for arduino/moteino. +// This works with 256byte/page SPI flash memory +// For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) +// Minimal modifications should allow chips that have different page size but modifications +// DEPENDS ON: Arduino SPI library +// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. +// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) +// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4 +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code #ifndef _SPIFLASH_H_ #define _SPIFLASH_H_ @@ -33,19 +53,19 @@ /// Assuming the WP pin is pulled up (to disable hardware write protection) /// To use any write commands the WEL bit in the status register must be set to 1. /// This is accomplished by sending a 0x06 command before any such write/erase command. -/// The WEL bit in the status register resets to the logical “0” state after a -/// device power-up or reset. In addition, the WEL bit will be reset to the logical “0” state automatically under the following conditions: -/// • Write Disable operation completes successfully -/// • Write Status Register operation completes successfully or aborts -/// • Protect Sector operation completes successfully or aborts -/// • Unprotect Sector operation completes successfully or aborts -/// • Byte/Page Program operation completes successfully or aborts -/// • Sequential Program Mode reaches highest unprotected memory location -/// • Sequential Program Mode reaches the end of the memory array -/// • Sequential Program Mode aborts -/// • Block Erase operation completes successfully or aborts -/// • Chip Erase operation completes successfully or aborts -/// • Hold condition aborts +/// The WEL bit in the status register resets to the logical ?0? state after a +/// device power-up or reset. In addition, the WEL bit will be reset to the logical ?0? state automatically under the following conditions: +/// ? Write Disable operation completes successfully +/// ? Write Status Register operation completes successfully or aborts +/// ? Protect Sector operation completes successfully or aborts +/// ? Unprotect Sector operation completes successfully or aborts +/// ? Byte/Page Program operation completes successfully or aborts +/// ? Sequential Program Mode reaches highest unprotected memory location +/// ? Sequential Program Mode reaches the end of the memory array +/// ? Sequential Program Mode aborts +/// ? Block Erase operation completes successfully or aborts +/// ? Chip Erase operation completes successfully or aborts +/// ? Hold condition aborts #define SPIFLASH_WRITEENABLE 0x06 // write enable #define SPIFLASH_WRITEDISABLE 0x04 // write disable @@ -69,21 +89,21 @@ class SPIFlash { public: - static byte UNIQUEID[8]; - SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + static uint8_t UNIQUEID[8]; + SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); boolean initialize(); - void command(byte cmd, boolean isWrite=false); - byte readStatus(); - byte readByte(long addr); - void readBytes(long addr, void* buf, word len); - void writeByte(long addr, byte byt); - void writeBytes(long addr, const void* buf, uint16_t len); + void command(uint8_t cmd, boolean isWrite=false); + uint8_t readStatus(); + uint8_t readByte(uint32_t addr); + void readBytes(uint32_t addr, void* buf, uint16_t len); + void writeByte(uint32_t addr, uint8_t byt); + void writeBytes(uint32_t addr, const void* buf, uint16_t len); boolean busy(); void chipErase(); - void blockErase4K(long address); - void blockErase32K(long address); - word readDeviceId(); - byte* readUniqueId(); + void blockErase4K(uint32_t address); + void blockErase32K(uint32_t address); + uint16_t readDeviceId(); + uint8_t* readUniqueId(); void sleep(); void wakeup(); @@ -91,10 +111,13 @@ public: protected: void select(); void unselect(); - byte _slaveSelectPin; + uint8_t _slaveSelectPin; uint16_t _jedecID; - byte _SPCR; - byte _SPSR; + uint8_t _SPCR; + uint8_t _SPSR; +#ifdef SPI_HAS_TRANSACTION + SPISettings _settings; +#endif }; #endif \ No newline at end of file From ff3e8db1b62753b0c1b7d82085d55d539add4822 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 21 Jul 2015 21:08:12 +0200 Subject: [PATCH 151/660] Sensebender OTA: Blink Simple sketch to test OTA updates --- .../SensebenderBlink/SensebenderBlink.ino | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino diff --git a/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino b/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino new file mode 100644 index 0000000..099882e --- /dev/null +++ b/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino @@ -0,0 +1,47 @@ +// Sensebender Micro board +// Simple blinking FW to test OTA updates + +#include +#include + +#define SketchName "Sensebender Blink" +#define SketchVersion "20150721" +#define NODE_ID AUTO +#define CHILD_ID_COUNTER 0 + +#define LED_PIN A2 +#define BLINK_INTERVAL 500 +#define REPORT_TIME 5000L + +unsigned long lastUpdate = 0; +boolean LED_STATUS = false; + +SPIFlash flash(8, 0x1F65); +MySensor gw; +MyMessage msgCounter(CHILD_ID_COUNTER, V_VAR1); + +void setup() { + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LED_STATUS); + + // repeater mode on + gw.begin(NULL,NODE_ID,true); + gw.sendSketchInfo(SketchName, SketchVersion); + + gw.present(CHILD_ID_COUNTER, S_CUSTOM,"Millis()"); + +} + +void loop() { + gw.wait(BLINK_INTERVAL); + LED_STATUS ^= true; + digitalWrite(LED_PIN, LED_STATUS); + + if (millis()-lastUpdate > REPORT_TIME) { + gw.send(msgCounter.set( millis() )); + lastUpdate = millis(); + } + +} + + From 128aaacf70d916df6f0701e1e4c665a537521e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 27 Jul 2015 00:18:49 +0200 Subject: [PATCH 152/660] Updated platform.txt / boards.txt to reflect AVR platform target, and removed atmega1284 as GW target --- hardware/MySensors/avr/boards.txt | 25 ------------------------- hardware/MySensors/avr/platform.txt | 2 +- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt index 2a3c638..71b3220 100644 --- a/hardware/MySensors/avr/boards.txt +++ b/hardware/MySensors/avr/boards.txt @@ -30,28 +30,3 @@ MysensorsMicro.menu.cpu.8Mhz.build.f_cpu=8000000L MysensorsMicro.menu.cpu.1Mhz=Atmega328 1Mhz MysensorsMicro.menu.cpu.1Mhz.build.f_cpu=1000000L - - -######################################## -## Gateway settings - -MysensorsGW.name=Sensebender Gateway -MysensorsGW.build.core=arduino:arduino -MysensorsGW.build.variant=GW -MysensorsGW.build.board=AVR_1284 -MysensorsGW.build.mcu=atmega1284p -MysensorsGW.build.f_cpu=20000000L - -MysensorsGW.upload.tool=arduino:avrdude -MysensorsGW.upload.protocol=arduino -MysensorsGW.upload.maximum_size=123720 -MysensorsGW.upload.maximum_data_size=16384 -MysensorsGW.upload.speed=115200 - -MysensorsGW.bootloader.tool=arduino:avrdude -MysensorsGW.bootloader.unlock_bits=0x3F -MysensorsGW.bootloader.lock_bits=0x0F -MysensorsGW.bootloader.low_fuses=0xE2 -MysensorsGW.bootloader.high_fuses=0xD2 -MysensorsGW.bootloader.extended_fuses=0xFE -MysensorsGW.bootloader.file=DualOptiboot/optiboot_atmega1284.hex diff --git a/hardware/MySensors/avr/platform.txt b/hardware/MySensors/avr/platform.txt index 247f5cc..28f482c 100644 --- a/hardware/MySensors/avr/platform.txt +++ b/hardware/MySensors/avr/platform.txt @@ -5,7 +5,7 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification -name=MySensors Boards +name=MySensors AVR based boards version=1.6.0 # AVR compile variables From a22f712d60fd2cb404c5ab509dcb7405ec7332b1 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 28 Jul 2015 11:32:52 -0300 Subject: [PATCH 153/660] respond to a I_FIND_PARENT after findParentNode() When a repeater receives a I_FIND_PARENT, it first update the nc.distance if is invalid and then respond the request --- libraries/MySensors/MySensor.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 099a927..19b03c4 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -781,14 +781,17 @@ boolean MySensor::process() { // If this node have an id, relay the message if (command == C_INTERNAL && type == I_FIND_PARENT) { - if (nc.distance == DISTANCE_INVALID) { - findParentNode(); - } else if (sender != nc.parentNodeId) { - // Relaying nodes should always answer ping messages - // Wait a random delay of 0-2 seconds to minimize collision - // between ping ack messages from other relaying nodes - wait(hw_millis() & 0x3ff); - sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); + if (sender != nc.parentNodeId) { + if (nc.distance == DISTANCE_INVALID) + findParentNode(); + + if (nc.distance != DISTANCE_INVALID) { + // Relaying nodes should always answer ping messages + // Wait a random delay of 0-2 seconds to minimize collision + // between ping ack messages from other relaying nodes + wait(hw_millis() & 0x3ff); + sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); + } } } else if (to == nc.nodeId) { // We should try to relay this message to another node From 79c4cee47535dba34d18ed84e023e14c1bd24e19 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 28 Jul 2015 19:44:46 +0200 Subject: [PATCH 154/660] Fix signing problem reported by @scalz http://forum.mysensors.org/topic/1021/security-introducing-signing-support-to-mysensors/103 --- libraries/MySensors/MySensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index b065d7c..6949e83 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -343,7 +343,7 @@ boolean MySensor::sendRoute(MyMessage &message) { #ifdef MY_SIGNING_FEATURE // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message - if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(msg) && + if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(message) && (mGetCommand(message) != C_INTERNAL || (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && From 8c2e835f92c549752a96a4e3fb30501038cc24ea Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 30 Jul 2015 14:09:11 +0200 Subject: [PATCH 155/660] Added HVAC and some other new device types and variables from the development branch. --- libraries/MySensors/MyMessage.h | 109 +++++++++++++++--- .../AirQualitySensor/AirQualitySensor.ino | 2 +- .../examples/DustSensor/DustSensor.ino | 2 +- .../LightLuxSensor/LightLuxSensor.ino | 5 + 4 files changed, 103 insertions(+), 15 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 643bdb2..49e85cd 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -32,16 +32,106 @@ typedef enum { C_STREAM = 4 // For Firmware and other larger chunks of data that need to be divided into pieces. } mysensor_command; +// Type of sensor (used when presenting sensors) +typedef enum { + S_DOOR, // Door sensor, V_TRIPPED, V_ARMED + S_MOTION, // Motion sensor, V_TRIPPED, V_ARMED + S_SMOKE, // Smoke sensor, V_TRIPPED, V_ARMED + S_LIGHT, // Binary light or relay, V_STATUS (or V_LIGHT), V_WATT + S_BINARY=3, // Binary light or relay, V_STATUS (or V_LIGHT), V_WATT (same as S_LIGHT) + S_DIMMER, // Dimmable light or fan device, V_STATUS (on/off), V_DIMMER (dimmer level 0-100), V_WATT + S_COVER, // Blinds or window cover, V_UP, V_DOWN, V_STOP, V_DIMMER (open/close to a percentage) + S_TEMP, // Temperature sensor, V_TEMP + S_HUM, // Humidity sensor, V_HUM + S_BARO, // Barometer sensor, V_PRESSURE, V_FORECAST + S_WIND, // Wind sensor, V_WIND, V_GUST + S_RAIN, // Rain sensor, V_RAIN, V_RAINRATE + S_UV, // Uv sensor, V_UV + S_WEIGHT, // Personal scale sensor, V_WEIGHT, V_IMPEDANCE + S_POWER, // Power meter, V_WATT, V_KWH + S_HEATER, // Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE + S_DISTANCE, // Distance sensor, V_DISTANCE + S_LIGHT_LEVEL, // Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux) + S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node + S_ARDUINO_REPEATER_NODE, // Used (internally) for presenting a repeating Arduino node + S_LOCK, // Lock device, V_LOCK_STATUS + S_IR, // Ir device, V_IR_SEND, V_IR_RECEIVE + S_WATER, // Water meter, V_FLOW, V_VOLUME + S_AIR_QUALITY, // Air quality sensor, V_LEVEL + S_CUSTOM, // Custom sensor + S_DUST, // Dust sensor, V_LEVEL + S_SCENE_CONTROLLER, // Scene controller device, V_SCENE_ON, V_SCENE_OFF. + S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT + S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT + S_COLOR_SENSOR, // Color sensor, send color information using V_RGB + S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE + S_MULTIMETER, // Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE + S_SPRINKLER, // Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) + S_WATER_LEAK, // Water leak sensor, V_TRIPPED, V_ARMED + S_SOUND, // Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB) + S_VIBRATION, // Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz) + S_MOISTURE, // Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?) +} mysensor_sensor; + // Type of sensor data (for set/req/ack messages) typedef enum { - V_TEMP,V_HUM, V_LIGHT, V_DIMMER, V_PRESSURE, V_FORECAST, V_RAIN, - V_RAINRATE, V_WIND, V_GUST, V_DIRECTION, V_UV, V_WEIGHT, V_DISTANCE, - V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF, - V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, - V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME, V_LOCK_STATUS, - V_DUST_LEVEL, V_VOLTAGE, V_CURRENT + V_TEMP, // S_TEMP + V_HUM, // S_HUM + V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, Used for setting binary (on/off) status. 1=on, 0=off + V_LIGHT=2, // S_LIGHT, S_DIMMER. Same as V_STATUS + V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value (0-100). + V_DIMMER=3, // S_DIMMER. Same as V_PERCENTAGE. + V_PRESSURE, // S_BARO + V_FORECAST, // S_BARO + V_RAIN, // S_RAIN + V_RAINRATE, // S_RAIN + V_WIND, // S_WIND + V_GUST, // S_WIND + V_DIRECTION, // S_WIND + V_UV, // S_UV + V_WEIGHT, // S_WEIGHT + V_DISTANCE, // S_DISTANCE + V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT + V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER + V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER (for sprinklers with fire detection) + V_WATT, // S_POWER, S_LIGHT, S_DIMMER + V_KWH, // S_POWER + V_SCENE_ON, // S_SCENE_CONTROLLER + V_SCENE_OFF, // S_SCENE_CONTROLLER + V_HEATER, // Deprecated. Use V_HVAC_FLOW_STATE instead. + V_HVAC_FLOW_STATE=21, // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC + V_HVAC_SPEED, // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + V_LIGHT_LEVEL, // S_LIGHT_LEVEL (light level in uncalibrated percentage) or S_LEVEL (light level in lux) + V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, + V_UP, // S_COVER + V_DOWN, // S_COVER + V_STOP, // S_COVER + V_IR_SEND, // S_IR + V_IR_RECEIVE, // S_IR + V_FLOW, // S_WATER + V_VOLUME, // S_WATER + V_LOCK_STATUS, // S_LOCK + V_LEVEL, // S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux) + V_VOLTAGE, // S_MULTIMETER + V_CURRENT, // S_MULTIMETER + V_RGB, // S_RGB_LIGHT, S_COLOR_SENSOR. + // Used for sending color information for multi color LED lighting or color sensors. + // Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component) + V_RGBW, // S_RGBW_LIGHT + // Used for sending color information to multi color LED lighting. + // Sent as ASCII hex: RRGGBBWW (WW=while component) + V_ID, // S_TEMP + // Used for sending in sensors hardware ids (i.e. OneWire DS1820b). + V_UNIT_PREFIX, // Allows sensors to send in a string representing the + // unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch. + // Can be used for S_DISTANCE or gas concentration (S_DUST, S_AIR_QUALITY) + V_HVAC_SETPOINT_COLD, // HVAC cold setpoint (Integer between 0-100). S_HVAC + V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC + V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn"). S_HVAC + } mysensor_data; + // Type of internal messages (for internal messages) typedef enum { I_BATTERY_LEVEL, I_TIME, I_VERSION, I_ID_REQUEST, I_ID_RESPONSE, @@ -50,13 +140,6 @@ typedef enum { I_REBOOT, I_GATEWAY_READY } mysensor_internal; -// Type of sensor (for presentation message) -typedef enum { - S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, - S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, - S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER -} mysensor_sensor; // Type of data stream (for streamed message) typedef enum { diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino index efe12f3..a206300 100644 --- a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino +++ b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino @@ -59,7 +59,7 @@ float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from MySensor gw; -MyMessage msg(CHILD_ID_MQ, V_VAR1); +MyMessage msg(CHILD_ID_MQ, V_LEVEL); void setup() diff --git a/libraries/MySensors/examples/DustSensor/DustSensor.ino b/libraries/MySensors/examples/DustSensor/DustSensor.ino index 4ebe804..8c3115d 100644 --- a/libraries/MySensors/examples/DustSensor/DustSensor.ino +++ b/libraries/MySensors/examples/DustSensor/DustSensor.ino @@ -36,7 +36,7 @@ float calcVoltage = 0; float dustDensity = 0; MySensor gw; -MyMessage dustMsg(CHILD_ID_DUST, V_DUST_LEVEL); +MyMessage dustMsg(CHILD_ID_DUST, V_LEVEL); void setup() { diff --git a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino index b3e4f49..df8be69 100644 --- a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino +++ b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino @@ -26,7 +26,12 @@ unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) BH1750 lightSensor; MySensor gw; + +// V_LIGHT_LEVEL should only be used for uncalibrated light level 0-100%. +// If your controller supports the new V_LEVEL variable, use this instead for +// transmitting LUX light level. MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL); +// MyMessage msg(CHILD_ID_LIGHT, V_LEVEL); uint16_t lastlux; void setup() From 5bab725f81a98cd47d15c731a2d70754a8f229bc Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 30 Jul 2015 14:41:57 +0200 Subject: [PATCH 156/660] Bump version to 1.5 --- libraries/MySensors/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/Version.h b/libraries/MySensors/Version.h index 437cd2c..c782265 100644 --- a/libraries/MySensors/Version.h +++ b/libraries/MySensors/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.5 b1" +#define LIBRARY_VERSION "1.5" #endif From 190479df6dd2fc5a159b9793ee88320649a4f895 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 30 Jul 2015 15:34:23 +0200 Subject: [PATCH 157/660] Final 1.4 release --- libraries/MySensors/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/Version.h b/libraries/MySensors/Version.h index 82462b7..14ef8ff 100644 --- a/libraries/MySensors/Version.h +++ b/libraries/MySensors/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.4.1" +#define LIBRARY_VERSION "1.4.2" #endif From 34ace0bad7c6b4c1539e007dfb01ab5f801d7282 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 30 Jul 2015 20:58:50 +0200 Subject: [PATCH 158/660] Fix spelling error on setpoint cool --- libraries/MySensors/MyMessage.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 6dc504b..129801f 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -86,8 +86,8 @@ typedef enum { typedef enum { V_TEMP, // S_TEMP V_HUM, // S_HUM - V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, Used for setting binary (on/off) status. 1=on, 0=off - V_LIGHT=2, // S_LIGHT, S_DIMMER. Same as V_STATUS + V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting binary (on/off) status. 1=on, 0=off + V_LIGHT=2, // Same as V_STATUS V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value (0-100). V_DIMMER=3, // S_DIMMER. Same as V_PERCENTAGE. V_PRESSURE, // S_BARO @@ -110,7 +110,7 @@ typedef enum { V_HEATER, // Deprecated. Use V_HVAC_FLOW_STATE instead. V_HVAC_FLOW_STATE=21, // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC V_HVAC_SPEED, // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") - V_LIGHT_LEVEL, // S_LIGHT_LEVEL (light level in uncalibrated percentage) or S_LEVEL (light level in lux) + V_LIGHT_LEVEL, // Used for sending light level in uncalibrated percentage. See also V_LEVEL (light level in lux). S_LIGHT_LEVEL V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, V_UP, // S_COVER V_DOWN, // S_COVER @@ -134,7 +134,7 @@ typedef enum { V_UNIT_PREFIX, // Allows sensors to send in a string representing the // unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch. // Can be used for S_DISTANCE or gas concentration (S_DUST, S_AIR_QUALITY) - V_HVAC_SETPOINT_COLD, // HVAC cold setpoint (Integer between 0-100). S_HVAC + V_HVAC_SETPOINT_COOL, // HVAC cool setpoint (Integer between 0-100). S_HVAC V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn"). S_HVAC From 237b080b2eeb3b0858b602a43099888036ffe6f9 Mon Sep 17 00:00:00 2001 From: Barduino Date: Thu, 30 Jul 2015 15:04:02 -0400 Subject: [PATCH 159/660] Create MockMySensors Arduino sketch to mock sensors for the MySensors Library This skecth is intended to crate fake sensors which register and respond to the controller Barduino 2015 ----------------- Comment/Uncomment the sensors you would like to test Arduino Uno R3 can support about 12 sensors before it runs out of memory. You probably need to turn of the MySensor Lib debug to save some memory Nest step will be to remove the read/write to the eprom and extend to support the v1.5 sensors --- libraries/MySensors/examples/MockMySensors | 1018 ++++++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 libraries/MySensors/examples/MockMySensors diff --git a/libraries/MySensors/examples/MockMySensors b/libraries/MySensors/examples/MockMySensors new file mode 100644 index 0000000..4397208 --- /dev/null +++ b/libraries/MySensors/examples/MockMySensors @@ -0,0 +1,1018 @@ +/* +* FakeMySensors +* +* This skecth is intended to crate fake sensors which register and respond to the controller +* +* Barduino 2015 +*/ + +#include +#include + +// SPI Pins +#define CE_PIN 9 +#define CS_PIN 10 + +// Wait times +#define LONG_WAIT 500 +#define SHORT_WAIT 50 + +#define SKETCH_NAME "FakeMySensors " +#define SKETCH_VERSION "v0.2" + +// Define Sensors ids +/* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, + S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, + S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, + S_SCENE_CONTROLLER +*/ + +////#define ID_S_ARDUINO_NODE //auto defined in initialization +////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization + +//#define ID_S_DOOR 1 +//#define ID_S_MOTION 2 +//#define ID_S_SMOKE 3 +//#define ID_S_LIGHT 4 +//#define ID_S_DIMMER 5 +//#define ID_S_COVER 6 +//#define ID_S_TEMP 7 +//#define ID_S_HUM 8 +//#define ID_S_BARO 9 +//#define ID_S_WIND 10 +//#define ID_S_RAIN 11 +//#define ID_S_UV 12 +//#define ID_S_WEIGHT 13 +#define ID_S_POWER 14 +#define ID_S_HEATER 15 +#define ID_S_DISTANCE 16 +#define ID_S_LIGHT_LEVEL 17 +#define ID_S_LOCK 18 +#define ID_S_IR 19 +#define ID_S_WATER 20 +#define ID_S_AIR_QUALITY 21 +#define ID_S_DUST 22 +#define ID_S_SCENE_CONTROLLER 23 + +#define ID_S_CUSTOM 24 + +// Global Vars +unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) +boolean metric = true; +long randNumber; + +// Instanciate MySersors Gateway +MySensor gw(CE_PIN,CS_PIN); + +//Instanciate Messages objects + +#ifdef ID_S_DOOR + MyMessage msg_S_DOOR(ID_S_DOOR,V_TRIPPED); +#endif + +#ifdef ID_S_MOTION + MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); + MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); +#endif + +#ifdef ID_S_SMOKE + MyMessage msg_S_SMOKE(ID_S_SMOKE,V_TRIPPED); +#endif + +#ifdef ID_S_LIGHT + MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); +#endif + +#ifdef ID_S_DIMMER + MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); +#endif + +#ifdef ID_S_COVER + MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); + MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); + MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); +#endif + +#ifdef ID_S_TEMP + MyMessage msg_S_TEMP(ID_S_TEMP,V_TEMP); +#endif + +#ifdef ID_S_HUM + MyMessage msg_S_HUM(ID_S_HUM,V_HUM); +#endif + +#ifdef ID_S_BARO + MyMessage msg_S_BARO_P(ID_S_BARO,V_PRESSURE); + MyMessage msg_S_BARO_F(ID_S_BARO,V_FORECAST); +#endif + +#ifdef ID_S_WIND + MyMessage msg_S_WIND_S(ID_S_WIND,V_WIND); + MyMessage msg_S_WIND_G(ID_S_WIND,V_GUST); + MyMessage msg_S_WIND_D(ID_S_WIND,V_DIRECTION); +#endif + +#ifdef ID_S_RAIN + MyMessage msg_S_RAIN_A(ID_S_RAIN,V_RAIN); + MyMessage msg_S_RAIN_R(ID_S_RAIN,V_RAINRATE); +#endif + +#ifdef ID_S_UV + MyMessage msg_S_UV(ID_S_UV,V_UV); +#endif + +#ifdef ID_S_WEIGHT + MyMessage msg_S_WEIGHT(ID_S_WEIGHT,V_WEIGHT); +#endif + +#ifdef ID_S_POWER + MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); + MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); + MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); + MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); + MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); +#endif + +#ifdef ID_S_HEATER + MyMessage msg_S_HEATER_M(ID_S_HEATER,V_HEATER); + MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HEATER_SW); +#endif + +#ifdef ID_S_DISTANCE + MyMessage msg_S_DISTANCE(ID_S_DISTANCE,V_DISTANCE); +#endif + +#ifdef ID_S_LIGHT_LEVEL + MyMessage msg_S_LIGHT_LEVEL(ID_S_LIGHT_LEVEL,V_LIGHT_LEVEL); +#endif + +#ifdef ID_S_LOCK + MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); +#endif + +#ifdef ID_S_IR + MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); + MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); +#endif + +#ifdef ID_S_WATER + MyMessage msg_S_WATER_F(ID_S_WATER,V_FLOW); + MyMessage msg_S_WATER_V(ID_S_WATER,V_VOLUME); +#endif + +#ifdef ID_S_AIR_QUALITY + MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_VAR1); +#endif + +#ifdef ID_S_DUST + MyMessage msg_S_DUST(ID_S_DUST,V_DUST_LEVEL); +#endif + +#ifdef ID_S_SCENE_CONTROLLER + MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); + MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); +#endif + +#ifdef ID_S_CUSTOM + MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); + MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); + MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); + MyMessage msg_S_CUSTOM_5(ID_S_CUSTOM,V_VAR5); +#endif + + + + +void setup() +{ + // Random SEED + randomSeed(analogRead(0)); + + // Start the gateway + gw.begin(incomingMessage,254); + gw.wait(LONG_WAIT); + Serial.println("GW Started"); + + // Send the Sketch Version Information to the Gateway + Serial.print("Send Sketch Info: "); + gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); + Serial.print(SKETCH_NAME); + Serial.println(SKETCH_VERSION); + gw.wait(LONG_WAIT); + + // Get controller configuration + Serial.print("Get Config: "); + metric = gw.getConfig().isMetric; + Serial.println(metric ? "Metric":"Imperial"); + gw.wait(LONG_WAIT); + + // Register all sensors to gw (they will be created as child devices) + Serial.println("Presenting Nodes"); + Serial.println("________________"); + + #ifdef ID_S_DOOR + Serial.println(" S_DOOR"); + gw.present(ID_S_DOOR,S_DOOR); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_MOTION + Serial.println(" S_MOTION"); + gw.present(ID_S_MOTION,S_MOTION); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_SMOKE + Serial.println(" S_SMOKE"); + gw.present(ID_S_SMOKE,S_SMOKE); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LIGHT + Serial.println(" S_LIGHT"); + gw.present(ID_S_LIGHT,S_LIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DIMMER + Serial.println(" S_DIMMER"); + gw.present(ID_S_DIMMER,S_DIMMER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_COVER + Serial.println(" S_COVER"; + gw.present(ID_S_COVER,S_COVER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_TEMP + Serial.println(" S_TMEP"); + gw.present(ID_S_TEMP,S_TEMP); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_HUM + Serial.println(" S_HUM"); + gw.present(ID_S_HUM,S_HUM); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_BARO + Serial.println(" S_BARO"); + gw.present(ID_S_BARO,S_BARO); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WIND + Serial.println(" S_WIND"); + gw.present(ID_S_WIND,S_WIND); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_RAIN + Serial.println(" S_RAIN"); + gw.present(ID_S_RAIN,S_RAIN); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_UV + Serial.println(" S_UV"); + gw.present(ID_S_UV,S_UV); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WEIGHT + Serial.println(" S_WEIGHT"): + gw.present(ID_S_WEIGHT,S_WEIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_POWER + Serial.println(" S_POWER"); + gw.present(ID_S_POWER,S_POWER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_HEATER + Serial.println(" S_HEATER"); + gw.present(ID_S_HEATER,S_HEATER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DISTANCE + Serial.println(" S_DISTANCE"); + gw.present(ID_S_DISTANCE,S_DISTANCE); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LIGHT_LEVEL + Serial.println(" S_LIGHT_LEVEL"); + gw.present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LOCK + Serial.println(" S_LOCK"); + gw.present(ID_S_LOCK,S_LOCK); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_IR + Serial.println(" S_IR"); + gw.present(ID_S_IR,S_IR); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WATER + Serial.println(" S_WATER"); + gw.present(ID_S_WATER,S_WATER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_AIR_QUALITY + Serial.println(" S_AIR_QUALITY"); + gw.present(ID_S_AIR_QUALITY,S_AIR_QUALITY); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DUST + Serial.println(" S_DUST"); + gw.present(ID_S_DUST,S_DUST); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_SCENE_CONTROLLER + Serial.println(" S_SCENE_CONTROLLER"); + gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_CUSTOM + Serial.println(" S_CUSTOM"); + gw.present(ID_S_CUSTOM,S_CUSTOM); + gw.wait(SHORT_WAIT); + #endif + + + +Serial.println("________________"); + +} + +void loop() +{ + Serial.println(""); + Serial.println(""); + Serial.println(""); + Serial.println("#########################"); + randNumber=random(0,101); + + Serial.print("RandomNumber:"); + Serial.println(randNumber); + // Send fake battery level + Serial.println("Send Battery Level"); + gw.sendBatteryLevel(randNumber); + gw.wait(LONG_WAIT); + + // Request time + Serial.println("Request Time"); + gw.requestTime(receiveTime); + gw.wait(LONG_WAIT); + + //Read Sensors + #ifdef S_ID_DOOR + door(); + #endif + + #ifdef ID_S_MOTION + motion(); + #endif + + #ifdef ID_S_SMOKE + smoke(); + #endif + + #ifdef ID_S_LIGHT + light(); + #endif + + #ifdef ID_S_DIMMER + dimmer(); + #endif + + #ifdef ID_S_COVER + cover(); + #endif + + #ifdef ID_S_TEMP + temp(); + #endif + + #ifdef ID_S_HUM + hum(); + #endif + + #ifdef ID_S_BARO + baro(); + #endif + + #ifdef ID_S_WIND + wind(); + #endif + + #ifdef ID_S_RAIN + rain(); + #endif + + #ifdef ID_S_UV + uv(); + #endif + + #ifdef ID_S_WEIGHT + weight(); + #endif + + #ifdef ID_S_POWER + power(); + #endif + + #ifdef ID_S_HEATER + heater(); + #endif + + #ifdef ID_S_DISTANCE + distance(); + #endif + + #ifdef ID_S_LIGHT_LEVEL + light_level(); + #endif + + #ifdef ID_S_LOCK + lock(); + #endif + + #ifdef ID_S_IR + ir(); + #endif + + #ifdef ID_S_WATER + water(); + #endif + + #ifdef ID_S_AIR_QUALITY + air(); + #endif + + #ifdef ID_S_DUST + dust(); + #endif + + #ifdef ID_S_SCENE_CONTROLLER + scene(); + #endif + + #ifdef ID_S_CUSTOM + custom(); + #endif + + gw.sendBatteryLevel(randNumber); + gw.wait(SHORT_WAIT); + gw.process(); + Serial.println("#########################"); + gw.wait(SLEEP_TIME); //sleep a bit +} + +// This is called when a new time value was received +void receiveTime(unsigned long controllerTime) { + + Serial.print("Time value received: "); + Serial.println(controllerTime); + +} + +//void door(){} + +#ifdef S_ID_DOOR +void door(){ + + Serial.print("Door is: " ); + + if (randNumber <= 50) { + Serial.println("Open"); + gw.send(msg_S_DOOR.set(1)); + } else { + Serial.println("Closed"); + gw.send(msg_S_DOOR.set(0)); + } + +} +#endif + +#ifdef ID_S_MOTION +void motion(){ + + Serial.print("Motion is: " ); + + if (randNumber <= 50) { + Serial.println("Active"); + gw.send(msg_S_MOTION_T.set(1)); + } else { + Serial.println("Quiet"); + gw.send(msg_S_MOTION_T.set(0)); + } + +} +#endif + +#ifdef ID_S_SMOKE +void smoke(){ + + Serial.print("Smoke is: " ); + + if (randNumber <= 50) { + Serial.println("Active"); + gw.send(msg_S_SMOKE.set(1)); + } else { + Serial.println("Quiet"); + gw.send(msg_S_SMOKE.set(0)); + } + +} +#endif + +#ifdef ID_S_LIGHT +void light(){ + + bool isLightOn = gw.loadState(ID_S_LIGHT); + + Serial.print("Light is: " ); + + if (isLightOn) { + Serial.println("On"); + gw.send(msg_S_LIGHT.set(1)); + } else { + Serial.println("Off"); + gw.send(msg_S_LIGHT.set(0)); + } + +} +#endif + +#ifdef ID_S_DIMMER +void dimmer(){ + + int dimmerVal = gw.loadState(ID_S_DIMMER); + + Serial.print("Dimmer is set to: " ); + Serial.println(dimmerVal); + + gw.send(msg_S_DIMMER.set(dimmerVal)); + +} +#endif + +#ifdef ID_S_COVER +void cover(){ + + int coverVal = gw.loadState(ID_S_COVER); + + Serial.print("Cover is : " ); + + switch (coverVal) { + case 0: + Serial.println("Opening"); + gw.send(msg_S_COVER_U.set(V_UP)); + break; + case 1: + Serial.println("Closing"); + gw.send(msg_S_COVER_D.set(V_DOWN)); + break; + default: + Serial.println("Idle"); + gw.send(msg_S_COVER_S.set(V_STOP)); + } + +} +#endif + +#ifdef ID_S_TEMP +void temp(){ + + Serial.print("Temperature is: " ); + Serial.println(map(randNumber,1,100,0,45)); + + gw.send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); + +} +#endif + +#ifdef ID_S_HUM +void hum(){ + + Serial.print("Humitidty is: " ); + Serial.println(randNumber); + + gw.send(msg_S_HUM.set(randNumber)); + +} +#endif + +#ifdef ID_S_BARO +void baro(){ + + const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; + long pressure = map(randNumber,1,100,87000,108600); + int forecast = map(randNumber,1,100,0,5); + + Serial.print("Atmosferic Pressure is: " ); + Serial.println(pressure); + gw.send(msg_S_BARO_P.set(pressure)); + + Serial.print("Weather forecast: " ); + Serial.println(weather[forecast]); + gw.send(msg_S_BARO_F.set(weather[forecast])); + +} +#endif + +#ifdef ID_S_WIND +void wind(){ + + Serial.print("Wind Speed is: " ); + Serial.println(randNumber); + gw.send(msg_S_WIND_S.set(randNumber)); + + Serial.print("Wind Gust is: " ); + Serial.println(randNumber+10); + gw.send(msg_S_WIND_G.set(randNumber+10)); + + Serial.print("Wind Direction is: " ); + Serial.println(map(randNumber,1,100,0,360)); + gw.send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); + +} +#endif + +#ifdef ID_S_RAIN +void rain(){ + + Serial.print("Rain ammount is: " ); + Serial.println(randNumber); + + gw.send(msg_S_RAIN_A.set(randNumber)); + + Serial.print("Rain rate is: " ); + Serial.println(randNumber/60); + + gw.send(msg_S_RAIN_R.set(randNumber/60,1)); + +} +#endif + +#ifdef ID_S_UV +void uv(){ + + Serial.print("Ultra Violet level is: " ); + Serial.println(map(randNumber,1,100,0,15)); + + gw.send(msg_S_UV.set(map(randNumber,1,100,0,15))); + +} +#endif + +#ifdef ID_S_WEIGHT +void weight(){ + + Serial.print("Weight is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_POWER +void power(){ + + Serial.print("Impedance is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); + + Serial.print("Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); + + Serial.print("KWH is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); + + Serial.print("Voltage is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); + + Serial.print("Current is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_HEATER +void heater(){ + int heater_mode = gw.loadState(ID_S_HEATER); + bool heater_switch = gw.loadState(ID_S_HEATER+1); + + Serial.print("Heater mode is: " ); + + if (heater_mode == 0){ + Serial.println("Off"); + } + else if (heater_mode == 1){ + Serial.println("Heat On"); + } + else if (heater_mode == 2){ + Serial.println("Cool On"); + } + else if (heater_mode == 3){ + Serial.println("Auto Change Over"); + } + else { + Serial.print("Unknown Heater Mode: "); + Serial.println(heater_mode); + } + + gw.send(msg_S_HEATER_M.set(heater_mode)); + + Serial.print("Heater is: " ); + Serial.println(heater_switch?"On":"Off"); + + gw.send(msg_S_HEATER_S.set(heater_switch)); + +} +#endif + +#ifdef ID_S_DISTANCE +void distance(){ + + Serial.print("Distance is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_LIGHT_LEVEL +void light_level(){ + + Serial.print("Light is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_LOCK +void lock(){ + + bool isLocked = gw.loadState(ID_S_LOCK); + + Serial.print("Lock is: " ); + + if (isLocked) { + Serial.println("On"); + gw.send(msg_S_LOCK.set(1)); + } else { + Serial.println("Off"); + gw.send(msg_S_LOCK.set(0)); + } + +} +#endif + +#ifdef ID_S_IR +void ir(){ + + int irVal = gw.loadState(ID_S_IR); + + Serial.print("Infrared is: " ); + Serial.println(irVal); + + gw.send(msg_S_IR_S.set(irVal)); + +} +#endif + +#ifdef ID_S_WATER +void water(){ + + Serial.print("Water flow is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); + + Serial.print("Water volume is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_AIR_QUALITY +void air(){ + + Serial.print("Air Quality is: " ); + Serial.println(randNumber); + + gw.send(msg_S_AIR_QUALITY.set(randNumber)); + +} +#endif + +#ifdef ID_S_DUST +void dust(){ + + Serial.print("Dust level is: " ); + Serial.println(randNumber); + + gw.send(msg_S_DUST.set(randNumber)); + +} +#endif + +#ifdef ID_S_SCENE_CONTROLLER +void scene(){ + + bool isSceneOn = gw.loadState(ID_S_SCENE_CONTROLLER); + + Serial.print("Scene is: " ); + Serial.println(isSceneOn ? "On":"Off"); + + if(isSceneOn) + gw.send(msg_S_SCENE_CONTROLLER_ON.set(isSceneOn)); + else + gw.send(msg_S_SCENE_CONTROLLER_OF.set(isSceneOn)); + +} +#endif + +#ifdef ID_S_CUSTOM +void custom(){ + + Serial.print("Custom value is: " ); + Serial.println(randNumber); + + gw.send(msg_S_CUSTOM_2.set(randNumber)); + gw.send(msg_S_CUSTOM_3.set(randNumber)); + gw.send(msg_S_CUSTOM_4.set(randNumber)); + gw.send(msg_S_CUSTOM_5.set(randNumber)); + +} +#endif + + +void incomingMessage(const MyMessage &message) { + switch (message.type) { + #ifdef ID_S_LIGHT + case V_LIGHT: + gw.saveState(ID_S_LIGHT, message.getBool()); + Serial.print("Incoming change for ID_S_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + break; + #endif + + #ifdef ID_S_DIMMER + case V_DIMMER: + if ((message.getInt()<0)||(message.getInt()>100)) { + Serial.println( "V_DIMMER data invalid (should be 0..100)" ); + break; + } + gw.saveState(ID_S_DIMMER, message.getInt()); + Serial.print("Incoming change for ID_S_DIMMER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getInt()); + break; + #endif + + #ifdef ID_S_COVER + case V_UP: + gw.saveState(ID_S_COVER, 0); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_UP"); + break; + + case V_DOWN: + gw.saveState(ID_S_COVER, 1); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_DOWN"); + break; + + case V_STOP: + gw.saveState(ID_S_COVER, 2); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_STOP"); + break; + #endif + + #ifdef ID_S_HEATER + case V_HEATER: + gw.saveState(ID_S_HEATER, message.getInt()); + Serial.print("Incoming change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + + if (message.getInt() == 0){ + Serial.println("Off"); + } + else if (message.getInt() == 1){ + Serial.println("Heat On"); + } + else if (message.getInt() == 2){ + Serial.println("Cool On"); + } + else if (message.getInt() == 3){ + Serial.println("Auto Change Over"); + } + else { + Serial.print("Unknown Heater Mode: "); + Serial.println(message.getInt()); + } + break; + + case V_HEATER_SW: + gw.saveState(ID_S_HEATER+1, message.getBool()); + Serial.print("Incoming change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println((message.getBool() ? "On":"Off")); + break; + #endif + + #ifdef ID_S_LOCK + case V_LOCK_STATUS: + gw.saveState(ID_S_LOCK, message.getBool()); + Serial.print("Incoming change for ID_S_LOCK:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()?"Locked":"Unlocked"); + break; + #endif + + #ifdef ID_S_IR + case V_IR_RECEIVE: + gw.saveState(ID_S_IR, message.getInt()); + Serial.print("Incoming change for ID_S_IR:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getInt()); + break; + #endif + + #ifdef ID_S_SCENE_CONTROLLER + case V_SCENE_ON: + gw.saveState(ID_S_SCENE_CONTROLLER, 1); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("On"); + break; + case V_SCENE_OFF: + gw.saveState(ID_S_SCENE_CONTROLLER, 0); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("Off"); + break; + #endif + + default: + Serial.print("Unknown/UnImplemented message type:"); + Serial.println(message.type); + } + +} + + + + + + + From 0b2aa6dd16582bd47fd12071284262ce436bce97 Mon Sep 17 00:00:00 2001 From: Barduino Date: Thu, 30 Jul 2015 15:04:58 -0400 Subject: [PATCH 160/660] Delete MockMySensors --- libraries/MySensors/examples/MockMySensors | 1018 -------------------- 1 file changed, 1018 deletions(-) delete mode 100644 libraries/MySensors/examples/MockMySensors diff --git a/libraries/MySensors/examples/MockMySensors b/libraries/MySensors/examples/MockMySensors deleted file mode 100644 index 4397208..0000000 --- a/libraries/MySensors/examples/MockMySensors +++ /dev/null @@ -1,1018 +0,0 @@ -/* -* FakeMySensors -* -* This skecth is intended to crate fake sensors which register and respond to the controller -* -* Barduino 2015 -*/ - -#include -#include - -// SPI Pins -#define CE_PIN 9 -#define CS_PIN 10 - -// Wait times -#define LONG_WAIT 500 -#define SHORT_WAIT 50 - -#define SKETCH_NAME "FakeMySensors " -#define SKETCH_VERSION "v0.2" - -// Define Sensors ids -/* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, - S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, - S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER -*/ - -////#define ID_S_ARDUINO_NODE //auto defined in initialization -////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization - -//#define ID_S_DOOR 1 -//#define ID_S_MOTION 2 -//#define ID_S_SMOKE 3 -//#define ID_S_LIGHT 4 -//#define ID_S_DIMMER 5 -//#define ID_S_COVER 6 -//#define ID_S_TEMP 7 -//#define ID_S_HUM 8 -//#define ID_S_BARO 9 -//#define ID_S_WIND 10 -//#define ID_S_RAIN 11 -//#define ID_S_UV 12 -//#define ID_S_WEIGHT 13 -#define ID_S_POWER 14 -#define ID_S_HEATER 15 -#define ID_S_DISTANCE 16 -#define ID_S_LIGHT_LEVEL 17 -#define ID_S_LOCK 18 -#define ID_S_IR 19 -#define ID_S_WATER 20 -#define ID_S_AIR_QUALITY 21 -#define ID_S_DUST 22 -#define ID_S_SCENE_CONTROLLER 23 - -#define ID_S_CUSTOM 24 - -// Global Vars -unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) -boolean metric = true; -long randNumber; - -// Instanciate MySersors Gateway -MySensor gw(CE_PIN,CS_PIN); - -//Instanciate Messages objects - -#ifdef ID_S_DOOR - MyMessage msg_S_DOOR(ID_S_DOOR,V_TRIPPED); -#endif - -#ifdef ID_S_MOTION - MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); - MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); -#endif - -#ifdef ID_S_SMOKE - MyMessage msg_S_SMOKE(ID_S_SMOKE,V_TRIPPED); -#endif - -#ifdef ID_S_LIGHT - MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); -#endif - -#ifdef ID_S_DIMMER - MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); -#endif - -#ifdef ID_S_COVER - MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); - MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); - MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); -#endif - -#ifdef ID_S_TEMP - MyMessage msg_S_TEMP(ID_S_TEMP,V_TEMP); -#endif - -#ifdef ID_S_HUM - MyMessage msg_S_HUM(ID_S_HUM,V_HUM); -#endif - -#ifdef ID_S_BARO - MyMessage msg_S_BARO_P(ID_S_BARO,V_PRESSURE); - MyMessage msg_S_BARO_F(ID_S_BARO,V_FORECAST); -#endif - -#ifdef ID_S_WIND - MyMessage msg_S_WIND_S(ID_S_WIND,V_WIND); - MyMessage msg_S_WIND_G(ID_S_WIND,V_GUST); - MyMessage msg_S_WIND_D(ID_S_WIND,V_DIRECTION); -#endif - -#ifdef ID_S_RAIN - MyMessage msg_S_RAIN_A(ID_S_RAIN,V_RAIN); - MyMessage msg_S_RAIN_R(ID_S_RAIN,V_RAINRATE); -#endif - -#ifdef ID_S_UV - MyMessage msg_S_UV(ID_S_UV,V_UV); -#endif - -#ifdef ID_S_WEIGHT - MyMessage msg_S_WEIGHT(ID_S_WEIGHT,V_WEIGHT); -#endif - -#ifdef ID_S_POWER - MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); - MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); - MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); - MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); - MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); -#endif - -#ifdef ID_S_HEATER - MyMessage msg_S_HEATER_M(ID_S_HEATER,V_HEATER); - MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HEATER_SW); -#endif - -#ifdef ID_S_DISTANCE - MyMessage msg_S_DISTANCE(ID_S_DISTANCE,V_DISTANCE); -#endif - -#ifdef ID_S_LIGHT_LEVEL - MyMessage msg_S_LIGHT_LEVEL(ID_S_LIGHT_LEVEL,V_LIGHT_LEVEL); -#endif - -#ifdef ID_S_LOCK - MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); -#endif - -#ifdef ID_S_IR - MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); - MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); -#endif - -#ifdef ID_S_WATER - MyMessage msg_S_WATER_F(ID_S_WATER,V_FLOW); - MyMessage msg_S_WATER_V(ID_S_WATER,V_VOLUME); -#endif - -#ifdef ID_S_AIR_QUALITY - MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_VAR1); -#endif - -#ifdef ID_S_DUST - MyMessage msg_S_DUST(ID_S_DUST,V_DUST_LEVEL); -#endif - -#ifdef ID_S_SCENE_CONTROLLER - MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); - MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); -#endif - -#ifdef ID_S_CUSTOM - MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); - MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); - MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); - MyMessage msg_S_CUSTOM_5(ID_S_CUSTOM,V_VAR5); -#endif - - - - -void setup() -{ - // Random SEED - randomSeed(analogRead(0)); - - // Start the gateway - gw.begin(incomingMessage,254); - gw.wait(LONG_WAIT); - Serial.println("GW Started"); - - // Send the Sketch Version Information to the Gateway - Serial.print("Send Sketch Info: "); - gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); - Serial.print(SKETCH_NAME); - Serial.println(SKETCH_VERSION); - gw.wait(LONG_WAIT); - - // Get controller configuration - Serial.print("Get Config: "); - metric = gw.getConfig().isMetric; - Serial.println(metric ? "Metric":"Imperial"); - gw.wait(LONG_WAIT); - - // Register all sensors to gw (they will be created as child devices) - Serial.println("Presenting Nodes"); - Serial.println("________________"); - - #ifdef ID_S_DOOR - Serial.println(" S_DOOR"); - gw.present(ID_S_DOOR,S_DOOR); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_MOTION - Serial.println(" S_MOTION"); - gw.present(ID_S_MOTION,S_MOTION); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_SMOKE - Serial.println(" S_SMOKE"); - gw.present(ID_S_SMOKE,S_SMOKE); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LIGHT - Serial.println(" S_LIGHT"); - gw.present(ID_S_LIGHT,S_LIGHT); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DIMMER - Serial.println(" S_DIMMER"); - gw.present(ID_S_DIMMER,S_DIMMER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_COVER - Serial.println(" S_COVER"; - gw.present(ID_S_COVER,S_COVER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_TEMP - Serial.println(" S_TMEP"); - gw.present(ID_S_TEMP,S_TEMP); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_HUM - Serial.println(" S_HUM"); - gw.present(ID_S_HUM,S_HUM); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_BARO - Serial.println(" S_BARO"); - gw.present(ID_S_BARO,S_BARO); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WIND - Serial.println(" S_WIND"); - gw.present(ID_S_WIND,S_WIND); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_RAIN - Serial.println(" S_RAIN"); - gw.present(ID_S_RAIN,S_RAIN); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_UV - Serial.println(" S_UV"); - gw.present(ID_S_UV,S_UV); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WEIGHT - Serial.println(" S_WEIGHT"): - gw.present(ID_S_WEIGHT,S_WEIGHT); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_POWER - Serial.println(" S_POWER"); - gw.present(ID_S_POWER,S_POWER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_HEATER - Serial.println(" S_HEATER"); - gw.present(ID_S_HEATER,S_HEATER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DISTANCE - Serial.println(" S_DISTANCE"); - gw.present(ID_S_DISTANCE,S_DISTANCE); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LIGHT_LEVEL - Serial.println(" S_LIGHT_LEVEL"); - gw.present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LOCK - Serial.println(" S_LOCK"); - gw.present(ID_S_LOCK,S_LOCK); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_IR - Serial.println(" S_IR"); - gw.present(ID_S_IR,S_IR); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WATER - Serial.println(" S_WATER"); - gw.present(ID_S_WATER,S_WATER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_AIR_QUALITY - Serial.println(" S_AIR_QUALITY"); - gw.present(ID_S_AIR_QUALITY,S_AIR_QUALITY); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DUST - Serial.println(" S_DUST"); - gw.present(ID_S_DUST,S_DUST); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_SCENE_CONTROLLER - Serial.println(" S_SCENE_CONTROLLER"); - gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); - gw.wait(SHORT_WAIT); - #endif - - #ifdef ID_S_CUSTOM - Serial.println(" S_CUSTOM"); - gw.present(ID_S_CUSTOM,S_CUSTOM); - gw.wait(SHORT_WAIT); - #endif - - - -Serial.println("________________"); - -} - -void loop() -{ - Serial.println(""); - Serial.println(""); - Serial.println(""); - Serial.println("#########################"); - randNumber=random(0,101); - - Serial.print("RandomNumber:"); - Serial.println(randNumber); - // Send fake battery level - Serial.println("Send Battery Level"); - gw.sendBatteryLevel(randNumber); - gw.wait(LONG_WAIT); - - // Request time - Serial.println("Request Time"); - gw.requestTime(receiveTime); - gw.wait(LONG_WAIT); - - //Read Sensors - #ifdef S_ID_DOOR - door(); - #endif - - #ifdef ID_S_MOTION - motion(); - #endif - - #ifdef ID_S_SMOKE - smoke(); - #endif - - #ifdef ID_S_LIGHT - light(); - #endif - - #ifdef ID_S_DIMMER - dimmer(); - #endif - - #ifdef ID_S_COVER - cover(); - #endif - - #ifdef ID_S_TEMP - temp(); - #endif - - #ifdef ID_S_HUM - hum(); - #endif - - #ifdef ID_S_BARO - baro(); - #endif - - #ifdef ID_S_WIND - wind(); - #endif - - #ifdef ID_S_RAIN - rain(); - #endif - - #ifdef ID_S_UV - uv(); - #endif - - #ifdef ID_S_WEIGHT - weight(); - #endif - - #ifdef ID_S_POWER - power(); - #endif - - #ifdef ID_S_HEATER - heater(); - #endif - - #ifdef ID_S_DISTANCE - distance(); - #endif - - #ifdef ID_S_LIGHT_LEVEL - light_level(); - #endif - - #ifdef ID_S_LOCK - lock(); - #endif - - #ifdef ID_S_IR - ir(); - #endif - - #ifdef ID_S_WATER - water(); - #endif - - #ifdef ID_S_AIR_QUALITY - air(); - #endif - - #ifdef ID_S_DUST - dust(); - #endif - - #ifdef ID_S_SCENE_CONTROLLER - scene(); - #endif - - #ifdef ID_S_CUSTOM - custom(); - #endif - - gw.sendBatteryLevel(randNumber); - gw.wait(SHORT_WAIT); - gw.process(); - Serial.println("#########################"); - gw.wait(SLEEP_TIME); //sleep a bit -} - -// This is called when a new time value was received -void receiveTime(unsigned long controllerTime) { - - Serial.print("Time value received: "); - Serial.println(controllerTime); - -} - -//void door(){} - -#ifdef S_ID_DOOR -void door(){ - - Serial.print("Door is: " ); - - if (randNumber <= 50) { - Serial.println("Open"); - gw.send(msg_S_DOOR.set(1)); - } else { - Serial.println("Closed"); - gw.send(msg_S_DOOR.set(0)); - } - -} -#endif - -#ifdef ID_S_MOTION -void motion(){ - - Serial.print("Motion is: " ); - - if (randNumber <= 50) { - Serial.println("Active"); - gw.send(msg_S_MOTION_T.set(1)); - } else { - Serial.println("Quiet"); - gw.send(msg_S_MOTION_T.set(0)); - } - -} -#endif - -#ifdef ID_S_SMOKE -void smoke(){ - - Serial.print("Smoke is: " ); - - if (randNumber <= 50) { - Serial.println("Active"); - gw.send(msg_S_SMOKE.set(1)); - } else { - Serial.println("Quiet"); - gw.send(msg_S_SMOKE.set(0)); - } - -} -#endif - -#ifdef ID_S_LIGHT -void light(){ - - bool isLightOn = gw.loadState(ID_S_LIGHT); - - Serial.print("Light is: " ); - - if (isLightOn) { - Serial.println("On"); - gw.send(msg_S_LIGHT.set(1)); - } else { - Serial.println("Off"); - gw.send(msg_S_LIGHT.set(0)); - } - -} -#endif - -#ifdef ID_S_DIMMER -void dimmer(){ - - int dimmerVal = gw.loadState(ID_S_DIMMER); - - Serial.print("Dimmer is set to: " ); - Serial.println(dimmerVal); - - gw.send(msg_S_DIMMER.set(dimmerVal)); - -} -#endif - -#ifdef ID_S_COVER -void cover(){ - - int coverVal = gw.loadState(ID_S_COVER); - - Serial.print("Cover is : " ); - - switch (coverVal) { - case 0: - Serial.println("Opening"); - gw.send(msg_S_COVER_U.set(V_UP)); - break; - case 1: - Serial.println("Closing"); - gw.send(msg_S_COVER_D.set(V_DOWN)); - break; - default: - Serial.println("Idle"); - gw.send(msg_S_COVER_S.set(V_STOP)); - } - -} -#endif - -#ifdef ID_S_TEMP -void temp(){ - - Serial.print("Temperature is: " ); - Serial.println(map(randNumber,1,100,0,45)); - - gw.send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); - -} -#endif - -#ifdef ID_S_HUM -void hum(){ - - Serial.print("Humitidty is: " ); - Serial.println(randNumber); - - gw.send(msg_S_HUM.set(randNumber)); - -} -#endif - -#ifdef ID_S_BARO -void baro(){ - - const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; - long pressure = map(randNumber,1,100,87000,108600); - int forecast = map(randNumber,1,100,0,5); - - Serial.print("Atmosferic Pressure is: " ); - Serial.println(pressure); - gw.send(msg_S_BARO_P.set(pressure)); - - Serial.print("Weather forecast: " ); - Serial.println(weather[forecast]); - gw.send(msg_S_BARO_F.set(weather[forecast])); - -} -#endif - -#ifdef ID_S_WIND -void wind(){ - - Serial.print("Wind Speed is: " ); - Serial.println(randNumber); - gw.send(msg_S_WIND_S.set(randNumber)); - - Serial.print("Wind Gust is: " ); - Serial.println(randNumber+10); - gw.send(msg_S_WIND_G.set(randNumber+10)); - - Serial.print("Wind Direction is: " ); - Serial.println(map(randNumber,1,100,0,360)); - gw.send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); - -} -#endif - -#ifdef ID_S_RAIN -void rain(){ - - Serial.print("Rain ammount is: " ); - Serial.println(randNumber); - - gw.send(msg_S_RAIN_A.set(randNumber)); - - Serial.print("Rain rate is: " ); - Serial.println(randNumber/60); - - gw.send(msg_S_RAIN_R.set(randNumber/60,1)); - -} -#endif - -#ifdef ID_S_UV -void uv(){ - - Serial.print("Ultra Violet level is: " ); - Serial.println(map(randNumber,1,100,0,15)); - - gw.send(msg_S_UV.set(map(randNumber,1,100,0,15))); - -} -#endif - -#ifdef ID_S_WEIGHT -void weight(){ - - Serial.print("Weight is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); - -} -#endif - -#ifdef ID_S_POWER -void power(){ - - Serial.print("Impedance is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); - - Serial.print("Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); - - Serial.print("KWH is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); - - Serial.print("Voltage is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); - - Serial.print("Current is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); - -} -#endif - -#ifdef ID_S_HEATER -void heater(){ - int heater_mode = gw.loadState(ID_S_HEATER); - bool heater_switch = gw.loadState(ID_S_HEATER+1); - - Serial.print("Heater mode is: " ); - - if (heater_mode == 0){ - Serial.println("Off"); - } - else if (heater_mode == 1){ - Serial.println("Heat On"); - } - else if (heater_mode == 2){ - Serial.println("Cool On"); - } - else if (heater_mode == 3){ - Serial.println("Auto Change Over"); - } - else { - Serial.print("Unknown Heater Mode: "); - Serial.println(heater_mode); - } - - gw.send(msg_S_HEATER_M.set(heater_mode)); - - Serial.print("Heater is: " ); - Serial.println(heater_switch?"On":"Off"); - - gw.send(msg_S_HEATER_S.set(heater_switch)); - -} -#endif - -#ifdef ID_S_DISTANCE -void distance(){ - - Serial.print("Distance is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); - -} -#endif - -#ifdef ID_S_LIGHT_LEVEL -void light_level(){ - - Serial.print("Light is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); - -} -#endif - -#ifdef ID_S_LOCK -void lock(){ - - bool isLocked = gw.loadState(ID_S_LOCK); - - Serial.print("Lock is: " ); - - if (isLocked) { - Serial.println("On"); - gw.send(msg_S_LOCK.set(1)); - } else { - Serial.println("Off"); - gw.send(msg_S_LOCK.set(0)); - } - -} -#endif - -#ifdef ID_S_IR -void ir(){ - - int irVal = gw.loadState(ID_S_IR); - - Serial.print("Infrared is: " ); - Serial.println(irVal); - - gw.send(msg_S_IR_S.set(irVal)); - -} -#endif - -#ifdef ID_S_WATER -void water(){ - - Serial.print("Water flow is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); - - Serial.print("Water volume is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); - -} -#endif - -#ifdef ID_S_AIR_QUALITY -void air(){ - - Serial.print("Air Quality is: " ); - Serial.println(randNumber); - - gw.send(msg_S_AIR_QUALITY.set(randNumber)); - -} -#endif - -#ifdef ID_S_DUST -void dust(){ - - Serial.print("Dust level is: " ); - Serial.println(randNumber); - - gw.send(msg_S_DUST.set(randNumber)); - -} -#endif - -#ifdef ID_S_SCENE_CONTROLLER -void scene(){ - - bool isSceneOn = gw.loadState(ID_S_SCENE_CONTROLLER); - - Serial.print("Scene is: " ); - Serial.println(isSceneOn ? "On":"Off"); - - if(isSceneOn) - gw.send(msg_S_SCENE_CONTROLLER_ON.set(isSceneOn)); - else - gw.send(msg_S_SCENE_CONTROLLER_OF.set(isSceneOn)); - -} -#endif - -#ifdef ID_S_CUSTOM -void custom(){ - - Serial.print("Custom value is: " ); - Serial.println(randNumber); - - gw.send(msg_S_CUSTOM_2.set(randNumber)); - gw.send(msg_S_CUSTOM_3.set(randNumber)); - gw.send(msg_S_CUSTOM_4.set(randNumber)); - gw.send(msg_S_CUSTOM_5.set(randNumber)); - -} -#endif - - -void incomingMessage(const MyMessage &message) { - switch (message.type) { - #ifdef ID_S_LIGHT - case V_LIGHT: - gw.saveState(ID_S_LIGHT, message.getBool()); - Serial.print("Incoming change for ID_S_LIGHT:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getBool()); - break; - #endif - - #ifdef ID_S_DIMMER - case V_DIMMER: - if ((message.getInt()<0)||(message.getInt()>100)) { - Serial.println( "V_DIMMER data invalid (should be 0..100)" ); - break; - } - gw.saveState(ID_S_DIMMER, message.getInt()); - Serial.print("Incoming change for ID_S_DIMMER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getInt()); - break; - #endif - - #ifdef ID_S_COVER - case V_UP: - gw.saveState(ID_S_COVER, 0); - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_UP"); - break; - - case V_DOWN: - gw.saveState(ID_S_COVER, 1); - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_DOWN"); - break; - - case V_STOP: - gw.saveState(ID_S_COVER, 2); - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_STOP"); - break; - #endif - - #ifdef ID_S_HEATER - case V_HEATER: - gw.saveState(ID_S_HEATER, message.getInt()); - Serial.print("Incoming change for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - - if (message.getInt() == 0){ - Serial.println("Off"); - } - else if (message.getInt() == 1){ - Serial.println("Heat On"); - } - else if (message.getInt() == 2){ - Serial.println("Cool On"); - } - else if (message.getInt() == 3){ - Serial.println("Auto Change Over"); - } - else { - Serial.print("Unknown Heater Mode: "); - Serial.println(message.getInt()); - } - break; - - case V_HEATER_SW: - gw.saveState(ID_S_HEATER+1, message.getBool()); - Serial.print("Incoming change for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println((message.getBool() ? "On":"Off")); - break; - #endif - - #ifdef ID_S_LOCK - case V_LOCK_STATUS: - gw.saveState(ID_S_LOCK, message.getBool()); - Serial.print("Incoming change for ID_S_LOCK:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getBool()?"Locked":"Unlocked"); - break; - #endif - - #ifdef ID_S_IR - case V_IR_RECEIVE: - gw.saveState(ID_S_IR, message.getInt()); - Serial.print("Incoming change for ID_S_IR:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getInt()); - break; - #endif - - #ifdef ID_S_SCENE_CONTROLLER - case V_SCENE_ON: - gw.saveState(ID_S_SCENE_CONTROLLER, 1); - Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("On"); - break; - case V_SCENE_OFF: - gw.saveState(ID_S_SCENE_CONTROLLER, 0); - Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("Off"); - break; - #endif - - default: - Serial.print("Unknown/UnImplemented message type:"); - Serial.println(message.type); - } - -} - - - - - - - From a89469ebc8997cbca1a6d33c213dc54c1c24c1fd Mon Sep 17 00:00:00 2001 From: Barduino Date: Thu, 30 Jul 2015 15:17:53 -0400 Subject: [PATCH 161/660] Create MockMySensors.ino # FakeMySensors Arduino sketch to fake sensor for the MySensors Library This skecth is intended to crate fake sensors which register and respond to the controller Barduino 2015 ----------------- Comment/Uncomment the sensors you would like to test Arduino Uno R3 can support about 12 sensors before it runs out of memory. You probably need to turn of the MySensor Lib debug to save some memory Nest step will be to remove the read/write to the eprom and extend to support the v1.5 sensors --- .../examples/MockMySensors/MockMySensors.ino | 1018 +++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 libraries/MySensors/examples/MockMySensors/MockMySensors.ino diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino new file mode 100644 index 0000000..4397208 --- /dev/null +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -0,0 +1,1018 @@ +/* +* FakeMySensors +* +* This skecth is intended to crate fake sensors which register and respond to the controller +* +* Barduino 2015 +*/ + +#include +#include + +// SPI Pins +#define CE_PIN 9 +#define CS_PIN 10 + +// Wait times +#define LONG_WAIT 500 +#define SHORT_WAIT 50 + +#define SKETCH_NAME "FakeMySensors " +#define SKETCH_VERSION "v0.2" + +// Define Sensors ids +/* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, + S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, + S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, + S_SCENE_CONTROLLER +*/ + +////#define ID_S_ARDUINO_NODE //auto defined in initialization +////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization + +//#define ID_S_DOOR 1 +//#define ID_S_MOTION 2 +//#define ID_S_SMOKE 3 +//#define ID_S_LIGHT 4 +//#define ID_S_DIMMER 5 +//#define ID_S_COVER 6 +//#define ID_S_TEMP 7 +//#define ID_S_HUM 8 +//#define ID_S_BARO 9 +//#define ID_S_WIND 10 +//#define ID_S_RAIN 11 +//#define ID_S_UV 12 +//#define ID_S_WEIGHT 13 +#define ID_S_POWER 14 +#define ID_S_HEATER 15 +#define ID_S_DISTANCE 16 +#define ID_S_LIGHT_LEVEL 17 +#define ID_S_LOCK 18 +#define ID_S_IR 19 +#define ID_S_WATER 20 +#define ID_S_AIR_QUALITY 21 +#define ID_S_DUST 22 +#define ID_S_SCENE_CONTROLLER 23 + +#define ID_S_CUSTOM 24 + +// Global Vars +unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) +boolean metric = true; +long randNumber; + +// Instanciate MySersors Gateway +MySensor gw(CE_PIN,CS_PIN); + +//Instanciate Messages objects + +#ifdef ID_S_DOOR + MyMessage msg_S_DOOR(ID_S_DOOR,V_TRIPPED); +#endif + +#ifdef ID_S_MOTION + MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); + MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); +#endif + +#ifdef ID_S_SMOKE + MyMessage msg_S_SMOKE(ID_S_SMOKE,V_TRIPPED); +#endif + +#ifdef ID_S_LIGHT + MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); +#endif + +#ifdef ID_S_DIMMER + MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); +#endif + +#ifdef ID_S_COVER + MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); + MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); + MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); +#endif + +#ifdef ID_S_TEMP + MyMessage msg_S_TEMP(ID_S_TEMP,V_TEMP); +#endif + +#ifdef ID_S_HUM + MyMessage msg_S_HUM(ID_S_HUM,V_HUM); +#endif + +#ifdef ID_S_BARO + MyMessage msg_S_BARO_P(ID_S_BARO,V_PRESSURE); + MyMessage msg_S_BARO_F(ID_S_BARO,V_FORECAST); +#endif + +#ifdef ID_S_WIND + MyMessage msg_S_WIND_S(ID_S_WIND,V_WIND); + MyMessage msg_S_WIND_G(ID_S_WIND,V_GUST); + MyMessage msg_S_WIND_D(ID_S_WIND,V_DIRECTION); +#endif + +#ifdef ID_S_RAIN + MyMessage msg_S_RAIN_A(ID_S_RAIN,V_RAIN); + MyMessage msg_S_RAIN_R(ID_S_RAIN,V_RAINRATE); +#endif + +#ifdef ID_S_UV + MyMessage msg_S_UV(ID_S_UV,V_UV); +#endif + +#ifdef ID_S_WEIGHT + MyMessage msg_S_WEIGHT(ID_S_WEIGHT,V_WEIGHT); +#endif + +#ifdef ID_S_POWER + MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); + MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); + MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); + MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); + MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); +#endif + +#ifdef ID_S_HEATER + MyMessage msg_S_HEATER_M(ID_S_HEATER,V_HEATER); + MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HEATER_SW); +#endif + +#ifdef ID_S_DISTANCE + MyMessage msg_S_DISTANCE(ID_S_DISTANCE,V_DISTANCE); +#endif + +#ifdef ID_S_LIGHT_LEVEL + MyMessage msg_S_LIGHT_LEVEL(ID_S_LIGHT_LEVEL,V_LIGHT_LEVEL); +#endif + +#ifdef ID_S_LOCK + MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); +#endif + +#ifdef ID_S_IR + MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); + MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); +#endif + +#ifdef ID_S_WATER + MyMessage msg_S_WATER_F(ID_S_WATER,V_FLOW); + MyMessage msg_S_WATER_V(ID_S_WATER,V_VOLUME); +#endif + +#ifdef ID_S_AIR_QUALITY + MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_VAR1); +#endif + +#ifdef ID_S_DUST + MyMessage msg_S_DUST(ID_S_DUST,V_DUST_LEVEL); +#endif + +#ifdef ID_S_SCENE_CONTROLLER + MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); + MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); +#endif + +#ifdef ID_S_CUSTOM + MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); + MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); + MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); + MyMessage msg_S_CUSTOM_5(ID_S_CUSTOM,V_VAR5); +#endif + + + + +void setup() +{ + // Random SEED + randomSeed(analogRead(0)); + + // Start the gateway + gw.begin(incomingMessage,254); + gw.wait(LONG_WAIT); + Serial.println("GW Started"); + + // Send the Sketch Version Information to the Gateway + Serial.print("Send Sketch Info: "); + gw.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); + Serial.print(SKETCH_NAME); + Serial.println(SKETCH_VERSION); + gw.wait(LONG_WAIT); + + // Get controller configuration + Serial.print("Get Config: "); + metric = gw.getConfig().isMetric; + Serial.println(metric ? "Metric":"Imperial"); + gw.wait(LONG_WAIT); + + // Register all sensors to gw (they will be created as child devices) + Serial.println("Presenting Nodes"); + Serial.println("________________"); + + #ifdef ID_S_DOOR + Serial.println(" S_DOOR"); + gw.present(ID_S_DOOR,S_DOOR); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_MOTION + Serial.println(" S_MOTION"); + gw.present(ID_S_MOTION,S_MOTION); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_SMOKE + Serial.println(" S_SMOKE"); + gw.present(ID_S_SMOKE,S_SMOKE); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LIGHT + Serial.println(" S_LIGHT"); + gw.present(ID_S_LIGHT,S_LIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DIMMER + Serial.println(" S_DIMMER"); + gw.present(ID_S_DIMMER,S_DIMMER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_COVER + Serial.println(" S_COVER"; + gw.present(ID_S_COVER,S_COVER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_TEMP + Serial.println(" S_TMEP"); + gw.present(ID_S_TEMP,S_TEMP); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_HUM + Serial.println(" S_HUM"); + gw.present(ID_S_HUM,S_HUM); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_BARO + Serial.println(" S_BARO"); + gw.present(ID_S_BARO,S_BARO); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WIND + Serial.println(" S_WIND"); + gw.present(ID_S_WIND,S_WIND); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_RAIN + Serial.println(" S_RAIN"); + gw.present(ID_S_RAIN,S_RAIN); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_UV + Serial.println(" S_UV"); + gw.present(ID_S_UV,S_UV); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WEIGHT + Serial.println(" S_WEIGHT"): + gw.present(ID_S_WEIGHT,S_WEIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_POWER + Serial.println(" S_POWER"); + gw.present(ID_S_POWER,S_POWER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_HEATER + Serial.println(" S_HEATER"); + gw.present(ID_S_HEATER,S_HEATER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DISTANCE + Serial.println(" S_DISTANCE"); + gw.present(ID_S_DISTANCE,S_DISTANCE); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LIGHT_LEVEL + Serial.println(" S_LIGHT_LEVEL"); + gw.present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_LOCK + Serial.println(" S_LOCK"); + gw.present(ID_S_LOCK,S_LOCK); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_IR + Serial.println(" S_IR"); + gw.present(ID_S_IR,S_IR); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_WATER + Serial.println(" S_WATER"); + gw.present(ID_S_WATER,S_WATER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_AIR_QUALITY + Serial.println(" S_AIR_QUALITY"); + gw.present(ID_S_AIR_QUALITY,S_AIR_QUALITY); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_DUST + Serial.println(" S_DUST"); + gw.present(ID_S_DUST,S_DUST); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_SCENE_CONTROLLER + Serial.println(" S_SCENE_CONTROLLER"); + gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_CUSTOM + Serial.println(" S_CUSTOM"); + gw.present(ID_S_CUSTOM,S_CUSTOM); + gw.wait(SHORT_WAIT); + #endif + + + +Serial.println("________________"); + +} + +void loop() +{ + Serial.println(""); + Serial.println(""); + Serial.println(""); + Serial.println("#########################"); + randNumber=random(0,101); + + Serial.print("RandomNumber:"); + Serial.println(randNumber); + // Send fake battery level + Serial.println("Send Battery Level"); + gw.sendBatteryLevel(randNumber); + gw.wait(LONG_WAIT); + + // Request time + Serial.println("Request Time"); + gw.requestTime(receiveTime); + gw.wait(LONG_WAIT); + + //Read Sensors + #ifdef S_ID_DOOR + door(); + #endif + + #ifdef ID_S_MOTION + motion(); + #endif + + #ifdef ID_S_SMOKE + smoke(); + #endif + + #ifdef ID_S_LIGHT + light(); + #endif + + #ifdef ID_S_DIMMER + dimmer(); + #endif + + #ifdef ID_S_COVER + cover(); + #endif + + #ifdef ID_S_TEMP + temp(); + #endif + + #ifdef ID_S_HUM + hum(); + #endif + + #ifdef ID_S_BARO + baro(); + #endif + + #ifdef ID_S_WIND + wind(); + #endif + + #ifdef ID_S_RAIN + rain(); + #endif + + #ifdef ID_S_UV + uv(); + #endif + + #ifdef ID_S_WEIGHT + weight(); + #endif + + #ifdef ID_S_POWER + power(); + #endif + + #ifdef ID_S_HEATER + heater(); + #endif + + #ifdef ID_S_DISTANCE + distance(); + #endif + + #ifdef ID_S_LIGHT_LEVEL + light_level(); + #endif + + #ifdef ID_S_LOCK + lock(); + #endif + + #ifdef ID_S_IR + ir(); + #endif + + #ifdef ID_S_WATER + water(); + #endif + + #ifdef ID_S_AIR_QUALITY + air(); + #endif + + #ifdef ID_S_DUST + dust(); + #endif + + #ifdef ID_S_SCENE_CONTROLLER + scene(); + #endif + + #ifdef ID_S_CUSTOM + custom(); + #endif + + gw.sendBatteryLevel(randNumber); + gw.wait(SHORT_WAIT); + gw.process(); + Serial.println("#########################"); + gw.wait(SLEEP_TIME); //sleep a bit +} + +// This is called when a new time value was received +void receiveTime(unsigned long controllerTime) { + + Serial.print("Time value received: "); + Serial.println(controllerTime); + +} + +//void door(){} + +#ifdef S_ID_DOOR +void door(){ + + Serial.print("Door is: " ); + + if (randNumber <= 50) { + Serial.println("Open"); + gw.send(msg_S_DOOR.set(1)); + } else { + Serial.println("Closed"); + gw.send(msg_S_DOOR.set(0)); + } + +} +#endif + +#ifdef ID_S_MOTION +void motion(){ + + Serial.print("Motion is: " ); + + if (randNumber <= 50) { + Serial.println("Active"); + gw.send(msg_S_MOTION_T.set(1)); + } else { + Serial.println("Quiet"); + gw.send(msg_S_MOTION_T.set(0)); + } + +} +#endif + +#ifdef ID_S_SMOKE +void smoke(){ + + Serial.print("Smoke is: " ); + + if (randNumber <= 50) { + Serial.println("Active"); + gw.send(msg_S_SMOKE.set(1)); + } else { + Serial.println("Quiet"); + gw.send(msg_S_SMOKE.set(0)); + } + +} +#endif + +#ifdef ID_S_LIGHT +void light(){ + + bool isLightOn = gw.loadState(ID_S_LIGHT); + + Serial.print("Light is: " ); + + if (isLightOn) { + Serial.println("On"); + gw.send(msg_S_LIGHT.set(1)); + } else { + Serial.println("Off"); + gw.send(msg_S_LIGHT.set(0)); + } + +} +#endif + +#ifdef ID_S_DIMMER +void dimmer(){ + + int dimmerVal = gw.loadState(ID_S_DIMMER); + + Serial.print("Dimmer is set to: " ); + Serial.println(dimmerVal); + + gw.send(msg_S_DIMMER.set(dimmerVal)); + +} +#endif + +#ifdef ID_S_COVER +void cover(){ + + int coverVal = gw.loadState(ID_S_COVER); + + Serial.print("Cover is : " ); + + switch (coverVal) { + case 0: + Serial.println("Opening"); + gw.send(msg_S_COVER_U.set(V_UP)); + break; + case 1: + Serial.println("Closing"); + gw.send(msg_S_COVER_D.set(V_DOWN)); + break; + default: + Serial.println("Idle"); + gw.send(msg_S_COVER_S.set(V_STOP)); + } + +} +#endif + +#ifdef ID_S_TEMP +void temp(){ + + Serial.print("Temperature is: " ); + Serial.println(map(randNumber,1,100,0,45)); + + gw.send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); + +} +#endif + +#ifdef ID_S_HUM +void hum(){ + + Serial.print("Humitidty is: " ); + Serial.println(randNumber); + + gw.send(msg_S_HUM.set(randNumber)); + +} +#endif + +#ifdef ID_S_BARO +void baro(){ + + const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; + long pressure = map(randNumber,1,100,87000,108600); + int forecast = map(randNumber,1,100,0,5); + + Serial.print("Atmosferic Pressure is: " ); + Serial.println(pressure); + gw.send(msg_S_BARO_P.set(pressure)); + + Serial.print("Weather forecast: " ); + Serial.println(weather[forecast]); + gw.send(msg_S_BARO_F.set(weather[forecast])); + +} +#endif + +#ifdef ID_S_WIND +void wind(){ + + Serial.print("Wind Speed is: " ); + Serial.println(randNumber); + gw.send(msg_S_WIND_S.set(randNumber)); + + Serial.print("Wind Gust is: " ); + Serial.println(randNumber+10); + gw.send(msg_S_WIND_G.set(randNumber+10)); + + Serial.print("Wind Direction is: " ); + Serial.println(map(randNumber,1,100,0,360)); + gw.send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); + +} +#endif + +#ifdef ID_S_RAIN +void rain(){ + + Serial.print("Rain ammount is: " ); + Serial.println(randNumber); + + gw.send(msg_S_RAIN_A.set(randNumber)); + + Serial.print("Rain rate is: " ); + Serial.println(randNumber/60); + + gw.send(msg_S_RAIN_R.set(randNumber/60,1)); + +} +#endif + +#ifdef ID_S_UV +void uv(){ + + Serial.print("Ultra Violet level is: " ); + Serial.println(map(randNumber,1,100,0,15)); + + gw.send(msg_S_UV.set(map(randNumber,1,100,0,15))); + +} +#endif + +#ifdef ID_S_WEIGHT +void weight(){ + + Serial.print("Weight is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_POWER +void power(){ + + Serial.print("Impedance is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); + + Serial.print("Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); + + Serial.print("KWH is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); + + Serial.print("Voltage is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); + + Serial.print("Current is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_HEATER +void heater(){ + int heater_mode = gw.loadState(ID_S_HEATER); + bool heater_switch = gw.loadState(ID_S_HEATER+1); + + Serial.print("Heater mode is: " ); + + if (heater_mode == 0){ + Serial.println("Off"); + } + else if (heater_mode == 1){ + Serial.println("Heat On"); + } + else if (heater_mode == 2){ + Serial.println("Cool On"); + } + else if (heater_mode == 3){ + Serial.println("Auto Change Over"); + } + else { + Serial.print("Unknown Heater Mode: "); + Serial.println(heater_mode); + } + + gw.send(msg_S_HEATER_M.set(heater_mode)); + + Serial.print("Heater is: " ); + Serial.println(heater_switch?"On":"Off"); + + gw.send(msg_S_HEATER_S.set(heater_switch)); + +} +#endif + +#ifdef ID_S_DISTANCE +void distance(){ + + Serial.print("Distance is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_LIGHT_LEVEL +void light_level(){ + + Serial.print("Light is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_LOCK +void lock(){ + + bool isLocked = gw.loadState(ID_S_LOCK); + + Serial.print("Lock is: " ); + + if (isLocked) { + Serial.println("On"); + gw.send(msg_S_LOCK.set(1)); + } else { + Serial.println("Off"); + gw.send(msg_S_LOCK.set(0)); + } + +} +#endif + +#ifdef ID_S_IR +void ir(){ + + int irVal = gw.loadState(ID_S_IR); + + Serial.print("Infrared is: " ); + Serial.println(irVal); + + gw.send(msg_S_IR_S.set(irVal)); + +} +#endif + +#ifdef ID_S_WATER +void water(){ + + Serial.print("Water flow is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); + + Serial.print("Water volume is: " ); + Serial.println(map(randNumber,1,100,0,150)); + + gw.send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_AIR_QUALITY +void air(){ + + Serial.print("Air Quality is: " ); + Serial.println(randNumber); + + gw.send(msg_S_AIR_QUALITY.set(randNumber)); + +} +#endif + +#ifdef ID_S_DUST +void dust(){ + + Serial.print("Dust level is: " ); + Serial.println(randNumber); + + gw.send(msg_S_DUST.set(randNumber)); + +} +#endif + +#ifdef ID_S_SCENE_CONTROLLER +void scene(){ + + bool isSceneOn = gw.loadState(ID_S_SCENE_CONTROLLER); + + Serial.print("Scene is: " ); + Serial.println(isSceneOn ? "On":"Off"); + + if(isSceneOn) + gw.send(msg_S_SCENE_CONTROLLER_ON.set(isSceneOn)); + else + gw.send(msg_S_SCENE_CONTROLLER_OF.set(isSceneOn)); + +} +#endif + +#ifdef ID_S_CUSTOM +void custom(){ + + Serial.print("Custom value is: " ); + Serial.println(randNumber); + + gw.send(msg_S_CUSTOM_2.set(randNumber)); + gw.send(msg_S_CUSTOM_3.set(randNumber)); + gw.send(msg_S_CUSTOM_4.set(randNumber)); + gw.send(msg_S_CUSTOM_5.set(randNumber)); + +} +#endif + + +void incomingMessage(const MyMessage &message) { + switch (message.type) { + #ifdef ID_S_LIGHT + case V_LIGHT: + gw.saveState(ID_S_LIGHT, message.getBool()); + Serial.print("Incoming change for ID_S_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + break; + #endif + + #ifdef ID_S_DIMMER + case V_DIMMER: + if ((message.getInt()<0)||(message.getInt()>100)) { + Serial.println( "V_DIMMER data invalid (should be 0..100)" ); + break; + } + gw.saveState(ID_S_DIMMER, message.getInt()); + Serial.print("Incoming change for ID_S_DIMMER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getInt()); + break; + #endif + + #ifdef ID_S_COVER + case V_UP: + gw.saveState(ID_S_COVER, 0); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_UP"); + break; + + case V_DOWN: + gw.saveState(ID_S_COVER, 1); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_DOWN"); + break; + + case V_STOP: + gw.saveState(ID_S_COVER, 2); + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_STOP"); + break; + #endif + + #ifdef ID_S_HEATER + case V_HEATER: + gw.saveState(ID_S_HEATER, message.getInt()); + Serial.print("Incoming change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + + if (message.getInt() == 0){ + Serial.println("Off"); + } + else if (message.getInt() == 1){ + Serial.println("Heat On"); + } + else if (message.getInt() == 2){ + Serial.println("Cool On"); + } + else if (message.getInt() == 3){ + Serial.println("Auto Change Over"); + } + else { + Serial.print("Unknown Heater Mode: "); + Serial.println(message.getInt()); + } + break; + + case V_HEATER_SW: + gw.saveState(ID_S_HEATER+1, message.getBool()); + Serial.print("Incoming change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println((message.getBool() ? "On":"Off")); + break; + #endif + + #ifdef ID_S_LOCK + case V_LOCK_STATUS: + gw.saveState(ID_S_LOCK, message.getBool()); + Serial.print("Incoming change for ID_S_LOCK:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()?"Locked":"Unlocked"); + break; + #endif + + #ifdef ID_S_IR + case V_IR_RECEIVE: + gw.saveState(ID_S_IR, message.getInt()); + Serial.print("Incoming change for ID_S_IR:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getInt()); + break; + #endif + + #ifdef ID_S_SCENE_CONTROLLER + case V_SCENE_ON: + gw.saveState(ID_S_SCENE_CONTROLLER, 1); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("On"); + break; + case V_SCENE_OFF: + gw.saveState(ID_S_SCENE_CONTROLLER, 0); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("Off"); + break; + #endif + + default: + Serial.print("Unknown/UnImplemented message type:"); + Serial.println(message.type); + } + +} + + + + + + + From bb39d1f548c21ca2bcb014487b99a6d9b9337259 Mon Sep 17 00:00:00 2001 From: Barduino Date: Thu, 30 Jul 2015 15:18:13 -0400 Subject: [PATCH 162/660] Create README.md --- .../MySensors/examples/MockMySensors/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 libraries/MySensors/examples/MockMySensors/README.md diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md new file mode 100644 index 0000000..8b15212 --- /dev/null +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -0,0 +1,15 @@ +# FakeMySensors +Arduino sketch to fake sensor for the MySensors Library + +This skecth is intended to crate fake sensors which register and respond to the controller + +Barduino 2015 +----------------- + +Comment/Uncomment the sensors you would like to test + +Arduino Uno R3 can support about 12 sensors before it runs out of memory. +You probably need to turn of the MySensor Lib debug to save some memory + +Nest step will be to remove the read/write to the eprom +and extend to support the v1.5 sensors From 3fed88a3277fda211c9e58ed36279fe200590c86 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 30 Jul 2015 21:38:13 +0200 Subject: [PATCH 163/660] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebb4f31..b803e58 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Arduino ======= -MySensors Arduino Library v1.4 +MySensors Arduino Library v1.5 Please visit www.mysensors.org for more information From 668a5f649b4fee50d4bd7035b7f376cfca2c0c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 30 Jul 2015 22:34:47 +0200 Subject: [PATCH 164/660] Better "control" for determining if humiidty changes should fire off a transmission --- .../examples/SensebenderMicro/SensebenderMicro.ino | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 1dc3e77..02b88d3 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -15,7 +15,7 @@ #include #include #include -#include +//#include // Define a static node address, remove if you want auto address assignment //#define NODE_ADDRESS 3 @@ -149,7 +149,7 @@ void loop() { if ((measureCount == 5) && highfreq) { - clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. +// clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. highfreq = false; } @@ -182,21 +182,20 @@ void loop() { void sendTempHumidityMeasurements(bool force) { bool tx = force; - + si7021_env data = humiditySensor.getHumidityAndTemperature(); - float oldAvgHum = raHum.getAverage(); raHum.addValue(data.humidityPercent); float diffTemp = abs(lastTemperature - (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths)/100); - float diffHum = abs(oldAvgHum - raHum.getAverage()); + float diffHum = abs(lastHumidity - raHum.getAverage()); Serial.print(F("TempDiff :"));Serial.println(diffTemp); Serial.print(F("HumDiff :"));Serial.println(diffHum); if (isnan(diffHum)) tx = true; if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true; - if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true; + if (diffHum > HUMI_TRANSMIT_THRESHOLD) tx = true; if (tx) { measureCount = 0; @@ -246,7 +245,7 @@ void sendBattLevel(bool force) * Internal battery ADC measuring * *******************************************/ -long readVcc() { +long readVcc() {/* // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) @@ -270,6 +269,7 @@ long readVcc() { result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts + */ } /**************************************************** From 5cdc2ebb19f01cecaad89913a33f50da9ae6d567 Mon Sep 17 00:00:00 2001 From: Barduino Date: Fri, 31 Jul 2015 10:18:02 -0400 Subject: [PATCH 165/660] Update README.md Removed fake my sensors reference --- libraries/MySensors/examples/MockMySensors/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md index 8b15212..24e2ce9 100644 --- a/libraries/MySensors/examples/MockMySensors/README.md +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -1,4 +1,4 @@ -# FakeMySensors +# MockMySensors Arduino sketch to fake sensor for the MySensors Library This skecth is intended to crate fake sensors which register and respond to the controller From 48f3e78ec89d6dd426eafdc0e370d63b97a3c19f Mon Sep 17 00:00:00 2001 From: Barduino Date: Fri, 31 Jul 2015 10:19:05 -0400 Subject: [PATCH 166/660] Update MockMySensors.ino Removed FakeMySensors reference --- libraries/MySensors/examples/MockMySensors/MockMySensors.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 4397208..2eb1629 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -1,5 +1,5 @@ /* -* FakeMySensors +* MockMySensors * * This skecth is intended to crate fake sensors which register and respond to the controller * From c562f0f173de61c2c179eb2b9c2bb67def16c079 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 31 Jul 2015 20:47:22 +0200 Subject: [PATCH 167/660] fix #114 --- NodeJsController/NodeJsController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NodeJsController/NodeJsController.js b/NodeJsController/NodeJsController.js index 2c40fb4..4afba5f 100644 --- a/NodeJsController/NodeJsController.js +++ b/NodeJsController/NodeJsController.js @@ -364,7 +364,7 @@ function saveSketchVersion(sender, payload, db) { } function sendTime(destination, sensor, gw) { - var payload = new Date().getTime(); + var payload = new Date().getTime()/1000; var command = C_INTERNAL; var acknowledge = 0; // no ack var type = I_TIME; From 656ba2e4ab6586b695efa201a3aa6c1f9d924763 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 1 Aug 2015 00:05:09 +0200 Subject: [PATCH 168/660] Codebender adoption Had to make some chnages to make the code work on codebender (which seems to run a bit older version of AVR-LIBC. The compiler didn't like array constructor initializations either.. --- libraries/MySensors/MyConfig.h | 3 +- libraries/MySensors/MyHwATMega328.h | 28 ++++++++++++++++++- libraries/MySensors/MySigningAtsha204Soft.cpp | 4 ++- libraries/MySensors/MySigningAtsha204Soft.h | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 11c8af1..098a1f9 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -94,8 +94,7 @@ #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) -#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /********************************** diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 17a4222..12698d4 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -37,13 +37,39 @@ #include #endif +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + + // Define these as macros to save valuable space #define hw_init() Serial.begin(BAUD_RATE) #define hw_watchdogReset() wdt_reset() #define hw_reboot() wdt_enable(WDTO_15MS); while (1) #define hw_millis() millis() #define hw_readConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) -#define hw_writeConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) + +#ifndef eeprom_update_byte + #define hw_writeConfig(loc, val) if((uint8_t)(val) != eeprom_read_byte((uint8_t*)(loc))) { eeprom_write_byte((uint8_t*)(loc), (val)); } +#else + #define hw_writeConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) +#endif + +// #define hw_readConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) #define hw_writeConfigBlock(__pos, __buf, __length) (eeprom_write_block((void*)(__pos), (void*)__buf, (__length))) diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index d552c17..043d367 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -61,6 +61,9 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif +// Initialize hmacKey from MyConfig.h (codebender didn't like static initialization in constructor) +uint8_t MySigningAtsha204Soft::hmacKey[32] = { MY_HMAC_KEY }; + MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, #ifdef MY_SECURE_NODE_WHITELISTING uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, @@ -70,7 +73,6 @@ MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, : MySigning(requestSignatures), rndPin(randomseedPin), - hmacKey({MY_HMAC_KEY}), #ifdef MY_SECURE_NODE_WHITELISTING whitlist_sz(nof_whitelist_entries), whitelist(the_whitelist), diff --git a/libraries/MySensors/MySigningAtsha204Soft.h b/libraries/MySensors/MySigningAtsha204Soft.h index e516618..5d8090e 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.h +++ b/libraries/MySensors/MySigningAtsha204Soft.h @@ -73,7 +73,7 @@ private: bool verification_ongoing; uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; uint8_t temp_message[32]; - uint8_t hmacKey[32]; + static uint8_t hmacKey[32]; uint8_t rndPin; uint8_t hmac[32]; void calculateSignature(MyMessage &msg); From b9a5d6d5e1f7bf9efd155e6777445bbb9fae537e Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 1 Aug 2015 00:08:03 +0200 Subject: [PATCH 169/660] Add standard header to the Sensbender sketch --- .../SensebenderMicro/SensebenderMicro.ino | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index b86de21..32e959d 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -1,9 +1,35 @@ -// Default sensor sketch for Sensebender Micro module -// Act as a temperature / humidity sensor by default. -// -// If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals -// -// Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below) +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Thomas Bowman Mørch + * + * DESCRIPTION + * Default sensor sketch for Sensebender Micro module + * Act as a temperature / humidity sensor by default. + * + * If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals + * + * Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below) + * + */ #include From b1005042bf92068f9837b48e4eb480f095f11f87 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 1 Aug 2015 11:09:27 +0200 Subject: [PATCH 170/660] Fix #146 --- .../MySensors/examples/EthernetGateway/EthernetGateway.ino | 2 +- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 383cbdf..fe19206 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -92,7 +92,7 @@ // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); //MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 867c8be..0bb722d 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -118,7 +118,7 @@ byte TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You sh ////////////////////////////////////////////////////////////////// // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); //MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) From b28a28ddd6a2501c77579e758e58d82284a4027e Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 1 Aug 2015 22:13:11 +0200 Subject: [PATCH 171/660] Add ParkingSensor --- .../Adafruit_NeoPixel/Adafruit_NeoPixel.cpp | 1029 +++++++++++++++++ .../Adafruit_NeoPixel/Adafruit_NeoPixel.h | 97 ++ libraries/Adafruit_NeoPixel/COPYING | 794 +++++++++++++ libraries/Adafruit_NeoPixel/README.md | 12 + .../examples/buttoncycler/buttoncycler.ino | 165 +++ .../examples/simple/simple.ino | 45 + .../examples/strandtest/strandtest.ino | 131 +++ libraries/Adafruit_NeoPixel/keywords.txt | 29 + .../Adafruit_NeoPixel/library.properties | 9 + .../examples/ParkingSensor/ParkingSensor.ino | 164 +++ 10 files changed, 2475 insertions(+) create mode 100755 libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp create mode 100755 libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h create mode 100755 libraries/Adafruit_NeoPixel/COPYING create mode 100755 libraries/Adafruit_NeoPixel/README.md create mode 100755 libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino create mode 100755 libraries/Adafruit_NeoPixel/examples/simple/simple.ino create mode 100755 libraries/Adafruit_NeoPixel/examples/strandtest/strandtest.ino create mode 100755 libraries/Adafruit_NeoPixel/keywords.txt create mode 100755 libraries/Adafruit_NeoPixel/library.properties create mode 100644 libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino diff --git a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp new file mode 100755 index 0000000..af6386c --- /dev/null +++ b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp @@ -0,0 +1,1029 @@ +/*------------------------------------------------------------------------- + Arduino library to control a wide variety of WS2811- and WS2812-based RGB + LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. + Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega + MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide + output on PORTB and PORTD, while 16 MHz chips can handle most output pins + (possible exception with upper PORT registers on the Arduino Mega). + + Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, + contributions by PJRC and other members of the open source community. + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing products + from Adafruit! + + ------------------------------------------------------------------------- + This file is part of the Adafruit NeoPixel library. + + NeoPixel is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + NeoPixel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with NeoPixel. If not, see + . + -------------------------------------------------------------------------*/ + +#include "Adafruit_NeoPixel.h" + +Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : + numLEDs(n), numBytes(n * 3), pin(p), brightness(0), + pixels(NULL), type(t), endTime(0) +#ifdef __AVR__ + ,port(portOutputRegister(digitalPinToPort(p))), + pinMask(digitalPinToBitMask(p)) +#endif +{ + if((pixels = (uint8_t *)malloc(numBytes))) { + memset(pixels, 0, numBytes); + } + if(t & NEO_GRB) { // GRB vs RGB; might add others if needed + rOffset = 1; + gOffset = 0; + bOffset = 2; + } else if (t & NEO_BRG) { + rOffset = 1; + gOffset = 2; + bOffset = 0; + } else { + rOffset = 0; + gOffset = 1; + bOffset = 2; + } + +} + +Adafruit_NeoPixel::~Adafruit_NeoPixel() { + if(pixels) free(pixels); + pinMode(pin, INPUT); +} + +void Adafruit_NeoPixel::begin(void) { + pinMode(pin, OUTPUT); + digitalWrite(pin, LOW); +} + +void Adafruit_NeoPixel::show(void) { + + if(!pixels) return; + + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while(!canShow()); + // endTime is a private member (rather than global var) so that mutliple + // instances on different pins can be quickly issued in succession (each + // instance doesn't delay the next). + + // In order to make this code runtime-configurable to work with any pin, + // SBI/CBI instructions are eschewed in favor of full PORT writes via the + // OUT or ST instructions. It relies on two facts: that peripheral + // functions (such as PWM) take precedence on output pins, so our PORT- + // wide writes won't interfere, and that interrupts are globally disabled + // while data is being issued to the LEDs, so no other code will be + // accessing the PORT. The code takes an initial 'snapshot' of the PORT + // state, computes 'pin high' and 'pin low' values, and writes these back + // to the PORT register as needed. + + noInterrupts(); // Need 100% focus on instruction timing + +#ifdef __AVR__ + + volatile uint16_t + i = numBytes; // Loop counter + volatile uint8_t + *ptr = pixels, // Pointer to next byte + b = *ptr++, // Current byte value + hi, // PORT w/output bit set high + lo; // PORT w/output bit set low + + // Hand-tuned assembly code issues data to the LED drivers at a specific + // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) + // for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The + // datastream timing for the LED drivers allows a little wiggle room each + // way (listed in the datasheets), so the conditions for compiling each + // case are set up for a range of frequencies rather than just the exact + // 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on + // devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based + // on the datasheet figures and have not been extensively tested outside + // the canonical 8/12/16 MHz speeds; there's no guarantee these will work + // close to the extremes (or possibly they could be pushed further). + // Keep in mind only one CPU speed case actually gets compiled; the + // resulting program isn't as massive as it might look from source here. + +// 8 MHz(ish) AVR --------------------------------------------------------- +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) + +#ifdef NEO_KHZ400 + if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream +#endif + + volatile uint8_t n1, n2 = 0; // First, next bits out + + // Squeezing an 800 KHz stream out of an 8 MHz chip requires code + // specific to each PORT register. At present this is only written + // to work with pins on PORTD or PORTB, the most likely use case -- + // this covers all the pins on the Adafruit Flora and the bulk of + // digital pins on the Arduino Pro 8 MHz (keep in mind, this code + // doesn't even get compiled for 16 MHz boards like the Uno, Mega, + // Leonardo, etc., so don't bother extending this out of hand). + // Additional PORTs could be added if you really need them, just + // duplicate the else and loop and change the PORT. Each add'l + // PORT will require about 150(ish) bytes of program space. + + // 10 instruction clocks per bit: HHxxxxxLLL + // OUT instructions: ^ ^ ^ (T=0,2,7) + +#ifdef PORTD // PORTD isn't present on ATtiny85, etc. + + if(port == &PORTD) { + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + // Dirty trick: RJMPs proceeding to the next instruction are used + // to delay two clock cycles in one instruction word (rather than + // using two NOPs). This was necessary in order to squeeze the + // loop down to exactly 64 words -- the maximum possible for a + // relative branch. + + asm volatile( + "headD:" "\n\t" // Clk Pseudocode + // Bit 7: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 6: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 5: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 4: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 3: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 2: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 1: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "brne headD" "\n" // 2 while(i) (Z flag set above) + : [byte] "+r" (b), + [n1] "+r" (n1), + [n2] "+r" (n2), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + + } else if(port == &PORTB) { + +#endif // PORTD + + // Same as above, just switched to PORTB and stripped of comments. + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + asm volatile( + "headB:" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 6" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 5" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 4" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 3" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 2" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 1" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 0" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "brne headB" "\n" + : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + +#ifdef PORTD + } // endif PORTB +#endif + +#ifdef NEO_KHZ400 + } else { // end 800 KHz, do 400 KHz + + // Timing is more relaxed; unrolling the inner loop for each bit is + // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out + // of need but just to trim the code size down a little. + // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical + // to the 800-on-16 code later -- the hi/lo timing between WS2811 and + // WS2812 is not simply a 2:1 scale! + + // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "dec %[bit]" "\n\t" // 1 bit-- (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); + } +#endif + +// 12 MHz(ish) AVR -------------------------------------------------------- +#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) + +#ifdef NEO_KHZ400 + if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream +#endif + + // In the 12 MHz case, an optimized 800 KHz datastream (no dead time + // between bytes) requires a PORT-specific loop similar to the 8 MHz + // code (but a little more relaxed in this case). + + // 15 instruction clocks per bit: HHHHxxxxxxLLLLL + // OUT instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next; + +#ifdef PORTD + + if(port == &PORTD) { + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Don't "optimize" the OUT calls into the bitTime subroutine; + // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! + asm volatile( + "headD:" "\n\t" // (T = 0) + "out %[port], %[hi]" "\n\t" // (T = 1) + "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 6 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 5 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 4 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 3 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 2 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 1 + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) + "rjmp .+0" "\n\t" // 2 nop nop (T = 3) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) + "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) + "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) + "rjmp doneD" "\n\t" + "bitTimeD:" "\n\t" // nop nop nop (T = 4) + "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) + "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "ret" "\n\t" // 4 nop nop nop nop (T = 15) + "doneD:" "\n" + : [byte] "+r" (b), + [next] "+r" (next), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + + } else if(port == &PORTB) { + +#endif // PORTD + + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Same as above, just set for PORTB & stripped of comments + asm volatile( + "headB:" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port] , %[hi]" "\n\t" + "rjmp .+0" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "out %[port] , %[next]" "\n\t" + "mov %[next] , %[lo]" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[next] , %[hi]" "\n\t" + "nop" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "brne headB" "\n\t" + "rjmp doneB" "\n\t" + "bitTimeB:" "\n\t" + "out %[port], %[next]" "\n\t" + "mov %[next], %[lo]" "\n\t" + "rol %[byte]" "\n\t" + "sbrc %[byte], 7" "\n\t" + "mov %[next], %[hi]" "\n\t" + "nop" "\n\t" + "out %[port], %[lo]" "\n\t" + "ret" "\n\t" + "doneB:" "\n" + : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + +#ifdef PORTD + } +#endif + +#ifdef NEO_KHZ400 + } else { // 400 KHz + + // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,6,15) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head30:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) + "rjmp .+0" "\n\t" // 2 nop nop (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "nop" "\n\t" // 1 nop (T = 15) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) + "rjmp .+0" "\n\t" // 2 nop nop (T = 19) + "dec %[bit]" "\n\t" // 1 bit-- (T = 20) + "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) + "rjmp .+0" "\n\t" // 2 nop nop (T = 24) + "rjmp .+0" "\n\t" // 2 nop nop (T = 26) + "rjmp .+0" "\n\t" // 2 nop nop (T = 28) + "rjmp head30" "\n\t" // 2 -> head30 (next bit out) + "nextbyte30:" "\n\t" // (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) + "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); + } +#endif + +// 16 MHz(ish) AVR -------------------------------------------------------- +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) + +#ifdef NEO_KHZ400 + if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream +#endif + + // WS2811 and WS2812 have different hi/lo duty cycles; this is + // similar but NOT an exact copy of the prior 400-on-8 code. + + // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL + // ST instructions: ^ ^ ^ (T=0,5,13) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "dec %[bit]" "\n\t" // 1 bit-- (T = 5) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + +#ifdef NEO_KHZ400 + } else { // 400 KHz + + // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. + + // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,8,20) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head40:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "rjmp .+0" "\n\t" // 2 nop nop (T = 8) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp .+0" "\n\t" // 2 nop nop (T = 20) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) + "dec %[bit]" "\n\t" // 1 bit-- (T = 25) + "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) + "nop" "\n\t" // 1 nop (T = 28) + "rjmp .+0" "\n\t" // 2 nop nop (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "rjmp .+0" "\n\t" // 2 nop nop (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "rjmp .+0" "\n\t" // 2 nop nop (T = 38) + "rjmp head40" "\n\t" // 2 -> head40 (next bit out) + "nextbyte40:" "\n\t" // (T = 27) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) + "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + } +#endif + +#else + #error "CPU SPEED NOT SUPPORTED" +#endif + +#elif defined(__arm__) + +#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 +#define CYCLES_800_T0H (F_CPU / 4000000) +#define CYCLES_800_T1H (F_CPU / 1250000) +#define CYCLES_800 (F_CPU / 800000) +#define CYCLES_400_T0H (F_CPU / 2000000) +#define CYCLES_400_T1H (F_CPU / 833333) +#define CYCLES_400 (F_CPU / 400000) + + uint8_t *p = pixels, + *end = p + numBytes, pix, mask; + volatile uint8_t *set = portSetRegister(pin), + *clr = portClearRegister(pin); + uint32_t cyc; + + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + +#ifdef NEO_KHZ400 + if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream +#endif + cyc = ARM_DWT_CYCCNT + CYCLES_800; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); + cyc = ARM_DWT_CYCCNT; + *set = 1; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); + } + *clr = 1; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); +#ifdef NEO_KHZ400 + } else { // 400 kHz bitstream + cyc = ARM_DWT_CYCCNT + CYCLES_400; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + cyc = ARM_DWT_CYCCNT; + *set = 1; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); + } + *clr = 1; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + } +#endif + + + + + +#elif defined(__MKL26Z64__) // Teensy-LC + +#if F_CPU == 48000000 + uint8_t *p = pixels, + pix, count, dly, + bitmask = digitalPinToBitMask(pin); + volatile uint8_t *reg = portSetRegister(pin); + uint32_t num = numBytes; + asm volatile( + "L%=_begin:" "\n\t" + "ldrb %[pix], [%[p], #0]" "\n\t" + "lsl %[pix], #24" "\n\t" + "movs %[count], #7" "\n\t" + "L%=_loop:" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_loop_one" "\n\t" + "L%=_loop_zero:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0L" "\n\t" + "b L%=_next" "\n\t" + "L%=_loop_one:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_next:" "\n\t" + "sub %[count], #1" "\n\t" + "bne L%=_loop" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_last_one" "\n\t" + "L%=_last_zero:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_last_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #10" "\n\t" + "L%=_last_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0L" "\n\t" + "b L%=_repeat" "\n\t" + "L%=_last_one:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_last_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #1" "\n\t" + "L%=_last_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_repeat:" "\n\t" + "add %[p], #1" "\n\t" + "sub %[num], #1" "\n\t" + "bne L%=_begin" "\n\t" + "L%=_done:" "\n\t" + : [p] "+r" (p), + [pix] "=&r" (pix), + [count] "=&r" (count), + [dly] "=&r" (dly), + [num] "+r" (num) + : [bitmask] "r" (bitmask), + [reg] "r" (reg) + ); +#else +#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" +#endif + + +#else // Arduino Due + + #define SCALE VARIANT_MCK / 2UL / 1000000UL + #define INST (2UL * F_CPU / VARIANT_MCK) + #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) + #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) + #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) + #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) + #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) + #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) + + int pinMask, time0, time1, period, t; + Pio *port; + volatile WoReg *portSet, *portClear, *timeValue, *timeReset; + uint8_t *p, *end, pix, mask; + + pmc_set_writeprotect(false); + pmc_enable_periph_clk((uint32_t)TC3_IRQn); + TC_Configure(TC1, 0, + TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); + TC_Start(TC1, 0); + + pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into + port = g_APinDescription[pin].pPort; // declarations above. Want to + portSet = &(port->PIO_SODR); // burn a few cycles after + portClear = &(port->PIO_CODR); // starting timer to minimize + timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. + timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + +#ifdef NEO_KHZ400 + if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream +#endif + time0 = TIME_800_0; + time1 = TIME_800_1; + period = PERIOD_800; +#ifdef NEO_KHZ400 + } else { // 400 KHz bitstream + time0 = TIME_400_0; + time1 = TIME_400_1; + period = PERIOD_400; + } +#endif + + for(t = time0;; t = time0) { + if(pix & mask) t = time1; + while(*timeValue < period); + *portSet = pinMask; + *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; + while(*timeValue < t); + *portClear = pinMask; + if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes + if(p >= end) break; // idle time to minimize inter-byte delays. + pix = *p++; + mask = 0x80; + } + } + while(*timeValue < period); // Wait for last bit + TC_Stop(TC1, 0); + +#endif // end Arduino Due + +#endif // end Architecture select + + interrupts(); + endTime = micros(); // Save EOD time for latch on next call +} + +// Set the output pin number +void Adafruit_NeoPixel::setPin(uint8_t p) { + pinMode(pin, INPUT); + pin = p; + pinMode(p, OUTPUT); + digitalWrite(p, LOW); +#ifdef __AVR__ + port = portOutputRegister(digitalPinToPort(p)); + pinMask = digitalPinToBitMask(p); +#endif +} + +// Set pixel color from separate R,G,B components: +void Adafruit_NeoPixel::setPixelColor( + uint16_t n, uint8_t r, uint8_t g, uint8_t b) { + if(n < numLEDs) { + if(brightness) { // See notes in setBrightness() + r = (r * brightness) >> 8; + g = (g * brightness) >> 8; + b = (b * brightness) >> 8; + } + uint8_t *p = &pixels[n * 3]; + p[rOffset] = r; + p[gOffset] = g; + p[bOffset] = b; + } +} + +// Set pixel color from 'packed' 32-bit RGB color: +void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { + if(n < numLEDs) { + uint8_t + r = (uint8_t)(c >> 16), + g = (uint8_t)(c >> 8), + b = (uint8_t)c; + if(brightness) { // See notes in setBrightness() + r = (r * brightness) >> 8; + g = (g * brightness) >> 8; + b = (b * brightness) >> 8; + } + uint8_t *p = &pixels[n * 3]; + p[rOffset] = r; + p[gOffset] = g; + p[bOffset] = b; + } +} + +// Convert separate R,G,B into packed 32-bit RGB color. +// Packed format is always RGB, regardless of LED strand color order. +uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { + return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +// Query color from previously-set pixel (returns packed 32-bit RGB value) +uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { + if(n >= numLEDs) { + // Out of bounds, return no color. + return 0; + } + uint8_t *p = &pixels[n * 3]; + uint32_t c = ((uint32_t)p[rOffset] << 16) | + ((uint32_t)p[gOffset] << 8) | + (uint32_t)p[bOffset]; + // Adjust this back up to the true color, as setting a pixel color will + // scale it back down again. + if(brightness) { // See notes in setBrightness() + //Cast the color to a byte array + uint8_t * c_ptr =reinterpret_cast(&c); + c_ptr[0] = (c_ptr[0] << 8)/brightness; + c_ptr[1] = (c_ptr[1] << 8)/brightness; + c_ptr[2] = (c_ptr[2] << 8)/brightness; + } + return c; // Pixel # is out of bounds +} + +// Returns pointer to pixels[] array. Pixel data is stored in device- +// native format and is not translated here. Application will need to be +// aware whether pixels are RGB vs. GRB and handle colors appropriately. +uint8_t *Adafruit_NeoPixel::getPixels(void) const { + return pixels; +} + +uint16_t Adafruit_NeoPixel::numPixels(void) const { + return numLEDs; +} + +// Adjust output brightness; 0=darkest (off), 255=brightest. This does +// NOT immediately affect what's currently displayed on the LEDs. The +// next call to show() will refresh the LEDs at this level. However, +// this process is potentially "lossy," especially when increasing +// brightness. The tight timing in the WS2811/WS2812 code means there +// aren't enough free cycles to perform this scaling on the fly as data +// is issued. So we make a pass through the existing color data in RAM +// and scale it (subsequent graphics commands also work at this +// brightness level). If there's a significant step up in brightness, +// the limited number of steps (quantization) in the old data will be +// quite visible in the re-scaled version. For a non-destructive +// change, you'll need to re-render the full strip data. C'est la vie. +void Adafruit_NeoPixel::setBrightness(uint8_t b) { + // Stored brightness value is different than what's passed. + // This simplifies the actual scaling math later, allowing a fast + // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, + // adding 1 here may (intentionally) roll over...so 0 = max brightness + // (color values are interpreted literally; no scaling), 1 = min + // brightness (off), 255 = just below max brightness. + uint8_t newBrightness = b + 1; + if(newBrightness != brightness) { // Compare against prior value + // Brightness has changed -- re-scale existing data in RAM + uint8_t c, + *ptr = pixels, + oldBrightness = brightness - 1; // De-wrap old brightness value + uint16_t scale; + if(oldBrightness == 0) scale = 0; // Avoid /0 + else if(b == 255) scale = 65535 / oldBrightness; + else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; + for(uint16_t i=0; i> 8; + } + brightness = newBrightness; + } +} + +//Return the brightness value +uint8_t Adafruit_NeoPixel::getBrightness(void) const { + return brightness - 1; +} + +void Adafruit_NeoPixel::clear() { + memset(pixels, 0, numBytes); +} diff --git a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h new file mode 100755 index 0000000..264c199 --- /dev/null +++ b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h @@ -0,0 +1,97 @@ +/*-------------------------------------------------------------------- + This file is part of the Adafruit NeoPixel library. + + NeoPixel is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + NeoPixel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with NeoPixel. If not, see + . + --------------------------------------------------------------------*/ + +#ifndef ADAFRUIT_NEOPIXEL_H +#define ADAFRUIT_NEOPIXEL_H + +#if (ARDUINO >= 100) + #include +#else + #include + #include +#endif + +// 'type' flags for LED pixels (third parameter to constructor): +#define NEO_RGB 0x00 // Wired for RGB data order +#define NEO_GRB 0x01 // Wired for GRB data order +#define NEO_BRG 0x04 + +#define NEO_COLMASK 0x01 +#define NEO_KHZ800 0x02 // 800 KHz datastream +#define NEO_SPDMASK 0x02 +// Trinket flash space is tight, v1 NeoPixels aren't handled by default. +// Remove the ifndef/endif to add support -- but code will be bigger. +// Conversely, can comment out the #defines to save space on other MCUs. +#ifndef __AVR_ATtiny85__ +#define NEO_KHZ400 0x00 // 400 KHz datastream +#endif + +class Adafruit_NeoPixel { + + public: + + // Constructor: number of LEDs, pin number, LED type + Adafruit_NeoPixel(uint16_t n, uint8_t p=6, uint8_t t=NEO_GRB + NEO_KHZ800); + ~Adafruit_NeoPixel(); + + void + begin(void), + show(void), + setPin(uint8_t p), + setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), + setPixelColor(uint16_t n, uint32_t c), + setBrightness(uint8_t), + clear(); + uint8_t + *getPixels(void) const, + getBrightness(void) const; + uint16_t + numPixels(void) const; + static uint32_t + Color(uint8_t r, uint8_t g, uint8_t b); + uint32_t + getPixelColor(uint16_t n) const; + inline bool + canShow(void) { return (micros() - endTime) >= 50L; } + + private: + + const uint16_t + numLEDs, // Number of RGB LEDs in strip + numBytes; // Size of 'pixels' buffer below + uint8_t + pin, // Output pin number + brightness, + *pixels, // Holds LED color values (3 bytes each) + rOffset, // Index of red byte within each 3-byte pixel + gOffset, // Index of green byte + bOffset; // Index of blue byte + const uint8_t + type; // Pixel flags (400 vs 800 KHz, RGB vs GRB color) + uint32_t + endTime; // Latch timing reference +#ifdef __AVR__ + const volatile uint8_t + *port; // Output PORT register + uint8_t + pinMask; // Output PORT bitmask +#endif + +}; + +#endif // ADAFRUIT_NEOPIXEL_H diff --git a/libraries/Adafruit_NeoPixel/COPYING b/libraries/Adafruit_NeoPixel/COPYING new file mode 100755 index 0000000..7dcf8e8 --- /dev/null +++ b/libraries/Adafruit_NeoPixel/COPYING @@ -0,0 +1,794 @@ + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + + +LGPL ADDENDUM: + + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/libraries/Adafruit_NeoPixel/README.md b/libraries/Adafruit_NeoPixel/README.md new file mode 100755 index 0000000..2eeda47 --- /dev/null +++ b/libraries/Adafruit_NeoPixel/README.md @@ -0,0 +1,12 @@ +Adafruit NeoPixel library +========================= + +Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield]. + +After downloading, rename folder to 'Adafruit_NeoPixel' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch. + +[flora]: http://adafruit.com/products/1060 +[strip]: http://adafruit.com/products/1138 +[pixel]: http://adafruit.com/products/1312 +[stick]: http://adafruit.com/products/1426 +[shield]: http://adafruit.com/products/1430 diff --git a/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino b/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino new file mode 100755 index 0000000..45d9c6a --- /dev/null +++ b/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino @@ -0,0 +1,165 @@ +// This is a demonstration on how to use an input device to trigger changes on your neo pixels. +// You should wire a momentary push button to connect from ground to a digital IO pin. When you +// press the button it will change to a new pixel animation. Note that you need to press the +// button once to start the first animation! + +#include + +#define BUTTON_PIN 2 // Digital IO pin connected to the button. This will be + // driven with a pull-up resistor so the switch should + // pull the pin to ground momentarily. On a high -> low + // transition the button press logic will execute. + +#define PIXEL_PIN 6 // Digital IO pin connected to the NeoPixels. + +#define PIXEL_COUNT 16 + +// Parameter 1 = number of pixels in strip, neopixel stick has 8 +// Parameter 2 = pin number (most are valid) +// Parameter 3 = pixel type flags, add together as needed: +// NEO_RGB Pixels are wired for RGB bitstream +// NEO_GRB Pixels are wired for GRB bitstream, correct for neopixel stick +// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels) +// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick +Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); + +bool oldState = HIGH; +int showType = 0; + +void setup() { + pinMode(BUTTON_PIN, INPUT_PULLUP); + strip.begin(); + strip.show(); // Initialize all pixels to 'off' +} + +void loop() { + // Get current button state. + bool newState = digitalRead(BUTTON_PIN); + + // Check if state changed from high to low (button press). + if (newState == LOW && oldState == HIGH) { + // Short delay to debounce button. + delay(20); + // Check if button is still low after debounce. + newState = digitalRead(BUTTON_PIN); + if (newState == LOW) { + showType++; + if (showType > 9) + showType=0; + startShow(showType); + } + } + + // Set the last button state to the old state. + oldState = newState; +} + +void startShow(int i) { + switch(i){ + case 0: colorWipe(strip.Color(0, 0, 0), 50); // Black/off + break; + case 1: colorWipe(strip.Color(255, 0, 0), 50); // Red + break; + case 2: colorWipe(strip.Color(0, 255, 0), 50); // Green + break; + case 3: colorWipe(strip.Color(0, 0, 255), 50); // Blue + break; + case 4: theaterChase(strip.Color(127, 127, 127), 50); // White + break; + case 5: theaterChase(strip.Color(127, 0, 0), 50); // Red + break; + case 6: theaterChase(strip.Color( 0, 0, 127), 50); // Blue + break; + case 7: rainbow(20); + break; + case 8: rainbowCycle(20); + break; + case 9: theaterChaseRainbow(50); + break; + } +} + +// Fill the dots one after the other with a color +void colorWipe(uint32_t c, uint8_t wait) { + for(uint16_t i=0; i +#include + +// Which pin on the Arduino is connected to the NeoPixels? +// On a Trinket or Gemma we suggest changing this to 1 +#define PIN 6 + +// How many NeoPixels are attached to the Arduino? +#define NUMPIXELS 16 + +// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. +// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest +// example for more information on possible values. +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); + +int delayval = 500; // delay for half a second + +void setup() { + // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket +#if defined (__AVR_ATtiny85__) + if (F_CPU == 16000000) clock_prescale_set(clock_div_1); +#endif + // End of trinket special code + + pixels.begin(); // This initializes the NeoPixel library. +} + +void loop() { + + // For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one. + + for(int i=0;i +#include + +#define PIN 6 + +// Parameter 1 = number of pixels in strip +// Parameter 2 = Arduino pin number (most are valid) +// Parameter 3 = pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); + +// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across +// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input +// and minimize distance between Arduino and first pixel. Avoid connecting +// on a live circuit...if you must, connect GND first. + +void setup() { + // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket +#if defined (__AVR_ATtiny85__) + if (F_CPU == 16000000) clock_prescale_set(clock_div_1); +#endif + // End of trinket special code + + + strip.begin(); + strip.show(); // Initialize all pixels to 'off' +} + +void loop() { + // Some example procedures showing how to display to the pixels: + colorWipe(strip.Color(255, 0, 0), 50); // Red + colorWipe(strip.Color(0, 255, 0), 50); // Green + colorWipe(strip.Color(0, 0, 255), 50); // Blue + // Send a theater pixel chase in... + theaterChase(strip.Color(127, 127, 127), 50); // White + theaterChase(strip.Color(127, 0, 0), 50); // Red + theaterChase(strip.Color( 0, 0, 127), 50); // Blue + + rainbow(20); + rainbowCycle(20); + theaterChaseRainbow(50); +} + +// Fill the dots one after the other with a color +void colorWipe(uint32_t c, uint8_t wait) { + for(uint16_t i=0; i +sentence=Arduino library for controlling single-wire-based LED pixels and strip. +paragraph=Arduino library for controlling single-wire-based LED pixels and strip. +category=Display +url=https://github.com/adafruit/Adafruit_NeoPixel +architectures=* diff --git a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino new file mode 100644 index 0000000..d54e599 --- /dev/null +++ b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino @@ -0,0 +1,164 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Created by Henrik Ekblad + * + * DESCRIPTION + * Parking sensor using a neopixel led ring and distance sensor (HC-SR04). + * Configure the digital pins used for distance sensor and neopixels below. + * NOTE! Remeber to feed leds and distance sensor serparatly from your Arduino. + * It will probably not survive feeding more than a couple of LEDs. You + * can also adjust intesity below to reduce the power requirements. + * + * Sends parking status to the controller as a DOOR sensor if SEND_STATUS_TO_CONTROLLER + * is defined below. You can also use this _standalone_ without any radio by + * removing the SEND_STATUS_TO_CONTROLLER define. + */ + +#define SEND_STATUS_TO_CONTROLLER // Put a comment on this line for standalone mode + +#include +#include + +#ifdef SEND_STATUS_TO_CONTROLLER +#include +#include +#endif + +#define NEO_PIN 4 // NeoPixels input pin + +#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor. +#define ECHO_PIN 5 // Arduino pin tied to echo pin on the ultrasonic sensor. + +#define NUMPIXELS 24 // Number of nexpixels in ring/strip +#define MAX_INTESITY 20 // Intesity of leds (in percentage). Remeber more intesity requires more power. + +// The maximum rated measuring range for the HC-SR04 is about 400-500cm. +#define MAX_DISTANCE 100 // Max distance we want to start indicating green (in cm) +#define PANIC_DISTANCE 5 // Mix distance we red warning indication should be active (in cm) +#define PARKED_DISTANCE 20 // Distance when "parked signal" should be sent to controller (in cm) + +// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest +// example for more information on possible values. + +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ400); + +NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance. + +#ifdef SEND_STATUS_TO_CONTROLLER +#define CHILD_ID 1 +MySensor gw; +MyMessage msg(CHILD_ID,V_TRIPPED); +int oldParkedStatus=-1; +int sendInterval = 5000; // Send park status at maximum every 5 second. +unsigned long lastSend; +#endif + +int blinkInterval = 100; // blink interval (milliseconds) +unsigned long lastBlinkPeriod; +bool blinkColor = true; + +// To make a fading motion on the led ring/tape we only move one pixel/distDebounce time +int distDebounce = 30; +unsigned long lastDebouncePeriod; +int numLightPixels=0; +int skipZero=0; + +void setup() { + Serial.begin(115200); + Serial.println("Starting distance sensor"); + pixels.begin(); // This initializes the NeoPixel library. + Serial.println("Neopixels initialized"); +#ifdef SEND_STATUS_TO_CONTROLLER + gw.begin(); + gw.sendSketchInfo("Parking Sensor", "1.0"); + gw.present(CHILD_ID, S_DOOR, "Parking Status"); +#endif +} + +void loop() { + unsigned long now = millis(); + + int fullDist = sonar.ping_cm(); +// Serial.println(fullDist); + int displayDist = min(fullDist, MAX_DISTANCE); + if (displayDist == 0 && skipZero<10) { + // Try to filter zero readings + skipZero++; + return; + } + // Check if it is time to alter the leds + if (now-lastDebouncePeriod > distDebounce) { + lastDebouncePeriod = now; + +#ifdef SEND_STATUS_TO_CONTROLLER + // Update parked status + int parked = displayDist != 0 && displayDist sendInterval) { + if (parked) + Serial.println("Car Parked"); + else + Serial.println("Car Gone"); + gw.send(msg.set(parked)); + oldParkedStatus = parked; + lastSend = now; + } +#endif + + if (displayDist == 0) { + // No reading from sensor, assume no object found + numLightPixels--; + } else { + skipZero = 0; + int newLightPixels = NUMPIXELS - (NUMPIXELS*(displayDist-PANIC_DISTANCE)/MAX_DISTANCE); + if (newLightPixels>numLightPixels) { + // Fast raise + numLightPixels += max((newLightPixels - numLightPixels) / 2, 1); + } else if (newLightPixels=NUMPIXELS) { + // Do some intense red blinking + if (now-lastBlinkPeriod > blinkInterval) { + blinkColor = !blinkColor; + lastBlinkPeriod = now; + } + for(int i=0;i Date: Sun, 2 Aug 2015 13:15:11 +0200 Subject: [PATCH 172/660] OTA stability - add OTA-ongoing check - reduce OTA code size --- libraries/MySensors/MySensor.cpp | 62 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 4f3e930..bdab9c2 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -522,7 +522,7 @@ boolean MySensor::process() { #ifdef MY_OTA_FIRMWARE_FEATURE unsigned long enter = hw_millis(); if (fwUpdateOngoing && (enter - fwLastRequestTime > MY_OTA_RETRY_DELAY)) { - if (fwRetry == 0) { + if (!fwRetry) { debug(PSTR("fw upd fail\n")); // Give up. We have requested MY_OTA_RETRY times without any packet in return. fwUpdateOngoing = false; @@ -746,38 +746,38 @@ boolean MySensor::process() { return false; } else debug(PSTR("fw update skipped\n")); } else if (type == ST_FIRMWARE_RESPONSE) { - // Save block to flash - debug(PSTR("fw block %d\n"), fwBlock); - // extract FW block - ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data; - // write to flash - flash.writeBytes( ((fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); - // wait until flash written - while ( flash.busy() ); - fwBlock--; - if (!fwBlock) { - // We're finished! Do a checksum and reboot. - if (isValidFirmware()) { - debug(PSTR("fw checksum ok\n")); - // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - flash.writeBytes(0, "FLXIMG:", 7); - // FW size in flash - uint16_t fwsize = FIRMWARE_BLOCK_SIZE * fc.blocks; - flash.writeByte(7, fwsize >> 8); - flash.writeByte(8, fwsize); - // end of header - flash.writeByte(9, ':'); - // Write the new firmware config to eeprom - hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); - hw_reboot(); - } else { - debug(PSTR("fw checksum fail\n")); + if (fwUpdateOngoing) { + // Save block to flash + debug(PSTR("fw block %d\n"), fwBlock); + // extract FW block + ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data; + // write to flash + flash.writeBytes( ((fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + // wait until flash written + while ( flash.busy() ); + fwBlock--; + if (!fwBlock) { + // We're finished! Do a checksum and reboot. fwUpdateOngoing = false; - } + if (isValidFirmware()) { + debug(PSTR("fw checksum ok\n")); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + uint16_t fwsize = FIRMWARE_BLOCK_SIZE * fc.blocks; + uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; + flash.writeBytes(0, OTAbuffer, 10); + // Write the new firmware config to eeprom + hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hw_reboot(); + } else { + debug(PSTR("fw checksum fail\n")); + } + } + // reset flags + fwRetry = MY_OTA_RETRY+1; + fwLastRequestTime = 0; + } else { + debug(PSTR("No fw update ongoing\n")); } - // reset flags - fwRetry = MY_OTA_RETRY+1; - fwLastRequestTime = 0; return false; } From d98bacb56764428f5871a69bd887f5e9c37972dd Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 3 Aug 2015 20:22:30 +0200 Subject: [PATCH 173/660] Fix EthernetGateway connect problem. Reported by Carh H here: http://forum.mysensors.org/topic/1736/release-1-5-and-ethernet-gateway --- .../MySensors/examples/EthernetGateway/EthernetGateway.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index fe19206..5148648 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -135,7 +135,7 @@ void output(const char *fmt, ... ) { vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); va_end (args); Serial.print(serialBuffer); - client.write(serialBuffer); + server.write(serialBuffer); } void setup() From f7204cfcab106a079a09606205a223a0d45e697a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 3 Aug 2015 22:38:29 +0200 Subject: [PATCH 174/660] Enable OTA wait period after each transmission, if A1 is held low during bootup --- .../SensebenderMicro/SensebenderMicro.ino | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 9ac53de..64ded83 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -29,6 +29,12 @@ * * Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below) * + * + * Version 1.3 - Thomas Bowman Mørch + * Improved transmission logic, eliminating spurious transmissions (when temperatuere / humidity fluctuates 1 up and down between measurements) + * + * Added OTA boot mode, need to hold A1 low while applying power. (uses slightly more power as it's waiting for bootloader messages) + * */ @@ -49,7 +55,7 @@ // Uncomment the line below, to transmit battery voltage as a normal sensor value //#define BATT_SENSOR 199 -#define RELEASE "1.2" +#define RELEASE "1.3" #define AVERAGES 2 @@ -60,6 +66,9 @@ // How many milli seconds between each measurement #define MEASURE_INTERVAL 60000 +// How many milli seconds should we wait for OTA? +#define OTA_WAIT_PERIOD 1000 + // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller #define FORCE_TRANSMIT_INTERVAL 30 @@ -73,6 +82,7 @@ // Pin definitions #define TEST_PIN A0 +#define OTA_ENABLE A1 #define LED_PIN A2 #define ATSHA204_PIN 17 // A3 @@ -97,6 +107,8 @@ int measureCount = 0; int sendBattery = 0; boolean isMetric = true; boolean highfreq = true; +boolean ota_enabled = false; +boolean transmission_occured = false; // Storage of old measurements float lastTemperature = -100; @@ -126,11 +138,17 @@ void setup() { digitalWrite(TEST_PIN, HIGH); // Enable pullup if (!digitalRead(TEST_PIN)) testMode(); + pinMode(OTA_ENABLE, INPUT); + digitalWrite(OTA_ENABLE, HIGH); + if (!digitalRead(OTA_ENABLE)) ota_enabled = true; + // Make sure that ATSHA204 is not floating pinMode(ATSHA204_PIN, INPUT); digitalWrite(ATSHA204_PIN, HIGH); digitalWrite(TEST_PIN,LOW); + digitalWrite(OTA_ENABLE, LOW); // remove pullup, save some power. + digitalWrite(LED_PIN, HIGH); #ifdef NODE_ADDRESS @@ -169,13 +187,14 @@ void setup() { * ***********************************************/ void loop() { + measureCount ++; sendBattery ++; bool forceTransmit = false; - + transmission_occured = false; if ((measureCount == 5) && highfreq) { -// clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. + clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. highfreq = false; } @@ -192,7 +211,11 @@ void loop() { sendBattLevel(forceTransmit); // Not needed to send battery info that often sendBattery = 0; } - + + if (ota_enabled & transmission_occured) { + gw.wait(OTA_WAIT_PERIOD); + } + gw.sleep(MEASURE_INTERVAL); } @@ -235,6 +258,7 @@ void sendTempHumidityMeasurements(bool force) gw.send(msgHum.set(humidity)); lastTemperature = temperature; lastHumidity = humidity; + transmission_occured = true; } } @@ -263,6 +287,7 @@ void sendBattLevel(bool force) long percent = vcc / 14.0; gw.sendBatteryLevel(percent); + transmission_occured = true; } } @@ -271,7 +296,7 @@ void sendBattLevel(bool force) * Internal battery ADC measuring * *******************************************/ -long readVcc() {/* +long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) @@ -295,7 +320,7 @@ long readVcc() {/* result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts - */ + } /**************************************************** From 8e73752a037a4885ffa59d657954386ae22b46e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 3 Aug 2015 22:56:49 +0200 Subject: [PATCH 175/660] changed wait period to 300 mili seconds (@tekka recons 100-200mSeconds is enough, just want to be on the safe side, added serial debug string to indicate OTA FW updates enabled --- .../examples/SensebenderMicro/SensebenderMicro.ino | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 64ded83..87d0424 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -67,7 +67,7 @@ #define MEASURE_INTERVAL 60000 // How many milli seconds should we wait for OTA? -#define OTA_WAIT_PERIOD 1000 +#define OTA_WAIT_PERIOD 300 // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller #define FORCE_TRANSMIT_INTERVAL 30 @@ -140,7 +140,9 @@ void setup() { pinMode(OTA_ENABLE, INPUT); digitalWrite(OTA_ENABLE, HIGH); - if (!digitalRead(OTA_ENABLE)) ota_enabled = true; + if (!digitalRead(OTA_ENABLE)) { + ota_enabled = true; + } // Make sure that ATSHA204 is not floating pinMode(ATSHA204_PIN, INPUT); @@ -178,6 +180,8 @@ void setup() { raHum.clear(); sendTempHumidityMeasurements(false); sendBattLevel(false); + if (ota_enabled) Serial.println("OTA FW update enabled"); + } From 3cf4bb65af79f810f2bd1ec9d18c4079718ba7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 3 Aug 2015 23:02:19 +0200 Subject: [PATCH 176/660] don't scale CPU Freq, if OTA FW Updates are enabled --- .../MySensors/examples/SensebenderMicro/SensebenderMicro.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino index 87d0424..e14f5a8 100644 --- a/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino +++ b/libraries/MySensors/examples/SensebenderMicro/SensebenderMicro.ino @@ -198,7 +198,7 @@ void loop() { transmission_occured = false; if ((measureCount == 5) && highfreq) { - clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. + if (!ota_enabled) clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power. highfreq = false; } From cb83bfbdb3ed32ef57040cff9954b390ec9a2528 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 4 Aug 2015 21:00:32 +0200 Subject: [PATCH 177/660] Inverse the default rx/tx/err led behaviour and introduce WITH_LEDS_BLINKING_INVERSE option in MyConfig. This allows easy inversing of led blink behavior depending on how the leds were connected. Introduce hw-macro for digitalWrite used by the LED blinking. --- libraries/MySensors/MyConfig.h | 9 ++++++++- libraries/MySensors/MyHwATMega328.h | 2 ++ libraries/MySensors/MySensor.cpp | 18 +++++++++--------- libraries/MySensors/MySensor.h | 8 ++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 098a1f9..88db782 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -53,7 +53,14 @@ // but now can be used in any sensor node. Also the LEDs can now be // disabled in the gateway. -// #define WITH_LEDS_BLINKING +//#define WITH_LEDS_BLINKING + +// The following setting allows you to inverse the blinking feature WITH_LEDS_BLINKING +// When WITH_LEDS_BLINKING_INVERSE is enabled LEDSs are normally turned on and switches +// off when blinking + +//#define WITH_LEDS_BLINKING_INVERSE + // default LEDs blinking period in milliseconds #define DEFAULT_LED_BLINK_PERIOD 300 diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 12698d4..9e42b55 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -57,6 +57,8 @@ do { \ // Define these as macros to save valuable space + +#define hw_digitalWrite(__pin, __value) (digitalWrite(__pin, __value)) #define hw_init() Serial.begin(BAUD_RATE) #define hw_watchdogReset() wdt_reset() #define hw_reboot() wdt_enable(WDTO_15MS); while (1) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index bdab9c2..9d6ecb8 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -107,33 +107,33 @@ void MySensor::handleLedsBlinking() { // do the actual blinking if(countRx && countRx != 255) { // switch led on - digitalWrite(pinRx, HIGH); + hw_digitalWrite(pinRx, LED_ON); } else if(!countRx) { // switching off - digitalWrite(pinRx, LOW); + hw_digitalWrite(pinRx, LED_OFF); } if(countRx != 255) --countRx; if(countTx && countTx != 255) { // switch led on - digitalWrite(pinTx, HIGH); + hw_digitalWrite(pinTx, LED_ON); } else if(!countTx) { // switching off - digitalWrite(pinTx, LOW); + hw_digitalWrite(pinTx, LED_OFF); } if(countTx != 255) --countTx; if(countErr && countErr != 255) { // switch led on - digitalWrite(pinEr, HIGH); + hw_digitalWrite(pinEr, LED_ON); } else if(!countErr) { // switching off - digitalWrite(pinEr, LOW); + hw_digitalWrite(pinEr, LED_OFF); } if(countErr != 255) --countErr; @@ -179,9 +179,9 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b pinMode(pinEr, OUTPUT); // Set initial state of leds - digitalWrite(pinRx, LOW); - digitalWrite(pinTx, LOW); - digitalWrite(pinEr, LOW); + hw_digitalWrite(pinRx, LED_OFF); + hw_digitalWrite(pinTx, LED_OFF); + hw_digitalWrite(pinEr, LED_OFF); // initialize counters countRx = 0; diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index abf7283..0a54987 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -52,6 +52,14 @@ typedef MyHwATMega328 MyHwDriver; #define debug(x,...) #endif +#ifdef WITH_LEDS_BLINKING_INVERSE +#define LED_ON 0x1 +#define LED_OFF 0x0 +#else +#define LED_ON 0x0 +#define LED_OFF 0x1 +#endif + // EEPROM start address for mysensors library data #define EEPROM_START 0 From 2343d8ae8fb72bdcab467b158eb77c09af6fda5d Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 4 Aug 2015 21:38:10 +0200 Subject: [PATCH 178/660] Added sendHeatbeat() Allow a sensor to send a "dummy" message to controller to say "I'm still alive!". The payload will be an incremental uint16. --- libraries/MySensors/MyMessage.h | 3 ++- libraries/MySensors/MySensor.cpp | 5 +++++ libraries/MySensors/MySensor.h | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 129801f..03a203c 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -146,7 +146,8 @@ typedef enum { I_BATTERY_LEVEL, I_TIME, I_VERSION, I_ID_REQUEST, I_ID_RESPONSE, I_INCLUSION_MODE, I_CONFIG, I_FIND_PARENT, I_FIND_PARENT_RESPONSE, I_LOG_MESSAGE, I_CHILDREN, I_SKETCH_NAME, I_SKETCH_VERSION, - I_REBOOT, I_GATEWAY_READY, I_REQUEST_SIGNING, I_GET_NONCE, I_GET_NONCE_RESPONSE + I_REBOOT, I_GATEWAY_READY, I_REQUEST_SIGNING, I_GET_NONCE, I_GET_NONCE_RESPONSE, + I_HEARTBEAT } mysensor_internal; diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 9d6ecb8..5558d6a 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -487,6 +487,11 @@ void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } +void MySensor::sendHeartbeat(void) { + sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT, false).set(heartbeat++)); + +} + void MySensor::present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 0a54987..9b9e8dd 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -219,6 +219,12 @@ class MySensor */ void sendBatteryLevel(uint8_t level, bool ack=false); + /** + * Send a heartbeat message (I'm alive!) to the gateway/controller. + * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on. + */ + void sendHeartbeat(void); + /** * Requests a value from gateway or some other sensor in the radio network. * Make sure to add callback-method in begin-method to handle request responses. @@ -373,6 +379,7 @@ class MySensor char convBuf[MAX_PAYLOAD*2+1]; #endif uint8_t failedTransmissions; + uint16_t heartbeat; void (*timeCallback)(unsigned long); // Callback for requested time messages void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. From 9faaf8e6f8c395c2ef19cc7195652914f41bd053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Tue, 4 Aug 2015 22:33:06 +0200 Subject: [PATCH 179/660] Initial support for SAMD device in development branch --- hardware/MySensors/samd/boards.txt | 42 +++ .../CorrectADCResponse/CorrectADCResponse.ino | 210 +++++++++++ .../SAMD_AnalogCorrection/library.properties | 8 + .../src/SAMD_AnalogCorrection.cpp | 31 ++ .../src/SAMD_AnalogCorrection.h | 24 ++ hardware/MySensors/samd/libraries/SPI/SPI.cpp | 200 ++++++++++ hardware/MySensors/samd/libraries/SPI/SPI.h | 153 ++++++++ .../BarometricPressureSensor.ino | 143 +++++++ .../DigitalPotControl/DigitalPotControl.ino | 71 ++++ .../MySensors/samd/libraries/SPI/keywords.txt | 31 ++ .../MySensors/samd/libraries/Wire/Wire.cpp | 355 ++++++++++++++++++ hardware/MySensors/samd/libraries/Wire/Wire.h | 104 +++++ .../SFRRanger_reader/SFRRanger_reader.pde | 87 +++++ .../digital_potentiometer.pde | 39 ++ .../examples/master_reader/master_reader.pde | 32 ++ .../examples/master_writer/master_writer.pde | 31 ++ .../slave_receiver/slave_receiver.pde | 38 ++ .../examples/slave_sender/slave_sender.pde | 32 ++ .../samd/libraries/Wire/keywords.txt | 32 ++ hardware/MySensors/samd/platform.txt | 143 +++++++ .../mysensors_gw/debug_scripts/variant.gdb | 31 ++ .../gcc/flash_with_bootloader.ld | 211 +++++++++++ .../gcc/flash_without_bootloader.ld | 212 +++++++++++ .../openocd_scripts/mysensors_gw.cfg | 30 ++ .../samd/variants/mysensors_gw/pins_arduino.h | 21 ++ .../samd/variants/mysensors_gw/variant.cpp | 221 +++++++++++ .../samd/variants/mysensors_gw/variant.h | 201 ++++++++++ 27 files changed, 2733 insertions(+) create mode 100644 hardware/MySensors/samd/boards.txt create mode 100644 hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino create mode 100644 hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/library.properties create mode 100644 hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp create mode 100644 hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h create mode 100644 hardware/MySensors/samd/libraries/SPI/SPI.cpp create mode 100644 hardware/MySensors/samd/libraries/SPI/SPI.h create mode 100644 hardware/MySensors/samd/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino create mode 100644 hardware/MySensors/samd/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino create mode 100644 hardware/MySensors/samd/libraries/SPI/keywords.txt create mode 100644 hardware/MySensors/samd/libraries/Wire/Wire.cpp create mode 100644 hardware/MySensors/samd/libraries/Wire/Wire.h create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/master_reader/master_reader.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/master_writer/master_writer.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/slave_receiver/slave_receiver.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/examples/slave_sender/slave_sender.pde create mode 100644 hardware/MySensors/samd/libraries/Wire/keywords.txt create mode 100644 hardware/MySensors/samd/platform.txt create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/debug_scripts/variant.gdb create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_with_bootloader.ld create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_without_bootloader.ld create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/openocd_scripts/mysensors_gw.cfg create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/pins_arduino.h create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/variant.cpp create mode 100644 hardware/MySensors/samd/variants/mysensors_gw/variant.h diff --git a/hardware/MySensors/samd/boards.txt b/hardware/MySensors/samd/boards.txt new file mode 100644 index 0000000..1728623 --- /dev/null +++ b/hardware/MySensors/samd/boards.txt @@ -0,0 +1,42 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +mysensors_gw_native.name=Sensebender GW (Native USB Port) +mysensors_gw_native.vid.0=0x2341 +mysensors_gw_native.pid.0=0x804d +mysensors_gw_native.vid.1=0x2341 +mysensors_gw_native.pid.1=0x004d +mysensors_gw_native.upload.tool=bossac +mysensors_gw_native.upload.protocol=sam-ba +mysensors_gw_native.upload.maximum_size=262144 +mysensors_gw_native.upload.use_1200bps_touch=true +mysensors_gw_native.upload.wait_for_upload_port=true +mysensors_gw_native.upload.native_usb=true +mysensors_gw_native.build.mcu=cortex-m0plus +mysensors_gw_native.build.f_cpu=48000000L +mysensors_gw_native.build.usb_product="Arduino Zero" +mysensors_gw_native.build.usb_manufacturer="Arduino LLC" +mysensors_gw_native.build.board=SAMD_ZERO +mysensors_gw_native.build.core=arduino:arduino +mysensors_gw_native.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +mysensors_gw_native.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +mysensors_gw_native.build.openocdscript=openocd_scripts/mysensors_gw.cfg +mysensors_gw_native.build.variant=mysensors_gw +mysensors_gw_native.build.variant_system_lib= +mysensors_gw_native.build.vid=0x2341 +mysensors_gw_native.build.pid=0x804d +mysensors_gw_native.bootloader.tool=openocd +mysensors_gw_native.bootloader.file=zero/samd21_sam_ba.bin diff --git a/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino new file mode 100644 index 0000000..2b74538 --- /dev/null +++ b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino @@ -0,0 +1,210 @@ +/* + This sketch easily and quickly finds the right ADC correction values for a particular Arduino ZERO board. + The correction values that are found are only valid for the board where the sketch is executed. + + This example code is in the public domain. + + Written 6 May 2015 by Claudio Indellicati +*/ + +/* + How to use this sketch + + 1) Remove any connection cable, shield or jumper from your Arduino ZERO + 2) Connect pin A1 to the nearest GND pin using the shortest jumper possible + 3) Connect pin A2 to the 3.3V pin using the shortest jumper possible + 4) Connect the Arduino ZERO to your PC using a USB cable plugged in the USB programming port of the board + 5) Upload this sketch and leave the board powered on for at least one minute + 6) Open the Serial Monitor and press the reset button on the Arduino ZERO + 7) At the and of the procedure you can find logged + - the offset and gain values for the board where the sketch has been just executed + - the instruction line to copy/paste in the final sketch +*/ + +#include "SAMD_AnalogCorrection.h" + +#define ADC_GND_PIN A1 +#define ADC_3V3_PIN A2 + +#define ADC_READS_SHIFT 8 +#define ADC_READS_COUNT (1 << ADC_READS_SHIFT) + +#define ADC_MIN_GAIN 0x0400 +#define ADC_UNITY_GAIN 0x0800 +#define ADC_MAX_GAIN (0x1000 - 1) +#define ADC_RESOLUTION_BITS 12 +#define ADC_RANGE (1 << ADC_RESOLUTION_BITS) +#define ADC_TOP_VALUE (ADC_RANGE - 1) + +#define MAX_TOP_VALUE_READS 10 + +void setup() +{ + Serial.begin(9600); + + Serial.println("\r\nCalibrating ADC with factory values"); + + analogReadResolution(ADC_RESOLUTION_BITS); + + Serial.println("\r\nReading GND and 3.3V ADC levels"); + Serial.print(" "); + readGndLevel(); + Serial.print(" "); + read3V3Level(); + + int offsetCorrectionValue = 0; + uint16_t gainCorrectionValue = ADC_UNITY_GAIN; + + Serial.print("\r\nOffset correction (@gain = "); + Serial.print(gainCorrectionValue); + Serial.println(" (unity gain))"); + + // Set default correction values and enable correction + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + + for (int offset = 0; offset < (int)(ADC_OFFSETCORR_MASK >> 1); ++offset) + { + analogReadCorrection(offset, gainCorrectionValue); + + Serial.print(" Offset = "); + Serial.print(offset); + Serial.print(", "); + + if (readGndLevel() == 0) + { + offsetCorrectionValue = offset; + break; + } + } + + Serial.println("\r\nGain correction"); + + uint8_t topValueReadsCount = 0U; + + uint16_t minGain = 0U, + maxGain = 0U; + + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + Serial.print(" Gain = "); + Serial.print(gainCorrectionValue); + Serial.print(", "); + uint16_t highLevelRead = read3V3Level(); + + if (highLevelRead < ADC_TOP_VALUE) + { + for (uint16_t gain = ADC_UNITY_GAIN + 1; gain <= ADC_MAX_GAIN; ++gain) + { + analogReadCorrection(offsetCorrectionValue, gain); + + Serial.print(" Gain = "); + Serial.print(gain); + Serial.print(", "); + highLevelRead = read3V3Level(); + + if (highLevelRead == ADC_TOP_VALUE) + { + if (minGain == 0U) + minGain = gain; + + if (++topValueReadsCount >= MAX_TOP_VALUE_READS) + { + maxGain = minGain; + break; + } + + maxGain = gain; + } + + if (highLevelRead > ADC_TOP_VALUE) + break; + } + } + else if (highLevelRead >= ADC_TOP_VALUE) + { + if (highLevelRead == ADC_TOP_VALUE) + maxGain = ADC_UNITY_GAIN; + + for (uint16_t gain = ADC_UNITY_GAIN - 1; gain >= ADC_MIN_GAIN; --gain) + { + analogReadCorrection(offsetCorrectionValue, gain); + + Serial.print(" Gain = "); + Serial.print(gain); + Serial.print(", "); + highLevelRead = read3V3Level(); + + if (highLevelRead == ADC_TOP_VALUE) + { + if (maxGain == 0U) + maxGain = gain; + + minGain = gain; + } + + if (highLevelRead < ADC_TOP_VALUE) + break; + } + } + + gainCorrectionValue = (minGain + maxGain) >> 1; + + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + + Serial.println("\r\nReadings after corrections"); + Serial.print(" "); + readGndLevel(); + Serial.print(" "); + read3V3Level(); + + Serial.println("\r\n=================="); + Serial.println("\r\nCorrection values:"); + Serial.print(" Offset = "); + Serial.println(offsetCorrectionValue); + Serial.print(" Gain = "); + Serial.println(gainCorrectionValue); + Serial.println("\r\nAdd the next line to your sketch:"); + Serial.print(" analogReadCorrection("); + Serial.print(offsetCorrectionValue); + Serial.print(", "); + Serial.print(gainCorrectionValue); + Serial.println(");"); + Serial.println("\r\n=================="); +} + +void loop() +{ +} + +uint16_t readGndLevel() +{ + uint32_t readAccumulator = 0; + + for (int i = 0; i < ADC_READS_COUNT; ++i) + readAccumulator += analogRead(ADC_GND_PIN); + + uint16_t readValue = readAccumulator >> ADC_READS_SHIFT; + + Serial.print("ADC(GND) = "); + Serial.println(readValue); + + return readValue; +} + +uint16_t read3V3Level() +{ + uint32_t readAccumulator = 0; + + for (int i = 0; i < ADC_READS_COUNT; ++i) + readAccumulator += analogRead(ADC_3V3_PIN); + + uint16_t readValue = readAccumulator >> ADC_READS_SHIFT; + + if (readValue < (ADC_RANGE >> 1)) + readValue += ADC_RANGE; + + Serial.print("ADC(3.3V) = "); + Serial.println(readValue); + + return readValue; +} + diff --git a/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/library.properties b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/library.properties new file mode 100644 index 0000000..e12ada2 --- /dev/null +++ b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/library.properties @@ -0,0 +1,8 @@ +name=SAMD_AnalogCorrection +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Sets and enables the digital correction logic of the SAMD ADC. +paragraph=Useful to correct the values returned by the ADC. +url= +architectures=samd diff --git a/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp new file mode 100644 index 0000000..1681b0a --- /dev/null +++ b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp @@ -0,0 +1,31 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "SAMD_AnalogCorrection.h" + +void analogReadCorrection (int offset, uint16_t gain) +{ + // Set correction values + ADC->OFFSETCORR.reg = ADC_OFFSETCORR_OFFSETCORR(offset); + ADC->GAINCORR.reg = ADC_GAINCORR_GAINCORR(gain); + + // Enable digital correction logic + ADC->CTRLB.bit.CORREN = 1; + while(ADC->STATUS.bit.SYNCBUSY); +} + diff --git a/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h new file mode 100644 index 0000000..5edb91e --- /dev/null +++ b/hardware/MySensors/samd/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h @@ -0,0 +1,24 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +void analogReadCorrection (int offset, uint16_t gain); + diff --git a/hardware/MySensors/samd/libraries/SPI/SPI.cpp b/hardware/MySensors/samd/libraries/SPI/SPI.cpp new file mode 100644 index 0000000..e4af046 --- /dev/null +++ b/hardware/MySensors/samd/libraries/SPI/SPI.cpp @@ -0,0 +1,200 @@ +/* + * SPI Master library for Arduino Zero. + * Copyright (c) 2015 Arduino LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SPI.h" +#include +#include +#include + +#define SPI_IMODE_NONE 0 +#define SPI_IMODE_EXTINT 1 +#define SPI_IMODE_GLOBAL 2 + +const SPISettings DEFAULT_SPI_SETTINGS = SPISettings(); + +SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI) +{ + initialized = false; + assert(p_sercom != NULL); + _p_sercom = p_sercom; + + _uc_pinMiso = uc_pinMISO; + _uc_pinSCK = uc_pinSCK; + _uc_pinMosi = uc_pinMOSI; +} + +void SPIClass::begin() +{ + init(); + + // PIO init + pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType); + pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType); + pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType); + + config(DEFAULT_SPI_SETTINGS); +} + +void SPIClass::init() +{ + if (initialized) + return; + interruptMode = SPI_IMODE_NONE; + interruptSave = 0; + interruptMask = 0; + initialized = true; +} + +void SPIClass::config(SPISettings settings) +{ + _p_sercom->disableSPI(); + + _p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, settings.bitOrder); + _p_sercom->initSPIClock(settings.dataMode, settings.clockFreq); + + _p_sercom->enableSPI(); +} + +void SPIClass::end() +{ + _p_sercom->resetSPI(); + initialized = false; +} + +#ifndef interruptsStatus +#define interruptsStatus() __interruptsStatus() +static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused)); +static inline unsigned char __interruptsStatus(void) +{ + // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIBGJ.html + return (__get_PRIMASK() ? 0 : 1); +} +#endif + +void SPIClass::usingInterrupt(int interruptNumber) +{ + if ((interruptNumber == NOT_AN_INTERRUPT) || (interruptNumber == EXTERNAL_INT_NMI)) + return; + + uint8_t irestore = interruptsStatus(); + noInterrupts(); + + if (interruptNumber >= EXTERNAL_NUM_INTERRUPTS) + interruptMode = SPI_IMODE_GLOBAL; + else + { + interruptMode |= SPI_IMODE_EXTINT; + interruptMask |= (1 << interruptNumber); + } + + if (irestore) + interrupts(); +} + +void SPIClass::beginTransaction(SPISettings settings) +{ + if (interruptMode != SPI_IMODE_NONE) + { + if (interruptMode & SPI_IMODE_GLOBAL) + { + interruptSave = interruptsStatus(); + noInterrupts(); + } + else if (interruptMode & SPI_IMODE_EXTINT) + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(interruptMask); + } + + config(settings); +} + +void SPIClass::endTransaction(void) +{ + if (interruptMode != SPI_IMODE_NONE) + { + if (interruptMode & SPI_IMODE_GLOBAL) + { + if (interruptSave) + interrupts(); + } + else if (interruptMode & SPI_IMODE_EXTINT) + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(interruptMask); + } +} + +void SPIClass::setBitOrder(BitOrder order) +{ + if (order == LSBFIRST) { + _p_sercom->setDataOrderSPI(LSB_FIRST); + } else { + _p_sercom->setDataOrderSPI(MSB_FIRST); + } +} + +void SPIClass::setDataMode(uint8_t mode) +{ + switch (mode) + { + case SPI_MODE0: + _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_0); + break; + + case SPI_MODE1: + _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_1); + break; + + case SPI_MODE2: + _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_2); + break; + + case SPI_MODE3: + _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_3); + break; + + default: + break; + } +} + +void SPIClass::setClockDivider(uint8_t div) +{ + if (div < SPI_MIN_CLOCK_DIVIDER) { + _p_sercom->setBaudrateSPI(SPI_MIN_CLOCK_DIVIDER); + } else { + _p_sercom->setBaudrateSPI(div); + } +} + +byte SPIClass::transfer(uint8_t data) +{ + // Writing the data + _p_sercom->writeDataSPI(data); + + // Read data + return _p_sercom->readDataSPI() & 0xFF; +} + +void SPIClass::attachInterrupt() { + // Should be enableInterrupt() +} + +void SPIClass::detachInterrupt() { + // Should be disableInterrupt() +} + +SPIClass SPI( &sercom4, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI ); diff --git a/hardware/MySensors/samd/libraries/SPI/SPI.h b/hardware/MySensors/samd/libraries/SPI/SPI.h new file mode 100644 index 0000000..6259d2d --- /dev/null +++ b/hardware/MySensors/samd/libraries/SPI/SPI.h @@ -0,0 +1,153 @@ +/* + * SPI Master library for Arduino Zero. + * Copyright (c) 2015 Arduino LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include + +// SPI_HAS_TRANSACTION means SPI has +// - beginTransaction() +// - endTransaction() +// - usingInterrupt() +// - SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +#define SPI_MODE0 0x02 +#define SPI_MODE1 0x00 +#define SPI_MODE2 0x03 +#define SPI_MODE3 0x01 + +#if defined(__SAMD21G18A__) + // Even if not specified on the datasheet, the SAMD21G18A MCU + // doesn't operate correctly with clock dividers lower than 4. + // This allows a theoretical maximum SPI clock speed of 12Mhz + #define SPI_MIN_CLOCK_DIVIDER 4 + // Other SAMD21xxxxx MCU may be affected as well +#else + #define SPI_MIN_CLOCK_DIVIDER 2 +#endif + +class SPISettings { + public: + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + + // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first. + SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } + + private: + void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { + this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock); + + this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST); + + switch (dataMode) + { + case SPI_MODE0: + this->dataMode = SERCOM_SPI_MODE_0; break; + case SPI_MODE1: + this->dataMode = SERCOM_SPI_MODE_1; break; + case SPI_MODE2: + this->dataMode = SERCOM_SPI_MODE_2; break; + case SPI_MODE3: + this->dataMode = SERCOM_SPI_MODE_3; break; + default: + this->dataMode = SERCOM_SPI_MODE_0; break; + } + } + + uint32_t clockFreq; + SercomSpiClockMode dataMode; + SercomDataOrder bitOrder; + + friend class SPIClass; +}; + +class SPIClass { + public: + SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI); + + byte transfer(uint8_t data); + inline void transfer(void *buf, size_t count); + + // Transaction Functions + void usingInterrupt(int interruptNumber); + void beginTransaction(SPISettings settings); + void endTransaction(void); + + // SPI Configuration methods + void attachInterrupt(); + void detachInterrupt(); + + void begin(); + void end(); + + void setBitOrder(BitOrder order); + void setDataMode(uint8_t uc_mode); + void setClockDivider(uint8_t uc_div); + + private: + void init(); + void config(SPISettings settings); + + SERCOM *_p_sercom; + uint8_t _uc_pinMiso; + uint8_t _uc_pinMosi; + uint8_t _uc_pinSCK; + bool initialized; + uint8_t interruptMode; + char interruptSave; + uint32_t interruptMask; +}; + +void SPIClass::transfer(void *buf, size_t count) +{ + // TODO: Optimize for faster block-transfer + uint8_t *buffer = reinterpret_cast(buf); + for (size_t i=0; i 0 + extern SPIClass SPI; +#endif + +// For compatibility with sketches designed for AVR @ 16 MHz +// New programs should use SPI.beginTransaction to set the SPI clock +#if F_CPU == 48000000 + #define SPI_CLOCK_DIV2 6 + #define SPI_CLOCK_DIV4 12 + #define SPI_CLOCK_DIV8 24 + #define SPI_CLOCK_DIV16 48 + #define SPI_CLOCK_DIV32 96 + #define SPI_CLOCK_DIV64 192 + #define SPI_CLOCK_DIV128 255 +#endif + +#endif diff --git a/hardware/MySensors/samd/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/hardware/MySensors/samd/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..8104fcb --- /dev/null +++ b/hardware/MySensors/samd/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + diff --git a/hardware/MySensors/samd/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/hardware/MySensors/samd/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 0000000..b135a74 --- /dev/null +++ b/hardware/MySensors/samd/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 10 (SS pin) + * SDI - to digital pin 11 (MOSI pin) + * CLK - to digital pin 13 (SCK pin) + + created 10 Aug 2010 + by Tom Igoe + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// inslude the SPI library: +#include + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { + // set the slaveSelectPin as an output: + pinMode (slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +void digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin, LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin, HIGH); +} diff --git a/hardware/MySensors/samd/libraries/SPI/keywords.txt b/hardware/MySensors/samd/libraries/SPI/keywords.txt new file mode 100644 index 0000000..47738f9 --- /dev/null +++ b/hardware/MySensors/samd/libraries/SPI/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +#setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 + +SPI_CONTINUE LITERAL1 +SPI_LAST LITERAL1 diff --git a/hardware/MySensors/samd/libraries/Wire/Wire.cpp b/hardware/MySensors/samd/libraries/Wire/Wire.cpp new file mode 100644 index 0000000..aabc1ef --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/Wire.cpp @@ -0,0 +1,355 @@ +/* + * TWI/I2C library for Arduino Zero + * Copyright (c) 2015 Arduino LLC. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern "C" { +#include +} + +#include +#include + +#include "Wire.h" + +TwoWire::TwoWire(SERCOM * s) +{ + this->sercom = s; + transmissionBegun = false; +} + +void TwoWire::begin(void) { + //Master Mode + sercom->initMasterWIRE(TWI_CLOCK); + sercom->enableWIRE(); + + pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); + pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); +} + +void TwoWire::begin(uint8_t address) { + //Slave mode + sercom->initSlaveWIRE(address); + sercom->enableWIRE(); +} + +void TwoWire::setClock(uint32_t frequency) { + // dummy funtion +} + +uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) +{ + if(quantity == 0) + { + return 0; + } + + size_t byteRead = 0; + + if(sercom->startTransmissionWIRE(address, WIRE_READ_FLAG)) + { + // Read first data + rxBuffer.store_char(sercom->readDataWIRE()); + + // Connected to slave + //while(toRead--) + for(byteRead = 0; byteRead < quantity; ++byteRead) + { + if( byteRead == quantity - 1) // Stop transmission + { + sercom->prepareNackBitWIRE(); // Prepare NACK to stop slave transmission + //sercom->readDataWIRE(); // Clear data register to send NACK + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); // Send Stop + } + else // Continue transmission + { + sercom->prepareAckBitWIRE(); // Prepare Acknowledge + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_READ); // Prepare the ACK command for the slave + rxBuffer.store_char( sercom->readDataWIRE() ); // Read data and send the ACK + } + } + } + + return byteRead; +} + +uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity) +{ + return requestFrom(address, quantity, true); +} + +void TwoWire::beginTransmission(uint8_t address) { + // save address of target and clear buffer + txAddress = address; + txBuffer.clear(); + + transmissionBegun = true; +} + +// Errors: +// 0 : Success +// 1 : Data too long +// 2 : NACK on transmit of address +// 3 : NACK on transmit of data +// 4 : Other error +uint8_t TwoWire::endTransmission(bool stopBit) +{ + transmissionBegun = false ; + + // Check if there are data to send + if ( txBuffer.available() == 0) + { + return 4 ; + } + + // Start I2C transmission + if ( !sercom->startTransmissionWIRE( txAddress, WIRE_WRITE_FLAG ) ) + { + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + return 2 ; // Address error + } + + // Send all buffer + while( txBuffer.available() ) + { + // Trying to send data + if ( !sercom->sendDataMasterWIRE( txBuffer.read_char() ) ) + { + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + return 3 ; // Nack or error + } + + if(txBuffer.available() == 0) + { + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + } + } + + return 0; +} + +uint8_t TwoWire::endTransmission() +{ + return endTransmission(true); +} + +size_t TwoWire::write(uint8_t ucData) +{ + if(sercom->isMasterWIRE()) + { + // No writing, without begun transmission or a full buffer + if ( !transmissionBegun || txBuffer.isFull() ) + { + return 0 ; + } + + txBuffer.store_char( ucData ) ; + + return 1 ; + } + else + { + if(sercom->sendDataSlaveWIRE( ucData )) + { + return 1; + } + } + + return 0; +} + +size_t TwoWire::write(const uint8_t *data, size_t quantity) +{ + //Try to store all data + for(size_t i = 0; i < quantity; ++i) + { + //Return the number of data stored, when the buffer is full (if write return 0) + if(!write(data[i])) + return i; + } + + //All data stored + return quantity; +} + +int TwoWire::available(void) +{ + return rxBuffer.available(); +} + +int TwoWire::read(void) +{ + return rxBuffer.read_char(); +} + +int TwoWire::peek(void) +{ + return rxBuffer.peek(); +} + +void TwoWire::flush(void) +{ + // Do nothing, use endTransmission(..) to force + // data transfer. +} + +void TwoWire::onReceive(void(*function)(int)) +{ + onReceiveCallback = function; +} + +void TwoWire::onRequest(void(*function)(void)) +{ + onRequestCallback = function; +} + +void TwoWire::onService(void) +{ + if ( sercom->isSlaveWIRE() ) + { + //Received data + if(sercom->isDataReadyWIRE()) + { + //Store data + rxBuffer.store_char(sercom->readDataWIRE()); + + //Stop or Restart detected + if(sercom->isStopDetectedWIRE() || sercom->isRestartDetectedWIRE()) + { + //Calling onReceiveCallback, if exists + if(onReceiveCallback) + { + onReceiveCallback(available()); + } + } + } + + //Address Match + if(sercom->isAddressMatch()) + { + //Is a request ? + if(sercom->isMasterReadOperationWIRE()) + { + //Calling onRequestCallback, if exists + if(onRequestCallback) + { + onRequestCallback(); + } + } + } + } +} + +/* +void TwoWire::onService(void) +{ + // Retrieve interrupt status + uint32_t sr = TWI_GetStatus(twi); + + if (status == SLAVE_IDLE && TWI_STATUS_SVACC(sr)) { + TWI_DisableIt(twi, TWI_IDR_SVACC); + TWI_EnableIt(twi, TWI_IER_RXRDY | TWI_IER_GACC | TWI_IER_NACK + | TWI_IER_EOSACC | TWI_IER_SCL_WS | TWI_IER_TXCOMP); + + srvBufferLength = 0; + srvBufferIndex = 0; + + // Detect if we should go into RECV or SEND status + // SVREAD==1 means *master* reading -> SLAVE_SEND + if (!TWI_STATUS_SVREAD(sr)) { + status = SLAVE_RECV; + } else { + status = SLAVE_SEND; + + // Alert calling program to generate a response ASAP + if (onRequestCallback) + onRequestCallback(); + else + // create a default 1-byte response + write((uint8_t) 0); + } + } + + if (status != SLAVE_IDLE) { + if (TWI_STATUS_TXCOMP(sr) && TWI_STATUS_EOSACC(sr)) { + if (status == SLAVE_RECV && onReceiveCallback) { + // Copy data into rxBuffer + // (allows to receive another packet while the + // user program reads actual data) + for (uint8_t i = 0; i < srvBufferLength; ++i) + rxBuffer[i] = srvBuffer[i]; + rxBufferIndex = 0; + rxBufferLength = srvBufferLength; + + // Alert calling program + onReceiveCallback( rxBufferLength); + } + + // Transfer completed + TWI_EnableIt(twi, TWI_SR_SVACC); + TWI_DisableIt(twi, TWI_IDR_RXRDY | TWI_IDR_GACC | TWI_IDR_NACK + | TWI_IDR_EOSACC | TWI_IDR_SCL_WS | TWI_IER_TXCOMP); + status = SLAVE_IDLE; + } + } + + if (status == SLAVE_RECV) { + if (TWI_STATUS_RXRDY(sr)) { + if (srvBufferLength < BUFFER_LENGTH) + srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); + } + } + + if (status == SLAVE_SEND) { + if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) { + uint8_t c = 'x'; + if (srvBufferIndex < srvBufferLength) + c = srvBuffer[srvBufferIndex++]; + TWI_WriteByte(twi, c); + } + } +} +*/ + +#if WIRE_INTERFACES_COUNT > 0 +/*static void Wire_Init(void) { + pmc_enable_periph_clk(WIRE_INTERFACE_ID); + PIO_Configure( + g_APinDescription[PIN_WIRE_SDA].pPort, + g_APinDescription[PIN_WIRE_SDA].ulPinType, + g_APinDescription[PIN_WIRE_SDA].ulPin, + g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration); + PIO_Configure( + g_APinDescription[PIN_WIRE_SCL].pPort, + g_APinDescription[PIN_WIRE_SCL].ulPinType, + g_APinDescription[PIN_WIRE_SCL].ulPin, + g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration); + + NVIC_DisableIRQ(WIRE_ISR_ID); + NVIC_ClearPendingIRQ(WIRE_ISR_ID); + NVIC_SetPriority(WIRE_ISR_ID, 0); + NVIC_EnableIRQ(WIRE_ISR_ID); +}*/ + + +TwoWire Wire(&sercom3); + +void SERCOM3_Handler(void) { + Wire.onService(); +} + +#endif diff --git a/hardware/MySensors/samd/libraries/Wire/Wire.h b/hardware/MySensors/samd/libraries/Wire/Wire.h new file mode 100644 index 0000000..844168e --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/Wire.h @@ -0,0 +1,104 @@ +/* + * TWI/I2C library for Arduino Zero + * Copyright (c) 2015 Arduino LLC. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TwoWire_h +#define TwoWire_h + +#include "Stream.h" +#include "variant.h" + +#include "SERCOM.h" +#include "RingBuffer.h" + +#define BUFFER_LENGTH 32 + +class TwoWire : public Stream +{ + public: + TwoWire(SERCOM *s); + void begin(); + void begin(uint8_t); + void setClock(uint32_t); // dummy function + + void beginTransmission(uint8_t); + uint8_t endTransmission(bool stopBit); + uint8_t endTransmission(void); + + uint8_t requestFrom(uint8_t address, size_t quantity, bool stopBit); + uint8_t requestFrom(uint8_t address, size_t quantity); + + size_t write(uint8_t data); + size_t write(const uint8_t * data, size_t quantity); + + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive(void(*)(int)); + void onRequest(void(*)(void)); + + using Print::write; + + void onService(void); + + private: + SERCOM * sercom; + bool transmissionBegun; + + // RX Buffer + RingBuffer rxBuffer; + + //TX buffer + RingBuffer txBuffer; + uint8_t txAddress; + + + // Service buffer + //uint8_t srvBuffer[BUFFER_LENGTH]; + //uint8_t srvBufferIndex; + //uint8_t srvBufferLength; + + // Callback user functions + void (*onRequestCallback)(void); + void (*onReceiveCallback)(int); + + // TWI state + //enum TwoWireStatus + //{ + // UNINITIALIZED, + // MASTER_IDLE, + // MASTER_SEND, + // MASTER_RECV, + // SLAVE_IDLE, + // SLAVE_RECV, + // SLAVE_SEND + //}; + //TwoWireStatus status; + + // TWI clock frequency + static const uint32_t TWI_CLOCK = 100000; + + // Timeouts + //static const uint32_t RECV_TIMEOUT = 100000; + //static const uint32_t XMIT_TIMEOUT = 100000; +}; + +extern TwoWire Wire; + +#endif diff --git a/hardware/MySensors/samd/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.pde b/hardware/MySensors/samd/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.pde new file mode 100644 index 0000000..9c41c18 --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.pde @@ -0,0 +1,87 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder +// by Nicholas Zambetti +// and James Tichenor + +// Demonstrates use of the Wire library reading data from the +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial communication at 9600bps +} + +int reading = 0; + +void loop() +{ + // step 1: instruct sensor to read echoes + Wire.beginTransmission(112); // transmit to device #112 (0x70) + // the address specified in the datasheet is 224 (0xE0) + // but i2c adressing uses the high 7 bits so it's 112 + Wire.write(byte(0x00)); // sets register pointer to the command register (0x00) + Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50) + // use 0x51 for centimeters + // use 0x52 for ping microseconds + Wire.endTransmission(); // stop transmitting + + // step 2: wait for readings to happen + delay(70); // datasheet suggests at least 65 milliseconds + + // step 3: instruct sensor to return a particular echo reading + Wire.beginTransmission(112); // transmit to device #112 + Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02) + Wire.endTransmission(); // stop transmitting + + // step 4: request reading from sensor + Wire.requestFrom(112, 2); // request 2 bytes from slave device #112 + + // step 5: receive reading from sensor + if(2 <= Wire.available()) // if two bytes were received + { + reading = Wire.read(); // receive high byte (overwrites previous reading) + reading = reading << 8; // shift high byte to be high 8 bits + reading |= Wire.read(); // receive low byte as lower 8 bits + Serial.println(reading); // print the reading + } + + delay(250); // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA0)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xAA)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA5)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(newAddress); + Wire.endTransmission(); +} + +*/ diff --git a/hardware/MySensors/samd/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.pde b/hardware/MySensors/samd/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.pde new file mode 100644 index 0000000..38da1c5 --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.pde @@ -0,0 +1,39 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti +// and Shawn Bonkowski + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() +{ + Wire.beginTransmission(44); // transmit to device #44 (0x2c) + // device address is specified in datasheet + Wire.write(byte(0x00)); // sends instruction byte + Wire.write(val); // sends potentiometer value byte + Wire.endTransmission(); // stop transmitting + + val++; // increment value + if(val == 64) // if reached 64th position (max) + { + val = 0; // start over from lowest value + } + delay(500); +} + diff --git a/hardware/MySensors/samd/libraries/Wire/examples/master_reader/master_reader.pde b/hardware/MySensors/samd/libraries/Wire/examples/master_reader/master_reader.pde new file mode 100644 index 0000000..4124d7d --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/master_reader/master_reader.pde @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial for output +} + +void loop() +{ + Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 + + while(Wire.available()) // slave may send less than requested + { + char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + + delay(500); +} diff --git a/hardware/MySensors/samd/libraries/Wire/examples/master_writer/master_writer.pde b/hardware/MySensors/samd/libraries/Wire/examples/master_writer/master_writer.pde new file mode 100644 index 0000000..ccaa036 --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/master_writer/master_writer.pde @@ -0,0 +1,31 @@ +// Wire Master Writer +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() +{ + Wire.beginTransmission(4); // transmit to device #4 + Wire.write("x is "); // sends five bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} diff --git a/hardware/MySensors/samd/libraries/Wire/examples/slave_receiver/slave_receiver.pde b/hardware/MySensors/samd/libraries/Wire/examples/slave_receiver/slave_receiver.pde new file mode 100644 index 0000000..60dd4bd --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/slave_receiver/slave_receiver.pde @@ -0,0 +1,38 @@ +// Wire Slave Receiver +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(4); // join i2c bus with address #4 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) +{ + while(1 < Wire.available()) // loop through all but the last + { + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} diff --git a/hardware/MySensors/samd/libraries/Wire/examples/slave_sender/slave_sender.pde b/hardware/MySensors/samd/libraries/Wire/examples/slave_sender/slave_sender.pde new file mode 100644 index 0000000..d3b238a --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/examples/slave_sender/slave_sender.pde @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Wire.begin(2); // join i2c bus with address #2 + Wire.onRequest(requestEvent); // register event +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ + Wire.write("hello "); // respond with message of 6 bytes + // as expected by master +} diff --git a/hardware/MySensors/samd/libraries/Wire/keywords.txt b/hardware/MySensors/samd/libraries/Wire/keywords.txt new file mode 100644 index 0000000..e75e929 --- /dev/null +++ b/hardware/MySensors/samd/libraries/Wire/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire KEYWORD2 +Wire1 KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/hardware/MySensors/samd/platform.txt b/hardware/MySensors/samd/platform.txt new file mode 100644 index 0000000..b493921 --- /dev/null +++ b/hardware/MySensors/samd/platform.txt @@ -0,0 +1,143 @@ +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino SAMD Core and platform. +# +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification + +name=Mysensors SAMD (32-bits ARM Cortex-M0+) Boards +version=1.0.0 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O binary +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align +compiler.size.cmd=arm-none-eabi-size +compiler.define=-DARDUINO= + +# this can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +#compiler.c.elf.extra_flags=-v +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2hex.extra_flags= + +compiler.arm.cmsis.path="-I{runtime.tools.CMSIS.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS.path}/Device/ATMEL/" + +# USB Flags +# --------- +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# Default usb manufacturer will be replaced at compile time using +# numeric vendor ID if available or by board's specific value. +build.usb_manufacturer="Unknown" + + +# Compile patterns +# ---------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Save hex +recipe.output.tmp_file={build.project_name}.bin +recipe.output.save_file={build.project_name}.{build.variant}.bin + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=\.text\s+([0-9]+).* + + +# Uploader tools +# -------------- + +# +# BOSSA +# +tools.bossac.path={runtime.tools.bossac-1.6-arduino.path} +tools.bossac.cmd=bossac +tools.bossac.cmd.windows=bossac.exe + +tools.bossac.upload.params.verbose=-i -d +tools.bossac.upload.params.quiet= +tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -i -e -w -v "{build.path}/{build.project_name}.bin" -R + +# +# OpenOCD sketch upload +# + +tools.openocd.path={runtime.tools.openocd.path} +tools.openocd.cmd=bin/openocd +tools.openocd.cmd.windows=bin/openocd.exe + +tools.openocd.upload.params.verbose=-d2 +tools.openocd.upload.params.quiet=-d0 +tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.bin}} verify reset 0x00002000; shutdown" + +tools.openocd.program.params.verbose=-d2 +tools.openocd.program.params.quiet=-d0 +tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.elf}} verify reset; shutdown" + +tools.openocd.erase.params.verbose=-d3 +tools.openocd.erase.params.quiet=-d0 +tools.openocd.erase.pattern= + +tools.openocd.bootloader.params.verbose=-d2 +tools.openocd.bootloader.params.quiet=-d0 +tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{{runtime.platform.path}/bootloaders/{bootloader.file}}} verify reset; shutdown" + diff --git a/hardware/MySensors/samd/variants/mysensors_gw/debug_scripts/variant.gdb b/hardware/MySensors/samd/variants/mysensors_gw/debug_scripts/variant.gdb new file mode 100644 index 0000000..3c37ffd --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/debug_scripts/variant.gdb @@ -0,0 +1,31 @@ +# +# Arduino Zero OpenOCD script. +# +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +# Define 'reset' command +define reset + +info reg + +break main + +# End of 'reset' command +end + +target remote | openocd -c "interface cmsis-dap" -c "set CHIPNAME at91samd21g18" -f target/at91samdXX.cfg -c "gdb_port pipe; log_output openocd.log" diff --git a/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_with_bootloader.ld b/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_with_bootloader.ld new file mode 100644 index 0000000..4475f95 --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_with_bootloader.ld @@ -0,0 +1,211 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_without_bootloader.ld b/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_without_bootloader.ld new file mode 100644 index 0000000..0162f07 --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/linker_scripts/gcc/flash_without_bootloader.ld @@ -0,0 +1,212 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __ram_end__ + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM) ; + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/hardware/MySensors/samd/variants/mysensors_gw/openocd_scripts/mysensors_gw.cfg b/hardware/MySensors/samd/variants/mysensors_gw/openocd_scripts/mysensors_gw.cfg new file mode 100644 index 0000000..36c65c3 --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/openocd_scripts/mysensors_gw.cfg @@ -0,0 +1,30 @@ +# +# Arduino Zero OpenOCD script. +# +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME at91samd21g18 +set ENDIAN little + +# choose a port here +set telnet_port 0 + +source [find target/at91samdXX.cfg] diff --git a/hardware/MySensors/samd/variants/mysensors_gw/pins_arduino.h b/hardware/MySensors/samd/variants/mysensors_gw/pins_arduino.h new file mode 100644 index 0000000..db0e40c --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/pins_arduino.h @@ -0,0 +1,21 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// API compatibility +#include "variant.h" + diff --git a/hardware/MySensors/samd/variants/mysensors_gw/variant.cpp b/hardware/MySensors/samd/variants/mysensors_gw/variant.cpp new file mode 100644 index 0000000..84df403 --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/variant.cpp @@ -0,0 +1,221 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * + Pin number + ZERO Board pin | PIN | Label/Name | Comments (* is for default peripheral in use) + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | Digital Low | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 0 | 0 -> RX | PA11 | | EIC/EXTINT[11] ADC/AIN[19] PTC/X[3] *SERCOM0/PAD[3] SERCOM2/PAD[3] TCC0/WO[3] TCC1/WO[1] + * | 1 | 1 <- TX | PA10 | | EIC/EXTINT[10] ADC/AIN[18] PTC/X[2] *SERCOM0/PAD[2] TCC0/WO[2] TCC1/WO[0] + * | 2 | 2 | PA14 | | EIC/EXTINT[14] SERCOM2/PAD[2] SERCOM4/PAD[2] TC3/WO[0] TCC0/WO[4] + * | 3 | ~3 | PA09 | | EIC/EXTINT[9] ADC/AIN[17] PTC/X[1] SERCOM0/PAD[1] SERCOM2/PAD[1] *TCC0/WO[1] TCC1/WO[3] + * | 4 | ~4 | PA08 | | EIC/NMI ADC/AIN[16] PTC/X[0] SERCOM0/PAD[0] SERCOM2/PAD[0] *TCC0/WO[0] TCC1/WO[2] + * | 5 | ~5 | PA15 | | EIC/EXTINT[15] SERCOM2/PAD[3] SERCOM4/PAD[3] *TC3/WO[1] TCC0/WO[5] + * | 6 | ~6 | PA20 | | EIC/EXTINT[4] PTC/X[8] SERCOM5/PAD[2] SERCOM3/PAD[2] *TCC0/WO[6] + * | 7 | 7 | PA21 | | EIC/EXTINT[5] PTC/X[9] SERCOM5/PAD[3] SERCOM3/PAD[3] TCC0/WO[7] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | Digital High | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 8 | ~8 | PA06 | | EIC/EXTINT[6] ADC/AIN[6] AC/AIN[2] PTC/Y[4] SERCOM0/PAD[2] *TCC1/WO[0] + * | 9 | ~9 | PA07 | | EIC/EXTINT[7] ADC/AIN[7] AC/AIN[3] PTC/Y[5] SERCOM0/PAD[3] *TCC1/WO[1] + * | 10 | ~10 | PA18 | | EIC/EXTINT[2] PTC/X[6] +SERCOM1/PAD[2] SERCOM3/PAD[2] *TC3/WO[0] TCC0/WO[2] + * | 11 | ~11 | PA16 | | EIC/EXTINT[0] PTC/X[4] +SERCOM1/PAD[0] SERCOM3/PAD[0] *TCC2/WO[0] TCC0/WO[6] + * | 12 | ~12 | PA19 | | EIC/EXTINT[3] PTC/X[7] +SERCOM1/PAD[3] SERCOM3/PAD[3] TC3/WO[1] *TCC0/WO[3] + * | 13 | ~13 | PA17 | LED | EIC/EXTINT[1] PTC/X[5] +SERCOM1/PAD[1] SERCOM3/PAD[1] *TCC2/WO[1] TCC0/WO[7] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | Analog Connector | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 14 | A0 | PA02 | A0 | EIC/EXTINT[2] *ADC/AIN[0] DAC/VOUT PTC/Y[0] + * | 15 | A1 | PB08 | A1 | EIC/EXTINT[8] *ADC/AIN[2] PTC/Y[14] SERCOM4/PAD[0] TC4/WO[0] + * | 16 | A2 | PB09 | A2 | EIC/EXTINT[9] *ADC/AIN[3] PTC/Y[15] SERCOM4/PAD[1] TC4/WO[1] + * | 17 | A3 | PA04 | A3 | EIC/EXTINT[4] *ADC/AIN[4] AC/AIN[0] PTC/Y[2] SERCOM0/PAD[0] TCC0/WO[0] + * | 18 | A4 | PA05 | A4 | EIC/EXTINT[5] *ADC/AIN[5] AC/AIN[1] PTC/Y[5] SERCOM0/PAD[1] TCC0/WO[1] + * | 19 | A5 | PB02 | A5 | EIC/EXTINT[2] *ADC/AIN[10] PTC/Y[8] SERCOM5/PAD[0] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | Wire | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 20 | SDA | PA22 | SDA | EIC/EXTINT[6] PTC/X[10] *SERCOM3/PAD[0] SERCOM5/PAD[0] TC4/WO[0] TCC0/WO[4] + * | 21 | SCL | PA23 | SCL | EIC/EXTINT[7] PTC/X[11] *SERCOM3/PAD[1] SERCOM5/PAD[1] TC4/WO[1] TCC0/WO[5] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | |SPI (Legacy ICSP) | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 22 | 1 | PA12 | MISO | EIC/EXTINT[12] SERCOM2/PAD[0] *SERCOM4/PAD[0] TCC2/WO[0] TCC0/WO[6] + * | | 2 | | 5V0 | + * | 23 | 4 | PB10 | MOSI | EIC/EXTINT[10] *SERCOM4/PAD[2] TC5/WO[0] TCC0/WO[4] + * | 24 | 3 | PB11 | SCK | EIC/EXTINT[11] *SERCOM4/PAD[3] TC5/WO[1] TCC0/WO[5] + * | | 5 | | RESET | + * | | 6 | | GND | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | LEDs | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 25 | | PB03 | RX | + * | 26 | | PA27 | TX | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | USB | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 27 | | PA28 | USB_HOST_ENABLE | EIC/EXTINT[8] + * | 28 | | PA24 | USB_NEGATIVE | *USB/DM + * | 29 | | PA25 | USB_POSITIVE | *USB/DP + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | EDBG | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 30 | | PB22 | EDBG_UART TX | *SERCOM5/PAD[2] + * | 31 | | PB23 | EDBG_UART RX | *SERCOM5/PAD[3] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 32 | | PA22 | EDBG_SDA | Pin 20 (SDA) + * | 33 | | PA23 | EDBG_SCL | Pin 21 (SCL) + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 34 | | PA19 | EDBG_MISO | EIC/EXTINT[3] *SERCOM1/PAD[3] SERCOM3/PAD[3] TC3/WO[1] TCC0/WO[3] + * | 35 | | PA16 | EDBG_MOSI | EIC/EXTINT[0] *SERCOM1/PAD[0] SERCOM3/PAD[0] TCC2/WO[0] TCC0/WO[6] + * | 36 | | PA18 | EDBG_SS | EIC/EXTINT[2] *SERCOM1/PAD[2] SERCOM3/PAD[2] TC3/WO[0] TCC0/WO[2] + * | 37 | | PA17 | EDBG_SCK | EIC/EXTINT[1] *SERCOM1/PAD[1] SERCOM3/PAD[1] TCC2/WO[1] TCC0/WO[7] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | 38 | ATN | PA13 | EDBG_GPIO0 | EIC/EXTINT[13] SERCOM2/PAD[1] SERCOM4/PAD[1] *TCC2/WO[1] TCC0/WO[7] + * | 39 | | PA21 | EDBG_GPIO1 | Pin 7 + * | 40 | | PA06 | EDBG_GPIO2 | Pin 8 + * | 41 | | PA07 | EDBG_GPIO3 | Pin 9 + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | GND | | | + * | 42 | AREF | PA03 | | EIC/EXTINT[3] *[ADC|DAC]/VREFA ADC/AIN[1] PTC/Y[1] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | |32.768KHz Crystal | | | + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + * | | | PA00 | XIN32 | EIC/EXTINT[0] SERCOM1/PAD[0] TCC2/WO[0] + * | | | PA01 | XOUT32 | EIC/EXTINT[1] SERCOM1/PAD[1] TCC2/WO[1] + * +------------+------------------+--------+-----------------+-------------------------------------------------------------------------------------------------------- + */ + + +#include "variant.h" + +/* + * Pins descriptions + */ +const PinDescription g_APinDescription[]= +{ + // 0..13 - Digital pins + // ---------------------- + // 0/1 - SERCOM/UART (Serial1) + { PORTA, 11, PIO_SERCOM, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 }, // RX: SERCOM0/PAD[3] + { PORTA, 10, PIO_SERCOM, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 }, // TX: SERCOM0/PAD[2] + + // 2..12 + // Digital Low + { PORTA, 14, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14 }, + { PORTA, 9, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH1, TCC0_CH1, EXTERNAL_INT_9 }, // TCC0/WO[1] + { PORTA, 8, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_NMI }, // TCC0/WO[0] + { PORTA, 15, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM3_CH1, TC3_CH1, EXTERNAL_INT_15 }, // TC3/WO[1] + { PORTA, 20, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH6, TCC0_CH6, EXTERNAL_INT_4 }, // TCC0/WO[6] + { PORTA, 21, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, + + // Digital High + { PORTA, 6, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_4 }, // TCC1/WO[0] + { PORTA, 7, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_5 }, // TCC1/WO[1] + { PORTA, 18, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM3_CH0, TC3_CH0, EXTERNAL_INT_2 }, // TC3/WO[0] + { PORTA, 16, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_0 }, // TCC2/WO[0] + { PORTA, 19, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH3, TCC0_CH3, EXTERNAL_INT_3 }, // TCC0/WO[3] + + // 13 (LED) + { PORTA, 17, PIO_PWM, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM2_CH1, NOT_ON_TIMER, EXTERNAL_INT_1 }, // TCC2/WO[1] + + // 14..19 - Analog pins + // -------------------- + { PORTA, 2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // ADC/AIN[0] + { PORTB, 8, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8 }, // ADC/AIN[2] + { PORTB, 9, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel3, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9 }, // ADC/AIN[3] + { PORTA, 4, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel4, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4 }, // ADC/AIN[4] + { PORTA, 5, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel5, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, // ADC/AIN[5] + { PORTB, 2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel10, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // ADC/AIN[10] + + // 20..21 I2C pins (SDA/SCL and also EDBG:SDA/SCL) + // ---------------------- + { PORTA, 22, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6 }, // SDA: SERCOM3/PAD[0] + { PORTA, 23, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_7 }, // SCL: SERCOM3/PAD[1] + + // 22..24 - SPI pins (ICSP:MISO,SCK,MOSI) + // ---------------------- + { PORTA, 12, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 }, // MISO: SERCOM4/PAD[0] + { PORTB, 10, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 }, // MOSI: SERCOM4/PAD[2] + { PORTB, 11, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 }, // SCK: SERCOM4/PAD[3] + + // 25..26 - RX/TX LEDS (PB03/PA27) + // -------------------- + { PORTB, 3, PIO_OUTPUT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // used as output only + { PORTA, 27, PIO_OUTPUT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // used as output only + + // 27..29 - USB + // -------------------- + { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable + { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM + { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DP + + // 30..41 - EDBG + // ---------------------- + // 30/31 - EDBG/UART + { PORTB, 22, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // TX: SERCOM5/PAD[2] + { PORTB, 23, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // RX: SERCOM5/PAD[3] + + // 32/33 I2C (SDA/SCL and also EDBG:SDA/SCL) + { PORTA, 22, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SDA: SERCOM3/PAD[0] + { PORTA, 23, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SCL: SERCOM3/PAD[1] + + // 34..37 - EDBG/SPI + { PORTA, 19, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM1/PAD[3] + { PORTA, 16, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MOSI: SERCOM1/PAD[0] + { PORTA, 18, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: SERCOM1/PAD[2] + { PORTA, 17, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SCK: SERCOM1/PAD[1] + + // 38..41 - EDBG/Digital + { PORTA, 13, PIO_PWM, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM0_CH5, NOT_ON_TIMER, EXTERNAL_INT_13 }, // EIC/EXTINT[13] *TCC2/WO[1] TCC0/WO[7] + { PORTA, 21, PIO_PWM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM0_CH7, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // Pin 7 + { PORTA, 6, PIO_PWM, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM1_CH0, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // Pin 8 + { PORTA, 7, PIO_PWM, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM1_CH1, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // Pin 9 + + // 42 (AREF) + { PORTA, 3, PIO_ANALOG, PIN_ATTR_ANALOG, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // DAC/VREFP + + // ---------------------- + // 43 - Alternate use of A0 (DAC output) + { PORTA, 2, PIO_ANALOG, PIN_ATTR_ANALOG, DAC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // DAC/VOUT +} ; + +const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM]={ TCC0, TCC1, TCC2, TC3, TC4, TC5 } ; + +// Multi-serial objects instantiation +SERCOM sercom0( SERCOM0 ) ; +SERCOM sercom1( SERCOM1 ) ; +SERCOM sercom2( SERCOM2 ) ; +SERCOM sercom3( SERCOM3 ) ; +SERCOM sercom4( SERCOM4 ) ; +SERCOM sercom5( SERCOM5 ) ; + +Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; +Uart Serial( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; +void SERCOM0_Handler() +{ + Serial1.IrqHandler(); +} + +void SERCOM5_Handler() +{ + Serial.IrqHandler(); +} + diff --git a/hardware/MySensors/samd/variants/mysensors_gw/variant.h b/hardware/MySensors/samd/variants/mysensors_gw/variant.h new file mode 100644 index 0000000..a1f1506 --- /dev/null +++ b/hardware/MySensors/samd/variants/mysensors_gw/variant.h @@ -0,0 +1,201 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_ARDUINO_ZERO_ +#define _VARIANT_ARDUINO_ZERO_ + +/*---------------------------------------------------------------------------- + * Definitions + *----------------------------------------------------------------------------*/ + +/** Frequency of the board main oscillator */ +#define VARIANT_MAINOSC (32768ul) + +/** Master clock frequency */ +#define VARIANT_MCK (48000000ul) + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +#include "SERCOM.h" +#include "Uart.h" +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Pins + *----------------------------------------------------------------------------*/ + +// Number of pins defined in PinDescription array +#define PINS_COUNT (26u) +#define NUM_DIGITAL_PINS (14u) +#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_OUTPUTS (1u) + +#define digitalPinToPort(P) ( &(PORT->Group[g_APinDescription[P].ulPort]) ) +#define digitalPinToBitMask(P) ( 1 << g_APinDescription[P].ulPin ) +//#define analogInPinToBit(P) ( ) +#define portOutputRegister(port) ( &(port->OUT.reg) ) +#define portInputRegister(port) ( &(port->IN.reg) ) +#define portModeRegister(port) ( &(port->DIR.reg) ) +#define digitalPinHasPWM(P) ( g_APinDescription[P].ulPWMChannel != NOT_ON_PWM || g_APinDescription[P].ulTCChannel != NOT_ON_TIMER ) + +/* + * digitalPinToTimer(..) is AVR-specific and is not defined for SAMD + * architecture. If you need to check if a pin supports PWM you must + * use digitalPinHasPWM(..). + * + * https://github.com/arduino/Arduino/issues/1833 + */ +// #define digitalPinToTimer(P) + +// Interrupts +#define digitalPinToInterrupt(P) ( g_APinDescription[P].ulExtInt ) + +// LEDs +#define PIN_LED_13 (13u) +#define PIN_LED_RXL (25u) +#define PIN_LED_TXL (26u) +#define PIN_LED PIN_LED_13 +#define PIN_LED2 PIN_LED_RXL +#define PIN_LED3 PIN_LED_TXL +#define LED_BUILTIN PIN_LED_13 + +/* + * Analog pins + */ +#define PIN_A0 (14ul) +#define PIN_A1 (15ul) +#define PIN_A2 (16ul) +#define PIN_A3 (17ul) +#define PIN_A4 (18ul) +#define PIN_A5 (19ul) + +static const uint8_t A0 = PIN_A0 ; +static const uint8_t A1 = PIN_A1 ; +static const uint8_t A2 = PIN_A2 ; +static const uint8_t A3 = PIN_A3 ; +static const uint8_t A4 = PIN_A4 ; +static const uint8_t A5 = PIN_A5 ; +#define ADC_RESOLUTION 12 + +// Other pins +#define PIN_ATN (38ul) +static const uint8_t ATN = PIN_ATN; + +/* + * Serial interfaces + */ +// Serial (EDBG) +#define PIN_SERIAL_RX (31ul) +#define PIN_SERIAL_TX (30ul) +#define PAD_SERIAL_TX (UART_TX_PAD_2) +#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) + +// Serial1 +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (22u) +#define PIN_SPI_MOSI (23u) +#define PIN_SPI_SCK (24u) + +static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. +static const uint8_t MOSI = PIN_SPI_MOSI ; +static const uint8_t MISO = PIN_SPI_MISO ; +static const uint8_t SCK = PIN_SPI_SCK ; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (20u) +#define PIN_WIRE_SCL (21u) + +/* + * USB + */ +#define PIN_USB_HOST_ENABLE (27ul) +#define PIN_USB_DM (28ul) +#define PIN_USB_DP (29ul) + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + +/* ========================= + * ===== SERCOM DEFINITION + * ========================= +*/ +extern SERCOM sercom0; +extern SERCOM sercom1; +extern SERCOM sercom2; +extern SERCOM sercom3; +extern SERCOM sercom4; +extern SERCOM sercom5; + +extern Uart Serial; +extern Uart Serial1; + +#endif + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_USBVIRTUAL SerialUSB +#define SERIAL_PORT_MONITOR Serial +// Serial has no physical pins broken out, so it's not listed as HARDWARE port +#define SERIAL_PORT_HARDWARE Serial1 +#define SERIAL_PORT_HARDWARE_OPEN Serial1 + +#endif /* _VARIANT_ARDUINO_ZERO_ */ + From 1652d4b8209c9dd5f7ddfaccde3b887de586bbc1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 5 Aug 2015 09:26:48 +0200 Subject: [PATCH 180/660] Make sure RF69_IRQ_PIN and RF69_IRQ_NUM always is defined Without this compile breaks on Mega 2560. --- libraries/MySensors/MyConfig.h | 2 -- libraries/MySensors/utility/RFM69.h | 10 ++++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 88db782..a339c52 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -144,6 +144,4 @@ #define RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! - - #endif diff --git a/libraries/MySensors/utility/RFM69.h b/libraries/MySensors/utility/RFM69.h index 23eb044..452a2ae 100644 --- a/libraries/MySensors/utility/RFM69.h +++ b/libraries/MySensors/utility/RFM69.h @@ -36,13 +36,19 @@ #define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead) #define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on atmega328 -// INT0 on AVRs should be connected to RFM69's DIO0 (ex on Atmega328 it's D2, on Atmega644/1284 it's D2) -#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega32U4__) +// INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2) +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 0 #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 2 +#elif defined(__AVR_ATmega32U4__) + #define RF69_IRQ_PIN 3 + #define RF69_IRQ_NUM 0 +#else + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 0 #endif #define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access From 4aee5bd4489028393ddea13cc6c899a14a556d8f Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 7 Aug 2015 15:16:47 +0200 Subject: [PATCH 181/660] Demoted #error to #warning in SecureActuator.ino --- libraries/MySensors/examples/SecureActuator/SecureActuator.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index cae4b81..3211d79 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -71,7 +71,7 @@ MySigningAtsha204 signer; #endif MySensor gw(radio, hw, signer); #else -#error SecureActuator cannot possibly be secure without signing enabled +#warning SecureActuator cannot possibly be secure without signing enabled MySensor gw(radio, hw); #endif From 99cec3bb16b4bf7e4ffe92da42f00b4f6d4d1015 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 7 Aug 2015 21:09:23 +0200 Subject: [PATCH 182/660] Support Arduino MEGA boards for RFM69 interrupt config --- libraries/MySensors/utility/RFM69.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/utility/RFM69.h b/libraries/MySensors/utility/RFM69.h index 23eb044..c3e8d05 100644 --- a/libraries/MySensors/utility/RFM69.h +++ b/libraries/MySensors/utility/RFM69.h @@ -40,7 +40,7 @@ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega32U4__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 0 -#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2560__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 2 #endif From 997cb33226204dff30fd5c8698d71d38f68f5528 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 7 Aug 2015 23:57:34 +0200 Subject: [PATCH 183/660] Allow MySensor specific boards to be compiled with warnings enabled This commit enables the Arduino IDE to configure MySensor specific boards with more verbose warnings just as official Arduino boards. --- hardware/MySensors/avr/platform.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hardware/MySensors/avr/platform.txt b/hardware/MySensors/avr/platform.txt index 28f482c..8f61be7 100644 --- a/hardware/MySensors/avr/platform.txt +++ b/hardware/MySensors/avr/platform.txt @@ -11,17 +11,23 @@ version=1.6.0 # AVR compile variables # --------------------- +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra + # Default "compiler.path" is correct, change only if you want to overidde the initial value compiler.path={runtime.tools.avr-gcc.path}/bin/ compiler.c.cmd=avr-gcc -compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections -MMD +compiler.c.flags=-c -g -Os {compiler.warning_flags} -ffunction-sections -fdata-sections -MMD # -w flag added to avoid printing a wrong warning http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59396 # This is fixed in gcc 4.8.3 and will be removed as soon as we update the toolchain -compiler.c.elf.flags=-w -Os -Wl,--gc-sections +compiler.c.elf.flags={compiler.warning_flags} -Os -Wl,--gc-sections compiler.c.elf.cmd=avr-gcc compiler.S.flags=-c -g -x assembler-with-cpp compiler.cpp.cmd=avr-g++ -compiler.cpp.flags=-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD +compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD compiler.ar.cmd=avr-ar compiler.ar.flags=rcs compiler.objcopy.cmd=avr-objcopy From 5b3e955739fae87abe708d169c71e7bf22f00ca0 Mon Sep 17 00:00:00 2001 From: Ted Drain Date: Sat, 8 Aug 2015 13:45:55 -0700 Subject: [PATCH 184/660] Updated mock sensor code to newer hardware and radio API. --- .../examples/MockMySensors/MockMySensors.ino | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 2eb1629..37411ff 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -6,12 +6,20 @@ * Barduino 2015 */ +#include +#include +#include +#include +#include +#include + #include #include +#include -// SPI Pins -#define CE_PIN 9 -#define CS_PIN 10 +#define RADIO_ERROR_LED_PIN 4 // Error led pin +#define RADIO_RX_LED_PIN 6 // Receive led pin +#define RADIO_TX_LED_PIN 5 // the PCB, on board LED // Wait times #define LONG_WAIT 500 @@ -30,7 +38,10 @@ ////#define ID_S_ARDUINO_NODE //auto defined in initialization ////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization -//#define ID_S_DOOR 1 +// Some of these ID's have not been updated for v1.5. Uncommenting too many of them +// will make the sketch too large for a pro mini's memory so it's probably best to try +// one at a time. +#define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 @@ -43,18 +54,17 @@ //#define ID_S_RAIN 11 //#define ID_S_UV 12 //#define ID_S_WEIGHT 13 -#define ID_S_POWER 14 -#define ID_S_HEATER 15 -#define ID_S_DISTANCE 16 -#define ID_S_LIGHT_LEVEL 17 -#define ID_S_LOCK 18 -#define ID_S_IR 19 -#define ID_S_WATER 20 -#define ID_S_AIR_QUALITY 21 -#define ID_S_DUST 22 -#define ID_S_SCENE_CONTROLLER 23 - -#define ID_S_CUSTOM 24 +//#define ID_S_POWER 14 +//#define ID_S_HEATER 15 +//#define ID_S_DISTANCE 16 +//#define ID_S_LIGHT_LEVEL 17 +//#define ID_S_LOCK 18 +//#define ID_S_IR 19 +//#define ID_S_WATER 20 +//#define ID_S_AIR_QUALITY 21 +//#define ID_S_DUST 22 +//#define ID_S_SCENE_CONTROLLER 23 +//#define ID_S_CUSTOM 24 // Global Vars unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) @@ -62,7 +72,24 @@ boolean metric = true; long randNumber; // Instanciate MySersors Gateway -MySensor gw(CE_PIN,CS_PIN); +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRFM69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +//MySigningNone signer; +//MySigningAtsha204Soft signer; +//MySigningAtsha204 signer; + +// Hardware profile +MyHwATMega328 hw; + +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +#ifdef WITH_LEDS_BLINKING +MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else +MySensor gw(transport, hw /*, signer*/); +#endif //Instanciate Messages objects From af6e5d30197631f1a61c40fae712085d1c54c1db Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 2 Aug 2015 14:38:59 +0200 Subject: [PATCH 185/660] Resolved various compiler warnings This should make Jenkins happy. --- libraries/Bounce2/Bounce2.cpp | 4 ++-- libraries/Bounce2/Bounce2.h | 2 +- libraries/DHT/DHT.cpp | 6 +++--- .../DallasTemperature/DallasTemperature.cpp | 1 + libraries/DigitalIO/SoftI2cMaster.cpp | 1 - libraries/DigitalIO/SoftI2cMaster.h | 4 ++-- libraries/IRLib/IRLib.cpp | 12 ++++++++--- libraries/IRLib/IRLib.h | 2 +- libraries/LiquidCrystal/LCD.h | 14 +++++++------ .../LiquidCrystal/LiquidCrystal_I2C_ByVac.cpp | 2 +- libraries/LiquidCrystal/LiquidCrystal_SR.cpp | 6 ++++-- .../LiquidCrystal/LiquidCrystal_SR1W.cpp | 2 ++ libraries/LiquidCrystal/LiquidCrystal_SR1W.h | 2 +- .../LiquidCrystal/LiquidCrystal_SR2W.cpp | 2 ++ libraries/MySensors/MyConfig.h | 3 +-- libraries/MySensors/MySensor.cpp | 1 + libraries/MySensors/MySensor.h | 10 ++++----- libraries/MySensors/MySigningAtsha204.cpp | 2 ++ libraries/MySensors/MySigningAtsha204.h | 2 -- libraries/MySensors/MySigningAtsha204Soft.cpp | 7 ++++--- libraries/MySensors/MySigningAtsha204Soft.h | 2 -- libraries/MySensors/MySigningNone.cpp | 4 ++++ libraries/MySensors/MySigningNone.h | 2 -- libraries/MySensors/MyTransportNRF24.cpp | 1 + .../BatteryPoweredSensor.ino | 10 +++++---- .../IrrigationController.ino | 7 +++++-- .../RealTimeClockDisplaySensor.ino | 4 ++-- .../SecureActuator/SecureActuator.ino | 2 +- .../TouchDisplaySceneControllerSensor.ino | 21 ++++++++++--------- libraries/MySensors/utility/ATSHA204.cpp | 3 ++- libraries/MySensors/utility/RF24.cpp | 2 +- libraries/MySensors/utility/RFM69.cpp | 6 +++--- libraries/PN532/PN532.cpp | 8 ++++--- libraries/PN532/llcp.cpp | 5 ++++- libraries/PN532/snep.cpp | 2 +- .../PWFusion_AS3935.cpp | 13 +++--------- libraries/PinChangeInt/PinChangeInt.h | 3 ++- libraries/RemoteSwitch/RemoteTransmitter.cpp | 1 + libraries/UTFT/UTFT.cpp | 12 +++++------ libraries/UTFT_Buttons/UTFT_Buttons.cpp | 4 ++-- libraries/sha204/sha204_library.cpp | 13 ++++++++++++ 41 files changed, 123 insertions(+), 87 deletions(-) diff --git a/libraries/Bounce2/Bounce2.cpp b/libraries/Bounce2/Bounce2.cpp index 96e0d16..1d3b1f9 100644 --- a/libraries/Bounce2/Bounce2.cpp +++ b/libraries/Bounce2/Bounce2.cpp @@ -18,7 +18,7 @@ Bounce::Bounce() { void Bounce::attach(int pin) { this->pin = pin; debouncedState = unstableState = digitalRead(pin); - #ifdef BOUNCE_LOCK-OUT + #ifdef BOUNCE_LOCK_OUT previous_millis = 0; #else previous_millis = millis(); @@ -37,7 +37,7 @@ void Bounce::interval(unsigned long interval_millis) bool Bounce::update() { -#ifdef BOUNCE_LOCK-OUT +#ifdef BOUNCE_LOCK_OUT stateChanged = false; // Ignore everything if we are locked out if (millis() - previous_millis >= interval_millis) { diff --git a/libraries/Bounce2/Bounce2.h b/libraries/Bounce2/Bounce2.h index 6d2b62b..86c1520 100644 --- a/libraries/Bounce2/Bounce2.h +++ b/libraries/Bounce2/Bounce2.h @@ -24,7 +24,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Uncomment the following line for "LOCK-OUT" debounce method -//#define BOUNCE_LOCK-OUT +//#define BOUNCE_LOCK_OUT #ifndef Bounce2_h diff --git a/libraries/DHT/DHT.cpp b/libraries/DHT/DHT.cpp index d32c83f..1584d6a 100644 --- a/libraries/DHT/DHT.cpp +++ b/libraries/DHT/DHT.cpp @@ -142,9 +142,9 @@ void DHT::readSensor() // - Then 40 bits: RISING and then a FALLING edge per bit // To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long - word rawHumidity; - word rawTemperature; - word data; + word rawHumidity = 0; + word rawTemperature = 0; + word data = 0; for ( int8_t i = -3 ; i < 2 * 40; i++ ) { byte age; diff --git a/libraries/DallasTemperature/DallasTemperature.cpp b/libraries/DallasTemperature/DallasTemperature.cpp index 8cf7515..80ee4f8 100644 --- a/libraries/DallasTemperature/DallasTemperature.cpp +++ b/libraries/DallasTemperature/DallasTemperature.cpp @@ -700,6 +700,7 @@ void DallasTemperature::setAlarmHandler(AlarmHandler *handler) // The default alarm handler void DallasTemperature::defaultAlarmHandler(const uint8_t* deviceAddress) { + (void)deviceAddress; } #endif diff --git a/libraries/DigitalIO/SoftI2cMaster.cpp b/libraries/DigitalIO/SoftI2cMaster.cpp index efc338a..a698636 100644 --- a/libraries/DigitalIO/SoftI2cMaster.cpp +++ b/libraries/DigitalIO/SoftI2cMaster.cpp @@ -50,7 +50,6 @@ */ bool I2cMasterBase::transfer(uint8_t addrRW, void *buf, size_t nbytes, uint8_t option) { - uint8_t* p = reinterpret_cast(buf); if (_state != STATE_REP_START) { start(); } diff --git a/libraries/DigitalIO/SoftI2cMaster.h b/libraries/DigitalIO/SoftI2cMaster.h index e2d559a..7bf3c00 100644 --- a/libraries/DigitalIO/SoftI2cMaster.h +++ b/libraries/DigitalIO/SoftI2cMaster.h @@ -132,7 +132,7 @@ class SoftI2cMaster : public I2cMasterBase { //---------------------------------------------------------------------------- void sclDelay(uint8_t n) {_delay_loop_1(n);} //---------------------------------------------------------------------------- - bool writeScl(bool value) { + void writeScl(bool value) { uint8_t s = SREG; noInterrupts(); if (value == LOW) { @@ -145,7 +145,7 @@ class SoftI2cMaster : public I2cMasterBase { SREG = s; } //---------------------------------------------------------------------------- - bool writeSda(bool value) { + void writeSda(bool value) { uint8_t s = SREG; noInterrupts(); if (value == LOW) { diff --git a/libraries/IRLib/IRLib.cpp b/libraries/IRLib/IRLib.cpp index 7307bac..a8748bd 100644 --- a/libraries/IRLib/IRLib.cpp +++ b/libraries/IRLib/IRLib.cpp @@ -649,7 +649,7 @@ bool IRdecodeRC6::decode(void) { * Hopefully this code is unique for each button. */ #define FNV_PRIME_32 16777619 -#define FNV_BASIS_32 2166136261 +#define FNV_BASIS_32 2166136261UL // Compare two tick values, returning 0 if newval is shorter, // 1 if newval is equal, and 2 if newval is longer int IRdecodeHash::compare(unsigned int oldval, unsigned int newval) { @@ -730,12 +730,12 @@ void IRrecvBase::resume() { bool IRrecvLoop::GetResults(IRdecodeBase *decoder) { bool Finished=false; byte OldState=HIGH;byte NewState; - unsigned long StartTime, DeltaTime, EndTime; + unsigned long StartTime, DeltaTime=0, EndTime=0; StartTime=micros(); while(irparams.rawlen 10000) { //If it's a very long wait - if(Finished=irparams.rawlen) break; //finished unless it's the opening gap + if((Finished=irparams.rawlen)) break; //finished unless it's the opening gap } } if(Finished) break; @@ -798,6 +798,9 @@ void IRrecvPCI_Handler(){ case STATE_IDLE: if(digitalRead(irparams.recvpin)) return; else irparams.rcvstate=STATE_RUNNING; break; + default: + // what of STATE_UNKNOWN, STATE_MARK and STATE_SPACE? + break; }; irparams.rawbuf[irparams.rawlen]=DeltaTime; irparams.timer=ChangeTime; @@ -982,6 +985,9 @@ ISR(TIMER_INTR_NAME) irparams.timer = 0; } break; + default: + // what of STATE_UNKNOWN and STATE_RUNNING? + break; } do_Blink(); } diff --git a/libraries/IRLib/IRLib.h b/libraries/IRLib/IRLib.h index c8e6c38..0dd05a2 100644 --- a/libraries/IRLib/IRLib.h +++ b/libraries/IRLib/IRLib.h @@ -48,7 +48,7 @@ #define RAWBUF 100 // Length of raw duration buffer (cannot exceed 255) -typedef char IRTYPES; //formerly was an enum +typedef unsigned char IRTYPES; //formerly was an enum #define UNKNOWN 0 #define NEC 1 #define SONY 2 diff --git a/libraries/LiquidCrystal/LCD.h b/libraries/LiquidCrystal/LCD.h index 9b977f4..43367aa 100644 --- a/libraries/LiquidCrystal/LCD.h +++ b/libraries/LiquidCrystal/LCD.h @@ -90,6 +90,8 @@ inline static void waitUsec ( uint16_t uSec ) { #ifndef FAST_MODE delayMicroseconds ( uSec ); +#else + (void)uSec; #endif // FAST_MODE } @@ -481,7 +483,7 @@ public: @param value: pin associated to backlight control. @param pol: backlight polarity control (POSITIVE, NEGATIVE) */ - virtual void setBacklightPin ( uint8_t value, t_backlighPol pol ) { }; + virtual void setBacklightPin ( uint8_t /*value*/, t_backlighPol /*pol*/ ) { }; /*! @function @@ -500,7 +502,7 @@ public: BACKLIGHT_OFF will be interpreted as off and BACKLIGHT_ON will drive the backlight on. */ - virtual void setBacklight ( uint8_t value ) { }; + virtual void setBacklight ( uint8_t /*value*/ ) { }; /*! @function @@ -514,9 +516,9 @@ public: @param value[in] Value to write to the LCD. */ #if (ARDUINO < 100) - virtual void write(uint8_t value); + virtual void write(uint8_t /*value*/); #else - virtual size_t write(uint8_t value); + virtual size_t write(uint8_t /*value*/); #endif #if (ARDUINO < 100) @@ -566,9 +568,9 @@ private: the LCD. */ #if (ARDUINO < 100) - virtual void send(uint8_t value, uint8_t mode) { }; + virtual void send(uint8_t /*value*/, uint8_t /*mode*/) { }; #else - virtual void send(uint8_t value, uint8_t mode) = 0; + virtual void send(uint8_t /*value*/, uint8_t /*mode*/) = 0; #endif }; diff --git a/libraries/LiquidCrystal/LiquidCrystal_I2C_ByVac.cpp b/libraries/LiquidCrystal/LiquidCrystal_I2C_ByVac.cpp index 69dd9e7..9f73fab 100644 --- a/libraries/LiquidCrystal/LiquidCrystal_I2C_ByVac.cpp +++ b/libraries/LiquidCrystal/LiquidCrystal_I2C_ByVac.cpp @@ -38,7 +38,7 @@ LiquidCrystal_I2C_ByVac::LiquidCrystal_I2C_ByVac( uint8_t lcd_Addr ) { _Addr = lcd_Addr; - _polarity == NEGATIVE; + _polarity = NEGATIVE; } // PUBLIC METHODS diff --git a/libraries/LiquidCrystal/LiquidCrystal_SR.cpp b/libraries/LiquidCrystal/LiquidCrystal_SR.cpp index a966caa..64aae2f 100644 --- a/libraries/LiquidCrystal/LiquidCrystal_SR.cpp +++ b/libraries/LiquidCrystal/LiquidCrystal_SR.cpp @@ -110,6 +110,8 @@ LiquidCrystal_SR::LiquidCrystal_SR (uint8_t srdata, uint8_t srclock, void LiquidCrystal_SR::init(uint8_t srdata, uint8_t srclock, uint8_t enable, uint8_t lines, uint8_t font) { + (void)lines; + (void)font; // Initialise private variables _two_wire = 0; @@ -200,10 +202,10 @@ void LiquidCrystal_SR::send(uint8_t value, uint8_t mode) // // setBacklightPin void LiquidCrystal_SR::setBacklightPin ( uint8_t pin, t_backlighPol pol ) -{ } +{ (void)pin; (void)pol; } // // setBacklight void LiquidCrystal_SR::setBacklight ( uint8_t mode ) -{ } +{ (void)mode; } diff --git a/libraries/LiquidCrystal/LiquidCrystal_SR1W.cpp b/libraries/LiquidCrystal/LiquidCrystal_SR1W.cpp index f32ef70..a04dfb2 100644 --- a/libraries/LiquidCrystal/LiquidCrystal_SR1W.cpp +++ b/libraries/LiquidCrystal/LiquidCrystal_SR1W.cpp @@ -49,6 +49,8 @@ LiquidCrystal_SR1W::LiquidCrystal_SR1W (uint8_t srdata, t_sr1w_circuitType circu // init void LiquidCrystal_SR1W::init(uint8_t srdata, t_sr1w_circuitType circuitType, t_backlighPol blpol, uint8_t lines, uint8_t font) { + (void)lines; + (void)font; _srRegister = fio_pinToOutputRegister(srdata); _srMask = fio_pinToBit(srdata); diff --git a/libraries/LiquidCrystal/LiquidCrystal_SR1W.h b/libraries/LiquidCrystal/LiquidCrystal_SR1W.h index d71c173..7b26900 100644 --- a/libraries/LiquidCrystal/LiquidCrystal_SR1W.h +++ b/libraries/LiquidCrystal/LiquidCrystal_SR1W.h @@ -154,7 +154,7 @@ // | | | / | 1k // | +--8-|GND Q'H|--9-----+ | // | | +---------+ | | (GND)--(LCD RW) -// | | 0.1uF | \ +/* | | 0.1uF | \ */ // | (GND)-----||----(VCC) +------)--------------(LCD EN) // | | / // |----|<|----+--[ Resistor ]--| | diff --git a/libraries/LiquidCrystal/LiquidCrystal_SR2W.cpp b/libraries/LiquidCrystal/LiquidCrystal_SR2W.cpp index df4559a..e76a585 100644 --- a/libraries/LiquidCrystal/LiquidCrystal_SR2W.cpp +++ b/libraries/LiquidCrystal/LiquidCrystal_SR2W.cpp @@ -47,6 +47,8 @@ LiquidCrystal_SR2W::LiquidCrystal_SR2W (uint8_t srdata, uint8_t srclock, t_backl // init void LiquidCrystal_SR2W::init(uint8_t srdata, uint8_t srclock, t_backlighPol blpol, uint8_t lines, uint8_t font) { + (void)lines; + (void)font; _srDataRegister = fio_pinToOutputRegister(srdata); _srDataMask = fio_pinToBit(srdata); _srClockRegister = fio_pinToOutputRegister(srclock); diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 88db782..a79119a 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -53,7 +53,7 @@ // but now can be used in any sensor node. Also the LEDs can now be // disabled in the gateway. -//#define WITH_LEDS_BLINKING +// #define WITH_LEDS_BLINKING // The following setting allows you to inverse the blinking feature WITH_LEDS_BLINKING // When WITH_LEDS_BLINKING_INVERSE is enabled LEDSs are normally turned on and switches @@ -103,7 +103,6 @@ // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - /********************************** * NRF24L01 Driver Defaults ***********************************/ diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 9d6ecb8..2e75d0a 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -550,6 +550,7 @@ boolean MySensor::process() { #endif uint8_t len = radio.receive((uint8_t *)&msg); + (void)len; //until somebody makes use of 'len' #ifdef WITH_LEDS_BLINKING rxBlink(1); #endif diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 0a54987..3577693 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -343,11 +343,6 @@ class MySensor MyMessage msg; // Buffer for incoming messages. MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). -#ifdef MY_SIGNING_FEATURE - uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication - MyMessage msgSign; // Buffer for message to sign. - MySigning& signer; -#endif #ifdef WITH_LEDS_BLINKING uint8_t pinRx; // Rx led pin @@ -364,6 +359,11 @@ class MySensor #endif MyTransport& radio; +#ifdef MY_SIGNING_FEATURE + uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication + MyMessage msgSign; // Buffer for message to sign. + MySigning& signer; +#endif MyHw& hw; boolean sendWrite(uint8_t dest, MyMessage &message); diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 2baa0dd..29c4d59 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -28,6 +28,8 @@ #include "MySigning.h" #include "MySigningAtsha204.h" +#define SIGNING_IDENTIFIER (1) + // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/MySigningAtsha204.h index 5232c00..188a4aa 100644 --- a/libraries/MySensors/MySigningAtsha204.h +++ b/libraries/MySensors/MySigningAtsha204.h @@ -33,8 +33,6 @@ #include "utility/ATSHA204.h" #include -#define SIGNING_IDENTIFIER (1) - #ifdef MY_SECURE_NODE_WHITELISTING typedef struct { uint8_t nodeId; diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/MySigningAtsha204Soft.cpp index 043d367..971602c 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/MySigningAtsha204Soft.cpp @@ -33,6 +33,8 @@ #include "MySigningAtsha204Soft.h" #include "utility/sha256.h" +#define SIGNING_IDENTIFIER (1) + // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING @@ -72,15 +74,14 @@ MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, uint8_t randomseedPin) : MySigning(requestSignatures), - rndPin(randomseedPin), #ifdef MY_SECURE_NODE_WHITELISTING whitlist_sz(nof_whitelist_entries), whitelist(the_whitelist), node_serial_info(the_serial), #endif + Sha256(), verification_ongoing(false), - Sha256() - + rndPin(randomseedPin) { } diff --git a/libraries/MySensors/MySigningAtsha204Soft.h b/libraries/MySensors/MySigningAtsha204Soft.h index 5d8090e..cd65d2c 100644 --- a/libraries/MySensors/MySigningAtsha204Soft.h +++ b/libraries/MySensors/MySigningAtsha204Soft.h @@ -37,8 +37,6 @@ #include "utility/sha256.h" #include -#define SIGNING_IDENTIFIER (1) - #ifdef MY_SECURE_NODE_WHITELISTING typedef struct { uint8_t nodeId; diff --git a/libraries/MySensors/MySigningNone.cpp b/libraries/MySensors/MySigningNone.cpp index a73a375..d9aa5ab 100644 --- a/libraries/MySensors/MySigningNone.cpp +++ b/libraries/MySensors/MySigningNone.cpp @@ -29,6 +29,8 @@ #include "MySigning.h" #include "MySigningNone.h" +#define SIGNING_IDENTIFIER (0) + // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING @@ -61,6 +63,7 @@ MySigningNone::MySigningNone() : MySigning() { } bool MySigningNone::getNonce(MyMessage &msg) { + (void)msg; return true; } @@ -69,6 +72,7 @@ bool MySigningNone::checkTimer() { } bool MySigningNone::putNonce(MyMessage &msg) { + (void)msg; return true; } diff --git a/libraries/MySensors/MySigningNone.h b/libraries/MySensors/MySigningNone.h index b024b41..4b27103 100644 --- a/libraries/MySensors/MySigningNone.h +++ b/libraries/MySensors/MySigningNone.h @@ -32,8 +32,6 @@ #include "MySigning.h" #include -#define SIGNING_IDENTIFIER (0) - // The "none" signing driver that can be used for nodes // not requiring signing // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in diff --git a/libraries/MySensors/MyTransportNRF24.cpp b/libraries/MySensors/MyTransportNRF24.cpp index fee7dca..d11545d 100644 --- a/libraries/MySensors/MyTransportNRF24.cpp +++ b/libraries/MySensors/MyTransportNRF24.cpp @@ -74,6 +74,7 @@ bool MyTransportNRF24::send(uint8_t to, const void* data, uint8_t len) { bool MyTransportNRF24::available(uint8_t *to) { uint8_t pipe = 255; boolean avail = rf24.available(&pipe); + (void)avail; //until somebody makes use of 'avail' if (pipe == CURRENT_NODE_PIPE) *to = _address; else if (pipe == BROADCAST_PIPE) diff --git a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino index 40c51da..87d0d6e 100644 --- a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino +++ b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino @@ -30,8 +30,6 @@ #include #include -#define DEBUG 1 // Debug enables Serial.print 1 = Yes 0 = No - int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point MySensor gw; @@ -41,7 +39,11 @@ int oldBatteryPcnt = 0; void setup() { // use the 1.1 V internal reference +#if defined(__AVR_ATmega2560__) + analogReference(INTERNAL1V1); +#else analogReference(INTERNAL); +#endif gw.begin(); // Send the sketch version information to the gateway and Controller @@ -52,7 +54,7 @@ void loop() { // get the battery Voltage int sensorValue = analogRead(BATTERY_SENSE_PIN); - #if DEBUG > 0 + #ifdef DEBUG Serial.println(sensorValue); #endif @@ -63,7 +65,7 @@ void loop() float batteryV = sensorValue * 0.003363075; int batteryPcnt = sensorValue / 10; - #if DEBUG > 0 + #ifdef DEBUG Serial.print("Battery Voltage: "); Serial.print(batteryV); Serial.println(" V"); diff --git a/libraries/MySensors/examples/IrrigationController/IrrigationController.ino b/libraries/MySensors/examples/IrrigationController/IrrigationController.ino index 41e6eb9..abd26e0 100644 --- a/libraries/MySensors/examples/IrrigationController/IrrigationController.ino +++ b/libraries/MySensors/examples/IrrigationController/IrrigationController.ino @@ -191,7 +191,7 @@ void setup() //check for saved date in EEPROM DEBUG_PRINTLN(F("Checking EEPROM for stored date:")); delay(500); - if (gw.loadState(0) == 0xFF); // EEPROM flag + if (gw.loadState(0) == 0xFF) // EEPROM flag { DEBUG_PRINTLN(F("Retreiving last run time from EEPROM...")); for (int i = 0; i < 4 ; i++) @@ -439,7 +439,7 @@ void loop() state = STAND_BY_ALL_OFF; } } - else if (state = ZONE_SELECT_MENU) + else if (state == ZONE_SELECT_MENU) { displayMenu(); } @@ -771,6 +771,9 @@ void updateDisplay() lcd.print(totalTimeRan); lcd.print(" Minutes "); } + default: + // what of ZONE_SELECT_MENU? + break; } lastUpdateTime = millis(); } diff --git a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino index a4c5944..f0ca797 100644 --- a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino +++ b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino @@ -88,8 +88,8 @@ void loop() // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour - if ((!timeReceived && now-lastRequest > 10*1000) - || (timeReceived && now-lastRequest > 60*1000*60)) { + if ((!timeReceived && now-lastRequest > (unsigned long)(10*1000)) + || (timeReceived && now-lastRequest > (unsigned long)(60*1000*60))) { // Request time from controller. Serial.println("requesting time"); gw.requestTime(receiveTime); diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 3211d79..ae40fad 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -85,7 +85,7 @@ void setup() // Fetch lock status for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) { // Register all locks to gw (they will be created as child devices) - gw.present(lock, S_LOCK, false); + gw.present(lock, S_LOCK, "SecureActuator", false); // Then set lock pins in output mode pinMode(pin, OUTPUT); // Set lock to last known state (using eeprom storage) diff --git a/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino b/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino index 7a1946a..c5e9dec 100644 --- a/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino +++ b/libraries/MySensors/examples/TouchDisplaySceneControllerSensor/TouchDisplaySceneControllerSensor.ino @@ -77,17 +77,19 @@ int RESEND_DEBOUNCE = 2000; // Number of millisecons interval between sending of // Add your buttons here. Max is 5 if you still want time at the top. char *buttons[] = { - "Good Morning", - "Clean Up!", - "All Lights Off", - "Music On/Off" + (char *)"Good Morning", + (char *)"Clean Up!", + (char *)"All Lights Off", + (char *)"Music On/Off" }; const int buttonCount = sizeof(buttons)/sizeof(char *); const int padding = 10; const int topBarHeight = 60; -MySensor gw(17,18); +MyTransportNRF24 radio; // NRFRF24L01 radio driver +MyHwATMega328 hw; // Select AtMega328 hardware profile +MySensor gw(radio, hw); MyMessage on(CHILD_ID, V_SCENE_ON); MyMessage off(CHILD_ID, V_SCENE_OFF); @@ -142,13 +144,12 @@ void loop() unsigned long now = millis(); if (myTouch.dataAvailable()) { - unsigned long startPress = millis(); int pressedButton = myButtons.checkButtons(); if (pressedButton>=0) { - bool longPress = millis()-now>LONG_PRESS; + bool longPress = millis()-now>(unsigned long)LONG_PRESS; - if (pressedButton != lastPressedButton || now-lastPressedButtonTime > RESEND_DEBOUNCE) { + if (pressedButton != lastPressedButton || now-lastPressedButtonTime > (unsigned long)RESEND_DEBOUNCE) { if (longPress) { gw.send(off.set(pressedButton)); Serial.print("Long pressed: "); @@ -165,8 +166,8 @@ void loop() // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour - if ((!timeReceived && now-lastRequest > 10*1000) - || (timeReceived && now-lastRequest > 60*1000*60)) { + if ((!timeReceived && now-lastRequest > (unsigned long)10*1000) + || (timeReceived && now-lastRequest > (unsigned long)60*1000*60)) { // Request time from controller. Serial.println("requesting time"); gw.requestTime(receiveTime); diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index 504d73d..f639bab 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -463,7 +463,8 @@ uint8_t ATSHA204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t uint8_t poll_delay, poll_timeout, response_size; uint8_t *p_buffer; uint8_t len; - + (void)tx_size; + // Supply delays and response size. switch (op_code) { diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp index 5f5329d..a0d281f 100644 --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -41,7 +41,7 @@ void RF24::csn(bool mode) delayMicroseconds(11); // allow csn to settle } } -#else if !defined (__arm__) || defined (CORE_TEENSY) +#elif !defined (__arm__) || defined (CORE_TEENSY) digitalWrite(csn_pin,mode); #endif diff --git a/libraries/MySensors/utility/RFM69.cpp b/libraries/MySensors/utility/RFM69.cpp index 24bb2d3..4663480 100644 --- a/libraries/MySensors/utility/RFM69.cpp +++ b/libraries/MySensors/utility/RFM69.cpp @@ -55,9 +55,9 @@ bool RFM69::initialize(byte freqBand, byte nodeID, byte networkID) /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, //default:5khz, (FDEV + BitRate/2 <= 500Khz) /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, - /* 0x07 */ { REG_FRFMSB, (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, - /* 0x08 */ { REG_FRFMID, (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, - /* 0x09 */ { REG_FRFLSB, (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, + /* 0x07 */ { REG_FRFMSB, (freqBand==RF69_315MHZ ? (const byte)RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFMSB_868 : (const byte)RF_FRFMSB_915))) }, + /* 0x08 */ { REG_FRFMID, (freqBand==RF69_315MHZ ? (const byte)RF_FRFMID_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFMID_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFMID_868 : (const byte)RF_FRFMID_915))) }, + /* 0x09 */ { REG_FRFLSB, (freqBand==RF69_315MHZ ? (const byte)RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFLSB_868 : (const byte)RF_FRFLSB_915))) }, // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm // +17dBm and +20dBm are possible on RFM69HW diff --git a/libraries/PN532/PN532.cpp b/libraries/PN532/PN532.cpp index c6c5490..a9ab4c6 100644 --- a/libraries/PN532/PN532.cpp +++ b/libraries/PN532/PN532.cpp @@ -61,6 +61,7 @@ void PN532::begin() /**************************************************************************/ void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes) { + (void)data; for (uint8_t i = 0; i < numBytes; i++) { DMSG("0x"); DMSG_HEX(data[i]); @@ -86,11 +87,11 @@ void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes) } DMSG(" "); for (uint8_t i = 0; i < numBytes; i++) { - char c = data[i]; + uint8_t c = data[i]; if (c <= 0x1f || c > 0x7f) { DMSG('.'); } else { - DMSG(c); + DMSG((char)c); } } @@ -548,7 +549,7 @@ uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIden // in NDEF records // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message) - uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, (uint8_t)(len + 5), 0xD1, 0x01, (uint8_t)(len + 1), 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; @@ -653,6 +654,7 @@ uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer) bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength) { uint8_t i; + (void)i; pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE; pn532_packetbuffer[1] = inListedTag; diff --git a/libraries/PN532/llcp.cpp b/libraries/PN532/llcp.cpp index ad00236..68da733 100644 --- a/libraries/PN532/llcp.cpp +++ b/libraries/PN532/llcp.cpp @@ -37,6 +37,7 @@ int8_t LLCP::activate(uint16_t timeout) int8_t LLCP::waitForConnection(uint16_t timeout) { uint8_t type; + (void)timeout; sequence = 0; @@ -76,6 +77,7 @@ int8_t LLCP::waitForConnection(uint16_t timeout) int8_t LLCP::waitForDisconnection(uint16_t timeout) { uint8_t type; + (void)timeout; // Get DISC PDU DMSG("wait for a DISC PDU\n"); @@ -113,6 +115,7 @@ int8_t LLCP::waitForDisconnection(uint16_t timeout) int8_t LLCP::connect(uint16_t timeout) { uint8_t type; + (void)timeout; sequence = 0; @@ -165,6 +168,7 @@ int8_t LLCP::connect(uint16_t timeout) int8_t LLCP::disconnect(uint16_t timeout) { uint8_t type; + (void)timeout; // try to get a SYMM PDU if (2 > link.read(headerBuf, headerBufLen)) { @@ -207,7 +211,6 @@ int8_t LLCP::disconnect(uint16_t timeout) bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) { - uint8_t type; uint8_t buf[3]; if (2 != link.read(buf, sizeof(buf))) { diff --git a/libraries/PN532/snep.cpp b/libraries/PN532/snep.cpp index 650532d..f690878 100644 --- a/libraries/PN532/snep.cpp +++ b/libraries/PN532/snep.cpp @@ -79,7 +79,7 @@ int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout) } // check message's length - uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5]; + uint32_t length = ((uint32_t)buf[2] << 24) + ((uint32_t)buf[3] << 16) + (buf[4] << 8) + buf[5]; // length should not be more than 244 (header + body < 255, header = 6 + 3 + 2) if (length > (status - 6)) { DMSG("The SNEP message is too large\n"); diff --git a/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp index 1d2b8a0..b512121 100644 --- a/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp +++ b/libraries/PWF_AS3935_Lightning_Sensor/PWFusion_AS3935.cpp @@ -78,15 +78,8 @@ uint8_t PWF_AS3935::_sing_reg_read(uint8_t RegAdd) void PWF_AS3935::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData) { - // start by reading original register data (only modifying what we need to) - uint8_t OrigRegData = _sing_reg_read(RegAdd); - - // calculate new register data... 'delete' old targeted data, replace with new data - // note: 'DataMask' must be bits targeted for replacement - // add'l note: this function does NOT shift values into the proper place... they need to be there already - uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask)); - - // now configure and write the updated register value + (void)DataMask; + // Configure and write the updated register value digitalWrite(_cs, LOW); // set pin low to start talking to IC // next pack command byte, send AS3935.... structure is shown below // MODE Register Address/Direct Cmd @@ -228,7 +221,7 @@ uint32_t PWF_AS3935::AS3935_GetStrikeEnergyRaw(void) { uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB nrgy_raw |= _sing_reg_read(0x05); // read MSB - nrgy_raw <= 8; // shift 8 bits left, make room for LSB + nrgy_raw <<= 8; // shift 8 bits left, make room for LSB nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others return nrgy_raw; diff --git a/libraries/PinChangeInt/PinChangeInt.h b/libraries/PinChangeInt/PinChangeInt.h index 807b20d..6ccd1df 100644 --- a/libraries/PinChangeInt/PinChangeInt.h +++ b/libraries/PinChangeInt/PinChangeInt.h @@ -474,7 +474,8 @@ void PCintPort::detachInterrupt(uint8_t arduinoPin) // there isn't really a good way to back-map ports and masks to pins. void PCintPort::PCint() { uint8_t thisChangedPin; //MIKE - + (void)thisChangedPin; + #ifdef FLASH if (*led_port & led_mask) *led_port&=not_led_mask; else *led_port|=led_mask; diff --git a/libraries/RemoteSwitch/RemoteTransmitter.cpp b/libraries/RemoteSwitch/RemoteTransmitter.cpp index d4df6e6..648b5a8 100644 --- a/libraries/RemoteSwitch/RemoteTransmitter.cpp +++ b/libraries/RemoteSwitch/RemoteTransmitter.cpp @@ -230,6 +230,7 @@ unsigned long KaKuTransmitter::getTelegram(char address, byte device, boolean on } void KaKuTransmitter::sendSignal(char address, byte group, byte device, boolean on) { + (void)device; sendTelegram(getTelegram(address, group, on), _pin); } diff --git a/libraries/UTFT/UTFT.cpp b/libraries/UTFT/UTFT.cpp index 5bfd21d..17da918 100644 --- a/libraries/UTFT/UTFT.cpp +++ b/libraries/UTFT/UTFT.cpp @@ -854,8 +854,8 @@ void UTFT::printChar(byte c, int x, int y) { setXY(x,y,x+cfont.x_size-1,y+cfont.y_size-1); - temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4; - for(j=0;j<((cfont.x_size/8)*cfont.y_size);j++) + temp=(word)((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4; + for(j=0;j<(word)((cfont.x_size/8)*cfont.y_size);j++) { ch=pgm_read_byte(&cfont.font[temp]); for(i=0;i<8;i++) @@ -876,7 +876,7 @@ void UTFT::printChar(byte c, int x, int y) { temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4; - for(j=0;j<((cfont.x_size/8)*cfont.y_size);j+=(cfont.x_size/8)) + for(j=0;j<(word)((cfont.x_size/8)*cfont.y_size);j+=(cfont.x_size/8)) { setXY(x,y+(j/(cfont.x_size/8)),x+cfont.x_size-1,y+(j/(cfont.x_size/8))); for (int zz=(cfont.x_size/8)-1; zz>=0; zz--) @@ -1080,7 +1080,7 @@ void UTFT::printNumF(double num, byte dec, int x, int y, char divider, int lengt if (divider != '.') { - for (int i=0; i= buttons[i].pos_x) and (touch_x <= (buttons[i].pos_x + buttons[i].width)) and (touch_y >= buttons[i].pos_y) and (touch_y <= (buttons[i].pos_y + buttons[i].height))) + if ((touch_x >= (int)buttons[i].pos_x) and (touch_x <= (int)(buttons[i].pos_x + buttons[i].width)) and (touch_y >= (int)buttons[i].pos_y) and (touch_y <= (int)(buttons[i].pos_y + buttons[i].height))) result = i; } } diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp index 8e43890..8728096 100644 --- a/libraries/sha204/sha204_library.cpp +++ b/libraries/sha204/sha204_library.cpp @@ -791,6 +791,19 @@ uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, return SHA204_SUCCESS; #else + (void)rx_size; + (void)tx_size; + (void)tx_buffer; + (void)rx_buffer; + (void)param1; + (void)param2; + (void)data1; + (void)data2; + (void)data3; + (void)datalen1; + (void)datalen2; + (void)datalen3; + (void)op_code; return SHA204_SUCCESS; #endif } From 2b2a0ce294e7dcbcf72df9e88517d49249684b7d Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 9 Aug 2015 02:01:24 +0200 Subject: [PATCH 186/660] Fixed various sketch-specific warnings --- .../DimmableLightWithRotaryEncoderButton.ino | 2 +- .../MySensors/examples/DistanceSensor/DistanceSensor.ino | 2 +- .../MySensors/examples/LightningSensor/LightningSensor.ino | 3 +-- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 5 +++-- libraries/MySensors/examples/RainGauge/RainGauge.ino | 2 +- .../RealTimeClockDisplaySensor.ino | 4 ++-- .../examples/SecretKnockSensor/SecretKnockSensor.ino | 1 - .../MySensors/examples/SecureActuator/SecureActuator.ino | 2 +- .../examples/Sha204Personalizer/Sha204Personalizer.ino | 3 ++- .../MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino | 4 ++-- libraries/MySensors/examples/UVSensor/UVSensor.ino | 4 ++-- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/MySensors/examples/DimmableLightWithRotaryEncoderButton/DimmableLightWithRotaryEncoderButton.ino b/libraries/MySensors/examples/DimmableLightWithRotaryEncoderButton/DimmableLightWithRotaryEncoderButton.ino index 81fe076..2386526 100644 --- a/libraries/MySensors/examples/DimmableLightWithRotaryEncoderButton/DimmableLightWithRotaryEncoderButton.ino +++ b/libraries/MySensors/examples/DimmableLightWithRotaryEncoderButton/DimmableLightWithRotaryEncoderButton.ino @@ -133,7 +133,7 @@ void incomingMessage(const MyMessage &message) newLevel = loadLevelState(EEPROM_DIM_LEVEL_SAVE); } // Send dimmer level back to controller with ack enabled - gw.send(dimmerMsg.set(0), true); + gw.send(dimmerMsg.set(newLevel), true); // We do not change any levels here until ack comes back from gateway return; } else if (message.type == V_DIMMER) { diff --git a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino index a21e86a..59f15a8 100644 --- a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino +++ b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino @@ -51,7 +51,7 @@ void setup() // Register all sensors to gw (they will be created as child devices) gw.present(CHILD_ID, S_DISTANCE); - boolean metric = gw.getConfig().isMetric; + metric = gw.getConfig().isMetric; } void loop() diff --git a/libraries/MySensors/examples/LightningSensor/LightningSensor.ino b/libraries/MySensors/examples/LightningSensor/LightningSensor.ino index 8d2bace..63b1a53 100644 --- a/libraries/MySensors/examples/LightningSensor/LightningSensor.ino +++ b/libraries/MySensors/examples/LightningSensor/LightningSensor.ino @@ -42,7 +42,6 @@ void setup() // Register all sensors to gw (they will be created as child devices) gw.present(CHILD_ID_DISTANCE, S_DISTANCE); gw.present(CHILD_ID_INTENSITY, S_CUSTOM); - boolean metric = gw.getConfig().isMetric; Serial.begin(115200); Serial.println("Playing With Fusion: AS3935 Lightning Sensor, SEN-39001"); @@ -118,4 +117,4 @@ void loop() void AS3935_ISR() { AS3935_ISR_Trig = 1; -} \ No newline at end of file +} diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 0bb722d..34d3fff 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -279,6 +279,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) { uint8_t i = 0; buffer[0]= 0; buffsize = 0; + (void)inputPos; if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) { buffer[buffsize++] = MQTTCONNACK << 4; @@ -336,7 +337,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) { } else if (i==2) { msg.sensor = atoi(str); //SensorID } else if (i==3) { - char match=255; //SensorType + unsigned char match=255; //SensorType #ifdef MQTT_TRANSLATE_TYPES for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) { @@ -348,7 +349,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) { } #endif - if ( atoi(str)!=0 || str=="0" ) { + if ( atoi(str)!=0 || (str[0]=='0' && str[1] =='\0') ) { match=atoi(str); } diff --git a/libraries/MySensors/examples/RainGauge/RainGauge.ino b/libraries/MySensors/examples/RainGauge/RainGauge.ino index 475eb0c..59b84a6 100644 --- a/libraries/MySensors/examples/RainGauge/RainGauge.ino +++ b/libraries/MySensors/examples/RainGauge/RainGauge.ino @@ -123,7 +123,7 @@ volatile int wasTippedBuffer = 0; int rainSensorThreshold = 50; //default rain sensor sensitivity in hundredths. Will be overwritten with msgTrippedVar2. byte state = 0; byte oldState = -1; -int lastRainRate = 0; +unsigned int lastRainRate = 0; int lastMeasure = 0; boolean gotTime = false; byte lastHour; diff --git a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino index f0ca797..6db9727 100644 --- a/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino +++ b/libraries/MySensors/examples/RealTimeClockDisplaySensor/RealTimeClockDisplaySensor.ino @@ -88,8 +88,8 @@ void loop() // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour - if ((!timeReceived && now-lastRequest > (unsigned long)(10*1000)) - || (timeReceived && now-lastRequest > (unsigned long)(60*1000*60))) { + if ((!timeReceived && (now-lastRequest) > (10UL*1000UL)) + || (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) { // Request time from controller. Serial.println("requesting time"); gw.requestTime(receiveTime); diff --git a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino b/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino index ec2a4ef..56374e5 100644 --- a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -298,7 +298,6 @@ boolean validateKnock(){ // reads the secret knock from EEPROM. (if any.) void readSecretKnock(){ byte reading; - int i; reading = gw.loadState(1); if (reading == eepromValid){ // only read EEPROM if the signature byte is correct. for (int i=0; i < maximumKnocks ;i++){ diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index ae40fad..cb69354 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -71,7 +71,7 @@ MySigningAtsha204 signer; #endif MySensor gw(radio, hw, signer); #else -#warning SecureActuator cannot possibly be secure without signing enabled +// WARNING! SecureActuator cannot possibly be secure without signing enabled MySensor gw(radio, hw); #endif diff --git a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino index 92acedf..4c542df 100644 --- a/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino +++ b/libraries/MySensors/examples/Sha204Personalizer/Sha204Personalizer.ino @@ -237,7 +237,6 @@ void write_key(uint8_t* key) void dump_configuration() { - uint8_t config_word[4]; uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; uint8_t ret_code; @@ -682,6 +681,8 @@ void setup() uint8_t lockConfig = 0; uint8_t lockValue = 0; uint16_t crc; + (void)crc; + Serial.begin(115200); Serial.println(F("ATSHA204 personalization sketch for MySensors usage.")); diff --git a/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino b/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino index 7dfe1b0..f546119 100644 --- a/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino +++ b/libraries/MySensors/examples/TimeAwareSensor/TimeAwareSensor.ino @@ -59,8 +59,8 @@ void loop() // If no time has been received yet, request it every 10 second from controller // When time has been received, request update every hour - if ((!timeReceived && now-lastRequest > 10*1000) - || (timeReceived && now-lastRequest > 60*1000*60)) { + if ((!timeReceived && (now-lastRequest) > (10UL*1000UL)) + || (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) { // Request time from controller. Serial.println("requesting time"); gw.requestTime(receiveTime); diff --git a/libraries/MySensors/examples/UVSensor/UVSensor.ino b/libraries/MySensors/examples/UVSensor/UVSensor.ino index a00ed7f..7db2aae 100644 --- a/libraries/MySensors/examples/UVSensor/UVSensor.ino +++ b/libraries/MySensors/examples/UVSensor/UVSensor.ino @@ -53,7 +53,7 @@ MyMessage uvMsg(CHILD_ID_UV, V_UV); unsigned long lastSend =0; float uvIndex; float lastUV = -1; -int uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; +uint16_t uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; void setup() { @@ -98,7 +98,7 @@ void loop() //Serial.println(uvIndex,2); //Send value to gateway if changed, or at least every 5 minutes - if ((uvIndex != lastUV)||(currentTime-lastSend >= 5*60*1000)) { + if ((uvIndex != lastUV)||(currentTime-lastSend >= 5UL*60UL*1000UL)) { lastSend=currentTime; gw.send(uvMsg.set(uvIndex,2)); lastUV = uvIndex; From 396d200be383fb8fd060d32b3325c273f4e8721f Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 9 Aug 2015 14:56:27 +0200 Subject: [PATCH 187/660] Update README.md Now links and status of Jenkins jobs are presented on the frontpage of the Arduino git in github. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b803e58..3e4a778 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,7 @@ Arduino MySensors Arduino Library v1.5 Please visit www.mysensors.org for more information + +Current build status of master branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/master/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/master/) + +Current build status of development branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/development/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/development/) From 6c13c564486062157f79502a41e89b1ac31d9c06 Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 21:46:02 +0200 Subject: [PATCH 188/660] updated with Hek remarks --- .../AirQuality-CO2-MH-Z14.ino | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino b/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino new file mode 100644 index 0000000..a9cbca7 --- /dev/null +++ b/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino @@ -0,0 +1,100 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * MH-Z14 CO2 sensor + * + * Wiring: + * Pad 1, Pad 5: Vin (Voltage input 4.5V-6V) + * Pad 2, Pad 3, Pad 12: GND + * Pad 6: PWM output ==> pin 6 + * + * From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html + * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm. + * The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula: + * CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms) + * From: http://airqualityegg.wikispaces.com/Sensor+Tests + * - response time is less than 30 s + * - 3 minute warm up time + * datasheet: http://www.futurlec.com/Datasheet/Sensor/MH-Z14.pdf +* Contributor: epierre +**/ + + +#include +#include + +#define CHILD_ID_AIQ 0 +#define AIQ_SENSOR_ANALOG_PIN 6 + +unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) + +float valAIQ =0.0; +float lastAIQ =0.0; + +MySensor gw; +MyMessage msg(CHILD_ID_AIQ, V_LEVEL); +MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX); + +void setup() +{ + gw.begin(); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0"); + + // Register all sensors to gateway (they will be created as child devices) + gw.present(CHILD_ID_AIQ, S_AIR_QUALITY); + gw.send(msg2.set("ppm")); + + gw.sleep(SLEEP_TIME); + + pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT); + +} + +void loop() { + + //unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); + while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;} + //wait for the pin to go HIGH and measure HIGH time + unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); + + //Serial.print(duration/1000); Serial.println(" ms "); + //from datasheet + //CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms) + // given Tl + Th = 1004 + // Tl = 1004 - Th + // = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms) + // = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms) + long co2ppm = 2 * ((duration/1000) - 2); + //Serial.print(co2ppm); + if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { + gw.send(msg.set((long)ceil(co2ppm))); + lastAIQ = ceil(co2ppm); + } + + //Serial.println(); + + // Power down the radio. Note that the radio will get powered back up + // on the next write() call. + gw.sleep(SLEEP_TIME); //sleep for: sleepTime +} From 059d034f10d4763fceaed0733a99b0f78b857ba0 Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 21:51:20 +0200 Subject: [PATCH 189/660] good sensibility sensor --- .../DustSensor/DustSensor_SamYoung_DSM501.ino | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino diff --git a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino new file mode 100644 index 0000000..50514c8 --- /dev/null +++ b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino @@ -0,0 +1,139 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Dust Sensor for SamYoung DSM501 + * connect the sensor as follows : + * Pin 2 of dust sensor PM1 -> Digital 3 (PMW) + * Pin 3 of dust sensor -> +5V + * Pin 4 of dust sensor PM2.5 -> Digital 6 (PWM) + * Pin 5 of dust sensor -> Ground + * Datasheet: http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf +* Contributor: epierre +**/ + + +#include +#include + +#define CHILD_ID_DUST_PM10 0 +#define CHILD_ID_DUST_PM25 1 +#define DUST_SENSOR_DIGITAL_PIN_PM10 6 +#define DUST_SENSOR_DIGITAL_PIN_PM25 3 + +unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) +//VARIABLES +int val = 0; // variable to store the value coming from the sensor +float valDUSTPM25 =0.0; +float lastDUSTPM25 =0.0; +float valDUSTPM10 =0.0; +float lastDUSTPM10 =0.0; +unsigned long duration; +unsigned long starttime; +unsigned long endtime; +unsigned long sampletime_ms = 30000; +unsigned long lowpulseoccupancy = 0; +float ratio = 0; +long concentrationPM25 = 0; +long concentrationPM10 = 0; + +MySensor gw; +MyMessage dustMsgPM10(CHILD_ID_DUST_PM10, V_LEVEL); +MyMessage msgPM10(CHILD_ID_DUST_PM10, V_UNIT_PREFIX); +MyMessage dustMsgPM25(CHILD_ID_DUST_PM25, V_LEVEL); +MyMessage msgPM25(CHILD_ID_DUST_PM25, V_UNIT_PREFIX); + +void setup() +{ + gw.begin(); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("Dust Sensor DSM501", "1.4"); + + // Register all sensors to gateway (they will be created as child devices) + gw.present(CHILD_ID_DUST_PM10, S_DUST); + gw.send(msgPM10.set("ppm")); + gw.present(CHILD_ID_DUST_PM25, S_DUST); + gw.send(msgPM25.set("ppm")); + + pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT); + pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT); + Serial.begin(115200); +} + +void loop() +{ + + //get PM 2.5 density of particles over 2.5 μm. + concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25); + Serial.print("PM25: "); + Serial.println(concentrationPM25); + Serial.print("\n"); + + if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) { + gw.send(dustMsgPM25.set((long)ceil(concentrationPM25))); + lastDUSTPM25 = ceil(concentrationPM25); + } + //get PM 1.0 - density of particles over 1 μm. + concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10); + Serial.print("PM10: "); + Serial.println(concentrationPM10); + Serial.print("\n"); + if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { + gw.send(dustMsgPM10.set((long)ceil(concentrationPM10))); + lastDUSTPM10 = ceil(concentrationPM10); + } + + //sleep to save on radio + gw.sleep(SLEEP_TIME); + +} + + +long getPM(int DUST_SENSOR_DIGITAL_PIN) { + + starttime = millis(); + + while (1) { + + duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW); + lowpulseoccupancy += duration; + endtime = millis(); + + if ((endtime-starttime) > sampletime_ms) + { + ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0); // Integer percentage 0=>100 + long concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve + //Serial.print("lowpulseoccupancy:"); + //Serial.print(lowpulseoccupancy); + //Serial.print("\n"); + //Serial.print("ratio:"); + //Serial.print(ratio); + //Serial.print("\n"); + //Serial.print("DSM501A:"); + //Serial.println(concentration); + //Serial.print("\n"); + + lowpulseoccupancy = 0; + return(concentration); + } + } +} From e40939fba769457fbe8f58d5fb5d7894f3e0fb76 Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 21:56:33 +0200 Subject: [PATCH 190/660] Vibration sensor sketch --- .../VibrationSensor/VibrationSensor.ino | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino diff --git a/libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino b/libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino new file mode 100644 index 0000000..93db4c5 --- /dev/null +++ b/libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino @@ -0,0 +1,94 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Vibration Sensor + * + * connect the sensor as follows : + * + * VCC >>> 5V + * S >>> D3 + * GND >>> GND + * + * Based on: http://www.dfrobot.com/wiki/index.php/DFRobot_Digital_Vibration_Sensor_V2_SKU:DFR0027 + * Contributor: epierre +**/ + + +#include +#include +#include + +#define CHILD_ID_VIBRATION 0 +#define VIBRATION_SENSOR_DIGITAL_PIN 3 +#define SensorLED 13 + +unsigned long SLEEP_TIME = 10*1000; // Sleep time between reads (in seconds) + +//VARIABLES +int val = 0; // variable to store the value coming from the sensor +float valVIBRATION =0.0; +float lastVIBRATION =0.0; +unsigned char state = 0; + +MySensor gw; +MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL); + +void setup() +{ + gw.begin(); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("VIBRATION Sensor", "1.0"); + + // Register all sensors to gateway (they will be created as child devices) + gw.present(CHILD_ID_VIBRATION, S_VIBRATION); + + + pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT); + attachInterrupt(1, blink, FALLING);// Trigger the blink function when the falling edge is detected + pinMode(SensorLED, OUTPUT); +} + +void loop() +{ + + if(state>=40){ // basically below 40 so ignire basic level + gw.send(vibrationMsg.set(int(state))); + state = 0; + digitalWrite(SensorLED,HIGH); + } else { + state = 0; + digitalWrite(SensorLED,LOW); + } + + + // Power down the radio. Note that the radio will get powered back up + // on the next write() call. + delay(1000); //delay to allow serial to fully print before sleep + + gw.sleep(SLEEP_TIME); //sleep for: sleepTime +} + +void blink()//Interrupts function +{ + state++; +} From 3e734d467c1ae1824b26931de28ed60f20bf6025 Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 21:59:34 +0200 Subject: [PATCH 191/660] replacement with a better sketch --- .../SoilMoistSensor/SoilMoistSensor.ino | 65 ------ .../SoilMoistSensor/SoilMoistureSensor.ino | 185 ++++++++++++++++++ 2 files changed, 185 insertions(+), 65 deletions(-) delete mode 100644 libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino create mode 100644 libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino deleted file mode 100644 index 2a2a108..0000000 --- a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino +++ /dev/null @@ -1,65 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - ******************************* - * - * REVISION HISTORY - * Version 1.0 - Henrik Ekblad - * - * DESCRIPTION - * Example sketch sending soil moisture alarm to controller - * http://www.mysensors.org/build/moisture - */ - -#include -#include - -#define DIGITAL_INPUT_SOIL_SENSOR 3 // Digital input did you attach your soil sensor. -#define INTERRUPT DIGITAL_INPUT_SOIL_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) -#define CHILD_ID 0 // Id of the sensor child - -MySensor gw; -MyMessage msg(CHILD_ID, V_TRIPPED); -int lastSoilValue = -1; - -void setup() -{ - gw.begin(); - - // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Soil Moisture Sensor", "1.0"); - // sets the soil sensor digital pin as input - pinMode(DIGITAL_INPUT_SOIL_SENSOR, INPUT); - // Register all sensors to gw (they will be created as child devices) - gw.present(CHILD_ID, S_MOTION); -} - -void loop() -{ - // Read digital soil value - int soilValue = digitalRead(DIGITAL_INPUT_SOIL_SENSOR); // 1 = Not triggered, 0 = In soil with water - if (soilValue != lastSoilValue) { - Serial.println(soilValue); - gw.send(msg.set(soilValue==0?1:0)); // Send the inverse to gw as tripped should be when no water in soil - lastSoilValue = soilValue; - } - // Power down the radio and arduino until digital input changes. - gw.sleep(INTERRUPT,CHANGE); -} - - diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino new file mode 100644 index 0000000..de99a37 --- /dev/null +++ b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino @@ -0,0 +1,185 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * Arduino soil moisture based on gypsum sensor/resistive sensor to avoid electric catalyse in soil + * Required to interface the sensor: 2 * 4.7kOhm + 2 * 1N4148 + * + * Gypsum sensor and calibration: + * DIY: See http://vanderleevineyard.com/1/category/vinduino/1.html + * Built: Davis / Watermark 200SS + * http://www.cooking-hacks.com/watermark-soil-moisture-sensor?_bksrc=item2item&_bkloc=product + * http://www.irrometer.com/pdf/supportmaterial/sensors/voltage-WM-chart.pdf + * cb (centibar) http://www.irrometer.com/basics.html + * 0-10 Saturated Soil. Occurs for a day or two after irrigation + * 10-20 Soil is adequately wet (except coarse sands which are drying out at this range) + * 30-60 Usual range to irrigate or water (except heavy clay soils). + * 60-100 Usual range to irrigate heavy clay soils + * 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution. + * + * Connection: + * D6, D7: alternative powering to avoid sensor degradation + * A0, A1: alternative resistance mesuring + * + * Based on: + * "Vinduino" portable soil moisture sensor code V3.00 + * Date December 31, 2012 + * Reinier van der Lee and Theodore Kaskalis + * www.vanderleevineyard.com + * Contributor: epierre +**/ + +// Copyright (C) 2015, Reinier van der Lee +// www.vanderleevineyard.com + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#include // Conversion equation from resistance to % +#include +#include + +// Setting up format for reading 3 soil sensors +#define NUM_READS 10 // Number of sensor reads for filtering +#define CHILD_ID 0 + +MySensor gw; // Arduino initialization +MyMessage msg(CHILD_ID, V_LEVEL); +unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) + +long buffer[NUM_READS]; +int index; + +typedef struct { // Structure to be used in percentage and resistance values matrix to be filtered (have to be in pairs) + int moisture; + long resistance; +} values; + +const long knownResistor = 4700; // Constant value of known resistor in Ohms + +int supplyVoltage; // Measured supply voltage +int sensorVoltage; // Measured sensor voltage + +values valueOf[NUM_READS]; // Calculated moisture percentages and resistances to be sorted and filtered + +int i; // Simple index variable + +void setup() { + // initialize serial communications at 9600 bps: + Serial.begin(115200); + gw.begin(); + gw.sendSketchInfo("Soil Moisture Sensor Reverse Polarity", "1.0"); + gw.present(CHILD_ID, S_HUM); + // initialize the digital pins as an output. + // Pin 6,7 is for sensor 1 + // initialize the digital pin as an output. + // Pin 6 is sense resistor voltage supply 1 + pinMode(6, OUTPUT); + + // initialize the digital pin as an output. + // Pin 7 is sense resistor voltage supply 2 + pinMode(7, OUTPUT); + + +} + +void loop() { + + measure(1,6,7,1); + Serial.print ("\t"); + Serial.println (average()); + long read1 = average(); + + measure(1,7,6,0); + Serial.print ("\t"); + Serial.println (average()); + long read2= average(); + + long sensor1 = (read1 + read2)/2; + + Serial.print ("resistance bias =" ); + Serial.println (read1-read2); + Serial.print ("sensor bias compensated value = "); + Serial.println (sensor1); + Serial.println (); + + //send back the values + gw.send(msg.set((long int)ceil(sensor1))); + // delay until next measurement (msec) + gw.sleep(SLEEP_TIME); +} + +void measure (int sensor, int phase_b, int phase_a, int analog_input) +{ + // read sensor, filter, and calculate resistance value + // Noise filter: median filter + + for (i=0; i= NUM_READS) index = 0; +} + +long average(){ + long sum = 0; + for (int i = 0; i < NUM_READS; i++){ + sum += buffer[i]; + } + return (long)(sum / NUM_READS); +} From c146aa2d048b10d1c760e7681fa039ee495fe98d Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 22:03:59 +0200 Subject: [PATCH 192/660] formula is back --- .../examples/DustSensor/DustSensor_SamYoung_DSM501.ino | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino index 50514c8..43cae33 100644 --- a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino +++ b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino @@ -97,8 +97,13 @@ void loop() Serial.print("PM10: "); Serial.println(concentrationPM10); Serial.print("\n"); + //ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass + //0.08205 = Universal gas constant in atm·m3/(kmol·K) + int temp=20; //external temperature, if you can replace this with a DHT11 or better + long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01; + if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { - gw.send(dustMsgPM10.set((long)ceil(concentrationPM10))); + gw.send(dustMsgPM10.set((long)ppmv)); lastDUSTPM10 = ceil(concentrationPM10); } From 2ba7ce09a7988ea1d06d339636d3d0e091a2870f Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 22:06:29 +0200 Subject: [PATCH 193/660] removed serial initialization (<1.3) --- .../examples/DustSensor/DustSensor_SamYoung_DSM501.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino index 43cae33..ca88a73 100644 --- a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino +++ b/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino @@ -76,7 +76,7 @@ void setup() pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT); pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT); - Serial.begin(115200); + } void loop() From dff73e46bafa7fccbe8be4fd1fb9108c11de2e36 Mon Sep 17 00:00:00 2001 From: epierre Date: Mon, 10 Aug 2015 22:08:15 +0200 Subject: [PATCH 194/660] shorter name --- .../{SoilMoistureSensor.ino => SoilMoistSensor.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename libraries/MySensors/examples/SoilMoistSensor/{SoilMoistureSensor.ino => SoilMoistSensor.ino} (100%) diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino similarity index 100% rename from libraries/MySensors/examples/SoilMoistSensor/SoilMoistureSensor.ino rename to libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino From 9483683a5f659eb261ac120740100e4f4ba14703 Mon Sep 17 00:00:00 2001 From: empierre Date: Tue, 11 Aug 2015 12:37:40 +0200 Subject: [PATCH 195/660] Delete AirQuality-CO2-MH-Z14.ino compilation issue if twosketches in the same sub dir --- .../AirQuality-CO2-MH-Z14.ino | 100 ------------------ 1 file changed, 100 deletions(-) delete mode 100644 libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino b/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino deleted file mode 100644 index a9cbca7..0000000 --- a/libraries/MySensors/examples/AirQualitySensor/AirQuality-CO2-MH-Z14.ino +++ /dev/null @@ -1,100 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - ******************************* - * - * DESCRIPTION - * - * MH-Z14 CO2 sensor - * - * Wiring: - * Pad 1, Pad 5: Vin (Voltage input 4.5V-6V) - * Pad 2, Pad 3, Pad 12: GND - * Pad 6: PWM output ==> pin 6 - * - * From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html - * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm. - * The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula: - * CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms) - * From: http://airqualityegg.wikispaces.com/Sensor+Tests - * - response time is less than 30 s - * - 3 minute warm up time - * datasheet: http://www.futurlec.com/Datasheet/Sensor/MH-Z14.pdf -* Contributor: epierre -**/ - - -#include -#include - -#define CHILD_ID_AIQ 0 -#define AIQ_SENSOR_ANALOG_PIN 6 - -unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) - -float valAIQ =0.0; -float lastAIQ =0.0; - -MySensor gw; -MyMessage msg(CHILD_ID_AIQ, V_LEVEL); -MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX); - -void setup() -{ - gw.begin(); - - // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0"); - - // Register all sensors to gateway (they will be created as child devices) - gw.present(CHILD_ID_AIQ, S_AIR_QUALITY); - gw.send(msg2.set("ppm")); - - gw.sleep(SLEEP_TIME); - - pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT); - -} - -void loop() { - - //unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); - while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;} - //wait for the pin to go HIGH and measure HIGH time - unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); - - //Serial.print(duration/1000); Serial.println(" ms "); - //from datasheet - //CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms) - // given Tl + Th = 1004 - // Tl = 1004 - Th - // = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms) - // = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms) - long co2ppm = 2 * ((duration/1000) - 2); - //Serial.print(co2ppm); - if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { - gw.send(msg.set((long)ceil(co2ppm))); - lastAIQ = ceil(co2ppm); - } - - //Serial.println(); - - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - gw.sleep(SLEEP_TIME); //sleep for: sleepTime -} From df6579cf1a98ebcd573566669b1caa6fa615c15d Mon Sep 17 00:00:00 2001 From: empierre Date: Tue, 11 Aug 2015 12:41:09 +0200 Subject: [PATCH 196/660] Create AirQualityCO2 moved the file --- .../examples/CO2Sensor/AirQualityCO2 | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 libraries/MySensors/examples/CO2Sensor/AirQualityCO2 diff --git a/libraries/MySensors/examples/CO2Sensor/AirQualityCO2 b/libraries/MySensors/examples/CO2Sensor/AirQualityCO2 new file mode 100644 index 0000000..a9cbca7 --- /dev/null +++ b/libraries/MySensors/examples/CO2Sensor/AirQualityCO2 @@ -0,0 +1,100 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * DESCRIPTION + * + * MH-Z14 CO2 sensor + * + * Wiring: + * Pad 1, Pad 5: Vin (Voltage input 4.5V-6V) + * Pad 2, Pad 3, Pad 12: GND + * Pad 6: PWM output ==> pin 6 + * + * From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html + * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm. + * The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula: + * CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms) + * From: http://airqualityegg.wikispaces.com/Sensor+Tests + * - response time is less than 30 s + * - 3 minute warm up time + * datasheet: http://www.futurlec.com/Datasheet/Sensor/MH-Z14.pdf +* Contributor: epierre +**/ + + +#include +#include + +#define CHILD_ID_AIQ 0 +#define AIQ_SENSOR_ANALOG_PIN 6 + +unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) + +float valAIQ =0.0; +float lastAIQ =0.0; + +MySensor gw; +MyMessage msg(CHILD_ID_AIQ, V_LEVEL); +MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX); + +void setup() +{ + gw.begin(); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0"); + + // Register all sensors to gateway (they will be created as child devices) + gw.present(CHILD_ID_AIQ, S_AIR_QUALITY); + gw.send(msg2.set("ppm")); + + gw.sleep(SLEEP_TIME); + + pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT); + +} + +void loop() { + + //unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); + while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;} + //wait for the pin to go HIGH and measure HIGH time + unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); + + //Serial.print(duration/1000); Serial.println(" ms "); + //from datasheet + //CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms) + // given Tl + Th = 1004 + // Tl = 1004 - Th + // = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms) + // = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms) + long co2ppm = 2 * ((duration/1000) - 2); + //Serial.print(co2ppm); + if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { + gw.send(msg.set((long)ceil(co2ppm))); + lastAIQ = ceil(co2ppm); + } + + //Serial.println(); + + // Power down the radio. Note that the radio will get powered back up + // on the next write() call. + gw.sleep(SLEEP_TIME); //sleep for: sleepTime +} From d0290e48ef6f5f9af2f30b044e3adb0e1ca057d5 Mon Sep 17 00:00:00 2001 From: empierre Date: Tue, 11 Aug 2015 12:43:51 +0200 Subject: [PATCH 197/660] Rename libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino to libraries/MySensors/examples/DustSensorDSM/DustDSM501Sensor.ino renaming and moving --- .../DustDSM501Sensor.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename libraries/MySensors/examples/{DustSensor/DustSensor_SamYoung_DSM501.ino => DustSensorDSM/DustDSM501Sensor.ino} (100%) diff --git a/libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino b/libraries/MySensors/examples/DustSensorDSM/DustDSM501Sensor.ino similarity index 100% rename from libraries/MySensors/examples/DustSensor/DustSensor_SamYoung_DSM501.ino rename to libraries/MySensors/examples/DustSensorDSM/DustDSM501Sensor.ino From 6f42c7008ab2d587b135991fa0a718fa7d2f95f5 Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Wed, 12 Aug 2015 14:23:05 +0200 Subject: [PATCH 198/660] Update SoilMoistSensor.ino removed sensor parameter call as it is unused --- .../MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino index de99a37..2c3c74e 100644 --- a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -110,12 +110,12 @@ void setup() { void loop() { - measure(1,6,7,1); + measure(6,7,1); Serial.print ("\t"); Serial.println (average()); long read1 = average(); - measure(1,7,6,0); + measure(7,6,0); Serial.print ("\t"); Serial.println (average()); long read2= average(); @@ -134,7 +134,7 @@ void loop() { gw.sleep(SLEEP_TIME); } -void measure (int sensor, int phase_b, int phase_a, int analog_input) +void measure (int phase_b, int phase_a, int analog_input) { // read sensor, filter, and calculate resistance value // Noise filter: median filter From 34b831e73ddeb8f59ea4d1ab6cd56659a21704eb Mon Sep 17 00:00:00 2001 From: vil1driver Date: Wed, 12 Aug 2015 20:32:54 +0200 Subject: [PATCH 199/660] Create RGB-3D.ino --- .../MySensors/examples/RGB-3D/RGB-3D.ino | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 libraries/MySensors/examples/RGB-3D/RGB-3D.ino diff --git a/libraries/MySensors/examples/RGB-3D/RGB-3D.ino b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino new file mode 100644 index 0000000..3108760 --- /dev/null +++ b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino @@ -0,0 +1,306 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Created by vil1driver + * + * DESCRIPTION + * RGB led strip controled with three dimmers + one On/Off for run/stop rgb color cycle :p + * + */ + +#define SN "RGB Led strip 3D" +#define SV "v1" + + + // Load mysensors library + #include + // Load Serial Peripheral Interface library + #include + + // Arduino pin attached to MOSFET Gate pin + #define RED_PIN 3 + #define GREEN_PIN 5 + #define BLUE_PIN 6 + + MySensor gw; + + // Define message name and type to send sensor info + MyMessage RedStatus(RED_PIN, V_DIMMER); + MyMessage GreenStatus(GREEN_PIN, V_DIMMER); + MyMessage BlueStatus(BLUE_PIN, V_DIMMER); + MyMessage Status(1, V_DIMMER); + MyMessage rgbShowState(0, V_LIGHT); + + // Serial.print translate sensor id to sensor name + char color[][6] = {"","","","RED","","GREEN","BLUE"}; + + // Vars for rgbShow function + int redval = 0; + int greenval = 0; + int blueval = 0; + long time=0; + int isShow; + + void setup() + { + // Initializes the sensor node (Callback function for incoming messages, node id, is repeater) + gw.begin(incomingMessage, 31, true); + + // Present sketch (name, version) + gw.sendSketchInfo(SN, SV); + + // Register sensors (id, type, description, ack back) + gw.present(RED_PIN, S_DIMMER, "present RED light", false); + gw.present(GREEN_PIN, S_DIMMER, "present GREEN light", false); + gw.present(BLUE_PIN, S_DIMMER, "present BLUE light", false); + gw.present(0, S_LIGHT, "present Show button", false); + + // Define pin mode (pin number, type) + pinMode(RED_PIN, OUTPUT); + pinMode(GREEN_PIN, OUTPUT); + pinMode(BLUE_PIN, OUTPUT); + + // Correct saved RGB value for first start + gw.saveState(RED_PIN, constrain(gw.loadState(RED_PIN), 0, 100)); + gw.saveState(GREEN_PIN, constrain(gw.loadState(GREEN_PIN), 0, 100)); + gw.saveState(BLUE_PIN, constrain(gw.loadState(BLUE_PIN), 0, 100)); + + // Get value from eeprom and write to output + analogWrite(RED_PIN, 255 * gw.loadState(RED_PIN) / 100); + analogWrite(GREEN_PIN, 255 * gw.loadState(GREEN_PIN) / 100); + analogWrite(BLUE_PIN, 255 * gw.loadState(BLUE_PIN) / 100); + + // Write some debug info + Serial.print("Load from eeprom RED: "); + Serial.print(gw.loadState(RED_PIN)); + Serial.println("%"); + Serial.print("Load from eeprom GREEN: "); + Serial.print(gw.loadState(GREEN_PIN)); + Serial.println("%"); + Serial.print("Load from eeprom BLUE: "); + Serial.print(gw.loadState(BLUE_PIN)); + Serial.println("%"); + + // Send RGB value to controler (request ack back: true/false) + Serial.println("Send eeprom value to controler"); + gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); + gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); + gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); + + // Correct RGB show state for first start and load it (set to 'On' at first start) + gw.saveState(0, constrain(gw.loadState(0), 0, 1)); + isShow=gw.loadState(0); + + // Send RGB show state to controler (request ack back: true/false) + gw.send( rgbShowState.set(isShow), false); + + if (isShow==1){ Serial.println("RGB show running..."); } + Serial.println("Ready to receive messages..."); + } + + void loop() + { + // Process incoming messages (like config and light state from controller) + gw.process(); + + // Run RGB show if is set + if (isShow==1) + { + rgbShow(); + analogWrite(RED_PIN, redval); + analogWrite(GREEN_PIN, greenval); + analogWrite(BLUE_PIN, blueval); + } + } + + + void incomingMessage(const MyMessage &message) + { + if (message.isAck()) + { + Serial.println("Got ack from gateway"); + } + if (message.type == V_LIGHT) + { + // Incoming on/off command sent from controller ("1" or "0") + int lightState = message.getString()[0] == '1'; + + // if receive RGB Show On commands, start the show + if (message.sensor==0 && lightState==1){ rgbShowOn(); } + // if receive RGB Show Off commands, stop the show + else if (message.sensor==0 && lightState==0){ rgbShowOff(); } + + // if receive RGB switch On command + else if (lightState==1) + { + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.println(": On"); + Serial.print("Load from eeprom: "); + + if ( gw.loadState(message.sensor) == 0) + { + // Pick up last saved dimmer level from the eeprom + analogWrite(message.sensor, 255 * gw.loadState(10*message.sensor) / 100); + // Save loaded value to current + gw.saveState(message.sensor, gw.loadState(10*message.sensor)); + Serial.print(gw.loadState(10*message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(10*message.sensor)),false); + } + else + { + // Pick up last saved dimmer level from the eeprom + analogWrite(message.sensor, 255 * gw.loadState(message.sensor) / 100); + Serial.print(gw.loadState(message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + } + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } + } + // if recieve switch Off command + else if (lightState==0) + { + // Write output to 0 (Off) + analogWrite(message.sensor, 0); + // Save old value to eeprom if it'was not zero + if ( gw.loadState(message.sensor) != 0 ) + { + gw.saveState(10*message.sensor, constrain(gw.loadState(message.sensor), 0, 100)); + } + // Save new value to eeprom + gw.saveState(message.sensor, 0); + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.print(": "); + Serial.println("Off"); + Serial.print("Store old value: "); + Serial.print(gw.loadState(10*message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } + } + } + else if (message.type == V_DIMMER) + { + uint8_t incomingDimmerStatus = message.getByte(); + // limits range of sensor values to between 0 and 100 + incomingDimmerStatus = constrain(incomingDimmerStatus, 0, 100); + // Change Dimmer level + analogWrite(message.sensor, 255 * incomingDimmerStatus / 100); + //Save value to eeprom + gw.saveState(message.sensor, incomingDimmerStatus); + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.print(": "); + Serial.print(incomingDimmerStatus); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } + } + } + + void rgbShow() + { + time = millis(); + redval = 128+250*cos(2*PI/300000*time); + greenval = 128+250*cos(2*PI/300000*time-222); + blueval = 128+250*cos(2*PI/300000*time-111); + // limits range of sensor values to between 0 and 255 + redval = constrain(redval, 0, 255); + greenval = constrain(greenval, 0, 255); + blueval = constrain(blueval, 0, 255); + } + + void rgbShowOn() + { + // define show On + isShow=1; + // Save state + gw.saveState(0, 1); + // Write some debug info + Serial.println("Show must go on"); + } + + void rgbShowOff() + { + // define show Off + isShow=0; + // Save state + gw.saveState(0, 0); + // Save RGB value to eeprom + gw.saveState(RED_PIN, 100 * redval / 255); + gw.saveState(GREEN_PIN, 100 * greenval / 255); + gw.saveState(BLUE_PIN, 100 * blueval / 255); + // Write some debug info + Serial.println("Stop the show"); + // Send actual RGB value and state to controler and request ack back (true/false) + Serial.println("Send eeprom value to controler"); + gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); + gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); + gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); + gw.send( rgbShowState.set(0), false); + } + + void rgbShowStop(int sensor) + { + // define show Off + isShow=0; + // Save state + gw.saveState(0, 0); + // Write some debug info + Serial.println("Stop the show"); + // Send actual RGB value and state to controler and request ack back (true/false) + Serial.println("Send eeprom value to controler"); + if (sensor != RED_PIN) + { + gw.saveState(RED_PIN, 100 * redval / 255); + gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); + } + if (sensor != GREEN_PIN) + { + gw.saveState(GREEN_PIN, 100 * greenval / 255); + gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); + } + if (sensor != BLUE_PIN) + { + gw.saveState(BLUE_PIN, 100 * blueval / 255); + gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); + } + gw.send( rgbShowState.set(0), false); + } + + + From 26f6a04cfa553db94ecfb1d1d12cdee8e220f9f0 Mon Sep 17 00:00:00 2001 From: vil1driver Date: Wed, 12 Aug 2015 21:03:24 +0200 Subject: [PATCH 200/660] Update RGB-3D.ino --- .../MySensors/examples/RGB-3D/RGB-3D.ino | 473 +++++++++--------- 1 file changed, 236 insertions(+), 237 deletions(-) diff --git a/libraries/MySensors/examples/RGB-3D/RGB-3D.ino b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino index 3108760..5697a0a 100644 --- a/libraries/MySensors/examples/RGB-3D/RGB-3D.ino +++ b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino @@ -29,278 +29,277 @@ #define SN "RGB Led strip 3D" #define SV "v1" - - // Load mysensors library - #include - // Load Serial Peripheral Interface library - #include - - // Arduino pin attached to MOSFET Gate pin - #define RED_PIN 3 - #define GREEN_PIN 5 - #define BLUE_PIN 6 +// Load mysensors library +#include +// Load Serial Peripheral Interface library +#include - MySensor gw; +// Arduino pin attached to MOSFET Gate pin +#define RED_PIN 3 +#define GREEN_PIN 5 +#define BLUE_PIN 6 - // Define message name and type to send sensor info - MyMessage RedStatus(RED_PIN, V_DIMMER); - MyMessage GreenStatus(GREEN_PIN, V_DIMMER); - MyMessage BlueStatus(BLUE_PIN, V_DIMMER); - MyMessage Status(1, V_DIMMER); - MyMessage rgbShowState(0, V_LIGHT); +MySensor gw; + +// Define message name and type to send sensor info +MyMessage RedStatus(RED_PIN, V_DIMMER); +MyMessage GreenStatus(GREEN_PIN, V_DIMMER); +MyMessage BlueStatus(BLUE_PIN, V_DIMMER); +MyMessage Status(1, V_DIMMER); +MyMessage rgbShowState(0, V_LIGHT); - // Serial.print translate sensor id to sensor name - char color[][6] = {"","","","RED","","GREEN","BLUE"}; +// Serial.print translate sensor id to sensor name +char color[][6] = {"","","","RED","","GREEN","BLUE"}; - // Vars for rgbShow function - int redval = 0; - int greenval = 0; - int blueval = 0; - long time=0; - int isShow; +// Vars for rgbShow function +int redval = 0; +int greenval = 0; +int blueval = 0; +long time=0; +int isShow; - void setup() - { - // Initializes the sensor node (Callback function for incoming messages, node id, is repeater) - gw.begin(incomingMessage, 31, true); +void setup() +{ + // Initializes the sensor node (Callback function for incoming messages, node id, is repeater) + gw.begin(incomingMessage, 31, true); - // Present sketch (name, version) - gw.sendSketchInfo(SN, SV); + // Present sketch (name, version) + gw.sendSketchInfo(SN, SV); - // Register sensors (id, type, description, ack back) - gw.present(RED_PIN, S_DIMMER, "present RED light", false); - gw.present(GREEN_PIN, S_DIMMER, "present GREEN light", false); - gw.present(BLUE_PIN, S_DIMMER, "present BLUE light", false); - gw.present(0, S_LIGHT, "present Show button", false); + // Register sensors (id, type, description, ack back) + gw.present(RED_PIN, S_DIMMER, "present RED light", false); + gw.present(GREEN_PIN, S_DIMMER, "present GREEN light", false); + gw.present(BLUE_PIN, S_DIMMER, "present BLUE light", false); + gw.present(0, S_LIGHT, "present Show button", false); - // Define pin mode (pin number, type) - pinMode(RED_PIN, OUTPUT); - pinMode(GREEN_PIN, OUTPUT); - pinMode(BLUE_PIN, OUTPUT); + // Define pin mode (pin number, type) + pinMode(RED_PIN, OUTPUT); + pinMode(GREEN_PIN, OUTPUT); + pinMode(BLUE_PIN, OUTPUT); - // Correct saved RGB value for first start - gw.saveState(RED_PIN, constrain(gw.loadState(RED_PIN), 0, 100)); - gw.saveState(GREEN_PIN, constrain(gw.loadState(GREEN_PIN), 0, 100)); - gw.saveState(BLUE_PIN, constrain(gw.loadState(BLUE_PIN), 0, 100)); + // Correct saved RGB value for first start + gw.saveState(RED_PIN, constrain(gw.loadState(RED_PIN), 0, 100)); + gw.saveState(GREEN_PIN, constrain(gw.loadState(GREEN_PIN), 0, 100)); + gw.saveState(BLUE_PIN, constrain(gw.loadState(BLUE_PIN), 0, 100)); - // Get value from eeprom and write to output - analogWrite(RED_PIN, 255 * gw.loadState(RED_PIN) / 100); - analogWrite(GREEN_PIN, 255 * gw.loadState(GREEN_PIN) / 100); - analogWrite(BLUE_PIN, 255 * gw.loadState(BLUE_PIN) / 100); + // Get value from eeprom and write to output + analogWrite(RED_PIN, 255 * gw.loadState(RED_PIN) / 100); + analogWrite(GREEN_PIN, 255 * gw.loadState(GREEN_PIN) / 100); + analogWrite(BLUE_PIN, 255 * gw.loadState(BLUE_PIN) / 100); - // Write some debug info - Serial.print("Load from eeprom RED: "); - Serial.print(gw.loadState(RED_PIN)); - Serial.println("%"); - Serial.print("Load from eeprom GREEN: "); - Serial.print(gw.loadState(GREEN_PIN)); - Serial.println("%"); - Serial.print("Load from eeprom BLUE: "); - Serial.print(gw.loadState(BLUE_PIN)); - Serial.println("%"); + // Write some debug info + Serial.print("Load from eeprom RED: "); + Serial.print(gw.loadState(RED_PIN)); + Serial.println("%"); + Serial.print("Load from eeprom GREEN: "); + Serial.print(gw.loadState(GREEN_PIN)); + Serial.println("%"); + Serial.print("Load from eeprom BLUE: "); + Serial.print(gw.loadState(BLUE_PIN)); + Serial.println("%"); - // Send RGB value to controler (request ack back: true/false) - Serial.println("Send eeprom value to controler"); - gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); - gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); - gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); + // Send RGB value to controler (request ack back: true/false) + Serial.println("Send eeprom value to controler"); + gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); + gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); + gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); - // Correct RGB show state for first start and load it (set to 'On' at first start) - gw.saveState(0, constrain(gw.loadState(0), 0, 1)); - isShow=gw.loadState(0); + // Correct RGB show state for first start and load it (set to 'On' at first start) + gw.saveState(0, constrain(gw.loadState(0), 0, 1)); + isShow=gw.loadState(0); - // Send RGB show state to controler (request ack back: true/false) - gw.send( rgbShowState.set(isShow), false); + // Send RGB show state to controler (request ack back: true/false) + gw.send( rgbShowState.set(isShow), false); - if (isShow==1){ Serial.println("RGB show running..."); } - Serial.println("Ready to receive messages..."); - } + if (isShow==1){Serial.println("RGB show running..."); } + Serial.println("Ready to receive messages..."); +} - void loop() - { - // Process incoming messages (like config and light state from controller) - gw.process(); +void loop() +{ + // Process incoming messages (like config and light state from controller) + gw.process(); - // Run RGB show if is set - if (isShow==1) - { - rgbShow(); - analogWrite(RED_PIN, redval); - analogWrite(GREEN_PIN, greenval); - analogWrite(BLUE_PIN, blueval); - } - } + // Run RGB show if is set + if (isShow==1) + { + rgbShow(); + analogWrite(RED_PIN, redval); + analogWrite(GREEN_PIN, greenval); + analogWrite(BLUE_PIN, blueval); + } +} - void incomingMessage(const MyMessage &message) - { - if (message.isAck()) - { - Serial.println("Got ack from gateway"); - } - if (message.type == V_LIGHT) - { - // Incoming on/off command sent from controller ("1" or "0") - int lightState = message.getString()[0] == '1'; +void incomingMessage(const MyMessage &message) +{ + if (message.isAck()) + { + Serial.println("Got ack from gateway"); + } + if (message.type == V_LIGHT) + { + // Incoming on/off command sent from controller ("1" or "0") + int lightState = message.getString()[0] == '1'; - // if receive RGB Show On commands, start the show - if (message.sensor==0 && lightState==1){ rgbShowOn(); } + // if receive RGB Show On commands, start the show + if (message.sensor==0 && lightState==1){ rgbShowOn(); } // if receive RGB Show Off commands, stop the show - else if (message.sensor==0 && lightState==0){ rgbShowOff(); } + else if (message.sensor==0 && lightState==0){ rgbShowOff(); } - // if receive RGB switch On command - else if (lightState==1) - { - // Write some debug info - Serial.print("Incoming change for "); - Serial.print(color[message.sensor]); - Serial.println(": On"); - Serial.print("Load from eeprom: "); + // if receive RGB switch On command + else if (lightState==1) + { + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.println(": On"); + Serial.print("Load from eeprom: "); - if ( gw.loadState(message.sensor) == 0) - { - // Pick up last saved dimmer level from the eeprom - analogWrite(message.sensor, 255 * gw.loadState(10*message.sensor) / 100); - // Save loaded value to current - gw.saveState(message.sensor, gw.loadState(10*message.sensor)); - Serial.print(gw.loadState(10*message.sensor)); - Serial.println("%"); - // Send value to controler - Serial.println("Send value to controler"); - gw.send(Status.setSensor(message.sensor).set(gw.loadState(10*message.sensor)),false); - } - else - { - // Pick up last saved dimmer level from the eeprom - analogWrite(message.sensor, 255 * gw.loadState(message.sensor) / 100); - Serial.print(gw.loadState(message.sensor)); - Serial.println("%"); - // Send value to controler - Serial.println("Send value to controler"); - gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); - } - // Stop the show if it's running - if (isShow==1){ rgbShowStop(message.sensor); } + if ( gw.loadState(message.sensor) == 0) + { + // Pick up last saved dimmer level from the eeprom + analogWrite(message.sensor, 255 * gw.loadState(10*message.sensor) / 100); + // Save loaded value to current + gw.saveState(message.sensor, gw.loadState(10*message.sensor)); + Serial.print(gw.loadState(10*message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(10*message.sensor)),false); + } + else + { + // Pick up last saved dimmer level from the eeprom + analogWrite(message.sensor, 255 * gw.loadState(message.sensor) / 100); + Serial.print(gw.loadState(message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + } + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } } - // if recieve switch Off command - else if (lightState==0) - { - // Write output to 0 (Off) - analogWrite(message.sensor, 0); - // Save old value to eeprom if it'was not zero - if ( gw.loadState(message.sensor) != 0 ) - { - gw.saveState(10*message.sensor, constrain(gw.loadState(message.sensor), 0, 100)); - } - // Save new value to eeprom - gw.saveState(message.sensor, 0); - // Write some debug info - Serial.print("Incoming change for "); - Serial.print(color[message.sensor]); - Serial.print(": "); - Serial.println("Off"); - Serial.print("Store old value: "); - Serial.print(gw.loadState(10*message.sensor)); - Serial.println("%"); - // Send value to controler - Serial.println("Send value to controler"); - gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); - // Stop the show if it's running - if (isShow==1){ rgbShowStop(message.sensor); } - } - } - else if (message.type == V_DIMMER) - { - uint8_t incomingDimmerStatus = message.getByte(); - // limits range of sensor values to between 0 and 100 - incomingDimmerStatus = constrain(incomingDimmerStatus, 0, 100); - // Change Dimmer level - analogWrite(message.sensor, 255 * incomingDimmerStatus / 100); - //Save value to eeprom - gw.saveState(message.sensor, incomingDimmerStatus); - // Write some debug info - Serial.print("Incoming change for "); - Serial.print(color[message.sensor]); - Serial.print(": "); - Serial.print(incomingDimmerStatus); - Serial.println("%"); - // Send value to controler - Serial.println("Send value to controler"); - gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); - // Stop the show if it's running - if (isShow==1){ rgbShowStop(message.sensor); } - } - } - - void rgbShow() + // if recieve switch Off command + else if (lightState==0) { - time = millis(); - redval = 128+250*cos(2*PI/300000*time); - greenval = 128+250*cos(2*PI/300000*time-222); - blueval = 128+250*cos(2*PI/300000*time-111); - // limits range of sensor values to between 0 and 255 - redval = constrain(redval, 0, 255); - greenval = constrain(greenval, 0, 255); - blueval = constrain(blueval, 0, 255); + // Write output to 0 (Off) + analogWrite(message.sensor, 0); + // Save old value to eeprom if it'was not zero + if ( gw.loadState(message.sensor) != 0 ) + { + gw.saveState(10*message.sensor, constrain(gw.loadState(message.sensor), 0, 100)); + } + // Save new value to eeprom + gw.saveState(message.sensor, 0); + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.print(": "); + Serial.println("Off"); + Serial.print("Store old value: "); + Serial.print(gw.loadState(10*message.sensor)); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } } - - void rgbShowOn() - { - // define show On - isShow=1; - // Save state - gw.saveState(0, 1); - // Write some debug info - Serial.println("Show must go on"); - } - - void rgbShowOff() - { - // define show Off - isShow=0; - // Save state - gw.saveState(0, 0); - // Save RGB value to eeprom - gw.saveState(RED_PIN, 100 * redval / 255); - gw.saveState(GREEN_PIN, 100 * greenval / 255); - gw.saveState(BLUE_PIN, 100 * blueval / 255); - // Write some debug info - Serial.println("Stop the show"); - // Send actual RGB value and state to controler and request ack back (true/false) - Serial.println("Send eeprom value to controler"); - gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); - gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); - gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); - gw.send( rgbShowState.set(0), false); + } + else if (message.type == V_DIMMER) + { + uint8_t incomingDimmerStatus = message.getByte(); + // limits range of sensor values to between 0 and 100 + incomingDimmerStatus = constrain(incomingDimmerStatus, 0, 100); + // Change Dimmer level + analogWrite(message.sensor, 255 * incomingDimmerStatus / 100); + //Save value to eeprom + gw.saveState(message.sensor, incomingDimmerStatus); + // Write some debug info + Serial.print("Incoming change for "); + Serial.print(color[message.sensor]); + Serial.print(": "); + Serial.print(incomingDimmerStatus); + Serial.println("%"); + // Send value to controler + Serial.println("Send value to controler"); + gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false); + // Stop the show if it's running + if (isShow==1){ rgbShowStop(message.sensor); } } +} + +void rgbShow() +{ + time = millis(); + redval = 128+250*cos(2*PI/300000*time); + greenval = 128+250*cos(2*PI/300000*time-222); + blueval = 128+250*cos(2*PI/300000*time-111); + // limits range of sensor values to between 0 and 255 + redval = constrain(redval, 0, 255); + greenval = constrain(greenval, 0, 255); + blueval = constrain(blueval, 0, 255); +} - void rgbShowStop(int sensor) - { - // define show Off - isShow=0; - // Save state - gw.saveState(0, 0); - // Write some debug info - Serial.println("Stop the show"); - // Send actual RGB value and state to controler and request ack back (true/false) - Serial.println("Send eeprom value to controler"); - if (sensor != RED_PIN) - { +void rgbShowOn() +{ + // define show On + isShow=1; + // Save state + gw.saveState(0, 1); + // Write some debug info + Serial.println("Show must go on"); +} + +void rgbShowOff() +{ + // define show Off + isShow=0; + // Save state + gw.saveState(0, 0); + // Save RGB value to eeprom + gw.saveState(RED_PIN, 100 * redval / 255); + gw.saveState(GREEN_PIN, 100 * greenval / 255); + gw.saveState(BLUE_PIN, 100 * blueval / 255); + // Write some debug info + Serial.println("Stop the show"); + // Send actual RGB value and state to controler and request ack back (true/false) + Serial.println("Send eeprom value to controler"); + gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); + gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); + gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); + gw.send( rgbShowState.set(0), false); +} + +void rgbShowStop(int sensor) +{ + // define show Off + isShow=0; + // Save state + gw.saveState(0, 0); + // Write some debug info + Serial.println("Stop the show"); + // Send actual RGB value and state to controler and request ack back (true/false) + Serial.println("Send eeprom value to controler"); + if (sensor != RED_PIN) + { gw.saveState(RED_PIN, 100 * redval / 255); gw.send( RedStatus.set(gw.loadState(RED_PIN)), false ); - } - if (sensor != GREEN_PIN) - { + } + if (sensor != GREEN_PIN) + { gw.saveState(GREEN_PIN, 100 * greenval / 255); gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false ); - } - if (sensor != BLUE_PIN) - { + } + if (sensor != BLUE_PIN) + { gw.saveState(BLUE_PIN, 100 * blueval / 255); gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); - } - gw.send( rgbShowState.set(0), false); } + gw.send( rgbShowState.set(0), false); +} From e6a25ebb6b83573921acfb1a5b227ea2f8110f43 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 13 Aug 2015 16:01:06 +0200 Subject: [PATCH 201/660] Renamed illegaly named sketches so they can be built Also fixed the warnings in RGB-3D.ino --- .../CO2Sensor/{AirQualityCO2 => CO2Sensor.ino} | 0 .../{DustDSM501Sensor.ino => DustSensorDSM.ino} | 0 libraries/MySensors/examples/RGB-3D/RGB-3D.ino | 12 ++++++------ 3 files changed, 6 insertions(+), 6 deletions(-) rename libraries/MySensors/examples/CO2Sensor/{AirQualityCO2 => CO2Sensor.ino} (100%) rename libraries/MySensors/examples/DustSensorDSM/{DustDSM501Sensor.ino => DustSensorDSM.ino} (100%) diff --git a/libraries/MySensors/examples/CO2Sensor/AirQualityCO2 b/libraries/MySensors/examples/CO2Sensor/CO2Sensor.ino similarity index 100% rename from libraries/MySensors/examples/CO2Sensor/AirQualityCO2 rename to libraries/MySensors/examples/CO2Sensor/CO2Sensor.ino diff --git a/libraries/MySensors/examples/DustSensorDSM/DustDSM501Sensor.ino b/libraries/MySensors/examples/DustSensorDSM/DustSensorDSM.ino similarity index 100% rename from libraries/MySensors/examples/DustSensorDSM/DustDSM501Sensor.ino rename to libraries/MySensors/examples/DustSensorDSM/DustSensorDSM.ino diff --git a/libraries/MySensors/examples/RGB-3D/RGB-3D.ino b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino index 5697a0a..1862c53 100644 --- a/libraries/MySensors/examples/RGB-3D/RGB-3D.ino +++ b/libraries/MySensors/examples/RGB-3D/RGB-3D.ino @@ -78,9 +78,9 @@ void setup() pinMode(BLUE_PIN, OUTPUT); // Correct saved RGB value for first start - gw.saveState(RED_PIN, constrain(gw.loadState(RED_PIN), 0, 100)); - gw.saveState(GREEN_PIN, constrain(gw.loadState(GREEN_PIN), 0, 100)); - gw.saveState(BLUE_PIN, constrain(gw.loadState(BLUE_PIN), 0, 100)); + gw.saveState(RED_PIN, constrain((int8_t)gw.loadState(RED_PIN), 0, 100)); + gw.saveState(GREEN_PIN, constrain((int8_t)gw.loadState(GREEN_PIN), 0, 100)); + gw.saveState(BLUE_PIN, constrain((int8_t)gw.loadState(BLUE_PIN), 0, 100)); // Get value from eeprom and write to output analogWrite(RED_PIN, 255 * gw.loadState(RED_PIN) / 100); @@ -105,7 +105,7 @@ void setup() gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false ); // Correct RGB show state for first start and load it (set to 'On' at first start) - gw.saveState(0, constrain(gw.loadState(0), 0, 1)); + gw.saveState(0, constrain((int8_t)gw.loadState(0), 0, 1)); isShow=gw.loadState(0); // Send RGB show state to controler (request ack back: true/false) @@ -189,7 +189,7 @@ void incomingMessage(const MyMessage &message) // Save old value to eeprom if it'was not zero if ( gw.loadState(message.sensor) != 0 ) { - gw.saveState(10*message.sensor, constrain(gw.loadState(message.sensor), 0, 100)); + gw.saveState(10*message.sensor, constrain((int8_t)gw.loadState(message.sensor), 0, 100)); } // Save new value to eeprom gw.saveState(message.sensor, 0); @@ -212,7 +212,7 @@ void incomingMessage(const MyMessage &message) { uint8_t incomingDimmerStatus = message.getByte(); // limits range of sensor values to between 0 and 100 - incomingDimmerStatus = constrain(incomingDimmerStatus, 0, 100); + incomingDimmerStatus = constrain((int8_t)incomingDimmerStatus, 0, 100); // Change Dimmer level analogWrite(message.sensor, 255 * incomingDimmerStatus / 100); //Save value to eeprom From 21166528f88ca220731e35df41814360958c1b4f Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 13 Aug 2015 23:10:16 +0200 Subject: [PATCH 202/660] Removed warnings in parkingsensor example --- .../MySensors/examples/ParkingSensor/ParkingSensor.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino index d54e599..f8ad6de 100644 --- a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino +++ b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino @@ -68,16 +68,16 @@ NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and MySensor gw; MyMessage msg(CHILD_ID,V_TRIPPED); int oldParkedStatus=-1; -int sendInterval = 5000; // Send park status at maximum every 5 second. +unsigned long sendInterval = 5000; // Send park status at maximum every 5 second. unsigned long lastSend; #endif -int blinkInterval = 100; // blink interval (milliseconds) +unsigned long blinkInterval = 100; // blink interval (milliseconds) unsigned long lastBlinkPeriod; bool blinkColor = true; // To make a fading motion on the led ring/tape we only move one pixel/distDebounce time -int distDebounce = 30; +unsigned long distDebounce = 30; unsigned long lastDebouncePeriod; int numLightPixels=0; int skipZero=0; @@ -161,4 +161,4 @@ void loop() { } pixels.show(); // This sends the updated pixel color to the hardware. } -} +} \ No newline at end of file From 3b531e77e2964753907a3a6c0d326c84facbd8c6 Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Fri, 14 Aug 2015 08:31:32 +0200 Subject: [PATCH 203/660] MyMessage.h: Added some comments and presentation types from the web site, fixed a small typo MockMySensors sketch: Fixed some small issues to conform to the 1.5 API (S_HEATER still needs to done) --- libraries/MySensors/MyMessage.h | 83 ++++++++--------- .../examples/MockMySensors/MockMySensors.ino | 91 +++++++------------ .../examples/MockMySensors/README.md | 4 +- 3 files changed, 75 insertions(+), 103 deletions(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 129801f..6c7c471 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -58,7 +58,7 @@ typedef enum { S_UV, // Uv sensor, V_UV S_WEIGHT, // Personal scale sensor, V_WEIGHT, V_IMPEDANCE S_POWER, // Power meter, V_WATT, V_KWH - S_HEATER, // Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE + S_HEATER, // Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP S_DISTANCE, // Distance sensor, V_DISTANCE S_LIGHT_LEVEL, // Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux) S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node @@ -73,7 +73,7 @@ typedef enum { S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT S_COLOR_SENSOR, // Color sensor, send color information using V_RGB - S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE + S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP S_MULTIMETER, // Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE S_SPRINKLER, // Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) S_WATER_LEAK, // Water leak sensor, V_TRIPPED, V_ARMED @@ -84,42 +84,42 @@ typedef enum { // Type of sensor data (for set/req/ack messages) typedef enum { - V_TEMP, // S_TEMP - V_HUM, // S_HUM - V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting binary (on/off) status. 1=on, 0=off + V_TEMP, // S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC + V_HUM, // S_HUM. Humidity + V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off V_LIGHT=2, // Same as V_STATUS - V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value (0-100). + V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value 0-100 (%). V_DIMMER=3, // S_DIMMER. Same as V_PERCENTAGE. - V_PRESSURE, // S_BARO - V_FORECAST, // S_BARO - V_RAIN, // S_RAIN - V_RAINRATE, // S_RAIN - V_WIND, // S_WIND - V_GUST, // S_WIND - V_DIRECTION, // S_WIND - V_UV, // S_UV - V_WEIGHT, // S_WEIGHT - V_DISTANCE, // S_DISTANCE - V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT - V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER - V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER (for sprinklers with fire detection) - V_WATT, // S_POWER, S_LIGHT, S_DIMMER - V_KWH, // S_POWER - V_SCENE_ON, // S_SCENE_CONTROLLER - V_SCENE_OFF, // S_SCENE_CONTROLLER + V_PRESSURE, // S_BARO. Atmospheric Pressure + V_FORECAST, // S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown" + V_RAIN, // S_RAIN. Amount of rain + V_RAINRATE, // S_RAIN. Rate of rain + V_WIND, // S_WIND. Wind speed + V_GUST, // S_WIND. Gust + V_DIRECTION, // S_WIND. Wind direction 0-360 (degrees) + V_UV, // S_UV. UV light level + V_WEIGHT, // S_WEIGHT. Weight(for scales etc) + V_DISTANCE, // S_DISTANCE. Distance + V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT. Impedance value + V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed + V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0 + V_WATT, // S_POWER, S_LIGHT, S_DIMMER, S_RGB, S_RGBW. Watt value for power meters + V_KWH, // S_POWER. Accumulated number of KWH for a power meter + V_SCENE_ON, // S_SCENE_CONTROLLER. Turn on a scene + V_SCENE_OFF, // S_SCENE_CONTROLLER. Turn of a scene V_HEATER, // Deprecated. Use V_HVAC_FLOW_STATE instead. - V_HVAC_FLOW_STATE=21, // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC - V_HVAC_SPEED, // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") - V_LIGHT_LEVEL, // Used for sending light level in uncalibrated percentage. See also V_LEVEL (light level in lux). S_LIGHT_LEVEL + V_HVAC_FLOW_STATE=21, // S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver") + V_HVAC_SPEED, // S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + V_LIGHT_LEVEL, // S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5, - V_UP, // S_COVER - V_DOWN, // S_COVER - V_STOP, // S_COVER - V_IR_SEND, // S_IR - V_IR_RECEIVE, // S_IR - V_FLOW, // S_WATER - V_VOLUME, // S_WATER - V_LOCK_STATUS, // S_LOCK + V_UP, // S_COVER. Window covering. Up + V_DOWN, // S_COVER. Window covering. Down + V_STOP, // S_COVER. Window covering. Stop + V_IR_SEND, // S_IR. Send out an IR-command + V_IR_RECEIVE, // S_IR. This message contains a received IR-command + V_FLOW, // S_WATER. Flow of water (in meter) + V_VOLUME, // S_WATER. Water volume + V_LOCK_STATUS, // S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked V_LEVEL, // S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux) V_VOLTAGE, // S_MULTIMETER V_CURRENT, // S_MULTIMETER @@ -128,15 +128,16 @@ typedef enum { // Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component) V_RGBW, // S_RGBW_LIGHT // Used for sending color information to multi color LED lighting. - // Sent as ASCII hex: RRGGBBWW (WW=while component) + // Sent as ASCII hex: RRGGBBWW (WW=white component) V_ID, // S_TEMP // Used for sending in sensors hardware ids (i.e. OneWire DS1820b). - V_UNIT_PREFIX, // Allows sensors to send in a string representing the - // unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch. - // Can be used for S_DISTANCE or gas concentration (S_DUST, S_AIR_QUALITY) - V_HVAC_SETPOINT_COOL, // HVAC cool setpoint (Integer between 0-100). S_HVAC - V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC - V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn"). S_HVAC + V_UNIT_PREFIX, // S_DUST, S_AIR_QUALITY + // Allows sensors to send in a string representing the + // unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch. + // Can be used for S_DISTANCE or gas concentration + V_HVAC_SETPOINT_COOL, // S_HVAC. HVAC cool setpoint (Integer between 0-100) + V_HVAC_SETPOINT_HEAT, // S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100) + V_HVAC_FLOW_MODE, // S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") } mysensor_data; diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 37411ff..9ccf0a9 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -1,47 +1,29 @@ /* -* MockMySensors +* FakeMySensors * * This skecth is intended to crate fake sensors which register and respond to the controller * -* Barduino 2015 +* Barduino, GizMoCuz 2015 */ -#include -#include -#include -#include -#include -#include - -#include #include -#include +#include -#define RADIO_ERROR_LED_PIN 4 // Error led pin -#define RADIO_RX_LED_PIN 6 // Receive led pin -#define RADIO_TX_LED_PIN 5 // the PCB, on board LED +// SPI Pins +#define CE_PIN 9 +#define CS_PIN 10 // Wait times #define LONG_WAIT 500 #define SHORT_WAIT 50 #define SKETCH_NAME "FakeMySensors " -#define SKETCH_VERSION "v0.2" - -// Define Sensors ids -/* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, - S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, - S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, - S_SCENE_CONTROLLER -*/ +#define SKETCH_VERSION "v0.3" ////#define ID_S_ARDUINO_NODE //auto defined in initialization ////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization -// Some of these ID's have not been updated for v1.5. Uncommenting too many of them -// will make the sketch too large for a pro mini's memory so it's probably best to try -// one at a time. -#define ID_S_DOOR 1 +//#define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 @@ -51,11 +33,11 @@ //#define ID_S_HUM 8 //#define ID_S_BARO 9 //#define ID_S_WIND 10 -//#define ID_S_RAIN 11 +//#define ID_S_RAIN 11 //#define ID_S_UV 12 //#define ID_S_WEIGHT 13 //#define ID_S_POWER 14 -//#define ID_S_HEATER 15 +//#define ID_S_HEATER 15 <<-- not correctly implemented (1.5 API) //#define ID_S_DISTANCE 16 //#define ID_S_LIGHT_LEVEL 17 //#define ID_S_LOCK 18 @@ -67,29 +49,12 @@ //#define ID_S_CUSTOM 24 // Global Vars -unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) +unsigned long SLEEP_TIME = 12000; // Sleep time between reads (in milliseconds) boolean metric = true; long randNumber; // Instanciate MySersors Gateway -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRFM69 transport; - -// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -//MySigningNone signer; -//MySigningAtsha204Soft signer; -//MySigningAtsha204 signer; - -// Hardware profile -MyHwATMega328 hw; - -// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h -#ifdef WITH_LEDS_BLINKING -MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); -#else -MySensor gw(transport, hw /*, signer*/); -#endif +MySensor gw; //Instanciate Messages objects @@ -161,8 +126,10 @@ MySensor gw(transport, hw /*, signer*/); #endif #ifdef ID_S_HEATER - MyMessage msg_S_HEATER_M(ID_S_HEATER,V_HEATER); - MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HEATER_SW); + float current_set_point=21.5; + MyMessage msg_S_HEATER_SP(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); + MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); + MyMessage msg_S_HEATER_T(ID_S_HEATER,V_TEMP); #endif #ifdef ID_S_DISTANCE @@ -188,11 +155,11 @@ MySensor gw(transport, hw /*, signer*/); #endif #ifdef ID_S_AIR_QUALITY - MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_VAR1); + MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_LEVEL); #endif #ifdef ID_S_DUST - MyMessage msg_S_DUST(ID_S_DUST,V_DUST_LEVEL); + MyMessage msg_S_DUST(ID_S_DUST,V_LEVEL); #endif #ifdef ID_S_SCENE_CONTROLLER @@ -268,13 +235,13 @@ void setup() #endif #ifdef ID_S_COVER - Serial.println(" S_COVER"; + Serial.println(" S_COVER"); gw.present(ID_S_COVER,S_COVER); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_TEMP - Serial.println(" S_TMEP"); + Serial.println(" S_TEMP"); gw.present(ID_S_TEMP,S_TEMP); gw.wait(SHORT_WAIT); #endif @@ -408,7 +375,7 @@ void loop() gw.wait(LONG_WAIT); //Read Sensors - #ifdef S_ID_DOOR + #ifdef ID_S_DOOR door(); #endif @@ -519,9 +486,7 @@ void receiveTime(unsigned long controllerTime) { } -//void door(){} - -#ifdef S_ID_DOOR +#ifdef ID_S_DOOR void door(){ Serial.print("Door is: " ); @@ -650,7 +615,7 @@ void hum(){ void baro(){ const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; - long pressure = map(randNumber,1,100,87000,108600); + long pressure = map(randNumber,1,100,900,1200); int forecast = map(randNumber,1,100,0,5); Serial.print("Atmosferic Pressure is: " ); @@ -753,8 +718,9 @@ void power(){ #ifdef ID_S_HEATER void heater(){ - int heater_mode = gw.loadState(ID_S_HEATER); - bool heater_switch = gw.loadState(ID_S_HEATER+1); + int heater_set_point = gw.loadState(ID_S_HEATER); + int heater_flow_state = gw.loadState(ID_S_HEATER+1); + int heater_temp = gw.loadState(ID_S_HEATER+2); Serial.print("Heater mode is: " ); @@ -781,6 +747,11 @@ void heater(){ Serial.println(heater_switch?"On":"Off"); gw.send(msg_S_HEATER_S.set(heater_switch)); + + Serial.print("Heater Temperature is: " ); + Serial.println(map(randNumber,1,100,0,45)); + + gw.send(msg_S_HEATER_T.set(map(randNumber,1,100,0,45))); } #endif diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md index 24e2ce9..ccb11eb 100644 --- a/libraries/MySensors/examples/MockMySensors/README.md +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -3,7 +3,7 @@ Arduino sketch to fake sensor for the MySensors Library This skecth is intended to crate fake sensors which register and respond to the controller -Barduino 2015 +Barduino, GizMoCuz 2015 ----------------- Comment/Uncomment the sensors you would like to test @@ -12,4 +12,4 @@ Arduino Uno R3 can support about 12 sensors before it runs out of memory. You probably need to turn of the MySensor Lib debug to save some memory Nest step will be to remove the read/write to the eprom -and extend to support the v1.5 sensors +and extend 'ID_S_HEATER' to support the v1.5 API From 33ddd161d550cbe4e373669635092eb08bd9f444 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 15 Aug 2015 18:46:16 +0200 Subject: [PATCH 204/660] Include utility/SPIFlash.h in SensebenderBlink.ino --- .../MySensors/examples/SensebenderBlink/SensebenderBlink.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino b/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino index 099882e..b4bb4d7 100644 --- a/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino +++ b/libraries/MySensors/examples/SensebenderBlink/SensebenderBlink.ino @@ -3,6 +3,7 @@ #include #include +#include "utility/SPIFlash.h" #define SketchName "Sensebender Blink" #define SketchVersion "20150721" From 2f1df520abd935c9ff2186d71632b59751cb36ce Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 17 Aug 2015 20:45:56 +0200 Subject: [PATCH 205/660] Fix routing problem in repeaters. --- libraries/MySensors/MySensor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 2e75d0a..e5b2755 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -397,6 +397,10 @@ boolean MySensor::sendRoute(MyMessage &message) { #endif if (dest == GATEWAY_ADDRESS || !repeaterMode) { + // Store this address in routing table (if repeater) + if (repeaterMode) { + hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); + } // If destination is the gateway or if we aren't a repeater, let // our parent take care of the message ok = sendWrite(nc.parentNodeId, message); From 654cf695dfedf2a96c82067f82410a383a0b508a Mon Sep 17 00:00:00 2001 From: Barduino Date: Sat, 22 Aug 2015 15:13:09 -0400 Subject: [PATCH 206/660] Fix name Tet Commit --- libraries/MySensors/examples/MockMySensors/MockMySensors.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 9ccf0a9..eba66c0 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -1,5 +1,5 @@ /* -* FakeMySensors +* MockMySensors * * This skecth is intended to crate fake sensors which register and respond to the controller * From 608a22d51606422d3cd33da3672a55e70f6f310f Mon Sep 17 00:00:00 2001 From: Barduino Date: Sat, 22 Aug 2015 15:14:29 -0400 Subject: [PATCH 207/660] Fix name Test commit --- libraries/MySensors/examples/MockMySensors/MockMySensors.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index eba66c0..f222e34 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -17,13 +17,13 @@ #define LONG_WAIT 500 #define SHORT_WAIT 50 -#define SKETCH_NAME "FakeMySensors " +#define SKETCH_NAME "MockySensors " #define SKETCH_VERSION "v0.3" ////#define ID_S_ARDUINO_NODE //auto defined in initialization ////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization -//#define ID_S_DOOR 1 +#define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 From 2281c9283e8903765c1eac7bf62424785a15cf44 Mon Sep 17 00:00:00 2001 From: Barduino Date: Sat, 22 Aug 2015 15:26:51 -0400 Subject: [PATCH 208/660] Major Refactor of MockMySenors --- .../examples/MockMySensors/MockMySensors.ino | 349 ++++++++++-------- .../examples/MockMySensors/README.md | 15 +- 2 files changed, 205 insertions(+), 159 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index f222e34..466fb29 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -2,27 +2,47 @@ * MockMySensors * * This skecth is intended to crate fake sensors which register and respond to the controller -* -* Barduino, GizMoCuz 2015 +* *** +* Barduino 2015, GizMoCuz 2015 */ -#include -#include +#include +#include +#include +#include +#include +#include -// SPI Pins -#define CE_PIN 9 -#define CS_PIN 10 +#include +#include +#include + +#define RADIO_ERROR_LED_PIN 4 // Error led pin +#define RADIO_RX_LED_PIN 6 // Receive led pin +#define RADIO_TX_LED_PIN 5 // the PCB, on board LED // Wait times #define LONG_WAIT 500 #define SHORT_WAIT 50 -#define SKETCH_NAME "MockySensors " -#define SKETCH_VERSION "v0.3" +#define SKETCH_NAME "MockMySensors " +#define SKETCH_VERSION "v0.4" + +// Define Sensors ids +/* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, + S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE, + S_ARDUINO_REPEATER_NODE, S_LOCK, S_IR, S_WATER, S_AIR_QUALITY, S_CUSTOM, S_DUST, + S_SCENE_CONTROLLER +*/ ////#define ID_S_ARDUINO_NODE //auto defined in initialization ////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization + +// Some of these ID's have not been updated for v1.5. Uncommenting too many of them +// will make the sketch too large for a pro mini's memory so it's probably best to try +// one at a time. +#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 @@ -33,11 +53,11 @@ //#define ID_S_HUM 8 //#define ID_S_BARO 9 //#define ID_S_WIND 10 -//#define ID_S_RAIN 11 +//#define ID_S_RAIN 11 //#define ID_S_UV 12 //#define ID_S_WEIGHT 13 //#define ID_S_POWER 14 -//#define ID_S_HEATER 15 <<-- not correctly implemented (1.5 API) +//#define ID_S_HEATER 15 //#define ID_S_DISTANCE 16 //#define ID_S_LIGHT_LEVEL 17 //#define ID_S_LOCK 18 @@ -46,43 +66,71 @@ //#define ID_S_AIR_QUALITY 21 //#define ID_S_DUST 22 //#define ID_S_SCENE_CONTROLLER 23 -//#define ID_S_CUSTOM 24 +//#define ID_S_CUSTOM 99 // Global Vars -unsigned long SLEEP_TIME = 12000; // Sleep time between reads (in milliseconds) +unsigned long SLEEP_TIME = 180000; // Sleep time between reads (in milliseconds) boolean metric = true; long randNumber; // Instanciate MySersors Gateway -MySensor gw; +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRFM69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +//MySigningNone signer; +//MySigningAtsha204Soft signer; +//MySigningAtsha204 signer; + +// Hardware profile +MyHwATMega328 hw; + +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +#ifdef WITH_LEDS_BLINKING + MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else + MySensor gw(transport, hw /*, signer*/); +#endif + +//MySensor gw; //Instanciate Messages objects -#ifdef ID_S_DOOR - MyMessage msg_S_DOOR(ID_S_DOOR,V_TRIPPED); +#ifdef ID_S_ARMED + bool isArmed; #endif -#ifdef ID_S_MOTION +#ifdef ID_S_DOOR // V_TRIPPED, V_ARMED + MyMessage msg_S_DOOR_T(ID_S_DOOR,V_TRIPPED); + MyMessage msg_S_DOOR_A(ID_S_DOOR,V_ARMED); +#endif + +#ifdef ID_S_MOTION // V_TRIPPED, V_ARMED MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); #endif -#ifdef ID_S_SMOKE - MyMessage msg_S_SMOKE(ID_S_SMOKE,V_TRIPPED); +#ifdef ID_S_SMOKE // V_TRIPPED, V_ARMED + MyMessage msg_S_SMOKE_T(ID_S_SMOKE,V_TRIPPED); + MyMessage msg_S_SMOKE_A(ID_S_SMOKE,V_ARMED); #endif #ifdef ID_S_LIGHT MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); + bool isLightOn=0; #endif #ifdef ID_S_DIMMER MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); + int dimmerVal=100; #endif #ifdef ID_S_COVER MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); + const char* coverVal = "V_STOP"; #endif #ifdef ID_S_TEMP @@ -118,18 +166,18 @@ MySensor gw; #endif #ifdef ID_S_POWER - MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); - MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); - MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); +// MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); +// MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); +// MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); #endif -#ifdef ID_S_HEATER - float current_set_point=21.5; - MyMessage msg_S_HEATER_SP(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); - MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); - MyMessage msg_S_HEATER_T(ID_S_HEATER,V_TEMP); +#ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP + MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC + MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_FLOW_STATE); // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC + int heatTemp=18; + const char* heatState="Off"; #endif #ifdef ID_S_DISTANCE @@ -142,11 +190,13 @@ MySensor gw; #ifdef ID_S_LOCK MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); + bool isLocked = 0; #endif #ifdef ID_S_IR MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); + const char* irVal = ""; #endif #ifdef ID_S_WATER @@ -165,9 +215,22 @@ MySensor gw; #ifdef ID_S_SCENE_CONTROLLER MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); + // not sure if scene controller sends int or chars + // betting on ints as Touch Display Scen by Hek + char *scenes[] = { + "All off", + "Good Morning", + "Clean Up!", + "All Lights Off", + "Music On/Off" + }; + int sceneVal=0; + int sceneValPrevious=0; + #endif #ifdef ID_S_CUSTOM + MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1); MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); @@ -200,6 +263,11 @@ void setup() Serial.println(metric ? "Metric":"Imperial"); gw.wait(LONG_WAIT); + // Init Armed + #ifdef ID_S_ARMED + isArmed = true; + #endif + // Register all sensors to gw (they will be created as child devices) Serial.println("Presenting Nodes"); Serial.println("________________"); @@ -241,7 +309,7 @@ void setup() #endif #ifdef ID_S_TEMP - Serial.println(" S_TEMP"); + Serial.println(" S_TMEP"); gw.present(ID_S_TEMP,S_TEMP); gw.wait(SHORT_WAIT); #endif @@ -277,7 +345,7 @@ void setup() #endif #ifdef ID_S_WEIGHT - Serial.println(" S_WEIGHT"): + Serial.println(" S_WEIGHT"); gw.present(ID_S_WEIGHT,S_WEIGHT); gw.wait(SHORT_WAIT); #endif @@ -486,25 +554,31 @@ void receiveTime(unsigned long controllerTime) { } +//void door(){} + #ifdef ID_S_DOOR void door(){ - + Serial.print("Door is: " ); if (randNumber <= 50) { Serial.println("Open"); - gw.send(msg_S_DOOR.set(1)); + gw.send(msg_S_DOOR_T.set(1)); } else { Serial.println("Closed"); - gw.send(msg_S_DOOR.set(0)); + gw.send(msg_S_DOOR_T.set(0)); } - + #ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + gw.send(msg_S_DOOR_A.set(isArmed)); + #endif } #endif #ifdef ID_S_MOTION void motion(){ - + Serial.print("Motion is: " ); if (randNumber <= 50) { @@ -515,6 +589,11 @@ void motion(){ gw.send(msg_S_MOTION_T.set(0)); } + #ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + gw.send(msg_S_MOTION_A.set(isArmed)); + #endif } #endif @@ -525,38 +604,35 @@ void smoke(){ if (randNumber <= 50) { Serial.println("Active"); - gw.send(msg_S_SMOKE.set(1)); + gw.send(msg_S_SMOKE_T.set(1)); } else { Serial.println("Quiet"); - gw.send(msg_S_SMOKE.set(0)); + gw.send(msg_S_SMOKE_T.set(0)); } + #ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + gw.send(msg_S_SMOKE_A.set(isArmed)); + #endif + } #endif #ifdef ID_S_LIGHT void light(){ - bool isLightOn = gw.loadState(ID_S_LIGHT); - Serial.print("Light is: " ); + Serial.println((isLightOn ? "On":"Off")); - if (isLightOn) { - Serial.println("On"); - gw.send(msg_S_LIGHT.set(1)); - } else { - Serial.println("Off"); - gw.send(msg_S_LIGHT.set(0)); - } - + gw.send(msg_S_LIGHT.set(isLightOn)); + } #endif #ifdef ID_S_DIMMER void dimmer(){ - int dimmerVal = gw.loadState(ID_S_DIMMER); - Serial.print("Dimmer is set to: " ); Serial.println(dimmerVal); @@ -568,20 +644,15 @@ void dimmer(){ #ifdef ID_S_COVER void cover(){ - int coverVal = gw.loadState(ID_S_COVER); - Serial.print("Cover is : " ); - - switch (coverVal) { - case 0: + + if (coverVal == "V_UP"){ Serial.println("Opening"); gw.send(msg_S_COVER_U.set(V_UP)); - break; - case 1: + }else if (coverVal == "V_DONW"){ Serial.println("Closing"); gw.send(msg_S_COVER_D.set(V_DOWN)); - break; - default: + }else{ Serial.println("Idle"); gw.send(msg_S_COVER_S.set(V_STOP)); } @@ -615,7 +686,7 @@ void hum(){ void baro(){ const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; - long pressure = map(randNumber,1,100,900,1200); + long pressure = map(randNumber,1,100,87000,108600); int forecast = map(randNumber,1,100,0,5); Serial.print("Atmosferic Pressure is: " ); @@ -687,12 +758,7 @@ void weight(){ #ifdef ID_S_POWER void power(){ - - Serial.print("Impedance is: " ); - Serial.println(map(randNumber,1,100,0,150)); - gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); - Serial.print("Watt is: " ); Serial.println(map(randNumber,1,100,0,150)); @@ -703,55 +769,36 @@ void power(){ gw.send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); - Serial.print("Voltage is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); +// Serial.print("Impedance is: " ); +// Serial.println(map(randNumber,1,100,0,150)); +// +// gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); - Serial.print("Current is: " ); - Serial.println(map(randNumber,1,100,0,150)); - - gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); +// Serial.print("Voltage is: " ); +// Serial.println(map(randNumber,1,100,0,150)); +// +// gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); + +// Serial.print("Current is: " ); +// Serial.println(map(randNumber,1,100,0,150)); +// +// gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_HEATER void heater(){ - int heater_set_point = gw.loadState(ID_S_HEATER); - int heater_flow_state = gw.loadState(ID_S_HEATER+1); - int heater_temp = gw.loadState(ID_S_HEATER+2); - + Serial.print("Heater mode is: " ); + Serial.println(heatState); - if (heater_mode == 0){ - Serial.println("Off"); - } - else if (heater_mode == 1){ - Serial.println("Heat On"); - } - else if (heater_mode == 2){ - Serial.println("Cool On"); - } - else if (heater_mode == 3){ - Serial.println("Auto Change Over"); - } - else { - Serial.print("Unknown Heater Mode: "); - Serial.println(heater_mode); - } - - gw.send(msg_S_HEATER_M.set(heater_mode)); + gw.send(msg_S_HEATER_F.set(heatState)); - Serial.print("Heater is: " ); - Serial.println(heater_switch?"On":"Off"); + Serial.print("Heater Set Point is: " ); + Serial.println(heatTemp); - gw.send(msg_S_HEATER_S.set(heater_switch)); - - Serial.print("Heater Temperature is: " ); - Serial.println(map(randNumber,1,100,0,45)); - - gw.send(msg_S_HEATER_T.set(map(randNumber,1,100,0,45))); + gw.send(msg_S_HEATER_S.set(heatTemp)); } #endif @@ -781,25 +828,15 @@ void light_level(){ #ifdef ID_S_LOCK void lock(){ - bool isLocked = gw.loadState(ID_S_LOCK); - Serial.print("Lock is: " ); - - if (isLocked) { - Serial.println("On"); - gw.send(msg_S_LOCK.set(1)); - } else { - Serial.println("Off"); - gw.send(msg_S_LOCK.set(0)); - } + Serial.println((isLocked ? "Locked":"Unlocked")); + gw.send(msg_S_LOCK.set(isLocked)); } #endif #ifdef ID_S_IR void ir(){ - - int irVal = gw.loadState(ID_S_IR); Serial.print("Infrared is: " ); Serial.println(irVal); @@ -850,16 +887,15 @@ void dust(){ #ifdef ID_S_SCENE_CONTROLLER void scene(){ - bool isSceneOn = gw.loadState(ID_S_SCENE_CONTROLLER); - Serial.print("Scene is: " ); - Serial.println(isSceneOn ? "On":"Off"); - - if(isSceneOn) - gw.send(msg_S_SCENE_CONTROLLER_ON.set(isSceneOn)); - else - gw.send(msg_S_SCENE_CONTROLLER_OF.set(isSceneOn)); + Serial.println(scenes[sceneVal]); + if(sceneValPrevious != sceneVal){ + gw.send(msg_S_SCENE_CONTROLLER_OF.set(sceneValPrevious)); + gw.send(msg_S_SCENE_CONTROLLER_ON.set(sceneVal)); + sceneValPrevious=sceneVal; + } + } #endif @@ -869,6 +905,7 @@ void custom(){ Serial.print("Custom value is: " ); Serial.println(randNumber); + gw.send(msg_S_CUSTOM_1.set(randNumber)); gw.send(msg_S_CUSTOM_2.set(randNumber)); gw.send(msg_S_CUSTOM_3.set(randNumber)); gw.send(msg_S_CUSTOM_4.set(randNumber)); @@ -880,13 +917,24 @@ void custom(){ void incomingMessage(const MyMessage &message) { switch (message.type) { + #ifdef ID_S_ARMED + case V_ARMED: + isArmed = message.getBool(); + Serial.print("Incoming change for ID_S_ARMED:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println((isArmed ? "Armed":"Disarmed" )); + break; + #endif + #ifdef ID_S_LIGHT case V_LIGHT: - gw.saveState(ID_S_LIGHT, message.getBool()); + isLightOn = message.getBool(); Serial.print("Incoming change for ID_S_LIGHT:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println(message.getBool()); + Serial.println((isLightOn ? "On":"Off")); + light(); break; #endif @@ -896,7 +944,7 @@ void incomingMessage(const MyMessage &message) { Serial.println( "V_DIMMER data invalid (should be 0..100)" ); break; } - gw.saveState(ID_S_DIMMER, message.getInt()); + dimmerVal= message.getInt(); Serial.print("Incoming change for ID_S_DIMMER:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -906,7 +954,7 @@ void incomingMessage(const MyMessage &message) { #ifdef ID_S_COVER case V_UP: - gw.saveState(ID_S_COVER, 0); + coverVal="V_UP"; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -914,7 +962,7 @@ void incomingMessage(const MyMessage &message) { break; case V_DOWN: - gw.saveState(ID_S_COVER, 1); + coverVal="V_DOWN"; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -922,7 +970,7 @@ void incomingMessage(const MyMessage &message) { break; case V_STOP: - gw.saveState(ID_S_COVER, 2); + coverVal="V_STOP"; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -931,42 +979,27 @@ void incomingMessage(const MyMessage &message) { #endif #ifdef ID_S_HEATER - case V_HEATER: - gw.saveState(ID_S_HEATER, message.getInt()); + case V_HVAC_FLOW_STATE: + heatState = message.getString(); Serial.print("Incoming change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); + Serial.println(heatState); - if (message.getInt() == 0){ - Serial.println("Off"); - } - else if (message.getInt() == 1){ - Serial.println("Heat On"); - } - else if (message.getInt() == 2){ - Serial.println("Cool On"); - } - else if (message.getInt() == 3){ - Serial.println("Auto Change Over"); - } - else { - Serial.print("Unknown Heater Mode: "); - Serial.println(message.getInt()); - } break; - case V_HEATER_SW: - gw.saveState(ID_S_HEATER+1, message.getBool()); + case V_HVAC_SETPOINT_HEAT: + heatTemp = message.getInt(); Serial.print("Incoming change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println((message.getBool() ? "On":"Off")); + Serial.println(heatTemp); break; #endif #ifdef ID_S_LOCK case V_LOCK_STATUS: - gw.saveState(ID_S_LOCK, message.getBool()); + isLocked = message.getBool(); Serial.print("Incoming change for ID_S_LOCK:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -976,33 +1009,37 @@ void incomingMessage(const MyMessage &message) { #ifdef ID_S_IR case V_IR_RECEIVE: - gw.saveState(ID_S_IR, message.getInt()); + irVal = message.getString(); Serial.print("Incoming change for ID_S_IR:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println(message.getInt()); + Serial.println(irVal); break; #endif #ifdef ID_S_SCENE_CONTROLLER case V_SCENE_ON: - gw.saveState(ID_S_SCENE_CONTROLLER, 1); + sceneVal = message.getInt(); Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println("On"); + Serial.print(scenes[sceneVal]); + Serial.println(" On"); + scene(); break; case V_SCENE_OFF: - gw.saveState(ID_S_SCENE_CONTROLLER, 0); + sceneVal = message.getInt(); Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println("Off"); + Serial.print(scenes[sceneVal]); + Serial.println(" Off"); + scene(); break; #endif default: - Serial.print("Unknown/UnImplemented message type:"); + Serial.print("Unknown/UnImplemented message type: "); Serial.println(message.type); } diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md index ccb11eb..c835b2d 100644 --- a/libraries/MySensors/examples/MockMySensors/README.md +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -9,7 +9,16 @@ Barduino, GizMoCuz 2015 Comment/Uncomment the sensors you would like to test Arduino Uno R3 can support about 12 sensors before it runs out of memory. -You probably need to turn of the MySensor Lib debug to save some memory +(turning off the MySensors debug helps if you are memory limited) -Nest step will be to remove the read/write to the eprom -and extend 'ID_S_HEATER' to support the v1.5 API +With a Mega you can have them all + + +Changes Log +----------------- + +2015-08-19 +Removed the load/save to eeprom +Touched the heater sensor +Created a pseudo sensor to handle the V_ARMED message. +All sensors which support V_ARMED will arm/disarm at the same time From 3df1227147d248385eb67c800e9663b3fdf223d1 Mon Sep 17 00:00:00 2001 From: Jeeva Kandasamy Date: Mon, 24 Aug 2015 12:46:08 +0530 Subject: [PATCH 209/660] Fix to enable Tx/Rx as IO pin --- libraries/MySensors/MyConfig.h | 3 +++ libraries/MySensors/MyHwATMega328.cpp | 12 +++++++++--- libraries/MySensors/MySensor.cpp | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index a79119a..204389d 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -26,6 +26,9 @@ // to see what is actually is happening when developing #define DEBUG +//Comment this this line, If you are using TX(1), RX(0) as IO pin disable this +#define ENABLED_SERIAL + // Serial output baud rate (for debug prints and serial gateway) #define BAUD_RATE 115200 diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index a9e6de7..42517db 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -119,7 +119,9 @@ void powerDown(period_t period) { void MyHwATMega328::internalSleep(unsigned long ms) { // Let serial prints finish (debug, log etc) - Serial.flush(); + #ifdef ENABLED_SERIAL + Serial.flush(); + #endif pinIntTrigger = 0; while (!pinIntTrigger && ms >= 8000) { powerDown(SLEEP_8S); ms -= 8000; } if (!pinIntTrigger && ms >= 4000) { powerDown(SLEEP_4S); ms -= 4000; } @@ -148,7 +150,9 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { pinTriggeredWakeup = false; } } else { - Serial.flush(); + #ifdef ENABLED_SERIAL + Serial.flush(); + #endif powerDown(SLEEP_FOREVER); } detachInterrupt(interrupt); @@ -166,7 +170,9 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i retVal = -1; } } else { - Serial.flush(); + #ifdef ENABLED_SERIAL + Serial.flush(); + #endif powerDown(SLEEP_FOREVER); } detachInterrupt(interrupt1); diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index e5b2755..dc784c8 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -153,7 +153,9 @@ void MySensor::errBlink(uint8_t cnt) { #endif void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { - hw_init(); + #ifdef ENABLED_SERIAL + hw_init(); + #endif repeaterMode = _repeaterMode; msgCallback = _msgCallback; failedTransmissions = 0; From d7459ae0503feac0b38d3c923b8b16f4faa8e777 Mon Sep 17 00:00:00 2001 From: Jeeva Kandasamy Date: Mon, 24 Aug 2015 12:48:30 +0530 Subject: [PATCH 210/660] modified comment for ENABLED_SERIAL --- libraries/MySensors/MyConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 204389d..13978d5 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -26,7 +26,7 @@ // to see what is actually is happening when developing #define DEBUG -//Comment this this line, If you are using TX(1), RX(0) as IO pin disable this +// Disable this line, If you are using TX(1), RX(0) as normal I/O pin #define ENABLED_SERIAL // Serial output baud rate (for debug prints and serial gateway) From 86f71091e973bf2fc684e223c6d3147a63a73bea Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Mon, 24 Aug 2015 20:45:29 +0200 Subject: [PATCH 211/660] initialize digital pins internal pullup resistor Always send volume when not in sleep mode send frequency set to 30 seconds --- .../WaterMeterPulseSensor.ino | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index d676d6c..81c0c8e 100644 --- a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -20,6 +20,7 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad + * Version 1.1 - GizMoCuz * * DESCRIPTION * Use this sensor to measure volume and flow of your house watermeter. @@ -33,8 +34,8 @@ * http://www.mysensors.org/build/pulse_water */ -#include #include +#include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) #define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) @@ -47,7 +48,7 @@ #define CHILD_ID 1 // Id of the sensor child -unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. +unsigned long SEND_FREQUENCY = 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. MySensor gw; MyMessage flowMsg(CHILD_ID,V_FLOW); @@ -72,8 +73,11 @@ void setup() { gw.begin(incomingMessage); + // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion) + pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP); + // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Water Meter", "1.2"); + gw.sendSketchInfo("Water Meter", "1.1"); // Register this device as Waterflow sensor gw.present(CHILD_ID, S_WATER); @@ -85,7 +89,7 @@ void setup() lastSend = lastPulse = millis(); - attachInterrupt(SENSOR_INTERRUPT, onPulse, RISING); + attachInterrupt(SENSOR_INTERRUPT, onPulse, FALLING); } @@ -93,7 +97,7 @@ void loop() { gw.process(); unsigned long currentTime = millis(); - + // Only send values at a maximum frequency or woken up from sleep if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY)) { @@ -124,7 +128,7 @@ void loop() } // Pulse count has changed - if (pulseCount != oldPulseCount) { + if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) { oldPulseCount = pulseCount; Serial.print("pulsecount:"); @@ -133,7 +137,7 @@ void loop() gw.send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1 double volume = ((double)pulseCount/((double)PULSE_FACTOR)); - if (volume != oldvolume) { + if ((volume != oldvolume)||(!SLEEP_MODE)) { oldvolume = volume; Serial.print("volume:"); @@ -152,6 +156,7 @@ void incomingMessage(const MyMessage &message) { if (message.type==V_VAR1) { unsigned long gwPulseCount=message.getULong(); pulseCount += gwPulseCount; + flow=oldflow=0; Serial.print("Received last pulse count from gw:"); Serial.println(pulseCount); pcReceived = true; @@ -178,4 +183,3 @@ void onPulse() } pulseCount++; } - From c96ae8e27b7f76bcc8bbacc50f351300e0532c43 Mon Sep 17 00:00:00 2001 From: Barduino Date: Mon, 24 Aug 2015 16:04:13 -0400 Subject: [PATCH 212/660] Minor Fixes and a sensors active --- .../examples/MockMySensors/MockMySensors.ino | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 466fb29..809f9fe 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -44,37 +44,37 @@ // one at a time. #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 -//#define ID_S_MOTION 2 -//#define ID_S_SMOKE 3 -//#define ID_S_LIGHT 4 -//#define ID_S_DIMMER 5 -//#define ID_S_COVER 6 -//#define ID_S_TEMP 7 -//#define ID_S_HUM 8 -//#define ID_S_BARO 9 -//#define ID_S_WIND 10 -//#define ID_S_RAIN 11 -//#define ID_S_UV 12 -//#define ID_S_WEIGHT 13 -//#define ID_S_POWER 14 -//#define ID_S_HEATER 15 -//#define ID_S_DISTANCE 16 -//#define ID_S_LIGHT_LEVEL 17 -//#define ID_S_LOCK 18 -//#define ID_S_IR 19 -//#define ID_S_WATER 20 -//#define ID_S_AIR_QUALITY 21 -//#define ID_S_DUST 22 -//#define ID_S_SCENE_CONTROLLER 23 -//#define ID_S_CUSTOM 99 +#define ID_S_MOTION 2 +#define ID_S_SMOKE 3 +#define ID_S_LIGHT 4 +#define ID_S_DIMMER 5 +#define ID_S_COVER 6 +#define ID_S_TEMP 7 +#define ID_S_HUM 8 +#define ID_S_BARO 9 +#define ID_S_WIND 10 +#define ID_S_RAIN 11 +#define ID_S_UV 12 +#define ID_S_WEIGHT 13 +#define ID_S_POWER 14 +#define ID_S_HEATER 15 +#define ID_S_DISTANCE 16 +#define ID_S_LIGHT_LEVEL 17 +#define ID_S_LOCK 18 +#define ID_S_IR 19 +#define ID_S_WATER 20 +#define ID_S_AIR_QUALITY 21 +#define ID_S_DUST 22 +#define ID_S_SCENE_CONTROLLER 23 +#define ID_S_CUSTOM 99 // Global Vars -unsigned long SLEEP_TIME = 180000; // Sleep time between reads (in milliseconds) +unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds) boolean metric = true; long randNumber; // Instanciate MySersors Gateway -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL); //MyTransportRFM69 transport; // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) @@ -309,7 +309,7 @@ void setup() #endif #ifdef ID_S_TEMP - Serial.println(" S_TMEP"); + Serial.println(" S_TEMP"); gw.present(ID_S_TEMP,S_TEMP); gw.wait(SHORT_WAIT); #endif @@ -924,6 +924,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isArmed ? "Armed":"Disarmed" )); + motion();//temp ack break; #endif @@ -934,7 +935,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isLightOn ? "On":"Off")); - light(); + light(); // temp ack break; #endif @@ -1004,6 +1005,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(message.getBool()?"Locked":"Unlocked"); + lock(); //temp ack break; #endif From 628e90b15f4ab441b4cddf30949678345eafaa26 Mon Sep 17 00:00:00 2001 From: Barduino Date: Mon, 24 Aug 2015 16:59:34 -0400 Subject: [PATCH 213/660] Minor fixes --- .../MySensors/examples/MockMySensors/MockMySensors.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 809f9fe..9bc37ff 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -48,7 +48,7 @@ #define ID_S_SMOKE 3 #define ID_S_LIGHT 4 #define ID_S_DIMMER 5 -#define ID_S_COVER 6 +//#define ID_S_COVER 6 #define ID_S_TEMP 7 #define ID_S_HUM 8 #define ID_S_BARO 9 @@ -65,7 +65,7 @@ #define ID_S_WATER 20 #define ID_S_AIR_QUALITY 21 #define ID_S_DUST 22 -#define ID_S_SCENE_CONTROLLER 23 +//#define ID_S_SCENE_CONTROLLER 23 #define ID_S_CUSTOM 99 // Global Vars @@ -649,7 +649,7 @@ void cover(){ if (coverVal == "V_UP"){ Serial.println("Opening"); gw.send(msg_S_COVER_U.set(V_UP)); - }else if (coverVal == "V_DONW"){ + }else if (coverVal == "V_DOWN"){ Serial.println("Closing"); gw.send(msg_S_COVER_D.set(V_DOWN)); }else{ From 8166bbaf95e4a12637fe649f3a8b053ef93138ce Mon Sep 17 00:00:00 2001 From: Barduino Date: Tue, 25 Aug 2015 09:44:42 -0400 Subject: [PATCH 214/660] Minor Fixes Most Sensor comment out --- .../examples/MockMySensors/MockMySensors.ino | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 9bc37ff..d27770e 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -45,28 +45,28 @@ #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 #define ID_S_MOTION 2 -#define ID_S_SMOKE 3 -#define ID_S_LIGHT 4 -#define ID_S_DIMMER 5 +//#define ID_S_SMOKE 3 +//#define ID_S_LIGHT 4 +//#define ID_S_DIMMER 5 //#define ID_S_COVER 6 -#define ID_S_TEMP 7 -#define ID_S_HUM 8 -#define ID_S_BARO 9 -#define ID_S_WIND 10 -#define ID_S_RAIN 11 -#define ID_S_UV 12 -#define ID_S_WEIGHT 13 -#define ID_S_POWER 14 -#define ID_S_HEATER 15 -#define ID_S_DISTANCE 16 -#define ID_S_LIGHT_LEVEL 17 -#define ID_S_LOCK 18 -#define ID_S_IR 19 -#define ID_S_WATER 20 -#define ID_S_AIR_QUALITY 21 -#define ID_S_DUST 22 +//#define ID_S_TEMP 7 +//#define ID_S_HUM 8 +//#define ID_S_BARO 9 +//#define ID_S_WIND 10 +//#define ID_S_RAIN 11 +//#define ID_S_UV 12 +//#define ID_S_WEIGHT 13 +//#define ID_S_POWER 14 +//#define ID_S_HEATER 15 +//#define ID_S_DISTANCE 16 +//#define ID_S_LIGHT_LEVEL 17 +//#define ID_S_LOCK 18 +//#define ID_S_IR 19 +//#define ID_S_WATER 20 +//#define ID_S_AIR_QUALITY 21 +//#define ID_S_DUST 22 //#define ID_S_SCENE_CONTROLLER 23 -#define ID_S_CUSTOM 99 +//#define ID_S_CUSTOM 99 // Global Vars unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds) @@ -130,7 +130,7 @@ MyHwATMega328 hw; MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); - const char* coverVal = "V_STOP"; + const char* coverVal = "V_STOP"; //compiler warnings #endif #ifdef ID_S_TEMP @@ -216,7 +216,7 @@ MyHwATMega328 hw; MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); // not sure if scene controller sends int or chars - // betting on ints as Touch Display Scen by Hek + // betting on ints as Touch Display Scen by Hek // compiler warnings char *scenes[] = { "All off", "Good Morning", @@ -686,7 +686,7 @@ void hum(){ void baro(){ const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; - long pressure = map(randNumber,1,100,87000,108600); + long pressure = map(randNumber,1,100,870,1086);// hPa? int forecast = map(randNumber,1,100,0,5); Serial.print("Atmosferic Pressure is: " ); From cce5209368d3606168635fbe0bed58743e66acee Mon Sep 17 00:00:00 2001 From: Barduino Date: Tue, 25 Aug 2015 10:32:06 -0400 Subject: [PATCH 215/660] Minor Fixes Only Door and Armed Active --- libraries/MySensors/examples/MockMySensors/MockMySensors.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index d27770e..c599aab 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -44,7 +44,7 @@ // one at a time. #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 -#define ID_S_MOTION 2 +//#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 //#define ID_S_DIMMER 5 @@ -924,7 +924,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isArmed ? "Armed":"Disarmed" )); - motion();//temp ack + door();//temp ack break; #endif From 875875ab388dc68eee6f4c4dc0bcdd765491d020 Mon Sep 17 00:00:00 2001 From: Barduino Date: Tue, 25 Aug 2015 10:36:53 -0400 Subject: [PATCH 216/660] Minor Changes --- libraries/MySensors/examples/MockMySensors/MockMySensors.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index c599aab..9510270 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -924,7 +924,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isArmed ? "Armed":"Disarmed" )); - door();//temp ack + door();//temp ack for door break; #endif From 64e28005b4574af467c4fad051e687f9c92f372f Mon Sep 17 00:00:00 2001 From: Yveaux Date: Wed, 26 Aug 2015 12:00:29 +0200 Subject: [PATCH 217/660] Added initial support for ESP8266 as WiFi gateway for MySensors --- libraries/MySensors/MyHwATMega328.cpp | 3 + libraries/MySensors/MyHwATMega328.h | 3 + libraries/MySensors/MyHwESP8266.cpp | 184 +++++++++++++++ libraries/MySensors/MyHwESP8266.h | 86 +++++++ libraries/MySensors/MyMessage.h | 2 + libraries/MySensors/MySensor.h | 5 + libraries/MySensors/MySigningAtsha204.cpp | 2 + .../Esp8266Gateway/Esp8266Gateway.ino | 216 ++++++++++++++++++ .../examples/Esp8266Gateway/GatewayUtil.h | 133 +++++++++++ libraries/MySensors/utility/ATSHA204.cpp | 4 + libraries/MySensors/utility/RF24.cpp | 47 ++-- libraries/MySensors/utility/RF24_config.h | 11 +- libraries/MySensors/utility/RFM69.cpp | 4 + libraries/MySensors/utility/RFM69.h | 4 + libraries/MySensors/utility/SPIFlash.cpp | 6 + libraries/MySensors/utility/nRF24L01.h | 2 +- libraries/MySensors/utility/sha256.cpp | 8 +- 17 files changed, 694 insertions(+), 26 deletions(-) create mode 100644 libraries/MySensors/MyHwESP8266.cpp create mode 100644 libraries/MySensors/MyHwESP8266.h create mode 100644 libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino create mode 100644 libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index 42517db..dfe4b5c 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -17,6 +17,8 @@ * version 2 as published by the Free Software Foundation. */ +#ifdef __AVR_ATmega328P__ + #include "MyHw.h" #include "MyHwATMega328.h" @@ -215,3 +217,4 @@ void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) { } #endif +#endif // #ifdef __AVR_ATmega328P__ diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index 9e42b55..a873ba9 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -20,6 +20,8 @@ #ifndef MyHwATMega328_h #define MyHwATMega328_h +#ifdef __AVR_ATmega328P__ + #include "MyHw.h" #include "MyConfig.h" #include "MyMessage.h" @@ -116,3 +118,4 @@ private: void internalSleep(unsigned long ms); }; #endif +#endif // #ifdef __AVR_ATmega328P__ diff --git a/libraries/MySensors/MyHwESP8266.cpp b/libraries/MySensors/MyHwESP8266.cpp new file mode 100644 index 0000000..7d83215 --- /dev/null +++ b/libraries/MySensors/MyHwESP8266.cpp @@ -0,0 +1,184 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifdef ESP8266 + +#include "MyHw.h" +#include "MyHwESP8266.h" +#include + +/* +int8_t pinIntTrigger = 0; +void wakeUp() //place to send the interrupts +{ + pinIntTrigger = 1; +} +void wakeUp2() //place to send the second interrupts +{ + pinIntTrigger = 2; +} + +// Watchdog Timer interrupt service routine. This routine is required +// to allow automatic WDIF and WDIE bit clearance in hardware. +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} +*/ + +static void hw_initConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ ) +{ + static bool initDone = false; + if (!initDone) + { + EEPROM.begin(length); + initDone = true; + } +} + +void hw_readConfigBlock(void* buf, void* adr, size_t length) +{ + hw_initConfigBlock(); + uint8_t* dst = static_cast(buf); + int offs = reinterpret_cast(adr); + while (length-- > 0) + { + *dst++ = EEPROM.read(offs++); + } +} + +void hw_writeConfigBlock(void* buf, void* adr, size_t length) +{ + hw_initConfigBlock(); + uint8_t* src = static_cast(buf); + int offs = reinterpret_cast(adr); + while (length-- > 0) + { + EEPROM.write(offs++, *src++); + } + EEPROM.commit(); +} + +uint8_t hw_readConfig(int adr) +{ + uint8_t value; + hw_readConfigBlock(&value, reinterpret_cast(adr), 1); + return value; +} + +void hw_writeConfig(int adr, uint8_t value) +{ + uint8_t curr = hw_readConfig(adr); + if (curr != value) + { + hw_writeConfigBlock(&value, reinterpret_cast(adr), 1); + } +} + + + +MyHwESP8266::MyHwESP8266() : MyHw() +{ +} + + +/* + +// The following was redifined as macros to save space + +inline uint8_t MyHwATMega328::readConfig(uint8_t pos) { + return eeprom_read_byte((uint8_t*)pos); +} + +inline void MyHwATMega328::writeConfig(uint8_t pos, uint8_t value) { + eeprom_update_byte((uint8_t*)pos, value); +} + +inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { + eeprom_read_block(buf, (void*)pos, length); +} + +inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { + eeprom_write_block((void*)pos, (void*)buf, length); +} + + +inline void MyHwATMega328::init() { + Serial.begin(BAUD_RATE); +} + +inline void MyHwATMega328::watchdogReset() { + wdt_reset(); +} + +inline void MyHwATMega328::reboot() { + wdt_enable(WDTO_15MS); for (;;); +} + +inline unsigned long MyHwATMega328::millis() { + return ::millis(); +} +*/ + + +void MyHwESP8266::sleep(unsigned long ms) { + // TODO: Not supported! +} + +bool MyHwESP8266::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { + // TODO: Not supported! + return false; +} + +inline uint8_t MyHwESP8266::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { + // TODO: Not supported! + return 0; +} + + + +#ifdef DEBUG +void MyHwESP8266::debugPrint(bool isGW, const char *fmt, ... ) { + char fmtBuffer[300]; + if (isGW) { + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + Serial.print(fmtBuffer); + } + va_list args; + va_start (args, fmt ); + va_end (args); + if (isGW) { + // Truncate message if this is gateway node + vsnprintf_P(fmtBuffer, 60, fmt, args); + fmtBuffer[59] = '\n'; + fmtBuffer[60] = '\0'; + } else { + vsnprintf_P(fmtBuffer, 299, fmt, args); + } + va_end (args); + Serial.print(fmtBuffer); + Serial.flush(); + + //Serial.write(freeRam()); +} +#endif + +#endif // #ifdef ESP8266 diff --git a/libraries/MySensors/MyHwESP8266.h b/libraries/MySensors/MyHwESP8266.h new file mode 100644 index 0000000..87ea8e8 --- /dev/null +++ b/libraries/MySensors/MyHwESP8266.h @@ -0,0 +1,86 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifdef ESP8266 + +#ifndef MyHwESP8266_h +#define MyHwESP8266_h + +#include "MyHw.h" +#include "MyConfig.h" +#include "MyMessage.h" + + +#ifdef __cplusplus +#include +#include +#endif + +// Define these as macros to save valuable space + +#define hw_digitalWrite(__pin, __value) (digitalWrite(__pin, __value)) +#define hw_init() Serial.begin(BAUD_RATE) +#define hw_watchdogReset() wdt_reset() +#define hw_reboot() wdt_enable(WDTO_15MS); while (1) +#define hw_millis() millis() + +void hw_readConfigBlock(void* buf, void* adr, size_t length); +void hw_writeConfigBlock(void* buf, void* adr, size_t length); +void hw_writeConfig(int adr, uint8_t value); +uint8_t hw_readConfig(int adr); + +enum period_t +{ + SLEEP_15Ms, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +class MyHwESP8266 : public MyHw +{ +public: + MyHwESP8266(); + +/* void init(); + void watchdogReset(); + void reboot(); + unsigned long millis(); + uint8_t readConfig(uint8_t pos); + void writeConfig(uint8_t pos, uint8_t value); + void readConfigBlock(void* buf, void * pos, size_t length); + void writeConfigBlock(void* pos, void* buf, size_t length); */ + + void sleep(unsigned long ms); + bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms); + uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +#ifdef DEBUG + void debugPrint(bool isGW, const char *fmt, ... ); +#endif +}; +#endif + +#endif // #ifdef ESP8266 diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 6c7c471..d3be005 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -163,7 +163,9 @@ typedef enum { +#ifndef BIT #define BIT(n) ( 1<<(n) ) +#endif // Create a bitmask of length len. #define BIT_MASK(len) ( BIT(len)-1 ) // Create a bitfield mask of length starting at bit 'start'. diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 3577693..3444077 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -41,8 +41,13 @@ // Set the hardware driver to use (initialized by MySensor-class) //#if defined __AVR_ATmega328P__ +#if defined(ESP8266) +#include "MyHwESP8266.h" +typedef MyHwESP8266 MyHwDriver; +#else #include "MyHwATMega328.h" typedef MyHwATMega328 MyHwDriver; +#endif //#endif diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 29c4d59..6444dd3 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -24,6 +24,7 @@ * HMAC-SHA256 authentication with a readout-protected key. * */ +#if defined(__AVR__) #include "MySigning.h" #include "MySigningAtsha204.h" @@ -266,3 +267,4 @@ uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { DEBUG_SIGNING_PRINTBUF(F("SHA:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return &rx_buffer[SHA204_BUFFER_POS_DATA]; } +#endif // #if defined(__AVR__) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino new file mode 100644 index 0000000..e71af42 --- /dev/null +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -0,0 +1,216 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Henrik EKblad + * Contribution by a-lurker and Anticimex, + * Contribution by Norbert Truchsess + * Contribution by Ivo Pullens (ESP8266 support) + * + * DESCRIPTION + * The EthernetGateway sends data received from sensors to the WiFi link. + * The gateway also accepts input on ethernet interface, which is then sent out to the radio network. + * + * VERA CONFIGURATION: + * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. + * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 + * + * LED purposes: + * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved + * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * + * See http://www.mysensors.org/build/ethernet_gateway for wiring instructions. + * The ESP8266 however requires different wiring: + * nRF24L01+ ESP8266 + * VCC VCC + * CE GPIO4 + * CSN/CS GPIO15 + * SCK GPIO14 + * MISO GPIO12 + * MOSI GPIO13 + * + * Not all ESP8266 modules have all pins available on their external interface. + * This code has been tested on an ESP-12 module. + * The ESP8266 requires a certain pin configuration to download code, and another one to run code: + * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch') + * - Connect GPIO15 via 10K pulldown resistor to GND + * - Connect CH_PD via 10K resistor to VCC + * - Connect GPIO2 via 10K resistor to VCC + * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') + * + * Signing, RF69 radio, inclusion button and a separate SPI flash are not supported yet! + * + * Make sure to fill in your ssid and WiFi password below for ssid & pass. + */ +#define NO_PORTB_PINCHANGES + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include "GatewayUtil.h" + +const char *ssid = "MySSID"; // cannot be longer than 32 characters! +const char *pass = "MyVerySecretPassword"; // + + #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled +// #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button + +#define RADIO_CE_PIN 4 // radio chip enable +#define RADIO_SPI_SS_PIN 15 // radio SPI serial select + +#define RADIO_ERROR_LED_PIN 7 // Error led pin +#define RADIO_RX_LED_PIN 8 // Receive led pin +#define RADIO_TX_LED_PIN 9 // the PCB, on board LED + + +// NRFRF24L01 radio driver (set low transmit power by default) +MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); + +// Hardware profile +MyHwESP8266 hw; + +// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +#ifdef WITH_LEDS_BLINKING +MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); +#else +MySensor gw(transport, hw /*, signer*/); +#endif + + +#define IP_PORT 5003 // The port you want to open + +// a R/W server on the port +WiFiServer server(IP_PORT); +// handle to open connection +WiFiClient client; + +char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface +int inputPos = 0; +bool sentReady = false; + +void output(const char *fmt, ... ) { + va_list args; + va_start (args, fmt ); + vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); + va_end (args); + Serial.print(serialBuffer); + server.write(serialBuffer); +} + +void setup() +{ + // Setup console + Serial.begin(115200); + + Serial.println(); + Serial.println("ESP8266 MySensors Gateway"); + Serial.print("Connecting to "); Serial.println(ssid); + + (void)WiFi.begin(ssid, pass); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("Connected!"); + Serial.print("IP: "); Serial.println(WiFi.localIP()); + Serial.flush(); + +#ifndef INCLUSION_MODE_PIN + setupGateway(255, INCLUSION_MODE_TIME, output); +#else + setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); + + // Add interrupt for inclusion button to pin + PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); +#endif + + // Initialize gateway at maximum PA level, channel 70 and callback for write operations + gw.begin(incomingMessage, 0, true, 0); + + // start listening for clients + server.begin(); +} + + +void loop() { + gw.process(); + +#ifdef INCLUSION_MODE_PIN + checkButtonTriggeredInclusion(); + checkInclusionFinished(); +#endif + + //check if there are any new clients + if (server.hasClient()) + { + if (client) + { + client.stop(); + } + client = server.available(); + output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); + } + + if (client) { + if (!client.connected()) { + client.stop(); + } else if (client.available()) { + // read the bytes incoming from the client + char inChar = client.read(); + if (inputPos + + +#ifdef ARDUINO + + +uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled +uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode + +#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller +#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller + +volatile boolean buttonTriggeredInclusion; +boolean inclusionMode; // Keeps track on inclusion mode +bool inclusionButtonSupported = false; +void (*serial)(const char *fmt, ... ); + +MyParserSerial parser; + +void setInclusionMode(boolean newMode); + +char convBuf[MAX_PAYLOAD*2+1]; +char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera +unsigned long inclusionStartTime; + +void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { + inclusionMode = 0; + buttonTriggeredInclusion = false; + serial = _serial; + + inclusionTime = _incTime; + inclusionButtonSupported = (_inc != 255); + if (inclusionButtonSupported) + { + pinInclusion = _inc; + + // Setup digital in that triggers inclusion mode + pinMode(pinInclusion, INPUT); + digitalWrite(pinInclusion, HIGH); + } +} + + + +void startInclusionInterrupt() { + buttonTriggeredInclusion = true; +} + +void incomingMessage(const MyMessage &message) { +// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { +// gw.rxBlink(3); +// } else { +// gw.rxBlink(1); +// } + // Pass along the message from sensors to serial line + serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf)); +} + + + +void checkButtonTriggeredInclusion() { + if (inclusionButtonSupported) + { + if (buttonTriggeredInclusion) { + // Ok, someone pressed the inclusion button on the gateway + // start inclusion mode for 1 munute. + #ifdef DEBUG + serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE); + #endif + buttonTriggeredInclusion = false; + setInclusionMode(true); + } + } +} + +void checkInclusionFinished() { + if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) { + // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode + setInclusionMode(false); + } +} + +void parseAndSend(MySensor &gw, char *commandBuffer) { + boolean ok; + MyMessage &msg = gw.getLastMessage(); + + if (parser.parse(msg, commandBuffer)) { + uint8_t command = mGetCommand(msg); + + if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) { + // Handle messages directed to gateway + if (msg.type == I_VERSION) { + // Request for version + serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION); + } else if (msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(msg.data) == 1); + } + } else { + #ifdef WITH_LEDS_BLINKING + gw.txBlink(1); + #endif + ok = gw.sendRoute(msg); + if (!ok) { + #ifdef WITH_LEDS_BLINKING + gw.errBlink(1); + #endif + } + } + } +} + +void setInclusionMode(boolean newMode) { + if (newMode != inclusionMode) { + inclusionMode = newMode; + // Send back mode change on serial line to ack command + serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0); + + if (inclusionMode) { + inclusionStartTime = millis(); + } + } +} + + +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + +#endif diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index f639bab..5fb8288 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -1,3 +1,5 @@ +#if defined(__AVR__) + #include "Arduino.h" #include "ATSHA204.h" @@ -572,3 +574,5 @@ uint8_t ATSHA204Class::sha204c_check_crc(uint8_t *response) return (crc[0] == response[count] && crc[1] == response[count + 1]) ? SHA204_SUCCESS : SHA204_BAD_CRC; } + +#endif // defined(__AVR__) \ No newline at end of file diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp index a0d281f..c117f4b 100644 --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -498,7 +498,7 @@ void RF24::begin(void) // Reset current status // Notice reset and flush is the last thing we do - write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); // Set up default configuration. Callers can always change it later. // This channel should be universally safe and not bleed over into adjacent @@ -525,7 +525,7 @@ void RF24::startListening(void) powerUp(); #endif write_register(CONFIG, read_register(CONFIG) | _BV(PRIM_RX)); - write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + write_register(RF24_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); // Restore the pipe0 adddress, if exists if (pipe0_reading_address[0] > 0){ @@ -546,22 +546,31 @@ void RF24::startListening(void) } /****************************************************************************/ -static const uint8_t child_pipe_enable[] PROGMEM = +static uint8_t get_child_pipe_mask(const uint8_t idx) { - ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5 -}; + static const uint8_t child_pipe_enable[] PROGMEM = + { + _BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5) + }; +#ifdef ESP8266 + return child_pipe_enable[0]; +#else + return pgm_read_byte(&child_pipe_enable[0]); +#endif +} void RF24::stopListening(void) { - ce(LOW); #if defined(__arm__) delayMicroseconds(300); #endif delayMicroseconds(130); + if(read_register(FEATURE) & _BV(EN_ACK_PAY)){ flush_tx(); } + //flush_rx(); write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) ); @@ -569,13 +578,13 @@ void RF24::stopListening(void) // for 3 pins solution TX mode is only left with additonal powerDown/powerUp cycle if (ce_pin == csn_pin) { powerDown(); - powerUp(); + powerUp(); } #endif - write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0]))); // Enable RX on pipe0 + + write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(0)); // Enable RX on pipe0 delayMicroseconds(100); - } /****************************************************************************/ @@ -636,7 +645,7 @@ bool RF24::write( const void* buf, uint8_t len, const bool multicast ) ce(LOW); - uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + uint8_t status = write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); //Max retries exceeded if( status & _BV(MAX_RT)){ @@ -686,7 +695,7 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout ) /****************************************************************************/ void RF24::reUseTX(){ - write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag + write_register(RF24_STATUS,_BV(MAX_RT) ); //Clear max retry flag spiTrans( REUSE_TX_PL ); ce(LOW); //Re-Transfer packet ce(HIGH); @@ -709,7 +718,7 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) if( get_status() & _BV(MAX_RT)){ //reUseTX(); //Set re-transmit - write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag + write_register(RF24_STATUS,_BV(MAX_RT) ); //Clear max retry flag return 0; //Return 0. The previous payload has been retransmitted //From the user perspective, if you get a 0, just keep trying to send the same payload } @@ -777,7 +786,7 @@ bool RF24::txStandBy(){ #endif while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ - write_register(STATUS,_BV(MAX_RT) ); + write_register(RF24_STATUS,_BV(MAX_RT) ); ce(LOW); flush_tx(); //Non blocking, flush the data return 0; @@ -802,7 +811,7 @@ bool RF24::txStandBy(uint32_t timeout){ while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ - write_register(STATUS,_BV(MAX_RT) ); + write_register(RF24_STATUS,_BV(MAX_RT) ); ce(LOW); //Set re-transmit ce(HIGH); if(millis() - start >= timeout){ @@ -891,7 +900,7 @@ void RF24::read( void* buf, uint8_t len ){ read_payload( buf, len ); //Clear the two possible interrupt flags with one command - write_register(STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS) ); + write_register(RF24_STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS) ); } @@ -901,7 +910,7 @@ void RF24::whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready) { // Read the status & reset the status in one easy call // Or is that such a good idea? - uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + uint8_t status = write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); // Report to the user what happened tx_ok = status & _BV(TX_DS); @@ -972,7 +981,7 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address) // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. - write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child]))); + write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(child)); } } @@ -1009,7 +1018,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t *address) // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. - write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child]))); + write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(child)); } } @@ -1018,7 +1027,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t *address) void RF24::closeReadingPipe( uint8_t pipe ) { - write_register(EN_RXADDR,read_register(EN_RXADDR) & ~_BV(pgm_read_byte(&child_pipe_enable[pipe]))); + write_register(EN_RXADDR,read_register(EN_RXADDR) & ~get_child_pipe_mask(pipe)); } /****************************************************************************/ diff --git a/libraries/MySensors/utility/RF24_config.h b/libraries/MySensors/utility/RF24_config.h index 2addc27..d38ac88 100644 --- a/libraries/MySensors/utility/RF24_config.h +++ b/libraries/MySensors/utility/RF24_config.h @@ -87,7 +87,7 @@ // Avoid spurious warnings // Arduino DUE is arm and uses traditional PROGMEM constructs #if 1 -#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) && ! defined( CORE_TEENSY3 ) +#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) && ! defined( CORE_TEENSY3 ) && ! defined(ESP8266) #undef PROGMEM #define PROGMEM __attribute__(( section(".progmem.data") )) #undef PSTR @@ -97,18 +97,21 @@ // Progmem is Arduino-specific // Arduino DUE is arm and does not include avr/pgmspace -#if defined(ARDUINO) && ! defined(__arm__) +#if defined(__AVR__) #include #define PRIPSTR "%S" #else +#if defined(ESP8266) +#include +#else #if ! defined(ARDUINO) // This doesn't work on Arduino DUE typedef char const char; #else // Fill in pgm_read_byte that is used, but missing from DUE #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) #endif +#endif - -#if !defined ( CORE_TEENSY ) +#if !defined ( CORE_TEENSY ) && ! defined(ESP8266) typedef uint16_t prog_uint16_t; #define PSTR(x) (x) #define printf_P printf diff --git a/libraries/MySensors/utility/RFM69.cpp b/libraries/MySensors/utility/RFM69.cpp index 4663480..56e47e5 100644 --- a/libraries/MySensors/utility/RFM69.cpp +++ b/libraries/MySensors/utility/RFM69.cpp @@ -384,8 +384,10 @@ void RFM69::writeReg(byte addr, byte value) void RFM69::select() { noInterrupts(); //save current SPI settings +#ifndef ESP8266 _SPCR = SPCR; _SPSR = SPSR; +#endif //set RFM69 SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); @@ -397,8 +399,10 @@ void RFM69::select() { void RFM69::unselect() { digitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to RFM69 +#ifndef ESP8266 SPCR = _SPCR; SPSR = _SPSR; +#endif interrupts(); } diff --git a/libraries/MySensors/utility/RFM69.h b/libraries/MySensors/utility/RFM69.h index c3e8d05..bcc3201 100644 --- a/libraries/MySensors/utility/RFM69.h +++ b/libraries/MySensors/utility/RFM69.h @@ -43,6 +43,10 @@ #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2560__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 2 +#elif defined(ESP8266) + // TODO !! + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 0 #endif #define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access diff --git a/libraries/MySensors/utility/SPIFlash.cpp b/libraries/MySensors/utility/SPIFlash.cpp index e250c17..00e1601 100644 --- a/libraries/MySensors/utility/SPIFlash.cpp +++ b/libraries/MySensors/utility/SPIFlash.cpp @@ -56,8 +56,10 @@ void SPIFlash::select() { #ifndef SPI_HAS_TRANSACTION noInterrupts(); #endif +#ifndef ESP8266 _SPCR = SPCR; _SPSR = SPSR; +#endif #ifdef SPI_HAS_TRANSACTION SPI.beginTransaction(_settings); @@ -80,15 +82,19 @@ void SPIFlash::unselect() { #else interrupts(); #endif +#ifndef ESP8266 SPCR = _SPCR; SPSR = _SPSR; +#endif } /// setup SPI, read device ID etc... boolean SPIFlash::initialize() { +#ifndef ESP8266 _SPCR = SPCR; _SPSR = SPSR; +#endif pinMode(_slaveSelectPin, OUTPUT); #ifdef SPI_HAS_TRANSACTION _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); diff --git a/libraries/MySensors/utility/nRF24L01.h b/libraries/MySensors/utility/nRF24L01.h index 132de94..02e1d4f 100644 --- a/libraries/MySensors/utility/nRF24L01.h +++ b/libraries/MySensors/utility/nRF24L01.h @@ -31,7 +31,7 @@ #define SETUP_RETR 0x04 #define RF_CH 0x05 #define RF_SETUP 0x06 -#define STATUS 0x07 +#define RF24_STATUS 0x07 #define OBSERVE_TX 0x08 #define CD 0x09 #define RX_ADDR_P0 0x0A diff --git a/libraries/MySensors/utility/sha256.cpp b/libraries/MySensors/utility/sha256.cpp index f0376ab..511d78a 100644 --- a/libraries/MySensors/utility/sha256.cpp +++ b/libraries/MySensors/utility/sha256.cpp @@ -1,6 +1,10 @@ #include -#include -#include +#if defined(__AVR__) + #include + #define PRIPSTR "%S" +#elif defined(ESP8266) +#include +#endif #include "sha256.h" From 0bb5e223b2d63d1d9f406d5e494f09053ae9a22d Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 10:53:35 +0200 Subject: [PATCH 218/660] Fixed inclusion mode --- .../Esp8266Gateway/Esp8266Gateway.ino | 22 +++++--------- .../examples/Esp8266Gateway/GatewayUtil.h | 30 +++++++++---------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino index e71af42..ae7b9e2 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -57,7 +57,10 @@ * - Connect GPIO2 via 10K resistor to VCC * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') * - * Signing, RF69 radio, inclusion button and a separate SPI flash are not supported yet! + * Inclusion mode button: + * - Connect GPIO5 via switch to GND ('inclusion switch') + * + * * Signing, RF69 radio and a separate SPI flash are not supported yet! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ @@ -78,8 +81,8 @@ const char *ssid = "MySSID"; // cannot be longer than 32 characters! const char *pass = "MyVerySecretPassword"; // - #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled -// #define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button +#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled +#define INCLUSION_MODE_PIN 5 // Digital pin used for inclusion mode button #define RADIO_CE_PIN 4 // radio chip enable #define RADIO_SPI_SS_PIN 15 // radio SPI serial select @@ -127,9 +130,9 @@ void output(const char *fmt, ... ) { void setup() { // Setup console - Serial.begin(115200); + hw_init(); - Serial.println(); + Serial.println(); Serial.println(); Serial.println("ESP8266 MySensors Gateway"); Serial.print("Connecting to "); Serial.println(ssid); @@ -142,15 +145,8 @@ void setup() Serial.print("IP: "); Serial.println(WiFi.localIP()); Serial.flush(); -#ifndef INCLUSION_MODE_PIN - setupGateway(255, INCLUSION_MODE_TIME, output); -#else setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output); - // Add interrupt for inclusion button to pin - PCintPort::attachInterrupt(pinInclusion, startInclusionInterrupt, RISING); -#endif - // Initialize gateway at maximum PA level, channel 70 and callback for write operations gw.begin(incomingMessage, 0, true, 0); @@ -162,10 +158,8 @@ void setup() void loop() { gw.process(); -#ifdef INCLUSION_MODE_PIN checkButtonTriggeredInclusion(); checkInclusionFinished(); -#endif //check if there are any new clients if (server.hasClient()) diff --git a/libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h b/libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h index 96a65a2..c926f5e 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h +++ b/libraries/MySensors/examples/Esp8266Gateway/GatewayUtil.h @@ -1,20 +1,17 @@ #ifndef __GATEWAYUTIL_H__ #define __GATEWAYUTIL_H__ -#include - - #ifdef ARDUINO -uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled -uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode +static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled +static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode #define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller #define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller -volatile boolean buttonTriggeredInclusion; -boolean inclusionMode; // Keeps track on inclusion mode +static volatile boolean buttonTriggeredInclusion; +static boolean inclusionMode; // Keeps track on inclusion mode bool inclusionButtonSupported = false; void (*serial)(const char *fmt, ... ); @@ -26,6 +23,11 @@ char convBuf[MAX_PAYLOAD*2+1]; char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera unsigned long inclusionStartTime; + +void startInclusionInterrupt() { + buttonTriggeredInclusion = true; +} + void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) { inclusionMode = 0; buttonTriggeredInclusion = false; @@ -36,19 +38,15 @@ void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, if (inclusionButtonSupported) { pinInclusion = _inc; - + // Setup digital in that triggers inclusion mode - pinMode(pinInclusion, INPUT); - digitalWrite(pinInclusion, HIGH); + pinMode(pinInclusion, INPUT_PULLUP); + + // Add interrupt for inclusion button to pin + attachInterrupt(pinInclusion, startInclusionInterrupt, FALLING); } } - - -void startInclusionInterrupt() { - buttonTriggeredInclusion = true; -} - void incomingMessage(const MyMessage &message) { // if (mGetCommand(message) == C_PRESENTATION && inclusionMode) { // gw.rxBlink(3); From d6cc1b46fc4b2c7fcaca0a6cda51a835116f194e Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 11:20:35 +0200 Subject: [PATCH 219/660] Fix led blinking --- libraries/MySensors/MySensor.cpp | 6 ++---- libraries/MySensors/MySensor.h | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index dc784c8..6c3a348 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -95,14 +95,12 @@ bool MySensor::isValidFirmware() { #ifdef WITH_LEDS_BLINKING void MySensor::handleLedsBlinking() { - static unsigned long next_time = hw_millis() + ledBlinkPeriod; - // Just return if it is not the time... // http://playground.arduino.cc/Code/TimingRollover - if ((long)(hw_millis() - next_time) < 0) + if ((long)(hw_millis() - blink_next_time) < 0) return; else - next_time = hw_millis() + ledBlinkPeriod; + blink_next_time = hw_millis() + ledBlinkPeriod; // do the actual blinking if(countRx && countRx != 255) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 3444077..7190d7f 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -361,6 +361,7 @@ class MySensor unsigned long ledBlinkPeriod; void handleLedsBlinking(); // do the actual blinking + unsigned long blink_next_time; #endif MyTransport& radio; From e2c715c387e5c4a5faa020dc20b00101ed259b5b Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 12:11:49 +0200 Subject: [PATCH 220/660] Fix support for signing. Only software ATSHA204 supported! --- .../Esp8266Gateway/Esp8266Gateway.ino | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino index ae7b9e2..dc678f3 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -60,7 +60,7 @@ * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') * - * * Signing, RF69 radio and a separate SPI flash are not supported yet! + * Hardware SHA204 signing, RF69 radio and a separate SPI flash are not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ @@ -68,6 +68,8 @@ #include +#include +#include #include #include #include @@ -87,25 +89,36 @@ const char *pass = "MyVerySecretPassword"; // #define RADIO_CE_PIN 4 // radio chip enable #define RADIO_SPI_SS_PIN 15 // radio SPI serial select +#ifdef WITH_LEDS_BLINKING #define RADIO_ERROR_LED_PIN 7 // Error led pin #define RADIO_RX_LED_PIN 8 // Receive led pin #define RADIO_TX_LED_PIN 9 // the PCB, on board LED +#endif // NRFRF24L01 radio driver (set low transmit power by default) MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +#ifdef MY_SIGNING_FEATURE +MySigningNone signer; +//MySigningAtsha204Soft signer; +#endif + // Hardware profile MyHwESP8266 hw; // Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) // To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h -#ifdef WITH_LEDS_BLINKING -MySensor gw(transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); -#else -MySensor gw(transport, hw /*, signer*/); +MySensor gw(transport, hw +#ifdef MY_SIGNING_FEATURE + , signer #endif - +#ifdef WITH_LEDS_BLINKING + , RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN +#endif + ); + #define IP_PORT 5003 // The port you want to open From c0d2177afa0c928120b1f804ac06c309f5c3c1c4 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 12:12:16 +0200 Subject: [PATCH 221/660] Software SHA204 signing uses only analog input avaiable: A0 --- libraries/MySensors/MyConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 13978d5..6766b2b 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -101,7 +101,7 @@ #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached // MySigningAtsha204Soft default settings -#define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) +#define MY_RANDOMSEED_PIN A0 // A0 - Pin used for random generation (do not connect anything to this) // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 From dae4f8172bb654c3ea828db3906c0880905c54ae Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 12:21:31 +0200 Subject: [PATCH 222/660] Got RF69 support compiling --- .../MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino index dc678f3..23aec57 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -60,7 +60,7 @@ * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') * - * Hardware SHA204 signing, RF69 radio and a separate SPI flash are not supported! + * Hardware SHA204 signing and a separate SPI flash are not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ @@ -71,6 +71,7 @@ #include #include #include +#include #include #include #include @@ -97,7 +98,9 @@ const char *pass = "MyVerySecretPassword"; // // NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); +MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRFM69 transport; + // Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) #ifdef MY_SIGNING_FEATURE From f407617dda298ac748fc5441516e4f796b329999 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 27 Aug 2015 12:32:48 +0200 Subject: [PATCH 223/660] Removed comment about external SPI flash not supported by gateway. External SPI flash is not required by gateway. ESP8266 has sufficient internal flash should it be required. --- libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino index 23aec57..c5be624 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -60,7 +60,7 @@ * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') * - * Hardware SHA204 signing and a separate SPI flash are not supported! + * Hardware SHA204 signing is currently not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ From 40dbcb1e37ef481e6404343f75e824ca40d66fe9 Mon Sep 17 00:00:00 2001 From: Thomas Krebs Date: Sun, 30 Aug 2015 20:08:02 +0200 Subject: [PATCH 224/660] Add MQTTClientGateway --- .../MQTTClientGateway/MQTTClientGateway.ino | 605 ++++++++++++++++++ .../examples/MQTTClientGateway/MyMQTTClient.h | 122 ++++ libraries/PubSubClient/CHANGES.txt | 47 ++ libraries/PubSubClient/LICENSE.txt | 20 + libraries/PubSubClient/PubSubClient.cpp | 427 ++++++++++++ libraries/PubSubClient/PubSubClient.h | 81 +++ .../examples/mqtt_auth/mqtt_auth.ino | 39 ++ .../examples/mqtt_basic/mqtt_basic.ino | 38 ++ .../mqtt_publish_in_callback.ino | 61 ++ .../examples/mqtt_stream/mqtt_stream.ino | 58 ++ libraries/PubSubClient/keywords.txt | 25 + 11 files changed, 1523 insertions(+) create mode 100644 libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino create mode 100644 libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h create mode 100755 libraries/PubSubClient/CHANGES.txt create mode 100755 libraries/PubSubClient/LICENSE.txt create mode 100755 libraries/PubSubClient/PubSubClient.cpp create mode 100755 libraries/PubSubClient/PubSubClient.h create mode 100755 libraries/PubSubClient/examples/mqtt_auth/mqtt_auth.ino create mode 100755 libraries/PubSubClient/examples/mqtt_basic/mqtt_basic.ino create mode 100755 libraries/PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino create mode 100755 libraries/PubSubClient/examples/mqtt_stream/mqtt_stream.ino create mode 100755 libraries/PubSubClient/keywords.txt diff --git a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino new file mode 100644 index 0000000..ece4e0c --- /dev/null +++ b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino @@ -0,0 +1,605 @@ +/* MyMQTT Client Gateway 0.1b + Created by Norbert Truchsess + Based on MyMQTT-broker gateway created by Daniel Wiegert + Based on MySensors Ethernet Gateway by Henrik Ekblad + http://www.mysensors.org + + Changes by Thomas Krebs + - Add signing support from MySensors 1.5 and update for MySensors 1.5; + - Restructured code back to a C like implementation following the existing MQTTGateway + Requires MySensors lib 1.5 + + * Change below; TCP_IP, TCP_PORT, TCP_MAC + This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also. + *1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges. + *2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change + the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details. + http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5 + * Don't forget to look at the definitions in libraries\MySensors\MyMQTT.h! + define TCPDUMP and connect serial interface if you have problems, please write on + http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to + turn on DEBUG in libraries\MySensors\MyConfig.h also. + MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition. + If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20. + To disable: set MQTT_FIRST_SENSORID to 255. + MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like. + MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes. + This can be useful if you want to send latest state back to the MQTT client. Just check if incoming + message has any length or not. + Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. + * Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType][/set | /get] + NodeID and SensorID is uint8 (0-255) number. + Segment after SensorID is translation of the sensor type, look inside MyMQTT.cpp for the definitions. + User can change this to their needs. We have also left some space for custom types. + Special: (sensor 255 reserved for special commands) + + The last seqment is a command to to be send down to the sensor. The gateway is subscribed to topics which have + a command present! This is to avoid that a publish by the gateway will end up in the gateway via it subsription. + You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version) + + So far tested in openhab and MyMQTT for Android (Not my creation) + - http://www.openhab.org/ + * How to set-up Openhab and MQTTGateway: + http://forum.mysensors.org/topic/303/mqtt-broker-gateway + + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MyMQTTClient.h" + +#ifdef MY_SIGNING_FEATURE +#include +#include +#include +#endif + +//#define DSRTC +#ifdef DSRTC +#include +#include // a basic DS1307 library that returns time as a time_t +#endif + +/* + * To configure MQTTClientGateway.ino to use an ENC28J60 based board include + * 'UIPEthernet.h' (SPI.h required for MySensors anyway). The UIPEthernet-library can be downloaded + * from: https://github.com/ntruchsess/arduino_uip + */ + +//#include +/* + * To execute MQTTClientGateway.ino on Yun uncomment Bridge.h and YunClient.h. + * Do not include Ethernet.h or SPI.h in this case. + * On Yun there's no need to configure local_ip and mac in the sketch + * as this is configured on the linux-side of Yun. + */ + +//#include +//#include +// * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! +/* + #define RADIO_CE_PIN 3 // radio chip enable + #define RADIO_SPI_SS_PIN 8 // radio SPI serial select + #define RADIO_ERROR_LED_PIN A2 // Error led pin + #define RADIO_RX_LED_PIN A1 // Receive led pin + #define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/ + +// * Use this for default configured pro mini / nano etc : +// + +//#define RADIO_CE_PIN 5 // radio chip enable +//#define RADIO_SPI_SS_PIN 6 // radio SPI serial select +//#define RADIO_ERROR_LED_PIN 7 // Error led pin +//#define RADIO_RX_LED_PIN 8 // Receive led pin +//#define RADIO_TX_LED_PIN 9 // the PCB, on board LED*/ + +// CE_PIN and SPI_SS_PIN for Mega +#define RADIO_CE_PIN 48 // radio chip enable +#define RADIO_SPI_SS_PIN 49 // radio SPI serial select +#define RADIO_ERROR_LED_PIN A2 // Error led pin +#define RADIO_RX_LED_PIN A1 // Receive led pin +#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/ + +//replace with ip of server you want to connect to, comment out if using 'remote_host' +uint8_t remote_ip[] = { 192, 168, 178, 74 }; // Mosquitto broker + +//replace with hostname of server you want to connect to, comment out if using 'remote_ip' +//char* remote_ip = "server.local"; +//replace with the port that your server is listening on +#define remote_port 1883 +//replace with arduinos ip-address. Comment out if Ethernet-startup should use dhcp. Is ignored on Yun +uint8_t local_ip[] = {192, 168, 178, 11}; +//replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun +uint8_t mac[] = { 0xA2, 0xAE, 0xAD, 0xA0, 0xA0, 0xA2 }; + +/////////////////////////////////////////////////////////////////// +#define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment +#define MQTT_USER "username" // username on MQTT broker +#define MQTT_PWD "pwd" // password for MQTT username above +////////////////////////////////////////////////////////////////// + +#if defined remote_ip && defined remote_host +#error "cannot define both remote_ip and remote_host at the same time!" +#endif + +#ifdef _YUN_CLIENT_H_ +YunClient ethClient; +#else +EthernetClient ethClient; +#endif + +//////////////////////////////////////////////////////////////// +// NRFRF24L01 radio driver (set low transmit power by default) +MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); +//MyTransportRFM69 transport; + +// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) +//MySigningNone signer; +//MySigningAtsha204Soft signer(true); +//MySigningAtsha204 signer; + +// Hardware profile +MyHwATMega328 hw; + +MyMessage msg; +char convBuf[MAX_PAYLOAD * 2 + 1]; +uint8_t buffsize; +char buffer[MQTT_MAX_PACKET_SIZE]; + +//////////////////////////////////////////////////////////////// + +volatile uint8_t countRx; +volatile uint8_t countTx; +volatile uint8_t countErr; + + +//////////////////////////////////////////////////////////////// + +void processMQTTMessages(char* topic, byte* payload, unsigned int length); +PubSubClient client(remote_ip, remote_port, processMQTTMessages, ethClient); + +//////////////////////////////////////////////////////////////// + + +// Declare and initialize MySensor instance +// Construct MyMQTTClient (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h, if signing +// feature not to be used, uncomment) +// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h +MySensor gw(transport, hw +#ifdef MY_SIGNING_FEATURE + , signer +#endif +#ifdef WITH_LEDS_BLINKING + , RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN +#endif + ); + +/* + * setup + */ +void setup() +{ + countRx = 0; + countTx = 0; + countErr = 0; + + Ethernet.begin(mac, local_ip); + //Bridge.begin(); + delay(1000); // Wait for Ethernet to get configured. + + begin(); +} + +/* + * loop + */ +void loop() +{ + if (!client.connected()) + { + client.connect("MySensor" +#ifdef MQTT_AUTH_REQUIRED + ,MQTT_USER,MQTT_PWD +#endif + ); + client.subscribe(MQTT_TOPIC_MASK); + } + client.loop(); + gw.process(); +} + +/* + * processRadioMessage + * + * Receives radio message, parses it and forwards it to the MQTT broker + */ +void processRadioMessage(const MyMessage &message) +{ + rxBlink(1); + sendMQTT(message); +} + +/* + * sendMQTT + * Handles processing of radio messages and eventually publishes it to the MQTT broker + */ +void sendMQTT(const MyMessage &inMsg) +{ + MyMessage msg = inMsg; + buffsize = 0; + if (!client.connected()) + return; //We have no connections - return + if (msg.isAck()) + { +#ifdef DEBUG + Serial.println("msg is ack!"); +#endif + if (msg.sender == 255 && mGetCommand(msg) == C_INTERNAL + && msg.type == I_ID_REQUEST) + { + // TODO: sending ACK request on id_response fucks node up. doesn't work. + // The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS. + } + } + else + { + // we have to check every message if its a newly assigned id or not. + // Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable. + uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1; + if (newNodeID <= MQTT_FIRST_SENSORID) + newNodeID = MQTT_FIRST_SENSORID; + if (msg.sender == newNodeID) + { + gw.saveState(EEPROM_LATEST_NODE_ADDRESS, newNodeID); + } + if (mGetCommand(msg) == C_INTERNAL) + { + if (msg.type == I_CONFIG) + { + txBlink(1); + if (!gw.sendRoute( + build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, + I_CONFIG, 0).set("M"))) + errBlink(1); + } + else if (msg.type == I_TIME) + { +#ifdef DEBUG + Serial.println("I_TIME requested!"); +#endif + txBlink(1); + if (!gw.sendRoute( + build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, + I_TIME, 0).set(now()))) + errBlink(1); + } + else if (msg.type == I_ID_REQUEST && msg.sender == 255) + { + uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1; + if (newNodeID <= MQTT_FIRST_SENSORID) + newNodeID = MQTT_FIRST_SENSORID; + if (newNodeID >= MQTT_LAST_SENSORID) + return; // Sorry no more id's left :( + txBlink(1); + if (!gw.sendRoute( + build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, + I_ID_RESPONSE, 0).set(newNodeID))) + errBlink(1); + } + else if (msg.type == I_BATTERY_LEVEL) + { + strcpy_P(buffer, mqtt_prefix); + buffsize += strlen_P(mqtt_prefix); + buffsize += sprintf(&buffer[buffsize], "/%i/255/BATTERY_LEVEL\0", msg.sender ); + msg.getString(convBuf); +#ifdef DEBUG + Serial.print("publish: "); + Serial.print((char*) buffer); + Serial.print(" "); + Serial.println((char*) convBuf); +#endif + client.publish(buffer, convBuf); + } + else if (msg.type == I_SKETCH_NAME) + { + strcpy_P(buffer, mqtt_prefix); + buffsize += strlen_P(mqtt_prefix); + buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_NAME\0", msg.sender ); + msg.getString(convBuf); +#ifdef DEBUG + Serial.print("publish: "); + Serial.print((char*) buffer); + Serial.print(" "); + Serial.println((char*) convBuf); +#endif + client.publish(buffer, convBuf); + } + else if (msg.type == I_SKETCH_VERSION) + { + strcpy_P(buffer, mqtt_prefix); + buffsize += strlen_P(mqtt_prefix); + buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_VERSION\0", msg.sender ); + msg.getString(convBuf); +#ifdef DEBUG + Serial.print("publish: "); + Serial.print((char*) buffer); + Serial.print(" "); + Serial.println((char*) convBuf); +#endif + client.publish(buffer, convBuf); + } + + } + else if (mGetCommand(msg) != 0) + { + if (mGetCommand(msg) == 3) + msg.type = msg.type + (S_FIRSTCUSTOM - 10); //Special message + + if (msg.type > VAR_TOTAL) + msg.type = VAR_TOTAL; // If type > defined types set to unknown. + strcpy_P(buffer, mqtt_prefix); + buffsize += strlen_P(mqtt_prefix); + buffsize += sprintf(&buffer[buffsize], "/%i/%i/V_%s\0", msg.sender, + msg.sensor, getType(convBuf, &VAR_Type[msg.type])); + msg.getString(convBuf); +#ifdef DEBUG + Serial.print("publish: "); + Serial.print((char*) buffer); + Serial.print(" "); + Serial.println((char*) convBuf); +#endif + client.publish(buffer, convBuf); + } + } +} + +/* + * build + * Constructs a radio message + */ +inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, + uint8_t command, uint8_t type, bool enableAck) +{ + msg.destination = destination; + msg.sender = sender; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg, command); + mSetRequestAck(msg, enableAck); + mSetAck(msg, false); + return msg; +} + +/* + * getType + */ +char *getType(char *b, const char **index) +{ + char *q = b; + char *p = (char *) pgm_read_word(index); + while (*q++ = pgm_read_byte(p++)) + ; + *q = 0; + return b; +} + +/* + * begin + * wraps MySensors begin method; setup of RTC and led timers interrupt + */ +void begin() +{ +#ifdef DEBUG + Serial.begin(BAUD_RATE); +#endif +#ifdef DSRTC + // Attach RTC + setSyncProvider(RTC.get); // the function to get the time from the RTC + setSyncInterval(60); +#endif + + gw.begin(processRadioMessage, 0, true, 0); + + MsTimer2::set(200, ledTimersInterrupt); + MsTimer2::start(); + +#ifdef DEBUG + Serial.print(getType(convBuf, &VAR_Type[S_FIRSTCUSTOM])); +#endif +} + +/* + * processMQTTMessages + * message handler for the PubSubClient + */ +void processMQTTMessages(char* topic, byte* payload, unsigned int length) +{ + processMQTTMessage(topic, payload, length); +} + +/* + * processMQTTMessage + * processes MQTT messages, parses the topic, extracts radio address out of topic and sends them + * to the respective radio + */ +void processMQTTMessage(char* topic, byte* payload, + unsigned int length) +{ + char *str, *p; + uint8_t i = 0; + buffer[0] = 0; + buffsize = 0; + uint8_t cmd = -1; + + for (str = strtok_r(topic, "/", &p); str && i < 5; + str = strtok_r(NULL, "/", &p)) + { + switch (i) + { + case 0: + { + if (strcmp_P(str, mqtt_prefix) != 0) + { //look for MQTT_PREFIX + return; //Message not for us or malformatted! + } + break; + } + case 1: + { + msg.destination = atoi(str); //NodeID + break; + } + case 2: + { + msg.sensor = atoi(str); //SensorID + break; + } + case 3: + { + char match = 0; //SensorType + //strcpy(str,(char*)&str[2]); //Strip VAR_ + + for (uint8_t j = 0; + strcpy_P(convBuf, (char*) pgm_read_word(&(VAR_Type[j]))); j++) + { + if (strcmp((char*) &str[2], convBuf) == 0) + { //Strip VAR_ and compare + match = j; + break; + } + if (j >= VAR_TOTAL) + { // No match found! + match = VAR_TOTAL; // last item. + break; + } + } + msg.type = match; + break; + } + case 4: + { + // support the command get and set; get will be mapped to a C_REQ and set to C_SET + if (strcmp(str,MQTT_CMD_SET) == 0) + { + cmd = C_SET; + } + else if (strcmp(str,MQTT_CMD_GET) == 0) { + cmd = C_REQ; + } + else { +#ifdef DEBUG + Serial.print("Received unsupported command - ignore: "); + Serial.println(str); +#endif + } + } + } + i++; + } //Check if packge has payload + + if (cmd != -1) { + char* ca; + ca = (char *)payload; + ca += length; + *ca = '\0'; + + msg.set((const char*)payload); //Payload + + txBlink(1); + // inject time + if ((msg.destination == 0) && (msg.sensor == 199)) { + unsigned long epoch = atol((char*)payload); + if (epoch > 10000) { +#ifdef DSRTC + RTC.set(epoch); // this sets the RTC to the time from controller - which we do want periodically +#endif + setTime(epoch); + } +#ifdef DEBUG + Serial.print("Time recieved "); + Serial.println(epoch); +#endif + } + // + if (!gw.sendRoute( + build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type, + 0))) + errBlink(1); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Led handling +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * ledTimersIntterupt + */ +void ledTimersInterrupt() { + if (countRx && countRx != 255) { + // switch led on + digitalWrite(RADIO_RX_LED_PIN, LOW); + } else if (!countRx) { + // switching off + digitalWrite(RADIO_RX_LED_PIN, HIGH); + } + if (countRx != 255) { + countRx--; + } + + if (countTx && countTx != 255) { + // switch led on + digitalWrite(RADIO_TX_LED_PIN, LOW); + } else if (!countTx) { + // switching off + digitalWrite(RADIO_TX_LED_PIN, HIGH); + } + if (countTx != 255) { + countTx--; + } + + if (countErr && countErr != 255) { + // switch led on + digitalWrite(RADIO_ERROR_LED_PIN, LOW); + } else if (!countErr) { + // switching off + digitalWrite(RADIO_ERROR_LED_PIN, HIGH); + } + if (countErr != 255) { + countErr--; + } +} + + +void rxBlink(uint8_t cnt) +{ + if (countRx == 255) + { + countRx = cnt; + } +} + +void txBlink(uint8_t cnt) +{ + if (countTx == 255) + { + countTx = cnt; + } +} + +void errBlink(uint8_t cnt) +{ + if (countErr == 255) + { + countErr = cnt; + } +} + + diff --git a/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h new file mode 100644 index 0000000..cd6e4fe --- /dev/null +++ b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h @@ -0,0 +1,122 @@ +#define MY_HMAC_KEY 0x10,0x23,0x0A,0x78,0x77,0x35,0xB0,0x01,0x70,0x47,0xF1,0xDE,0x21,0x94,0x94,0x67,0xEE,0x36,0x72,0x42,0x97,0xBB,0xA0,0x0A,0x0F,0x09,0x03,0xE2,0x00,0x31,0xE4,0x41/* +The MySensors library adds a new layer on top of the RF24 library. +It handles radio network routing, relaying and ids. +Created by Henrik Ekblad +Modified by Daniel Wiegert +Modified by Norbert Truchsess +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. +*/ + + +#ifndef MyMQTTClient_h +#define MyMQTTClient_h + +////////////////////////////////////////////////////////////////// + +#ifdef DEBUG +#define TCPDUMP // Dump TCP packages. +#endif +#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable +#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved. +#define MQTT_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short! +#define MQTT_TOPIC_MASK "MyMQTT/+/+/+/+" // Topic mask the client will subscribe to. This ensures that it will not receive any sensor data send by sensors + // the following topic structure is assumed: MyMQTT//// +#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request. +#define MQTT_CMD_SET "set" // command (see MQTT_TOPIC_MASK); mapped to C_SET command type of sensor network +#define MQTT_CMD_GET "get" // command (see MQTT_TOPIC_MASK); mapped to C_REQ command type of sensor network + +// NOTE above : Beware to check if there is any length on payload in your incommingMessage code: +// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. + +////////////////////////////////////////////////////////////////// + + +char VAR_0[] PROGMEM = "TEMP"; //V_TEMP +char VAR_1[] PROGMEM = "HUM"; //V_HUM +char VAR_2[] PROGMEM = "LIGHT"; //V_LIGHT +char VAR_3[] PROGMEM = "DIMMER"; //V_DIMMER +char VAR_4[] PROGMEM = "PRESSURE"; //V_PRESSURE +char VAR_5[] PROGMEM = "FORECAST"; //V_FORECAST +char VAR_6[] PROGMEM = "RAIN"; //V_RAIN +char VAR_7[] PROGMEM = "RAINRATE"; //V_RAINRATE +char VAR_8[] PROGMEM = "WIND"; //V_WIND +char VAR_9[] PROGMEM = "GUST"; //V_GUST +char VAR_10[] PROGMEM = "DIRECTON"; //V_DIRECTON +char VAR_11[] PROGMEM = "UV"; //V_UV +char VAR_12[] PROGMEM = "WEIGHT"; //V_WEIGHT +char VAR_13[] PROGMEM = "DISTANCE"; //V_DISTANCE +char VAR_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE +char VAR_15[] PROGMEM = "ARMED"; //V_ARMED +char VAR_16[] PROGMEM = "TRIPPED"; //V_TRIPPED +char VAR_17[] PROGMEM = "WATT"; //V_WATT +char VAR_18[] PROGMEM = "KWH"; //V_KWH +char VAR_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON +char VAR_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF +char VAR_21[] PROGMEM = "HEATER"; //V_HEATER +char VAR_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW +char VAR_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL +char VAR_24[] PROGMEM = "VAR1"; //V_VAR1 +char VAR_25[] PROGMEM = "VAR2"; //V_VAR2 +char VAR_26[] PROGMEM = "VAR3"; //V_VAR3 +char VAR_27[] PROGMEM = "VAR4"; //V_VAR4 +char VAR_28[] PROGMEM = "VAR5"; //V_VAR5 +char VAR_29[] PROGMEM = "UP"; //V_UP +char VAR_30[] PROGMEM = "DOWN"; //V_DOWN +char VAR_31[] PROGMEM = "STOP"; //V_STOP +char VAR_32[] PROGMEM = "IR_SEND"; //V_IR_SEND +char VAR_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE +char VAR_34[] PROGMEM = "FLOW"; //V_FLOW +char VAR_35[] PROGMEM = "VOLUME"; //V_VOLUME +char VAR_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS +char VAR_37[] PROGMEM = "LEVEL"; // S_DUST, S_LIGHT_LEVEL, ... +char VAR_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE +char VAR_39[] PROGMEM = "CURRENT"; //V_CURRENT +char VAR_40[] PROGMEM = "RGB"; //V_RGB +char VAR_41[] PROGMEM = ""; // +char VAR_42[] PROGMEM = ""; // +char VAR_43[] PROGMEM = ""; // +char VAR_44[] PROGMEM = ""; // +char VAR_45[] PROGMEM = ""; // +char VAR_46[] PROGMEM = ""; // +char VAR_47[] PROGMEM = ""; // +char VAR_48[] PROGMEM = ""; // +char VAR_49[] PROGMEM = ""; // +char VAR_50[] PROGMEM = ""; // +char VAR_51[] PROGMEM = ""; // +char VAR_52[] PROGMEM = ""; // +char VAR_53[] PROGMEM = ""; // +char VAR_54[] PROGMEM = ""; // +char VAR_55[] PROGMEM = ""; // +char VAR_56[] PROGMEM = ""; // +char VAR_57[] PROGMEM = ""; // +char VAR_58[] PROGMEM = ""; // +char VAR_59[] PROGMEM = ""; // +char VAR_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway +char VAR_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway +char VAR_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway +char VAR_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway + +////////////////////////////////////////////////////////////////// + +PROGMEM const char *VAR_Type[] = +{ VAR_0, VAR_1, VAR_2, VAR_3, VAR_4, VAR_5, VAR_6, VAR_7, VAR_8, VAR_9, VAR_10, VAR_11, VAR_12, VAR_13, + VAR_14, VAR_15, VAR_16, VAR_17, VAR_18, VAR_19, VAR_20, VAR_21, VAR_22, VAR_23, VAR_24, VAR_25, + VAR_26, VAR_27, VAR_28, VAR_29, VAR_30, VAR_31, VAR_32, VAR_33, VAR_34, VAR_35, VAR_36, VAR_37, + VAR_38, VAR_39, VAR_40, VAR_41, VAR_42, VAR_43, VAR_44, VAR_45, VAR_46, VAR_47, VAR_48, VAR_49, + VAR_50, VAR_51, VAR_52, VAR_53, VAR_54, VAR_55, VAR_56, VAR_57, VAR_58, VAR_59, VAR_60, VAR_61, + VAR_62, VAR_63 +}; + +char mqtt_prefix[] PROGMEM = MQTT_PREFIX; + +#define S_FIRSTCUSTOM 60 +#define TYPEMAXLEN 20 +#define VAR_TOTAL (sizeof(VAR_Type)/sizeof(char *))-1 + + +#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS) + +//#define DSRTC // RTC Dallas support -> disable debug and use isp programmer to free memory +#endif diff --git a/libraries/PubSubClient/CHANGES.txt b/libraries/PubSubClient/CHANGES.txt new file mode 100755 index 0000000..8688011 --- /dev/null +++ b/libraries/PubSubClient/CHANGES.txt @@ -0,0 +1,47 @@ +1.9 + * Do not split MQTT packets over multiple calls to _client->write() + * API change: All constructors now require an instance of Client + to be passed in. + * Fixed example to match 1.8 api changes - dpslwk + * Added username/password support - WilHall + * Added publish_P - publishes messages from PROGMEM - jobytaffey + +1.8 + * KeepAlive interval is configurable in PubSubClient.h + * Maximum packet size is configurable in PubSubClient.h + * API change: Return boolean rather than int from various functions + * API change: Length parameter in message callback changed + from int to unsigned int + * Various internal tidy-ups around types +1.7 + * Improved keepalive handling + * Updated to the Arduino-1.0 API +1.6 + * Added the ability to publish a retained message + +1.5 + * Added default constructor + * Fixed compile error when used with arduino-0021 or later + +1.4 + * Fixed connection lost handling + +1.3 + * Fixed packet reading bug in PubSubClient.readPacket + +1.2 + * Fixed compile error when used with arduino-0016 or later + + +1.1 + * Reduced size of library + * Added support for Will messages + * Clarified licensing - see LICENSE.txt + + +1.0 + * Only Quality of Service (QOS) 0 messaging is supported + * The maximum message size, including header, is 128 bytes + * The keepalive interval is set to 30 seconds + * No support for Will messages + diff --git a/libraries/PubSubClient/LICENSE.txt b/libraries/PubSubClient/LICENSE.txt new file mode 100755 index 0000000..f512cba --- /dev/null +++ b/libraries/PubSubClient/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-2012 Nicholas O'Leary + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/PubSubClient/PubSubClient.cpp b/libraries/PubSubClient/PubSubClient.cpp new file mode 100755 index 0000000..b3f5c0e --- /dev/null +++ b/libraries/PubSubClient/PubSubClient.cpp @@ -0,0 +1,427 @@ +/* + PubSubClient.cpp - A simple client for MQTT. + Nicholas O'Leary + http://knolleary.net +*/ + +#include "PubSubClient.h" +#include + +PubSubClient::PubSubClient() { + this->_client = NULL; + this->stream = NULL; +} + +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client) { + this->_client = &client; + this->callback = callback; + this->ip = ip; + this->port = port; + this->domain = NULL; + this->stream = NULL; +} + +PubSubClient::PubSubClient(char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client) { + this->_client = &client; + this->callback = callback; + this->domain = domain; + this->port = port; + this->stream = NULL; +} + +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client, Stream& stream) { + this->_client = &client; + this->callback = callback; + this->ip = ip; + this->port = port; + this->domain = NULL; + this->stream = &stream; +} + +PubSubClient::PubSubClient(char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client, Stream& stream) { + this->_client = &client; + this->callback = callback; + this->domain = domain; + this->port = port; + this->stream = &stream; +} + +boolean PubSubClient::connect(char *id) { + return connect(id,NULL,NULL,0,0,0,0); +} + +boolean PubSubClient::connect(char *id, char *user, char *pass) { + return connect(id,user,pass,0,0,0,0); +} + +boolean PubSubClient::connect(char *id, char* willTopic, uint8_t willQos, uint8_t willRetain, char* willMessage) +{ + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); +} + +boolean PubSubClient::connect(char *id, char *user, char *pass, char* willTopic, uint8_t willQos, uint8_t willRetain, char* willMessage) { + if (!connected()) { + int result = 0; + + if (domain != NULL) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } + + if (result) { + nextMsgId = 1; + uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p',MQTTPROTOCOLVERSION}; + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + unsigned int j; + for (j = 0;j<9;j++) { + buffer[length++] = d[j]; + } + + uint8_t v; + if (willTopic) { + v = 0x06|(willQos<<3)|(willRetain<<5); + } else { + v = 0x02; + } + + if(user != NULL) { + v = v|0x80; + + if(pass != NULL) { + v = v|(0x80>>1); + } + } + + buffer[length++] = v; + + buffer[length++] = ((MQTT_KEEPALIVE) >> 8); + buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + length = writeString(id,buffer,length); + if (willTopic) { + length = writeString(willTopic,buffer,length); + length = writeString(willMessage,buffer,length); + } + + if(user != NULL) { + length = writeString(user,buffer,length); + if(pass != NULL) { + length = writeString(pass,buffer,length); + } + } + + write(MQTTCONNECT,buffer,length-5); + + lastInActivity = lastOutActivity = millis(); + + while (!_client->available()) { + unsigned long t = millis(); + if (t-lastInActivity > MQTT_KEEPALIVE*1000UL) { + _client->stop(); + return false; + } + } + uint8_t llen; + uint16_t len = readPacket(&llen); + + if (len == 4 && buffer[3] == 0) { + lastInActivity = millis(); + pingOutstanding = false; + return true; + } + } + _client->stop(); + } + return false; +} + +uint8_t PubSubClient::readByte() { + while(!_client->available()) {} + return _client->read(); +} + +uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { + uint16_t len = 0; + buffer[len++] = readByte(); + bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; + uint32_t multiplier = 1; + uint16_t length = 0; + uint8_t digit = 0; + uint16_t skip = 0; + uint8_t start = 0; + + do { + digit = readByte(); + buffer[len++] = digit; + length += (digit & 127) * multiplier; + multiplier *= 128; + } while ((digit & 128) != 0); + *lengthLength = len-1; + + if (isPublish) { + // Read in topic length to calculate bytes to skip over for Stream writing + buffer[len++] = readByte(); + buffer[len++] = readByte(); + skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; + start = 2; + if (buffer[0]&MQTTQOS1) { + // skip message id + skip += 2; + } + } + + for (uint16_t i = start;istream) { + if (isPublish && len-*lengthLength-2>skip) { + this->stream->write(digit); + } + } + if (len < MQTT_MAX_PACKET_SIZE) { + buffer[len] = digit; + } + len++; + } + + if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + len = 0; // This will cause the packet to be ignored. + } + + return len; +} + +boolean PubSubClient::loop() { + if (connected()) { + unsigned long t = millis(); + if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { + if (pingOutstanding) { + _client->stop(); + return false; + } else { + buffer[0] = MQTTPINGREQ; + buffer[1] = 0; + _client->write(buffer,2); + lastOutActivity = t; + lastInActivity = t; + pingOutstanding = true; + } + } + if (_client->available()) { + uint8_t llen; + uint16_t len = readPacket(&llen); + uint16_t msgId = 0; + uint8_t *payload; + if (len > 0) { + lastInActivity = t; + uint8_t type = buffer[0]&0xF0; + if (type == MQTTPUBLISH) { + if (callback) { + uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; + char topic[tl+1]; + for (uint16_t i=0;i0 + if ((buffer[0]&0x06) == MQTTQOS1) { + msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; + payload = buffer+llen+3+tl+2; + callback(topic,payload,len-llen-3-tl-2); + + buffer[0] = MQTTPUBACK; + buffer[1] = 2; + buffer[2] = (msgId >> 8); + buffer[3] = (msgId & 0xFF); + _client->write(buffer,4); + lastOutActivity = t; + + } else { + payload = buffer+llen+3+tl; + callback(topic,payload,len-llen-3-tl); + } + } + } else if (type == MQTTPINGREQ) { + buffer[0] = MQTTPINGRESP; + buffer[1] = 0; + _client->write(buffer,2); + } else if (type == MQTTPINGRESP) { + pingOutstanding = false; + } + } + } + return true; + } + return false; +} + +boolean PubSubClient::publish(char* topic, char* payload) { + return publish(topic,(uint8_t*)payload,strlen(payload),false); +} + +boolean PubSubClient::publish(char* topic, uint8_t* payload, unsigned int plength) { + return publish(topic, payload, plength, false); +} + +boolean PubSubClient::publish(char* topic, uint8_t* payload, unsigned int plength, boolean retained) { + if (connected()) { + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + length = writeString(topic,buffer,length); + uint16_t i; + for (i=0;i 0) { + digit |= 0x80; + } + buffer[pos++] = digit; + llen++; + } while(len>0); + + pos = writeString(topic,buffer,pos); + + rc += _client->write(buffer,pos); + + for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); + } + + lastOutActivity = millis(); + + return rc == tlen + 4 + plength; +} + +boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { + uint8_t lenBuf[4]; + uint8_t llen = 0; + uint8_t digit; + uint8_t pos = 0; + uint8_t rc; + uint8_t len = length; + do { + digit = len % 128; + len = len / 128; + if (len > 0) { + digit |= 0x80; + } + lenBuf[pos++] = digit; + llen++; + } while(len>0); + + buf[4-llen] = header; + for (int i=0;iwrite(buf+(4-llen),length+1+llen); + + lastOutActivity = millis(); + return (rc == 1+llen+length); +} + +boolean PubSubClient::subscribe(char* topic) { + return subscribe(topic, 0); +} + +boolean PubSubClient::subscribe(char* topic, uint8_t qos) { + if (qos < 0 || qos > 1) + return false; + + if (connected()) { + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, buffer,length); + buffer[length++] = qos; + return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +boolean PubSubClient::unsubscribe(char* topic) { + if (connected()) { + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, buffer,length); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +void PubSubClient::disconnect() { + buffer[0] = MQTTDISCONNECT; + buffer[1] = 0; + _client->write(buffer,2); + _client->stop(); + lastInActivity = lastOutActivity = millis(); +} + +uint16_t PubSubClient::writeString(char* string, uint8_t* buf, uint16_t pos) { + char* idp = string; + uint16_t i = 0; + pos += 2; + while (*idp) { + buf[pos++] = *idp++; + i++; + } + buf[pos-i-2] = (i >> 8); + buf[pos-i-1] = (i & 0xFF); + return pos; +} + + +boolean PubSubClient::connected() { + boolean rc; + if (_client == NULL ) { + rc = false; + } else { + rc = (int)_client->connected(); + if (!rc) _client->stop(); + } + return rc; +} + diff --git a/libraries/PubSubClient/PubSubClient.h b/libraries/PubSubClient/PubSubClient.h new file mode 100755 index 0000000..f2faff8 --- /dev/null +++ b/libraries/PubSubClient/PubSubClient.h @@ -0,0 +1,81 @@ +/* + PubSubClient.h - A simple client for MQTT. + Nicholas O'Leary + http://knolleary.net +*/ + +#ifndef PubSubClient_h +#define PubSubClient_h + +#include +#include "Client.h" +#include "Stream.h" + +// MQTT_MAX_PACKET_SIZE : Maximum packet size +#define MQTT_MAX_PACKET_SIZE 128 + +// MQTT_KEEPALIVE : keepAlive interval in Seconds +#define MQTT_KEEPALIVE 15 + +#define MQTTPROTOCOLVERSION 3 +#define MQTTCONNECT 1 << 4 // Client request to connect to Server +#define MQTTCONNACK 2 << 4 // Connect Acknowledgment +#define MQTTPUBLISH 3 << 4 // Publish message +#define MQTTPUBACK 4 << 4 // Publish Acknowledgment +#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) +#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) +#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) +#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request +#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment +#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request +#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment +#define MQTTPINGREQ 12 << 4 // PING Request +#define MQTTPINGRESP 13 << 4 // PING Response +#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting +#define MQTTReserved 15 << 4 // Reserved + +#define MQTTQOS0 (0 << 1) +#define MQTTQOS1 (1 << 1) +#define MQTTQOS2 (2 << 1) + +class PubSubClient { +private: + Client* _client; + uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint16_t nextMsgId; + unsigned long lastOutActivity; + unsigned long lastInActivity; + bool pingOutstanding; + void (*callback)(char*,uint8_t*,unsigned int); + uint16_t readPacket(uint8_t*); + uint8_t readByte(); + boolean write(uint8_t header, uint8_t* buf, uint16_t length); + uint16_t writeString(char* string, uint8_t* buf, uint16_t pos); + uint8_t *ip; + char* domain; + uint16_t port; + Stream* stream; +public: + PubSubClient(); + PubSubClient(uint8_t *, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client); + PubSubClient(uint8_t *, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client, Stream&); + PubSubClient(char*, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client); + PubSubClient(char*, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client, Stream&); + boolean connect(char *); + boolean connect(char *, char *, char *); + boolean connect(char *, char *, uint8_t, uint8_t, char *); + boolean connect(char *, char *, char *, char *, uint8_t, uint8_t, char*); + void disconnect(); + boolean publish(char *, char *); + boolean publish(char *, uint8_t *, unsigned int); + boolean publish(char *, uint8_t *, unsigned int, boolean); + boolean publish_P(char *, uint8_t *, unsigned int, boolean); + boolean subscribe(char *); + boolean subscribe(char *, uint8_t qos); + boolean unsubscribe(char *); + boolean loop(); + boolean connected(); +}; + + +#endif diff --git a/libraries/PubSubClient/examples/mqtt_auth/mqtt_auth.ino b/libraries/PubSubClient/examples/mqtt_auth/mqtt_auth.ino new file mode 100755 index 0000000..c8a519a --- /dev/null +++ b/libraries/PubSubClient/examples/mqtt_auth/mqtt_auth.ino @@ -0,0 +1,39 @@ +/* + Basic MQTT example with Authentication + + - connects to an MQTT server, providing username + and password + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic" +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +byte server[] = { 172, 16, 0, 2 }; +byte ip[] = { 172, 16, 0, 100 }; + +void callback(char* topic, byte* payload, unsigned int length) { + // handle message arrived +} + +EthernetClient ethClient; +PubSubClient client(server, 1883, callback, ethClient); + +void setup() +{ + Ethernet.begin(mac, ip); + if (client.connect("arduinoClient", "testuser", "testpass")) { + client.publish("outTopic","hello world"); + client.subscribe("inTopic"); + } +} + +void loop() +{ + client.loop(); +} + diff --git a/libraries/PubSubClient/examples/mqtt_basic/mqtt_basic.ino b/libraries/PubSubClient/examples/mqtt_basic/mqtt_basic.ino new file mode 100755 index 0000000..72276cd --- /dev/null +++ b/libraries/PubSubClient/examples/mqtt_basic/mqtt_basic.ino @@ -0,0 +1,38 @@ +/* + Basic MQTT example + + - connects to an MQTT server + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic" +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +byte server[] = { 172, 16, 0, 2 }; +byte ip[] = { 172, 16, 0, 100 }; + +void callback(char* topic, byte* payload, unsigned int length) { + // handle message arrived +} + +EthernetClient ethClient; +PubSubClient client(server, 1883, callback, ethClient); + +void setup() +{ + Ethernet.begin(mac, ip); + if (client.connect("arduinoClient")) { + client.publish("outTopic","hello world"); + client.subscribe("inTopic"); + } +} + +void loop() +{ + client.loop(); +} + diff --git a/libraries/PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/libraries/PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino new file mode 100755 index 0000000..ece5c2e --- /dev/null +++ b/libraries/PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino @@ -0,0 +1,61 @@ +/* + Publishing in the callback + + - connects to an MQTT server + - subscribes to the topic "inTopic" + - when a message is received, republishes it to "outTopic" + + This example shows how to publish messages within the + callback function. The callback function header needs to + be declared before the PubSubClient constructor and the + actual callback defined afterwards. + This ensures the client reference in the callback function + is valid. + +*/ + +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +byte server[] = { 172, 16, 0, 2 }; +byte ip[] = { 172, 16, 0, 100 }; + +// Callback function header +void callback(char* topic, byte* payload, unsigned int length); + +EthernetClient ethClient; +PubSubClient client(server, 1883, callback, ethClient); + +// Callback function +void callback(char* topic, byte* payload, unsigned int length) { + // In order to republish this payload, a copy must be made + // as the orignal payload buffer will be overwritten whilst + // constructing the PUBLISH packet. + + // Allocate the correct amount of memory for the payload copy + byte* p = (byte*)malloc(length); + // Copy the payload to the new buffer + memcpy(p,payload,length); + client.publish("outTopic", p, length); + // Free the memory + free(p); +} + +void setup() +{ + + Ethernet.begin(mac, ip); + if (client.connect("arduinoClient")) { + client.publish("outTopic","hello world"); + client.subscribe("inTopic"); + } +} + +void loop() +{ + client.loop(); +} + diff --git a/libraries/PubSubClient/examples/mqtt_stream/mqtt_stream.ino b/libraries/PubSubClient/examples/mqtt_stream/mqtt_stream.ino new file mode 100755 index 0000000..a416ee2 --- /dev/null +++ b/libraries/PubSubClient/examples/mqtt_stream/mqtt_stream.ino @@ -0,0 +1,58 @@ +/* + Example of using a Stream object to store the message payload + + Uses SRAM library: https://github.com/ennui2342/arduino-sram + but could use any Stream based class such as SD + + - connects to an MQTT server + - publishes "hello world" to the topic "outTopic" + - subscribes to the topic "inTopic" +*/ + +#include +#include +#include +#include + +// Update these with values suitable for your network. +byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; +byte server[] = { 172, 16, 0, 2 }; +byte ip[] = { 172, 16, 0, 100 }; + +SRAM sram(4, SRAM_1024); + +void callback(char* topic, byte* payload, unsigned int length) { + sram.seek(1); + + // do something with the message + for(uint8_t i=0; i Date: Mon, 31 Aug 2015 08:41:30 +0200 Subject: [PATCH 225/660] fix warnings from compiler and move defines to header files --- .../MQTTClientGateway/MQTTClientGateway.ino | 37 ++++++++++--------- .../examples/MQTTClientGateway/MyMQTTClient.h | 9 ++++- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino index ece4e0c..a436889 100644 --- a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino +++ b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino @@ -119,12 +119,6 @@ uint8_t local_ip[] = {192, 168, 178, 11}; //replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun uint8_t mac[] = { 0xA2, 0xAE, 0xAD, 0xA0, 0xA0, 0xA2 }; -/////////////////////////////////////////////////////////////////// -#define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment -#define MQTT_USER "username" // username on MQTT broker -#define MQTT_PWD "pwd" // password for MQTT username above -////////////////////////////////////////////////////////////////// - #if defined remote_ip && defined remote_host #error "cannot define both remote_ip and remote_host at the same time!" #endif @@ -152,6 +146,10 @@ MyMessage msg; char convBuf[MAX_PAYLOAD * 2 + 1]; uint8_t buffsize; char buffer[MQTT_MAX_PACKET_SIZE]; +char user[sizeof(MQTT_USER)]; // introduced the bufs to get rid of compiler warnings +char pwd[sizeof(MQTT_PWD)]; // see above +char connID[sizeof(MQTT_CONN_ID)]; // see above +char mqttTopicMask[sizeof(MQTT_TOPIC_MASK)]; // see above //////////////////////////////////////////////////////////////// @@ -186,6 +184,9 @@ MySensor gw(transport, hw */ void setup() { + strcpy(connID,MQTT_CONN_ID); + strcpy(mqttTopicMask,MQTT_TOPIC_MASK); + countRx = 0; countTx = 0; countErr = 0; @@ -204,12 +205,14 @@ void loop() { if (!client.connected()) { - client.connect("MySensor" -#ifdef MQTT_AUTH_REQUIRED - ,MQTT_USER,MQTT_PWD -#endif - ); - client.subscribe(MQTT_TOPIC_MASK); +#ifdef MQTT_AUTH_REQUIRED + strcpy(user, MQTT_USER); + strcpy(pwd, MQTT_PWD); + client.connect(connID, user,pwd); +#else + client.connect(connID); +#endif + client.subscribe(mqttTopicMask); } client.loop(); gw.process(); @@ -297,7 +300,7 @@ void sendMQTT(const MyMessage &inMsg) { strcpy_P(buffer, mqtt_prefix); buffsize += strlen_P(mqtt_prefix); - buffsize += sprintf(&buffer[buffsize], "/%i/255/BATTERY_LEVEL\0", msg.sender ); + buffsize += sprintf(&buffer[buffsize], "/%i/255/BATTERY_LEVEL", msg.sender ); msg.getString(convBuf); #ifdef DEBUG Serial.print("publish: "); @@ -311,7 +314,7 @@ void sendMQTT(const MyMessage &inMsg) { strcpy_P(buffer, mqtt_prefix); buffsize += strlen_P(mqtt_prefix); - buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_NAME\0", msg.sender ); + buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_NAME", msg.sender ); msg.getString(convBuf); #ifdef DEBUG Serial.print("publish: "); @@ -325,7 +328,7 @@ void sendMQTT(const MyMessage &inMsg) { strcpy_P(buffer, mqtt_prefix); buffsize += strlen_P(mqtt_prefix); - buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_VERSION\0", msg.sender ); + buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_VERSION", msg.sender ); msg.getString(convBuf); #ifdef DEBUG Serial.print("publish: "); @@ -346,7 +349,7 @@ void sendMQTT(const MyMessage &inMsg) msg.type = VAR_TOTAL; // If type > defined types set to unknown. strcpy_P(buffer, mqtt_prefix); buffsize += strlen_P(mqtt_prefix); - buffsize += sprintf(&buffer[buffsize], "/%i/%i/V_%s\0", msg.sender, + buffsize += sprintf(&buffer[buffsize], "/%i/%i/V_%s", msg.sender, msg.sensor, getType(convBuf, &VAR_Type[msg.type])); msg.getString(convBuf); #ifdef DEBUG @@ -523,7 +526,7 @@ void processMQTTMessage(char* topic, byte* payload, setTime(epoch); } #ifdef DEBUG - Serial.print("Time recieved "); + Serial.print("Time received "); Serial.println(epoch); #endif } diff --git a/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h index cd6e4fe..87610f0 100644 --- a/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h +++ b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h @@ -1,4 +1,4 @@ -#define MY_HMAC_KEY 0x10,0x23,0x0A,0x78,0x77,0x35,0xB0,0x01,0x70,0x47,0xF1,0xDE,0x21,0x94,0x94,0x67,0xEE,0x36,0x72,0x42,0x97,0xBB,0xA0,0x0A,0x0F,0x09,0x03,0xE2,0x00,0x31,0xE4,0x41/* +/* The MySensors library adds a new layer on top of the RF24 library. It handles radio network routing, relaying and ids. Created by Henrik Ekblad @@ -27,6 +27,13 @@ version 2 as published by the Free Software Foundation. #define MQTT_CMD_SET "set" // command (see MQTT_TOPIC_MASK); mapped to C_SET command type of sensor network #define MQTT_CMD_GET "get" // command (see MQTT_TOPIC_MASK); mapped to C_REQ command type of sensor network + +#define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment +#define MQTT_USER "username" // username on MQTT broker +#define MQTT_PWD "pwd" // password for MQTT username above +#define MQTT_CONN_ID "MySensors" // passed as id to the MQTT broker + + // NOTE above : Beware to check if there is any length on payload in your incommingMessage code: // Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things. From 2491d8a2197f6a156b1b931bb34d0c9182023773 Mon Sep 17 00:00:00 2001 From: Thomas Krebs Date: Mon, 31 Aug 2015 09:46:13 +0200 Subject: [PATCH 226/660] fixed issue when signing was enabled Please enter the commit message for your changes. Lines starting --- .../examples/MQTTClientGateway/MQTTClientGateway.ino | 10 ++++++++-- .../examples/MQTTClientGateway/MyMQTTClient.h | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino index a436889..a1c07c9 100644 --- a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino +++ b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino @@ -205,13 +205,19 @@ void loop() { if (!client.connected()) { + boolean ret; #ifdef MQTT_AUTH_REQUIRED strcpy(user, MQTT_USER); strcpy(pwd, MQTT_PWD); - client.connect(connID, user,pwd); + ret = client.connect(connID, user,pwd); #else - client.connect(connID); + ret = client.connect(connID); #endif + if (ret) { + Serial.println("Connected to MQTT broker"); + } else { + Serial.println("Connection to MQTT broker failed"); + } client.subscribe(mqttTopicMask); } client.loop(); diff --git a/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h index 87610f0..d347825 100644 --- a/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h +++ b/libraries/MySensors/examples/MQTTClientGateway/MyMQTTClient.h @@ -29,8 +29,8 @@ version 2 as published by the Free Software Foundation. #define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment -#define MQTT_USER "username" // username on MQTT broker -#define MQTT_PWD "pwd" // password for MQTT username above +#define MQTT_USER "user" // username on MQTT broker +#define MQTT_PWD "pwd" // password for MQTT username above #define MQTT_CONN_ID "MySensors" // passed as id to the MQTT broker From 194b1be516e2dd47199ea35b3f3b30b1b791c5a4 Mon Sep 17 00:00:00 2001 From: Thomas Krebs Date: Mon, 31 Aug 2015 11:08:39 +0200 Subject: [PATCH 227/660] removed compiler warning by changing type for cmd in processMQTTMessage --- .../MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino index a1c07c9..9c5b60b 100644 --- a/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino +++ b/libraries/MySensors/examples/MQTTClientGateway/MQTTClientGateway.ino @@ -445,7 +445,7 @@ void processMQTTMessage(char* topic, byte* payload, uint8_t i = 0; buffer[0] = 0; buffsize = 0; - uint8_t cmd = -1; + int8_t cmd = -1; for (str = strtok_r(topic, "/", &p); str && i < 5; str = strtok_r(NULL, "/", &p)) From be427a2d380726eb88c8904e7c70db7505f2e1a5 Mon Sep 17 00:00:00 2001 From: Thomas Krebs Date: Mon, 31 Aug 2015 15:59:05 +0200 Subject: [PATCH 228/660] fixed compiler warning --- libraries/PubSubClient/PubSubClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/PubSubClient/PubSubClient.cpp b/libraries/PubSubClient/PubSubClient.cpp index b3f5c0e..dbb538a 100755 --- a/libraries/PubSubClient/PubSubClient.cpp +++ b/libraries/PubSubClient/PubSubClient.cpp @@ -358,7 +358,7 @@ boolean PubSubClient::subscribe(char* topic) { } boolean PubSubClient::subscribe(char* topic, uint8_t qos) { - if (qos < 0 || qos > 1) + if (qos > 1) return false; if (connected()) { From cb771ab680b2d9714173c7fa524354f1042141d3 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Mon, 31 Aug 2015 19:36:43 +0200 Subject: [PATCH 229/660] Fixes for compiling for Mega Make more consistent use of architecture #defines. --- libraries/MySensors/MyHwATMega328.cpp | 4 ++-- libraries/MySensors/MyHwATMega328.h | 4 ++-- libraries/MySensors/MyHwESP8266.cpp | 4 ++-- libraries/MySensors/MyHwESP8266.h | 4 ++-- libraries/MySensors/MySensor.h | 4 ++-- libraries/MySensors/MySigningAtsha204.cpp | 4 ++-- libraries/MySensors/utility/ATSHA204.cpp | 4 ++-- libraries/MySensors/utility/RFM69.h | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/MyHwATMega328.cpp index dfe4b5c..7d67563 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/MyHwATMega328.cpp @@ -17,7 +17,7 @@ * version 2 as published by the Free Software Foundation. */ -#ifdef __AVR_ATmega328P__ +#ifdef ARDUINO_ARCH_AVR #include "MyHw.h" #include "MyHwATMega328.h" @@ -217,4 +217,4 @@ void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) { } #endif -#endif // #ifdef __AVR_ATmega328P__ +#endif // #ifdef ARDUINO_ARCH_AVR diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/MyHwATMega328.h index a873ba9..e18b72e 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/MyHwATMega328.h @@ -20,7 +20,7 @@ #ifndef MyHwATMega328_h #define MyHwATMega328_h -#ifdef __AVR_ATmega328P__ +#ifdef ARDUINO_ARCH_AVR #include "MyHw.h" #include "MyConfig.h" @@ -118,4 +118,4 @@ private: void internalSleep(unsigned long ms); }; #endif -#endif // #ifdef __AVR_ATmega328P__ +#endif // #ifdef ARDUINO_ARCH_AVR diff --git a/libraries/MySensors/MyHwESP8266.cpp b/libraries/MySensors/MyHwESP8266.cpp index 7d83215..9c85f62 100644 --- a/libraries/MySensors/MyHwESP8266.cpp +++ b/libraries/MySensors/MyHwESP8266.cpp @@ -17,7 +17,7 @@ * version 2 as published by the Free Software Foundation. */ -#ifdef ESP8266 +#ifdef ARDUINO_ARCH_ESP8266 #include "MyHw.h" #include "MyHwESP8266.h" @@ -181,4 +181,4 @@ void MyHwESP8266::debugPrint(bool isGW, const char *fmt, ... ) { } #endif -#endif // #ifdef ESP8266 +#endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/MyHwESP8266.h b/libraries/MySensors/MyHwESP8266.h index 87ea8e8..e281421 100644 --- a/libraries/MySensors/MyHwESP8266.h +++ b/libraries/MySensors/MyHwESP8266.h @@ -17,7 +17,7 @@ * version 2 as published by the Free Software Foundation. */ -#ifdef ESP8266 +#ifdef ARDUINO_ARCH_ESP8266 #ifndef MyHwESP8266_h #define MyHwESP8266_h @@ -83,4 +83,4 @@ public: }; #endif -#endif // #ifdef ESP8266 +#endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 7190d7f..18f4cb7 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -41,10 +41,10 @@ // Set the hardware driver to use (initialized by MySensor-class) //#if defined __AVR_ATmega328P__ -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include "MyHwESP8266.h" typedef MyHwESP8266 MyHwDriver; -#else +#elif defined(ARDUINO_ARCH_AVR) #include "MyHwATMega328.h" typedef MyHwATMega328 MyHwDriver; #endif diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/MySigningAtsha204.cpp index 6444dd3..06d1b45 100644 --- a/libraries/MySensors/MySigningAtsha204.cpp +++ b/libraries/MySensors/MySigningAtsha204.cpp @@ -24,7 +24,7 @@ * HMAC-SHA256 authentication with a readout-protected key. * */ -#if defined(__AVR__) +#if defined(ARDUINO_ARCH_AVR) #include "MySigning.h" #include "MySigningAtsha204.h" @@ -267,4 +267,4 @@ uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { DEBUG_SIGNING_PRINTBUF(F("SHA:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); return &rx_buffer[SHA204_BUFFER_POS_DATA]; } -#endif // #if defined(__AVR__) +#endif // #if defined(ARDUINO_ARCH_AVR) diff --git a/libraries/MySensors/utility/ATSHA204.cpp b/libraries/MySensors/utility/ATSHA204.cpp index 5fb8288..113038f 100644 --- a/libraries/MySensors/utility/ATSHA204.cpp +++ b/libraries/MySensors/utility/ATSHA204.cpp @@ -1,4 +1,4 @@ -#if defined(__AVR__) +#if defined(ARDUINO_ARCH_AVR) #include "Arduino.h" #include "ATSHA204.h" @@ -575,4 +575,4 @@ uint8_t ATSHA204Class::sha204c_check_crc(uint8_t *response) ? SHA204_SUCCESS : SHA204_BAD_CRC; } -#endif // defined(__AVR__) \ No newline at end of file +#endif // defined(ARDUINO_ARCH_AVR) \ No newline at end of file diff --git a/libraries/MySensors/utility/RFM69.h b/libraries/MySensors/utility/RFM69.h index bcc3201..fe7abd1 100644 --- a/libraries/MySensors/utility/RFM69.h +++ b/libraries/MySensors/utility/RFM69.h @@ -43,8 +43,8 @@ #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2560__) #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 2 -#elif defined(ESP8266) - // TODO !! +#elif defined(ARDUINO_ARCH_ESP8266) + // TODO !! Untested code! Entering unknown territory... #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 0 #endif From 688261f069de908b26781cc72d2a293ec1bb598e Mon Sep 17 00:00:00 2001 From: Yveaux Date: Mon, 31 Aug 2015 20:13:03 +0200 Subject: [PATCH 230/660] Reverted default analog input for random seed generator --- libraries/MySensors/MyConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 6766b2b..13978d5 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -101,7 +101,7 @@ #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached // MySigningAtsha204Soft default settings -#define MY_RANDOMSEED_PIN A0 // A0 - Pin used for random generation (do not connect anything to this) +#define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 From c430672c3253241aa14fd1c011467bd70fa556a1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 1 Sep 2015 07:18:02 +0200 Subject: [PATCH 231/660] Fix timeout in parking sensor that turns light off when parked --- .../examples/ParkingSensor/ParkingSensor.ino | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino index f8ad6de..50e3e6c 100644 --- a/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino +++ b/libraries/MySensors/examples/ParkingSensor/ParkingSensor.ino @@ -56,6 +56,8 @@ #define PANIC_DISTANCE 5 // Mix distance we red warning indication should be active (in cm) #define PARKED_DISTANCE 20 // Distance when "parked signal" should be sent to controller (in cm) +#define PARK_OFF_TIMEOUT 20000 // Number of milliseconds until turning off light when parked. + // Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest // example for more information on possible values. @@ -67,10 +69,11 @@ NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and #define CHILD_ID 1 MySensor gw; MyMessage msg(CHILD_ID,V_TRIPPED); -int oldParkedStatus=-1; +#endif unsigned long sendInterval = 5000; // Send park status at maximum every 5 second. unsigned long lastSend; -#endif + +int oldParkedStatus=-1; unsigned long blinkInterval = 100; // blink interval (milliseconds) unsigned long lastBlinkPeriod; @@ -109,7 +112,6 @@ void loop() { if (now-lastDebouncePeriod > distDebounce) { lastDebouncePeriod = now; -#ifdef SEND_STATUS_TO_CONTROLLER // Update parked status int parked = displayDist != 0 && displayDist sendInterval) { @@ -117,48 +119,56 @@ void loop() { Serial.println("Car Parked"); else Serial.println("Car Gone"); +#ifdef SEND_STATUS_TO_CONTROLLER gw.send(msg.set(parked)); +#endif oldParkedStatus = parked; lastSend = now; } -#endif - - if (displayDist == 0) { - // No reading from sensor, assume no object found - numLightPixels--; - } else { - skipZero = 0; - int newLightPixels = NUMPIXELS - (NUMPIXELS*(displayDist-PANIC_DISTANCE)/MAX_DISTANCE); - if (newLightPixels>numLightPixels) { - // Fast raise - numLightPixels += max((newLightPixels - numLightPixels) / 2, 1); - } else if (newLightPixels=NUMPIXELS) { - // Do some intense red blinking - if (now-lastBlinkPeriod > blinkInterval) { - blinkColor = !blinkColor; - lastBlinkPeriod = now; - } - for(int i=0;i PARK_OFF_TIMEOUT) { + // We've been parked for a while now. Turn off all pixels + for(int i=0;inumLightPixels) { + // Fast raise + numLightPixels += max((newLightPixels - numLightPixels) / 2, 1); + } else if (newLightPixels=NUMPIXELS) { + // Do some intense red blinking + if (now-lastBlinkPeriod > blinkInterval) { + blinkColor = !blinkColor; + lastBlinkPeriod = now; + } + for(int i=0;i Date: Wed, 2 Sep 2015 17:46:37 +0200 Subject: [PATCH 232/660] Bugfix --- libraries/MySensors/utility/RF24.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp index c117f4b..7be6b98 100644 --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -553,9 +553,9 @@ static uint8_t get_child_pipe_mask(const uint8_t idx) _BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5) }; #ifdef ESP8266 - return child_pipe_enable[0]; + return child_pipe_enable[idx]; #else - return pgm_read_byte(&child_pipe_enable[0]); + return pgm_read_byte(&child_pipe_enable[idx]); #endif } From f4ef926f025dae0466c68d7a3942ab0de4a4ff6c Mon Sep 17 00:00:00 2001 From: nicbrink Date: Wed, 2 Sep 2015 21:33:53 -0400 Subject: [PATCH 233/660] Update MyTransportRFM69.cpp defined in myconfig.h as RFM69_ENCRYPTKEY --- libraries/MySensors/MyTransportRFM69.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/MyTransportRFM69.cpp b/libraries/MySensors/MyTransportRFM69.cpp index 4ad8fb4..757c9a5 100644 --- a/libraries/MySensors/MyTransportRFM69.cpp +++ b/libraries/MySensors/MyTransportRFM69.cpp @@ -33,7 +33,7 @@ bool MyTransportRFM69::init() { // Start up the radio library (_address will be set later by the MySensors library) radio.initialize(_freqBand, _address, _networkId); #ifdef RFM69_ENABLE_ENCRYPTION - radio.encrypt(ENCRYPTKEY); + radio.encrypt(RFM69_ENCRYPTKEY); #endif return true; } From b997861f5965344d95f7f59b469d4d99a7cae9a4 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Thu, 3 Sep 2015 20:33:34 +0200 Subject: [PATCH 234/660] Fix crash at startup --- libraries/MySensors/utility/RF24.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp index 7be6b98..16e7857 100644 --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -548,13 +548,17 @@ void RF24::startListening(void) /****************************************************************************/ static uint8_t get_child_pipe_mask(const uint8_t idx) { +#ifdef ESP8266 + static const uint8_t child_pipe_enable[] = + { + _BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5) + }; + return child_pipe_enable[idx]; +#else static const uint8_t child_pipe_enable[] PROGMEM = { _BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5) }; -#ifdef ESP8266 - return child_pipe_enable[idx]; -#else return pgm_read_byte(&child_pipe_enable[idx]); #endif } From f03f4f9412e465006ac7e52944691f3406a880a7 Mon Sep 17 00:00:00 2001 From: Yveaux Date: Fri, 4 Sep 2015 19:54:45 +0200 Subject: [PATCH 235/660] Hardened (dis)connections Added support fot multiple sessions (Currently 5 max. Each connection costs RAM!) Each session can send data to the gateway. Data from the gateway will be broadcasted to all connected clients. Added serial logging of client (dis)connections. Inspect serial terminal in case of problems. --- .../Esp8266Gateway/Esp8266Gateway.ino | 147 +++++++++++------- .../examples/Esp8266Gateway/GatewayUtil.h | 9 +- 2 files changed, 100 insertions(+), 56 deletions(-) diff --git a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino index c5be624..ee828b5 100644 --- a/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino +++ b/libraries/MySensors/examples/Esp8266Gateway/Esp8266Gateway.ino @@ -123,24 +123,34 @@ MySensor gw(transport, hw ); -#define IP_PORT 5003 // The port you want to open +#define IP_PORT 5003 // The port you want to open +#define MAX_SRV_CLIENTS 5 // how many clients should be able to telnet to this ESP8266 // a R/W server on the port -WiFiServer server(IP_PORT); -// handle to open connection -WiFiClient client; +static WiFiServer server(IP_PORT); +static WiFiClient clients[MAX_SRV_CLIENTS]; +static bool clientsConnected[MAX_SRV_CLIENTS]; +static inputBuffer inputString[MAX_SRV_CLIENTS]; -char inputString[MAX_RECEIVE_LENGTH] = ""; // A string to hold incoming commands from serial/ethernet interface -int inputPos = 0; -bool sentReady = false; +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -void output(const char *fmt, ... ) { - va_list args; - va_start (args, fmt ); - vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); - va_end (args); - Serial.print(serialBuffer); - server.write(serialBuffer); + +void output(const char *fmt, ... ) +{ + char serialBuffer[MAX_SEND_LENGTH]; + va_list args; + va_start (args, fmt ); + vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args); + va_end (args); + Serial.print(serialBuffer); + for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) + { + if (clients[i] && clients[i].connected()) + { +// Serial.print("Client "); Serial.print(i); Serial.println(" write"); + clients[i].write((uint8_t*)serialBuffer, strlen(serialBuffer)); + } + } } void setup() @@ -153,7 +163,8 @@ void setup() Serial.print("Connecting to "); Serial.println(ssid); (void)WiFi.begin(ssid, pass); - while (WiFi.status() != WL_CONNECTED) { + while (WiFi.status() != WL_CONNECTED) + { delay(500); Serial.print("."); } @@ -168,6 +179,7 @@ void setup() // start listening for clients server.begin(); + server.setNoDelay(true); } @@ -176,47 +188,74 @@ void loop() { checkButtonTriggeredInclusion(); checkInclusionFinished(); - - //check if there are any new clients - if (server.hasClient()) - { - if (client) - { - client.stop(); - } - client = server.available(); - output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY); - } - if (client) { - if (!client.connected()) { - client.stop(); - } else if (client.available()) { - // read the bytes incoming from the client - char inChar = client.read(); - if (inputPos Date: Fri, 4 Sep 2015 21:56:02 +0200 Subject: [PATCH 236/660] Add S_GAS, S_INFO and V_TEXT --- libraries/MySensors/MyMessage.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/MyMessage.h index 1fc7a40..fbf9295 100644 --- a/libraries/MySensors/MyMessage.h +++ b/libraries/MySensors/MyMessage.h @@ -80,6 +80,9 @@ typedef enum { S_SOUND, // Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB) S_VIBRATION, // Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz) S_MOISTURE, // Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?) + S_INFO, // LCD text device / Simple information device on controller, V_TEXT + S_GAS, // Gas meter, V_FLOW, V_VOLUME + } mysensor_sensor; // Type of sensor data (for set/req/ack messages) @@ -138,7 +141,7 @@ typedef enum { V_HVAC_SETPOINT_COOL, // S_HVAC. HVAC cool setpoint (Integer between 0-100) V_HVAC_SETPOINT_HEAT, // S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100) V_HVAC_FLOW_MODE, // S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") - + V_TEXT, // S_INFO. Text message to display on LCD or controller device } mysensor_data; From 104ad28c90be4aed2ad5e5a38bf64c5cdeea2533 Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Sat, 5 Sep 2015 11:46:37 +0200 Subject: [PATCH 237/660] Added V_STATUS to S_HEATER (as it is supported also) Added S_MOISTURE (a moisture sensor) --- .../examples/MockMySensors/MockMySensors.ino | 93 +++++++++++++------ 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 9510270..db15a6b 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -26,7 +26,7 @@ #define SHORT_WAIT 50 #define SKETCH_NAME "MockMySensors " -#define SKETCH_VERSION "v0.4" +#define SKETCH_VERSION "v0.5" // Define Sensors ids /* S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND, @@ -42,8 +42,8 @@ // Some of these ID's have not been updated for v1.5. Uncommenting too many of them // will make the sketch too large for a pro mini's memory so it's probably best to try // one at a time. -#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors -#define ID_S_DOOR 1 +//#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors +//#define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 @@ -66,6 +66,8 @@ //#define ID_S_AIR_QUALITY 21 //#define ID_S_DUST 22 //#define ID_S_SCENE_CONTROLLER 23 +#define ID_S_MOISTURE 24 + //#define ID_S_CUSTOM 99 // Global Vars @@ -173,11 +175,15 @@ MyHwATMega328 hw; // MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); #endif -#ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP - MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC - MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_FLOW_STATE); // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC - int heatTemp=18; - const char* heatState="Off"; +#ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP, V_STATUS + float heater_setpoint=21.5; + float heater_temp=23.5; + bool heater_status=false; + String heater_flow_state = "Off"; + MyMessage msg_S_HEATER_SETPOINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); + MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); + MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); + MyMessage msg_S_HEATER_FLOWSTATE(ID_S_HEATER,V_HVAC_FLOW_STATE); #endif #ifdef ID_S_DISTANCE @@ -229,6 +235,10 @@ MyHwATMega328 hw; #endif +#ifdef ID_S_MOISTURE + MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL); +#endif + #ifdef ID_S_CUSTOM MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1); MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); @@ -409,6 +419,12 @@ void setup() gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); gw.wait(SHORT_WAIT); #endif + + #ifdef ID_S_MOISTURE + Serial.println(" S_MOISTURE"); + gw.present(ID_S_MOISTURE,S_MOISTURE); + gw.wait(SHORT_WAIT); + #endif #ifdef ID_S_CUSTOM Serial.println(" S_CUSTOM"); @@ -535,6 +551,10 @@ void loop() scene(); #endif + #ifdef ID_S_MOISTURE + moisture(); + #endif + #ifdef ID_S_CUSTOM custom(); #endif @@ -789,17 +809,21 @@ void power(){ #ifdef ID_S_HEATER void heater(){ + Serial.print("Heater flow state is: " ); + Serial.println(heater_flow_state); + gw.send(msg_S_HEATER_FLOWSTATE.set(heater_flow_state.c_str())); - Serial.print("Heater mode is: " ); - Serial.println(heatState); + Serial.print("Heater on/off is: " ); + Serial.println((heater_status==true)?"On":"Off"); + gw.send(msg_S_HEATER_STATUS.set(heater_status)); - gw.send(msg_S_HEATER_F.set(heatState)); + Serial.print("Heater Temperature is: " ); + Serial.println(heater_temp,1); + gw.send(msg_S_HEATER_TEMP.set(heater_temp,1)); - Serial.print("Heater Set Point is: " ); - Serial.println(heatTemp); - - gw.send(msg_S_HEATER_S.set(heatTemp)); - + Serial.print("Heater Setpoint: " ); + Serial.println(heater_setpoint,1); + gw.send(msg_S_HEATER_SETPOINT.set(heater_setpoint,1)); } #endif @@ -899,6 +923,16 @@ void scene(){ } #endif +#ifdef ID_S_MOISTURE +void moisture(){ + + Serial.print("Moisture level is: " ); + Serial.println(randNumber); + + gw.send(msg_S_MOISTURE.set(randNumber)); +} +#endif + #ifdef ID_S_CUSTOM void custom(){ @@ -980,21 +1014,26 @@ void incomingMessage(const MyMessage &message) { #endif #ifdef ID_S_HEATER - case V_HVAC_FLOW_STATE: - heatState = message.getString(); - Serial.print("Incoming change for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(heatState); - - break; - case V_HVAC_SETPOINT_HEAT: - heatTemp = message.getInt(); + Serial.print("Incoming set point for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + heater_setpoint=message.getFloat(); + Serial.println(heater_setpoint,1); + break; + case V_STATUS: Serial.print("Incoming change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println(heatTemp); + heater_status = message.getBool(); + Serial.println(heater_status); + break; + case V_HVAC_FLOW_STATE: + Serial.print("Incoming flow state change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + heater_flow_state=message.getString(); + Serial.println(heater_flow_state); break; #endif From 6dcb162858234a76adf5655233a530abebd2015b Mon Sep 17 00:00:00 2001 From: Barduino Date: Sat, 5 Sep 2015 14:36:33 -0400 Subject: [PATCH 238/660] S_HEATER & S_SCENES fixed implementation of s_heater & s_scene_controller --- .../examples/MockMySensors/MockMySensors.ino | 82 +++++++++++-------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 9510270..7fa7659 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -44,32 +44,32 @@ // one at a time. #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 -//#define ID_S_MOTION 2 -//#define ID_S_SMOKE 3 -//#define ID_S_LIGHT 4 -//#define ID_S_DIMMER 5 -//#define ID_S_COVER 6 -//#define ID_S_TEMP 7 -//#define ID_S_HUM 8 -//#define ID_S_BARO 9 -//#define ID_S_WIND 10 -//#define ID_S_RAIN 11 -//#define ID_S_UV 12 -//#define ID_S_WEIGHT 13 -//#define ID_S_POWER 14 -//#define ID_S_HEATER 15 -//#define ID_S_DISTANCE 16 -//#define ID_S_LIGHT_LEVEL 17 -//#define ID_S_LOCK 18 -//#define ID_S_IR 19 -//#define ID_S_WATER 20 -//#define ID_S_AIR_QUALITY 21 -//#define ID_S_DUST 22 -//#define ID_S_SCENE_CONTROLLER 23 -//#define ID_S_CUSTOM 99 +#define ID_S_MOTION 2 +#define ID_S_SMOKE 3 +#define ID_S_LIGHT 4 +#define ID_S_DIMMER 5 +#define ID_S_COVER 6 +#define ID_S_TEMP 7 +#define ID_S_HUM 8 +#define ID_S_BARO 9 +#define ID_S_WIND 10 +#define ID_S_RAIN 11 +#define ID_S_UV 12 +#define ID_S_WEIGHT 13 +#define ID_S_POWER 14 +#define ID_S_HEATER 15 +#define ID_S_DISTANCE 16 +#define ID_S_LIGHT_LEVEL 17 +#define ID_S_LOCK 18 +#define ID_S_IR 19 +#define ID_S_WATER 20 +#define ID_S_AIR_QUALITY 21 +#define ID_S_DUST 22 +#define ID_S_SCENE_CONTROLLER 23 +#define ID_S_CUSTOM 99 // Global Vars -unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds) +unsigned long SLEEP_TIME = 900000; // Sleep time between reads (in milliseconds) boolean metric = true; long randNumber; @@ -175,9 +175,9 @@ MyHwATMega328 hw; #ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC - MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_FLOW_STATE); // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC + MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER int heatTemp=18; - const char* heatState="Off"; + String heatState="Off"; #endif #ifdef ID_S_DISTANCE @@ -218,12 +218,12 @@ MyHwATMega328 hw; // not sure if scene controller sends int or chars // betting on ints as Touch Display Scen by Hek // compiler warnings char *scenes[] = { - "All off", - "Good Morning", - "Clean Up!", - "All Lights Off", - "Music On/Off" + (char *)"Good Morning", + (char *)"Clean Up!", + (char *)"All Lights Off", + (char *)"Music On/Off" }; + int sceneVal=0; int sceneValPrevious=0; @@ -789,11 +789,13 @@ void power(){ #ifdef ID_S_HEATER void heater(){ + char cBuff[heatState.length()+1]; + heatState.toCharArray(cBuff,heatState.length()+1); Serial.print("Heater mode is: " ); - Serial.println(heatState); + Serial.println(cBuff); - gw.send(msg_S_HEATER_F.set(heatState)); + gw.send(msg_S_HEATER_F.set(cBuff)); Serial.print("Heater Set Point is: " ); Serial.println(heatTemp); @@ -924,7 +926,15 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isArmed ? "Armed":"Disarmed" )); - door();//temp ack for door + #ifdef ID_S_DOOR + door();//temp ack for door + #endif + #ifdef ID_S_MOTION + motion();//temp ack + #endif + #ifdef ID_S_SMOKE + smoke();//temp ack + #endif break; #endif @@ -950,6 +960,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(message.getInt()); + dimmer();// temp ack break; #endif @@ -986,6 +997,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(heatState); + heater();//temp ack break; @@ -995,6 +1007,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(heatTemp); + heater();//temp ack break; #endif @@ -1038,6 +1051,7 @@ void incomingMessage(const MyMessage &message) { Serial.println(" Off"); scene(); break; + scene(); // tmp ack #endif default: From fe86934360be67d68cff20c8013364218f3c2590 Mon Sep 17 00:00:00 2001 From: Barduino Date: Sun, 6 Sep 2015 10:27:00 -0400 Subject: [PATCH 239/660] S_COVER & S_IR implementation --- .../examples/MockMySensors/MockMySensors.ino | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) mode change 100644 => 100755 libraries/MySensors/examples/MockMySensors/MockMySensors.ino diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino old mode 100644 new mode 100755 index 7fa7659..629bfe3 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -130,7 +130,8 @@ MyHwATMega328 hw; MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); - const char* coverVal = "V_STOP"; //compiler warnings + MyMessage msg_S_COVER_V(ID_S_COVER,V_VAR1); + int coverState=0; //0=Stop; 1=up; -1=down #endif #ifdef ID_S_TEMP @@ -196,7 +197,7 @@ MyHwATMega328 hw; #ifdef ID_S_IR MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); - const char* irVal = ""; + long irVal = 0; #endif #ifdef ID_S_WATER @@ -646,17 +647,17 @@ void cover(){ Serial.print("Cover is : " ); - if (coverVal == "V_UP"){ + if (coverState == 1){ Serial.println("Opening"); - gw.send(msg_S_COVER_U.set(V_UP)); - }else if (coverVal == "V_DOWN"){ + gw.send(msg_S_COVER_U.set(1)); + }else if (coverState == -1){ Serial.println("Closing"); - gw.send(msg_S_COVER_D.set(V_DOWN)); + gw.send(msg_S_COVER_D.set(0)); }else{ Serial.println("Idle"); - gw.send(msg_S_COVER_S.set(V_STOP)); + gw.send(msg_S_COVER_S.set(-1)); } - + gw.send(msg_S_COVER_V.set(coverState)); } #endif @@ -844,6 +845,7 @@ void ir(){ Serial.println(irVal); gw.send(msg_S_IR_S.set(irVal)); + gw.send(msg_S_IR_R.set(irVal)); } #endif @@ -966,27 +968,30 @@ void incomingMessage(const MyMessage &message) { #ifdef ID_S_COVER case V_UP: - coverVal="V_UP"; + coverState=1; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println("V_UP"); + cover(); // temp ack break; case V_DOWN: - coverVal="V_DOWN"; + coverState=-1; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println("V_DOWN"); + cover(); //temp ack break; case V_STOP: - coverVal="V_STOP"; + coverState=0; Serial.print("Incoming change for ID_S_COVER:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println("V_STOP"); + cover(); //temp ack break; #endif @@ -1023,12 +1028,21 @@ void incomingMessage(const MyMessage &message) { #endif #ifdef ID_S_IR - case V_IR_RECEIVE: - irVal = message.getString(); + case V_IR_SEND: + irVal = message.getLong(); Serial.print("Incoming change for ID_S_IR:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(irVal); + ir(); // temp ack + break; + case V_IR_RECEIVE: + irVal = message.getLong(); + Serial.print("Incoming change for ID_S_IR:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(irVal); + ir(); // temp ack break; #endif From a19865318fdff2d9d3fbb7ed935f2b365bc29f1a Mon Sep 17 00:00:00 2001 From: Barduino Date: Sun, 6 Sep 2015 11:11:15 -0400 Subject: [PATCH 240/660] Merge w/ Gizmocuz; Implement S_COVER, S_IR, S_SCENE --- .../examples/MockMySensors/MockMySensors.ino | 102 +++++------------- 1 file changed, 29 insertions(+), 73 deletions(-) mode change 100755 => 100644 libraries/MySensors/examples/MockMySensors/MockMySensors.ino diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino old mode 100755 new mode 100644 index c5f7eb0..ce1e338 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -42,35 +42,9 @@ // Some of these ID's have not been updated for v1.5. Uncommenting too many of them // will make the sketch too large for a pro mini's memory so it's probably best to try // one at a time. -<<<<<<< HEAD + #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 -#define ID_S_MOTION 2 -#define ID_S_SMOKE 3 -#define ID_S_LIGHT 4 -#define ID_S_DIMMER 5 -#define ID_S_COVER 6 -#define ID_S_TEMP 7 -#define ID_S_HUM 8 -#define ID_S_BARO 9 -#define ID_S_WIND 10 -#define ID_S_RAIN 11 -#define ID_S_UV 12 -#define ID_S_WEIGHT 13 -#define ID_S_POWER 14 -#define ID_S_HEATER 15 -#define ID_S_DISTANCE 16 -#define ID_S_LIGHT_LEVEL 17 -#define ID_S_LOCK 18 -#define ID_S_IR 19 -#define ID_S_WATER 20 -#define ID_S_AIR_QUALITY 21 -#define ID_S_DUST 22 -#define ID_S_SCENE_CONTROLLER 23 -#define ID_S_CUSTOM 99 -======= -//#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors -//#define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 //#define ID_S_LIGHT 4 @@ -93,10 +67,11 @@ //#define ID_S_AIR_QUALITY 21 //#define ID_S_DUST 22 //#define ID_S_SCENE_CONTROLLER 23 -#define ID_S_MOISTURE 24 +//#define ID_S_MOISTURE 24 + +#define ID_S_CUSTOM 99 + -//#define ID_S_CUSTOM 99 ->>>>>>> mysensors/development // Global Vars unsigned long SLEEP_TIME = 900000; // Sleep time between reads (in milliseconds) @@ -204,23 +179,18 @@ MyHwATMega328 hw; // MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); #endif -<<<<<<< HEAD -#ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP - MyMessage msg_S_HEATER_S(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC - MyMessage msg_S_HEATER_F(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER - int heatTemp=18; - String heatState="Off"; -======= + #ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP, V_STATUS + MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC + MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER + MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); + MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); + float heater_setpoint=21.5; float heater_temp=23.5; bool heater_status=false; - String heater_flow_state = "Off"; - MyMessage msg_S_HEATER_SETPOINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); - MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); - MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); - MyMessage msg_S_HEATER_FLOWSTATE(ID_S_HEATER,V_HVAC_FLOW_STATE); ->>>>>>> mysensors/development + String heater_flow_state="Off"; + const bool dup_v_status=false; // V_STATUS & V_LIGHT are the same, does not compile in case statement of incoming s_heater message #endif #ifdef ID_S_DISTANCE @@ -846,18 +816,14 @@ void power(){ #ifdef ID_S_HEATER void heater(){ -<<<<<<< HEAD - char cBuff[heatState.length()+1]; - heatState.toCharArray(cBuff,heatState.length()+1); - - Serial.print("Heater mode is: " ); - Serial.println(cBuff); +// float heater_setpoint=21.5; +// float heater_temp=23.5; +// bool heater_status=false; +// String heatState="Off"; - gw.send(msg_S_HEATER_F.set(cBuff)); -======= Serial.print("Heater flow state is: " ); Serial.println(heater_flow_state); - gw.send(msg_S_HEATER_FLOWSTATE.set(heater_flow_state.c_str())); + gw.send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str())); Serial.print("Heater on/off is: " ); Serial.println((heater_status==true)?"On":"Off"); @@ -866,11 +832,10 @@ void heater(){ Serial.print("Heater Temperature is: " ); Serial.println(heater_temp,1); gw.send(msg_S_HEATER_TEMP.set(heater_temp,1)); ->>>>>>> mysensors/development Serial.print("Heater Setpoint: " ); Serial.println(heater_setpoint,1); - gw.send(msg_S_HEATER_SETPOINT.set(heater_setpoint,1)); + gw.send(msg_S_HEATER_SET_POINT.set(heater_setpoint,1)); } #endif @@ -1073,38 +1038,30 @@ void incomingMessage(const MyMessage &message) { break; #endif - #ifdef ID_S_HEATER + #ifdef ID_S_HEATER case V_HVAC_SETPOINT_HEAT: + heater_setpoint=message.getFloat(); + Serial.print("Incoming set point for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); -<<<<<<< HEAD - Serial.println(heatState); - heater();//temp ack - -======= - heater_setpoint=message.getFloat(); Serial.println(heater_setpoint,1); ->>>>>>> mysensors/development + heater();//temp ack break; - case V_STATUS: + case (V_STATUS || dup_v_status): //V_LIGHT & V_STATUS are the same; does not compile without hack + heater_status = message.getBool(); Serial.print("Incoming change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); -<<<<<<< HEAD - Serial.println(heatTemp); - heater();//temp ack -======= - heater_status = message.getBool(); Serial.println(heater_status); + heater();//temp ack break; case V_HVAC_FLOW_STATE: + heater_flow_state=message.getString(); Serial.print("Incoming flow state change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); - heater_flow_state=message.getString(); Serial.println(heater_flow_state); ->>>>>>> mysensors/development break; #endif @@ -1146,7 +1103,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(", New status: "); Serial.print(scenes[sceneVal]); Serial.println(" On"); - scene(); + scene();// temp ack break; case V_SCENE_OFF: sceneVal = message.getInt(); @@ -1155,9 +1112,8 @@ void incomingMessage(const MyMessage &message) { Serial.print(", New status: "); Serial.print(scenes[sceneVal]); Serial.println(" Off"); - scene(); + scene();// temp ack break; - scene(); // tmp ack #endif default: From 92b1b8d67a67c75179364050487fcec2290fa53f Mon Sep 17 00:00:00 2001 From: Barduino Date: Sun, 6 Sep 2015 11:18:40 -0400 Subject: [PATCH 241/660] Change Log --- libraries/MySensors/examples/MockMySensors/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md index c835b2d..fef8191 100644 --- a/libraries/MySensors/examples/MockMySensors/README.md +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -16,8 +16,14 @@ With a Mega you can have them all Changes Log ----------------- +2015-09-06 + +Merge with Gizmocuz (implementation of S_HEATER & S_MOISTURE +Implementation of S_COVER, S_IR, S_SCENE_CONTROLLER + 2015-08-19 + Removed the load/save to eeprom Touched the heater sensor Created a pseudo sensor to handle the V_ARMED message. From 896ca7850bbfcac6f8ae300c677aaf1b3ea4b1c1 Mon Sep 17 00:00:00 2001 From: Barduino Date: Mon, 7 Sep 2015 19:19:10 -0400 Subject: [PATCH 242/660] Five more sensors S_RGB_LIGHT S_RGBW_LIGHT S_COLOR_SENSOR S_HVAC S_MULTIMETER --- .../examples/MockMySensors/MockMySensors.ino | 471 +++++++++++++++--- .../examples/MockMySensors/README.md | 10 + 2 files changed, 420 insertions(+), 61 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index ce1e338..aee2435 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -43,33 +43,43 @@ // will make the sketch too large for a pro mini's memory so it's probably best to try // one at a time. -#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors -#define ID_S_DOOR 1 -//#define ID_S_MOTION 2 -//#define ID_S_SMOKE 3 -//#define ID_S_LIGHT 4 -//#define ID_S_DIMMER 5 -//#define ID_S_COVER 6 -//#define ID_S_TEMP 7 -//#define ID_S_HUM 8 -//#define ID_S_BARO 9 -//#define ID_S_WIND 10 -//#define ID_S_RAIN 11 -//#define ID_S_UV 12 -//#define ID_S_WEIGHT 13 -//#define ID_S_POWER 14 -//#define ID_S_HEATER 15 -//#define ID_S_DISTANCE 16 -//#define ID_S_LIGHT_LEVEL 17 -//#define ID_S_LOCK 18 -//#define ID_S_IR 19 -//#define ID_S_WATER 20 -//#define ID_S_AIR_QUALITY 21 -//#define ID_S_DUST 22 -//#define ID_S_SCENE_CONTROLLER 23 -//#define ID_S_MOISTURE 24 +#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors +#define ID_S_DOOR 1 +#define ID_S_MOTION 2 +#define ID_S_SMOKE 3 +#define ID_S_LIGHT 4 +#define ID_S_DIMMER 5 +#define ID_S_COVER 6 +#define ID_S_TEMP 7 +#define ID_S_HUM 8 +#define ID_S_BARO 9 +#define ID_S_WIND 10 +#define ID_S_RAIN 11 +#define ID_S_UV 12 +#define ID_S_WEIGHT 13 +#define ID_S_POWER 14 +#define ID_S_HEATER 15 +#define ID_S_DISTANCE 16 +#define ID_S_LIGHT_LEVEL 17 +#define ID_S_LOCK 18 +#define ID_S_IR 19 +#define ID_S_WATER 20 +#define ID_S_AIR_QUALITY 21 +#define ID_S_DUST 22 +#define ID_S_SCENE_CONTROLLER 23 +// Lib 1.5 sensors +#define ID_S_RGB_LIGHT 24 +#define ID_S_RGBW_LIGHT 25 +#define ID_S_COLOR_SENSOR 26 +#define ID_S_HVAC 27 +#define ID_S_MULTIMETER 28 +#define ID_S_SPRINKLER 29 +#define ID_S_WATER_LEAK 30 +#define ID_S_SOUND 31 +#define ID_S_VIBRATION 32 +#define ID_S_MOISTURE 33 -#define ID_S_CUSTOM 99 +//#define ID_S_CUSTOM 99 @@ -174,13 +184,13 @@ MyHwATMega328 hw; #ifdef ID_S_POWER MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); -// MyMessage msg_S_POWER_I(ID_S_POWER,V_IMPEDANCE); -// MyMessage msg_S_POWER_V(ID_S_POWER,V_VOLTAGE); -// MyMessage msg_S_POWER_C(ID_S_POWER,V_CURRENT); #endif -#ifdef ID_S_HEATER //V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP, V_STATUS +#ifdef ID_S_HEATER + + //////// REVIEW IMPLEMENTATION //////////// + MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); @@ -190,7 +200,12 @@ MyHwATMega328 hw; float heater_temp=23.5; bool heater_status=false; String heater_flow_state="Off"; - const bool dup_v_status=false; // V_STATUS & V_LIGHT are the same, does not compile in case statement of incoming s_heater message + + // V_TEMP // Temperature + // V_STATUS // Binary status. 0=off 1=on + // V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" + // V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + // V_HVAC_SETPOINT_HEAT // HVAC/Heater setpoint #endif #ifdef ID_S_DISTANCE @@ -242,6 +257,80 @@ MyHwATMega328 hw; #endif +#ifdef ID_S_RGB_LIGHT + MyMessage msg_S_RGB_LIGHT_V_RGB(ID_S_RGB_LIGHT,V_RGB); + MyMessage msg_S_RGB_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); + String rgbState="000000"; + //RGB light V_RGB, V_WATT + //RGB value transmitted as ASCII hex string (I.e "ff0000" for red) +#endif + +#ifdef ID_S_RGBW_LIGHT + MyMessage msg_S_RGBW_LIGHT_V_RGBW(ID_S_RGB_LIGHT,V_RGBW); + MyMessage msg_S_RGBW_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); + String rgbwState="00000000"; + //RGBW light (with separate white component) V_RGBW, V_WATT + //RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + full white) S_RGBW_LIGHT +#endif + +#ifdef ID_S_COLOR_SENSOR + MyMessage msg_S_COLOR_SENSOR_V_RGB(ID_S_COLOR_SENSOR,V_RGB); + //Color sensor V_RGB + //RGB value transmitted as ASCII hex string (I.e "ff0000" for red) S_RGB_LIGHT, S_COLOR_SENSOR +#endif + +#ifdef ID_S_HVAC + MyMessage msg_S_HVAC_V_HVAC_SETPOINT_HEAT(ID_S_HVAC,V_HVAC_SETPOINT_HEAT); + MyMessage msg_S_HVAC_V_HVAC_SETPOINT_COOL(ID_S_HVAC,V_HVAC_SETPOINT_COOL); + MyMessage msg_S_HVAC_V_HVAC_FLOW_STATET(ID_S_HVAC,V_HVAC_FLOW_STATE); + MyMessage msg_S_HVAC_V_HVAC_FLOW_MODE(ID_S_HVAC,V_HVAC_FLOW_MODE); + MyMessage msg_S_HVAC_V_HVAC_SPEED(ID_S_HVAC,V_HVAC_SPEED); + + float hvac_SetPointHeat = 16.5; + float hvac_SetPointCool = 25.5; + String hvac_FlowState = "AutoChangeOver"; + String hvac_FlowMode = "Auto"; + String hvac_Speed = "Normal"; + + //Thermostat/HVAC device + //V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint + //V_HVAC_SETPOINT_COOL, // HVAC cold setpoint + //V_HVAC_FLOW_STATE, // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" + //V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") + //V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + + // NOT IMPLEMENTED YET + //V_TEMP // Temperature + //V_STATUS // Binary status. 0=off 1=on +#endif + +#ifdef ID_S_MULTIMETER + MyMessage msg_S_MULTIMETER_V_IMPEDANCE(ID_S_POWER,V_IMPEDANCE); + MyMessage msg_S_MULTIMETER_V_VOLTAGE(ID_S_POWER,V_VOLTAGE); + MyMessage msg_S_MULTIMETER_V_CURRENT(ID_S_POWER,V_CURRENT); + + // Multimeter device V_VOLTAGE, V_CURRENT, V_IMPEDANCE + // V_IMPEDANCE 14 Impedance value + // V_VOLTAGE 38 Voltage level + // V_CURRENT 39 Current level +#endif + +#ifdef ID_S_SPRINKLER + // S_SPRINKLER 31 Sprinkler device V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) + // V_STATUS 2 Binary status. 0=off 1=on + // V_ARMED 15 Armed status of a security sensor. 1=Armed, 0=Bypassed + // V_TRIPPED 16 Tripped status of a security sensor. 1=Tripped, 0=Untripped +#endif + +#ifdef ID_S_WATER_LEAK +#endif +#ifdef ID_S_SOUND +#endif +#ifdef ID_S_VIBRATION +#endif +#ifdef ID_S_MOISTURE +#endif + #ifdef ID_S_MOISTURE MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL); #endif @@ -426,6 +515,47 @@ void setup() gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); gw.wait(SHORT_WAIT); #endif + + #ifdef ID_S_RGB_LIGHT + Serial.println(" RGB_LIGHT"); + gw.present(ID_S_RGB_LIGHT,S_RGB_LIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_RGBW_LIGHT + Serial.println(" RGBW_LIGHT"); + gw.present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_COLOR_SENSOR + Serial.println(" COLOR_SENSOR"); + gw.present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_HVAC + Serial.println(" HVAC"); + gw.present(ID_S_HVAC,S_HVAC); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_MULTIMETER + Serial.println(" MULTIMETER"); + gw.present(ID_S_MULTIMETER,S_MULTIMETER); + gw.wait(SHORT_WAIT); + #endif + + #ifdef ID_S_SPRINKLER + #endif + #ifdef ID_S_WATER_LEAK + #endif + #ifdef ID_S_SOUND + #endif + #ifdef ID_S_VIBRATION + #endif + #ifdef ID_S_MOISTURE + #endif #ifdef ID_S_MOISTURE Serial.println(" S_MOISTURE"); @@ -558,6 +688,37 @@ void loop() scene(); #endif + #ifdef ID_S_RGB_LIGHT + rgbLight(); + #endif + + #ifdef ID_S_RGBW_LIGHT + rgbwLight(); + #endif + + #ifdef ID_S_COLOR_SENSOR + color(); + #endif + + #ifdef ID_S_HVAC + hvac(); + #endif + + #ifdef ID_S_MULTIMETER + multimeter(); + #endif + + #ifdef ID_S_SPRINKLER + #endif + #ifdef ID_S_WATER_LEAK + #endif + #ifdef ID_S_SOUND + #endif + #ifdef ID_S_VIBRATION + #endif + #ifdef ID_S_MOISTURE + #endif + #ifdef ID_S_MOISTURE moisture(); #endif @@ -787,30 +948,13 @@ void weight(){ void power(){ Serial.print("Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); - + Serial.println(map(randNumber,1,100,0,150)); gw.send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); Serial.print("KWH is: " ); - Serial.println(map(randNumber,1,100,0,150)); - + Serial.println(map(randNumber,1,100,0,150)); gw.send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); -// Serial.print("Impedance is: " ); -// Serial.println(map(randNumber,1,100,0,150)); -// -// gw.send(msg_S_POWER_I.set(map(randNumber,1,100,0,150))); - -// Serial.print("Voltage is: " ); -// Serial.println(map(randNumber,1,100,0,150)); -// -// gw.send(msg_S_POWER_V.set(map(randNumber,1,100,0,150))); - -// Serial.print("Current is: " ); -// Serial.println(map(randNumber,1,100,0,150)); -// -// gw.send(msg_S_POWER_C.set(map(randNumber,1,100,0,150))); - } #endif @@ -936,6 +1080,115 @@ void scene(){ } #endif +#ifdef ID_S_RGB_LIGHT +void rgbLight(){ + + Serial.print("RGB Light state is: " ); + Serial.println(rgbState); + gw.send(msg_S_RGB_LIGHT_V_RGB.set(rgbState.c_str())); + + Serial.print("RGB Light Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + gw.send(msg_S_RGB_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_RGBW_LIGHT +void rgbwLight(){ + + Serial.print("RGBW Light state is: " ); + Serial.println(rgbwState); + gw.send(msg_S_RGBW_LIGHT_V_RGBW.set(rgbwState.c_str())); + + Serial.print("RGBW Light Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + gw.send(msg_S_RGBW_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); + +} +#endif + +#ifdef ID_S_COLOR_SENSOR +void color(){ + String colorState; + + String red = String(random(0,256),HEX); + String green = String(random(0,256),HEX); + String blue = String(random(0,256),HEX); + + colorState=String(red + green + blue); + + Serial.print("Color state is: " ); + Serial.println(colorState); + gw.send(msg_S_COLOR_SENSOR_V_RGB.set(colorState.c_str())); + +} +#endif + +#ifdef ID_S_HVAC +void hvac(){ + +// float hvac_SetPointHeat = 16.5; +// float hvac_SetPointCool = 25.5; +// String hvac_FlowState = "AutoChangeOver"; +// String hvac_FlowMode = "Auto"; +// String hvac_Speed = "Normal"; + + Serial.print("HVAC Set Point Heat is: " ); + Serial.println(hvac_SetPointHeat); + gw.send(msg_S_HVAC_V_HVAC_SETPOINT_HEAT.set(hvac_SetPointHeat,1)); + + Serial.print("HVAC Set Point Cool is: " ); + Serial.println(hvac_SetPointCool); + gw.send(msg_S_HVAC_V_HVAC_SETPOINT_COOL.set(hvac_SetPointCool,1)); + + Serial.print("HVAC Flow State is: " ); + Serial.println(hvac_FlowState); + gw.send(msg_S_HVAC_V_HVAC_FLOW_STATET.set(hvac_FlowState.c_str())); + + Serial.print("HVAC Flow Mode is: " ); + Serial.println(hvac_FlowMode); + gw.send(msg_S_HVAC_V_HVAC_FLOW_MODE.set(hvac_FlowMode.c_str())); + + Serial.print("HVAC Speed is: " ); + Serial.println(hvac_Speed); + gw.send(msg_S_HVAC_V_HVAC_SPEED.set(hvac_Speed.c_str())); + +} +#endif + +#ifdef ID_S_MULTIMETER +void multimeter(){ + int impedance=map(randNumber,1,100,0,15000); + int volt=map(randNumber,1,100,0,380); + int amps=map(randNumber,1,100,0,16); + + Serial.print("Impedance is: " ); + Serial.println(impedance); + gw.send(msg_S_MULTIMETER_V_IMPEDANCE.set(impedance)); + + Serial.print("Voltage is: " ); + Serial.println(volt); + gw.send(msg_S_MULTIMETER_V_VOLTAGE.set(volt)); + + Serial.print("Current is: " ); + Serial.println(amps); + gw.send(msg_S_MULTIMETER_V_CURRENT.set(amps)); + +} +#endif + +#ifdef ID_S_SPRINKLER +#endif +#ifdef ID_S_WATER_LEAK +#endif +#ifdef ID_S_SOUND +#endif +#ifdef ID_S_VIBRATION +#endif +#ifdef ID_S_MOISTURE +#endif + #ifdef ID_S_MOISTURE void moisture(){ @@ -983,16 +1236,30 @@ void incomingMessage(const MyMessage &message) { break; #endif + + case V_STATUS: // V_LIGHT: #ifdef ID_S_LIGHT - case V_LIGHT: + if(message.sensor==ID_S_LIGHT){ isLightOn = message.getBool(); Serial.print("Incoming change for ID_S_LIGHT:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println((isLightOn ? "On":"Off")); light(); // temp ack - break; + } #endif + #ifdef ID_S_HEATER + if(message.sensor == ID_S_HEATER){ + heater_status = message.getBool(); + Serial.print("Incoming change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(heater_status); + heater();//temp ack + } + #endif + break; + #ifdef ID_S_DIMMER case V_DIMMER: @@ -1038,8 +1305,11 @@ void incomingMessage(const MyMessage &message) { break; #endif - #ifdef ID_S_HEATER + case V_HVAC_SETPOINT_HEAT: + + #ifdef ID_S_HEATER + if(message.sensor == ID_S_HEATER){ heater_setpoint=message.getFloat(); Serial.print("Incoming set point for ID_S_HEATER:"); @@ -1047,23 +1317,44 @@ void incomingMessage(const MyMessage &message) { Serial.print(", New status: "); Serial.println(heater_setpoint,1); heater();//temp ack - break; - case (V_STATUS || dup_v_status): //V_LIGHT & V_STATUS are the same; does not compile without hack - heater_status = message.getBool(); - Serial.print("Incoming change for ID_S_HEATER:"); + } + #endif + + #ifdef ID_S_HVAC + if(message.sensor == ID_S_HVAC){ + hvac_SetPointHeat=message.getFloat(); + Serial.print("Incoming set point for ID_S_HVAC:"); Serial.print(message.sensor); Serial.print(", New status: "); - Serial.println(heater_status); - heater();//temp ack + Serial.println(hvac_SetPointHeat,1); + hvac();//temp ack + } + #endif break; + case V_HVAC_FLOW_STATE: + #ifdef ID_S_HEATER + if(message.sensor == ID_S_HEATER){ heater_flow_state=message.getString(); Serial.print("Incoming flow state change for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(heater_flow_state); + } + #endif + + #ifdef ID_S_HVAC + if(message.sensor == ID_S_HVAC){ + hvac_FlowState=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_FlowState); + hvac();//temp ack + } + #endif break; - #endif #ifdef ID_S_LOCK case V_LOCK_STATUS: @@ -1115,7 +1406,65 @@ void incomingMessage(const MyMessage &message) { scene();// temp ack break; #endif - + + #ifdef ID_S_RGB_LIGHT + case V_RGB: + rgbState=message.getString(); + Serial.print("Incoming flow state change for ID_S_RGB_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(rgbState); + break; + #endif + + #ifdef ID_S_RGBW_LIGHT + case V_RGBW: + rgbwState=message.getString(); + Serial.print("Incoming flow state change for ID_S_RGBW_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(rgbwState); + break; + #endif + + #ifdef ID_S_HVAC + // hvac_SetPointHeat + // hvac_SetPointCool + // hvac_FlowState + // hvac_FlowMode + // hvac_Speed + + case V_HVAC_SETPOINT_COOL: + hvac_SetPointCool=message.getFloat(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_SetPointCool,1); + hvac();//temp ack + break; + + case V_HVAC_FLOW_MODE: + hvac_Speed=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_Speed); + hvac();//temp ack + break; + + case V_HVAC_SPEED: + hvac_FlowMode=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_FlowMode); + hvac();//temp ack + break; + #endif + default: Serial.print("Unknown/UnImplemented message type: "); Serial.println(message.type); diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/libraries/MySensors/examples/MockMySensors/README.md index fef8191..ef2062e 100644 --- a/libraries/MySensors/examples/MockMySensors/README.md +++ b/libraries/MySensors/examples/MockMySensors/README.md @@ -16,6 +16,16 @@ With a Mega you can have them all Changes Log ----------------- + +2015-09-07 +Five more sensors + S_RGB_LIGHT + S_RGBW_LIGHT + S_COLOR_SENSOR + S_HVAC + S_MULTIMETER +Consolidated HVAC and HEATER incoming message + 2015-09-06 Merge with Gizmocuz (implementation of S_HEATER & S_MOISTURE From 10d37716e72a3b3297042834755fb0ebec26657f Mon Sep 17 00:00:00 2001 From: Barduino Date: Mon, 7 Sep 2015 19:23:17 -0400 Subject: [PATCH 243/660] Set for Jenkins build Most code commented --- .../examples/MockMySensors/MockMySensors.ino | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index aee2435..36cddd5 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -45,39 +45,39 @@ #define ID_S_ARMED 0 // dummy to controll armed stated for several sensors #define ID_S_DOOR 1 -#define ID_S_MOTION 2 -#define ID_S_SMOKE 3 -#define ID_S_LIGHT 4 -#define ID_S_DIMMER 5 -#define ID_S_COVER 6 -#define ID_S_TEMP 7 -#define ID_S_HUM 8 -#define ID_S_BARO 9 -#define ID_S_WIND 10 -#define ID_S_RAIN 11 -#define ID_S_UV 12 -#define ID_S_WEIGHT 13 -#define ID_S_POWER 14 -#define ID_S_HEATER 15 -#define ID_S_DISTANCE 16 -#define ID_S_LIGHT_LEVEL 17 -#define ID_S_LOCK 18 -#define ID_S_IR 19 -#define ID_S_WATER 20 -#define ID_S_AIR_QUALITY 21 -#define ID_S_DUST 22 -#define ID_S_SCENE_CONTROLLER 23 -// Lib 1.5 sensors -#define ID_S_RGB_LIGHT 24 -#define ID_S_RGBW_LIGHT 25 -#define ID_S_COLOR_SENSOR 26 -#define ID_S_HVAC 27 -#define ID_S_MULTIMETER 28 -#define ID_S_SPRINKLER 29 -#define ID_S_WATER_LEAK 30 -#define ID_S_SOUND 31 -#define ID_S_VIBRATION 32 -#define ID_S_MOISTURE 33 +//#define ID_S_MOTION 2 +//#define ID_S_SMOKE 3 +//#define ID_S_LIGHT 4 +//#define ID_S_DIMMER 5 +//#define ID_S_COVER 6 +//#define ID_S_TEMP 7 +//#define ID_S_HUM 8 +//#define ID_S_BARO 9 +//#define ID_S_WIND 10 +//#define ID_S_RAIN 11 +//#define ID_S_UV 12 +//#define ID_S_WEIGHT 13 +//#define ID_S_POWER 14 +//#define ID_S_HEATER 15 +//#define ID_S_DISTANCE 16 +//#define ID_S_LIGHT_LEVEL 17 +//#define ID_S_LOCK 18 +//#define ID_S_IR 19 +//#define ID_S_WATER 20 +//#define ID_S_AIR_QUALITY 21 +//#define ID_S_DUST 22 +//#define ID_S_SCENE_CONTROLLER 23 +//// Lib 1.5 sensors +//#define ID_S_RGB_LIGHT 24 +//#define ID_S_RGBW_LIGHT 25 +//#define ID_S_COLOR_SENSOR 26 +//#define ID_S_HVAC 27 +//#define ID_S_MULTIMETER 28 +//#define ID_S_SPRINKLER 29 +//#define ID_S_WATER_LEAK 30 +//#define ID_S_SOUND 31 +//#define ID_S_VIBRATION 32 +//#define ID_S_MOISTURE 33 //#define ID_S_CUSTOM 99 From 255a8d821c12ceef4fcd148df61846d3e36097a7 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Tue, 8 Sep 2015 23:41:33 +0200 Subject: [PATCH 244/660] Fixed "invalid suffix on literal" warning --- .../BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino index 34e0a17..bd3a81f 100644 --- a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino +++ b/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino @@ -75,7 +75,7 @@ void setup() digitalWrite(SECONDARY_BUTTON_PIN, HIGH); // Send the sketch version information to the gateway and Controller - sensor_node.sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER"."SKETCH_MINOR_VER); + sensor_node.sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER); // Register binary input sensor to sensor_node (they will be created as child devices) // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. From a6e13bb4f1883c3ee3d9a25dd7ded6941cfeb726 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 9 Sep 2015 11:48:22 +0200 Subject: [PATCH 245/660] Added build badges for the nightly builds of "future" Arduino IDE --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3e4a778..c79ceb0 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,7 @@ Please visit www.mysensors.org for more information Current build status of master branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/master/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/master/) Current build status of development branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/development/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/development/) + +Current build status of master branch (nightly build of Arduino IDE): [![Build Status](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/badge/icon)](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/) + +Current build status of development branch (nightly build of Arduino IDE): [![Build Status](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/badge/icon)](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/) From 253540c3e18f8bfaeca6e2d3e141a66b13c87733 Mon Sep 17 00:00:00 2001 From: Barduino Date: Thu, 10 Sep 2015 08:32:01 -0400 Subject: [PATCH 246/660] Generel fixes --- .../examples/MockMySensors/MockMySensors.ino | 119 +++++++++--------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino index 36cddd5..c88a700 100644 --- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino +++ b/libraries/MySensors/examples/MockMySensors/MockMySensors.ino @@ -78,7 +78,7 @@ //#define ID_S_SOUND 31 //#define ID_S_VIBRATION 32 //#define ID_S_MOISTURE 33 - +// //#define ID_S_CUSTOM 99 @@ -193,14 +193,17 @@ MyHwATMega328 hw; MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER - MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); - MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); + + //MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); + //MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); float heater_setpoint=21.5; - float heater_temp=23.5; - bool heater_status=false; String heater_flow_state="Off"; +// float heater_temp=23.5; +// bool heater_status=false; + + // V_TEMP // Temperature // V_STATUS // Binary status. 0=off 1=on // V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" @@ -266,8 +269,8 @@ MyHwATMega328 hw; #endif #ifdef ID_S_RGBW_LIGHT - MyMessage msg_S_RGBW_LIGHT_V_RGBW(ID_S_RGB_LIGHT,V_RGBW); - MyMessage msg_S_RGBW_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); + MyMessage msg_S_RGBW_LIGHT_V_RGBW(ID_S_RGBW_LIGHT,V_RGBW); + MyMessage msg_S_RGBW_LIGHT_V_WATT(ID_S_RGBW_LIGHT,V_WATT); String rgbwState="00000000"; //RGBW light (with separate white component) V_RGBW, V_WATT //RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + full white) S_RGBW_LIGHT @@ -305,9 +308,9 @@ MyHwATMega328 hw; #endif #ifdef ID_S_MULTIMETER - MyMessage msg_S_MULTIMETER_V_IMPEDANCE(ID_S_POWER,V_IMPEDANCE); - MyMessage msg_S_MULTIMETER_V_VOLTAGE(ID_S_POWER,V_VOLTAGE); - MyMessage msg_S_MULTIMETER_V_CURRENT(ID_S_POWER,V_CURRENT); + MyMessage msg_S_MULTIMETER_V_IMPEDANCE(ID_S_MULTIMETER,V_IMPEDANCE); + MyMessage msg_S_MULTIMETER_V_VOLTAGE(ID_S_MULTIMETER,V_VOLTAGE); + MyMessage msg_S_MULTIMETER_V_CURRENT(ID_S_MULTIMETER,V_CURRENT); // Multimeter device V_VOLTAGE, V_CURRENT, V_IMPEDANCE // V_IMPEDANCE 14 Impedance value @@ -380,169 +383,169 @@ void setup() #ifdef ID_S_DOOR Serial.println(" S_DOOR"); - gw.present(ID_S_DOOR,S_DOOR); + gw.present(ID_S_DOOR,S_DOOR,"Outside Door"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_MOTION Serial.println(" S_MOTION"); - gw.present(ID_S_MOTION,S_MOTION); + gw.present(ID_S_MOTION,S_MOTION,"Outside Motion"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_SMOKE Serial.println(" S_SMOKE"); - gw.present(ID_S_SMOKE,S_SMOKE); + gw.present(ID_S_SMOKE,S_SMOKE,"Kitchen Smoke"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_LIGHT Serial.println(" S_LIGHT"); - gw.present(ID_S_LIGHT,S_LIGHT); + gw.present(ID_S_LIGHT,S_LIGHT,"Hall Light"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_DIMMER Serial.println(" S_DIMMER"); - gw.present(ID_S_DIMMER,S_DIMMER); + gw.present(ID_S_DIMMER,S_DIMMER,"Living room dimmer"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_COVER Serial.println(" S_COVER"); - gw.present(ID_S_COVER,S_COVER); + gw.present(ID_S_COVER,S_COVER,"Window cover"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_TEMP Serial.println(" S_TEMP"); - gw.present(ID_S_TEMP,S_TEMP); + gw.present(ID_S_TEMP,S_TEMP,"House Temperarue"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_HUM Serial.println(" S_HUM"); - gw.present(ID_S_HUM,S_HUM); + gw.present(ID_S_HUM,S_HUM,"Current Humidity"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_BARO Serial.println(" S_BARO"); - gw.present(ID_S_BARO,S_BARO); + gw.present(ID_S_BARO,S_BARO," Air pressure"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_WIND Serial.println(" S_WIND"); - gw.present(ID_S_WIND,S_WIND); + gw.present(ID_S_WIND,S_WIND,"Wind Station"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_RAIN Serial.println(" S_RAIN"); - gw.present(ID_S_RAIN,S_RAIN); + gw.present(ID_S_RAIN,S_RAIN,"Rain Station"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_UV Serial.println(" S_UV"); - gw.present(ID_S_UV,S_UV); + gw.present(ID_S_UV,S_UV,"Ultra Violet"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_WEIGHT Serial.println(" S_WEIGHT"); - gw.present(ID_S_WEIGHT,S_WEIGHT); + gw.present(ID_S_WEIGHT,S_WEIGHT,"Outdoor Scale"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_POWER Serial.println(" S_POWER"); - gw.present(ID_S_POWER,S_POWER); + gw.present(ID_S_POWER,S_POWER,"Power Metric"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_HEATER Serial.println(" S_HEATER"); - gw.present(ID_S_HEATER,S_HEATER); + gw.present(ID_S_HEATER,S_HEATER,"Garage Heater"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_DISTANCE Serial.println(" S_DISTANCE"); - gw.present(ID_S_DISTANCE,S_DISTANCE); + gw.present(ID_S_DISTANCE,S_DISTANCE,"Distance Measure"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_LIGHT_LEVEL Serial.println(" S_LIGHT_LEVEL"); - gw.present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL); + gw.present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL,"Outside Light Level"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_LOCK Serial.println(" S_LOCK"); - gw.present(ID_S_LOCK,S_LOCK); + gw.present(ID_S_LOCK,S_LOCK,"Front Door Lock"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_IR Serial.println(" S_IR"); - gw.present(ID_S_IR,S_IR); + gw.present(ID_S_IR,S_IR,"Univeral Command"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_WATER Serial.println(" S_WATER"); - gw.present(ID_S_WATER,S_WATER); + gw.present(ID_S_WATER,S_WATER,"Water Level"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_AIR_QUALITY Serial.println(" S_AIR_QUALITY"); - gw.present(ID_S_AIR_QUALITY,S_AIR_QUALITY); + gw.present(ID_S_AIR_QUALITY,S_AIR_QUALITY,"Air Station"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_DUST Serial.println(" S_DUST"); - gw.present(ID_S_DUST,S_DUST); + gw.present(ID_S_DUST,S_DUST,"Dust Level"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_SCENE_CONTROLLER Serial.println(" S_SCENE_CONTROLLER"); - gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER); + gw.present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER,"Scene Controller"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_RGB_LIGHT Serial.println(" RGB_LIGHT"); - gw.present(ID_S_RGB_LIGHT,S_RGB_LIGHT); + gw.present(ID_S_RGB_LIGHT,S_RGB_LIGHT,"Mood Light"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_RGBW_LIGHT Serial.println(" RGBW_LIGHT"); - gw.present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT); + gw.present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT,"Mood Light 2"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_COLOR_SENSOR Serial.println(" COLOR_SENSOR"); - gw.present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR); + gw.present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR,"Hall Painting"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_HVAC Serial.println(" HVAC"); - gw.present(ID_S_HVAC,S_HVAC); + gw.present(ID_S_HVAC,S_HVAC,"HVAC"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_MULTIMETER Serial.println(" MULTIMETER"); - gw.present(ID_S_MULTIMETER,S_MULTIMETER); + gw.present(ID_S_MULTIMETER,S_MULTIMETER,"Electric Staion"); gw.wait(SHORT_WAIT); #endif @@ -559,13 +562,13 @@ void setup() #ifdef ID_S_MOISTURE Serial.println(" S_MOISTURE"); - gw.present(ID_S_MOISTURE,S_MOISTURE); + gw.present(ID_S_MOISTURE,S_MOISTURE,"Basement Sensor"); gw.wait(SHORT_WAIT); #endif #ifdef ID_S_CUSTOM Serial.println(" S_CUSTOM"); - gw.present(ID_S_CUSTOM,S_CUSTOM); + gw.present(ID_S_CUSTOM,S_CUSTOM,"Other Stuff"); gw.wait(SHORT_WAIT); #endif @@ -969,13 +972,13 @@ void heater(){ Serial.println(heater_flow_state); gw.send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str())); - Serial.print("Heater on/off is: " ); - Serial.println((heater_status==true)?"On":"Off"); - gw.send(msg_S_HEATER_STATUS.set(heater_status)); +// Serial.print("Heater on/off is: " ); +// Serial.println((heater_status==true)?"On":"Off"); +// gw.send(msg_S_HEATER_STATUS.set(heater_status)); - Serial.print("Heater Temperature is: " ); - Serial.println(heater_temp,1); - gw.send(msg_S_HEATER_TEMP.set(heater_temp,1)); +// Serial.print("Heater Temperature is: " ); +// Serial.println(heater_temp,1); +// gw.send(msg_S_HEATER_TEMP.set(heater_temp,1)); Serial.print("Heater Setpoint: " ); Serial.println(heater_setpoint,1); @@ -1248,16 +1251,16 @@ void incomingMessage(const MyMessage &message) { light(); // temp ack } #endif - #ifdef ID_S_HEATER - if(message.sensor == ID_S_HEATER){ - heater_status = message.getBool(); - Serial.print("Incoming change for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(heater_status); - heater();//temp ack - } - #endif +// #ifdef ID_S_HEATER +// if(message.sensor == ID_S_HEATER){ +// heater_status = message.getBool(); +// Serial.print("Incoming change for ID_S_HEATER:"); +// Serial.print(message.sensor); +// Serial.print(", New status: "); +// Serial.println(heater_status); +// heater();//temp ack +// } +// #endif break; @@ -1340,6 +1343,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(heater_flow_state); + heater();//temp ack } #endif @@ -1414,6 +1418,8 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(rgbState); + rgbLight(); // temp ack + break; #endif @@ -1424,6 +1430,7 @@ void incomingMessage(const MyMessage &message) { Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(rgbwState); + rgbwLight(); break; #endif From bdae50886bb0d7726fa13fa14fc2052507860b90 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 12 Sep 2015 00:34:44 +0200 Subject: [PATCH 247/660] MotionSensor working --- libraries/MySensors/MyConfig.h | 78 +- libraries/MySensors/MySensor.h | 437 +--- .../{ => core}/MyGatewayTransport.cpp | 0 .../MySensors/{ => core}/MyGatewayTransport.h | 0 .../{ => core}/MyGatewayTransportEthernet.cpp | 0 .../{ => core}/MyGatewayTransportEthernet.h | 0 .../{ => core}/MyGatewayTransportSerial.cpp | 0 .../{ => core}/MyGatewayTransportSerial.h | 0 libraries/MySensors/{ => core}/MyHw.cpp | 0 libraries/MySensors/{ => core}/MyHw.h | 0 .../MySensors/{ => core}/MyHwATMega328.cpp | 6 +- .../MySensors/{ => core}/MyHwATMega328.h | 1 - .../MySensors/{ => core}/MyHwESP8266.cpp | 0 libraries/MySensors/{ => core}/MyHwESP8266.h | 0 libraries/MySensors/{ => core}/MyMessage.cpp | 0 libraries/MySensors/{ => core}/MyMessage.h | 0 libraries/MySensors/{ => core}/MyProtocol.cpp | 0 libraries/MySensors/{ => core}/MyProtocol.h | 0 .../{ => core}/MyProtocolDefault.cpp | 0 .../MySensors/{ => core}/MyProtocolDefault.h | 0 .../{MySensor.cpp => core/MySensorCore.cpp} | 24 +- libraries/MySensors/core/MySensorCore.h | 448 ++++ libraries/MySensors/{ => core}/MySigning.cpp | 0 libraries/MySensors/{ => core}/MySigning.h | 0 .../{ => core}/MySigningAtsha204.cpp | 0 .../MySensors/{ => core}/MySigningAtsha204.h | 0 .../{ => core}/MySigningAtsha204Soft.cpp | 0 .../{ => core}/MySigningAtsha204Soft.h | 0 .../MySensors/{ => core}/MySigningNone.cpp | 0 .../MySensors/{ => core}/MySigningNone.h | 0 .../MySensors/{ => core}/MyTransport.cpp | 0 libraries/MySensors/{ => core}/MyTransport.h | 0 .../MySensors/{ => core}/MyTransportNRF24.cpp | 0 .../MySensors/{ => core}/MyTransportNRF24.h | 0 .../MySensors/{ => core}/MyTransportRFM69.cpp | 2 +- .../MySensors/{ => core}/MyTransportRFM69.h | 4 +- libraries/MySensors/{ => core}/Version.h | 0 .../drivers}/DigitalIO/DigitalIO.h | 0 .../drivers}/DigitalIO/DigitalPin.h | 0 .../drivers}/DigitalIO/I2cConstants.h | 0 .../drivers}/DigitalIO/PinIO.cpp | 0 .../{ => MySensors/drivers}/DigitalIO/PinIO.h | 0 .../drivers}/DigitalIO/SoftI2cMaster.cpp | 0 .../drivers}/DigitalIO/SoftI2cMaster.h | 0 .../drivers}/DigitalIO/SoftSPI.h | 0 .../drivers}/DigitalIO/attic/ADS7818.h | 0 .../drivers}/DigitalIO/attic/MCP320X.h | 0 .../drivers}/DigitalIO/attic/MCP355X.h | 0 .../DigitalPinBlink/DigitalPinBlink.ino | 0 .../DigitalPinConfigToggle.ino | 0 .../DigitalPinReadWrite.ino | 0 .../DigitalPinShiftOut/DigitalPinShiftOut.ino | 0 .../examples/PinIOBegin/PinIOBegin.ino | 0 .../PinIOConfigToggle/PinIOConfigToggle.ino | 0 .../PinIOReadWrite/PinIOReadWrite.ino | 0 .../examples/ScanI2cBus/ScanI2cBus.ino | 0 .../SoftDS1307Utility/SoftDS1307Utility.ino | 0 .../examples/testArduino/testArduino.ino | 0 .../testDigitalPin/testDigitalPin.ino | 0 .../testFastDigital/testFastDigital.ino | 0 .../examples/testPinIO/testPinIO.ino | 0 .../examples/testSoftSPI/testSoftSPI.ino | 0 .../MySensors/drivers/Ethernet_UIP/Dhcp.cpp | 478 +++++ .../MySensors/drivers/Ethernet_UIP/Dhcp.h | 178 ++ .../MySensors/drivers/Ethernet_UIP/Dns.cpp | 422 ++++ .../MySensors/drivers/Ethernet_UIP/Dns.h | 41 + .../MySensors/drivers/Ethernet_UIP/README | 227 ++ .../drivers/Ethernet_UIP/UIPClient.cpp | 583 +++++ .../drivers/Ethernet_UIP/UIPClient.h | 112 + .../drivers/Ethernet_UIP/UIPEthernet.cpp | 485 +++++ .../drivers/Ethernet_UIP/UIPEthernet.h | 127 ++ .../drivers/Ethernet_UIP/UIPServer.cpp | 63 + .../drivers/Ethernet_UIP/UIPServer.h | 40 + .../MySensors/drivers/Ethernet_UIP/UIPUdp.cpp | 383 ++++ .../MySensors/drivers/Ethernet_UIP/UIPUdp.h | 126 ++ .../drivers/Ethernet_UIP/ethernet_comp.h | 9 + .../AdvancedChatServer/AdvancedChatServer.ino | 104 + .../examples/EchoServer/EchoServer.ino | 58 + .../examples/TcpClient/TcpClient.ino | 76 + .../examples/TcpServer/TcpServer.ino | 53 + .../examples/UdpClient/UdpClient.ino | 93 + .../examples/UdpServer/UdpServer.ino | 88 + .../drivers/Ethernet_UIP/keywords.txt | 58 + .../drivers/Ethernet_UIP/library.properties | 10 + .../Ethernet_UIP/tests/perl/tcpclient.pl | 34 + .../Ethernet_UIP/tests/perl/tcpserver.pl | 53 + .../Ethernet_UIP/tests/perl/udpclient.pl | 26 + .../Ethernet_UIP/tests/perl/udpserver.pl | 40 + .../Ethernet_UIP/utility/Enc28J60Network.cpp | 612 ++++++ .../Ethernet_UIP/utility/Enc28J60Network.h | 91 + .../drivers/Ethernet_UIP/utility/clock-arch.c | 28 + .../drivers/Ethernet_UIP/utility/clock-arch.h | 27 + .../drivers/Ethernet_UIP/utility/enc28j60.h | 257 +++ .../drivers/Ethernet_UIP/utility/mempool.cpp | 168 ++ .../drivers/Ethernet_UIP/utility/mempool.h | 54 + .../Ethernet_UIP/utility/mempool_conf.h | 34 + .../drivers/Ethernet_UIP/utility/uip-conf.h | 185 ++ .../drivers/Ethernet_UIP/utility/uip.c | 1897 +++++++++++++++++ .../drivers/Ethernet_UIP/utility/uip.h | 1601 ++++++++++++++ .../drivers/Ethernet_UIP/utility/uip_arch.h | 138 ++ .../drivers/Ethernet_UIP/utility/uip_arp.c | 423 ++++ .../drivers/Ethernet_UIP/utility/uip_arp.h | 144 ++ .../drivers/Ethernet_UIP/utility/uip_clock.h | 88 + .../Ethernet_UIP/utility/uip_debug.cpp | 170 ++ .../drivers/Ethernet_UIP/utility/uip_debug.h | 18 + .../drivers/Ethernet_UIP/utility/uip_timer.c | 127 ++ .../drivers/Ethernet_UIP/utility/uip_timer.h | 86 + .../Ethernet_UIP/utility/uipethernet-conf.h | 29 + .../drivers/Ethernet_UIP/utility/uipopt.h | 543 +++++ .../drivers/Ethernet_UIP/utility/util.h | 13 + .../MySensors/drivers/Ethernet_W5100/Client.h | 45 + .../MySensors/drivers/Ethernet_W5100/Dhcp.cpp | 471 ++++ .../MySensors/drivers/Ethernet_W5100/Dhcp.h | 177 ++ .../MySensors/drivers/Ethernet_W5100/Dns.cpp | 423 ++++ .../MySensors/drivers/Ethernet_W5100/Dns.h | 41 + .../drivers/Ethernet_W5100/Ethernet.cpp | 136 ++ .../drivers/Ethernet_W5100/Ethernet.h | 41 + .../drivers/Ethernet_W5100/EthernetClient.cpp | 177 ++ .../drivers/Ethernet_W5100/EthernetClient.h | 42 + .../drivers/Ethernet_W5100/EthernetServer.cpp | 92 + .../drivers/Ethernet_W5100/EthernetServer.h | 22 + .../drivers/Ethernet_W5100/EthernetUdp.cpp | 252 +++ .../drivers/Ethernet_W5100/EthernetUdp.h | 102 + .../drivers/Ethernet_W5100/IPAddress.cpp | 74 + .../drivers/Ethernet_W5100/IPAddress.h | 75 + .../MySensors/drivers/Ethernet_W5100/Server.h | 30 + .../drivers/Ethernet_W5100/utility/socket.cpp | 469 ++++ .../drivers/Ethernet_W5100/utility/socket.h | 44 + .../drivers/Ethernet_W5100/utility/util.h | 14 + .../drivers/Ethernet_W5100/utility/w5100.cpp | 225 ++ .../drivers/Ethernet_W5100/utility/w5100.h | 422 ++++ libraries/MySensors/drivers/RF24/RF24.h | 4 +- .../MySensors/drivers/RF24/RF24_config.h | 20 +- libraries/MySensors/drivers/RFM69/RFM69.cpp | 2 +- libraries/MySensors/drivers/SPI/SPI.cpp | 201 ++ libraries/MySensors/drivers/SPI/SPI.h | 324 +++ .../BarometricPressureSensor.ino | 143 ++ .../DigitalPotControl/DigitalPotControl.ino | 71 + libraries/MySensors/drivers/SPI/keywords.txt | 36 + .../MySensors/drivers/SPI/library.properties | 9 + .../MySensors/drivers/SPIFlash/SPIFlash.h | 4 +- .../EthernetGateway/EthernetGateway.ino | 21 +- .../examples/MotionSensor/MotionSensor.ino | 8 +- 143 files changed, 15417 insertions(+), 500 deletions(-) rename libraries/MySensors/{ => core}/MyGatewayTransport.cpp (100%) rename libraries/MySensors/{ => core}/MyGatewayTransport.h (100%) rename libraries/MySensors/{ => core}/MyGatewayTransportEthernet.cpp (100%) rename libraries/MySensors/{ => core}/MyGatewayTransportEthernet.h (100%) rename libraries/MySensors/{ => core}/MyGatewayTransportSerial.cpp (100%) rename libraries/MySensors/{ => core}/MyGatewayTransportSerial.h (100%) rename libraries/MySensors/{ => core}/MyHw.cpp (100%) rename libraries/MySensors/{ => core}/MyHw.h (100%) rename libraries/MySensors/{ => core}/MyHwATMega328.cpp (98%) rename libraries/MySensors/{ => core}/MyHwATMega328.h (99%) rename libraries/MySensors/{ => core}/MyHwESP8266.cpp (100%) rename libraries/MySensors/{ => core}/MyHwESP8266.h (100%) rename libraries/MySensors/{ => core}/MyMessage.cpp (100%) rename libraries/MySensors/{ => core}/MyMessage.h (100%) rename libraries/MySensors/{ => core}/MyProtocol.cpp (100%) rename libraries/MySensors/{ => core}/MyProtocol.h (100%) rename libraries/MySensors/{ => core}/MyProtocolDefault.cpp (100%) rename libraries/MySensors/{ => core}/MyProtocolDefault.h (100%) rename libraries/MySensors/{MySensor.cpp => core/MySensorCore.cpp} (98%) create mode 100644 libraries/MySensors/core/MySensorCore.h rename libraries/MySensors/{ => core}/MySigning.cpp (100%) rename libraries/MySensors/{ => core}/MySigning.h (100%) rename libraries/MySensors/{ => core}/MySigningAtsha204.cpp (100%) rename libraries/MySensors/{ => core}/MySigningAtsha204.h (100%) rename libraries/MySensors/{ => core}/MySigningAtsha204Soft.cpp (100%) rename libraries/MySensors/{ => core}/MySigningAtsha204Soft.h (100%) rename libraries/MySensors/{ => core}/MySigningNone.cpp (100%) rename libraries/MySensors/{ => core}/MySigningNone.h (100%) rename libraries/MySensors/{ => core}/MyTransport.cpp (100%) rename libraries/MySensors/{ => core}/MyTransport.h (100%) rename libraries/MySensors/{ => core}/MyTransportNRF24.cpp (100%) rename libraries/MySensors/{ => core}/MyTransportNRF24.h (100%) rename libraries/MySensors/{ => core}/MyTransportRFM69.cpp (98%) rename libraries/MySensors/{ => core}/MyTransportRFM69.h (83%) rename libraries/MySensors/{ => core}/Version.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/DigitalIO.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/DigitalPin.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/I2cConstants.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/PinIO.cpp (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/PinIO.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/SoftI2cMaster.cpp (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/SoftI2cMaster.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/SoftSPI.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/attic/ADS7818.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/attic/MCP320X.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/attic/MCP355X.h (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/PinIOBegin/PinIOBegin.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/testArduino/testArduino.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/testDigitalPin/testDigitalPin.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/testFastDigital/testFastDigital.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/testPinIO/testPinIO.ino (100%) rename libraries/{ => MySensors/drivers}/DigitalIO/examples/testSoftSPI/testSoftSPI.ino (100%) create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/Dns.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/README create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/keywords.txt create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/library.properties create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.c create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h create mode 100644 libraries/MySensors/drivers/Ethernet_UIP/utility/util.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Client.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Dns.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/Server.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/utility/util.h create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp create mode 100644 libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h create mode 100644 libraries/MySensors/drivers/SPI/SPI.cpp create mode 100644 libraries/MySensors/drivers/SPI/SPI.h create mode 100644 libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino create mode 100644 libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino create mode 100644 libraries/MySensors/drivers/SPI/keywords.txt create mode 100644 libraries/MySensors/drivers/SPI/library.properties diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 9731a71..71d87c0 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -24,10 +24,10 @@ // Enable debug flag for debug prints. This will add a lot to the size of the final sketch but good // to see what is actually is happening when developing -#define MY_DEBUG +//#define MY_DEBUG -// Disable this line, If you are using TX(1), RX(0) as normal I/O pin -#define MY_ENABLED_SERIAL +// Enable this line, If you are using TX(1), RX(0) as normal I/O pin +// #define MY_DISABLED_SERIAL // Serial output baud rate (for debug prints and serial gateway) #ifndef MY_BAUD_RATE @@ -112,33 +112,41 @@ /********************************** * Message Signing Settings ***********************************/ -// Disable to completly disable signing functionality in library +// Disable to completely disable signing functionality in library //#define MY_SIGNING_FEATURE // Define a suitable timeout for a signature verification session -// Consider the turnaround from a nonce being generated to a signed message being received +// Consider the turn-around from a nonce being generated to a signed message being received // which might vary, especially in networks with many hops. 5s ought to be enough for anyone. +#ifndef MY_VERIFICATION_TIMEOUT_MS #define MY_VERIFICATION_TIMEOUT_MS 5000 +#endif -// Enable to turn on whitelisting +// Enable to turn on white-listing // When enabled, a signing node will salt the signature with it's unique signature and nodeId. // The verifying node will look up the sender in a local table of trusted nodes and // do the corresponding salting in order to verify the signature. -// For this reason, if whitelisting is enabled on one of the nodes in a sign-verify pair, both -// nodes have to implement whitelisting for this to work. -// Note that a node can still transmit a non-salted message (i.e. have whitelisting disabled) -// to a node that has whitelisting enabled (assuming the receiver does not have a matching entry -// for the sender in it's whitelist) +// For this reason, if white listing is enabled on one of the nodes in a sign-verify pair, both +// nodes have to implement white listing for this to work. +// Note that a node can still transmit a non-salted message (i.e. have white listing disabled) +// to a node that has white listing enabled (assuming the receiver does not have a matching entry +// for the sender in it's white list) //#define MY_SECURE_NODE_WHITELISTING // MySigningAtsha204 default setting +#ifndef MY_ATSHA204_PIN #define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached +#endif // MySigningAtsha204Soft default settings +#ifndef MY_RANDOMSEED_PIN #define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) +#endif // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) +#ifndef MY_HMAC_KEY #define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +#endif /********************************** * NRF24L01 Driver Defaults @@ -155,30 +163,48 @@ #define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) // Enable SOFTSPI for NRF24L01 when using the W5100 Ethernet module -//#define SOFTSPI -#ifdef SOFTSPI - // Define the soft SPI pins used for NRF radio - const uint8_t SOFT_SPI_MISO_PIN = 16; - const uint8_t SOFT_SPI_MOSI_PIN = 15; - const uint8_t SOFT_SPI_SCK_PIN = 14; -#endif +//#define MY_SOFTSPI +#ifndef MY_SOFT_SPI_SCK_PIN +#define MY_SOFT_SPI_SCK_PIN 14 +#endif +#ifndef MY_SOFT_SPI_MISO_PIN +#define MY_SOFT_SPI_MISO_PIN 16 +#endif +#ifndef MY_SOFT_SPI_MOSI_PIN +#define MY_SOFT_SPI_MOSI_PIN 15 +#endif /********************************** * RFM69 Driver Defaults ***********************************/ -// Default network id. Use the same for all nodes that will talk to each other -#define RFM69_NETWORKID 100 // Default frequency to use. This must match the hardware version of the RFM69 radio (uncomment one): -// #define RFM69_FREQUENCY RF69_433MHZ -#define RFM69_FREQUENCY RF69_868MHZ -//#define FREQUENCY RF69_915MHZ +#ifndef MY_RFM69_FREQUENCY +// #define MY_RFM69_FREQUENCY RF69_433MHZ +#define MY_RFM69_FREQUENCY RF69_868MHZ +//#define MY_RFM69_FREQUENCY RF69_915MHZ +#endif + +// Default network id. Use the same for all nodes that will talk to each other +#ifndef MY_RFM69_NETWORKID +#define MY_RFM69_NETWORKID 100 +#endif +#ifndef MY_RF69_IRQ_PIN +#define MY_RF69_IRQ_PIN RF69_IRQ_PIN +#endif +#ifndef MY_RF69_SPI_CS +#define MY_RF69_SPI_CS RF69_SPI_CS +#endif +#ifndef MY_RF69_IRQ_NUM +#define MY_RF69_IRQ_NUM RF69_IRQ_NUM +#endif // Enable this for encryption of packets -//#define RFM69_ENABLE_ENCRYPTION -#define RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! - +//#define MY_RFM69_ENABLE_ENCRYPTION +#ifndef MY_RFM69_ENCRYPTKEY +#define MY_RFM69_ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#endif /************************************** * Gateway Transport Ethernet Defaults diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index b1d3795..94f7e45 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -21,430 +21,45 @@ #ifndef MySensor_h #define MySensor_h -#include "Version.h" // Auto generated by bot #include "MyConfig.h" -#include "MyHw.h" -#include "MyTransport.h" -#include "MyTransportNRF24.h" -#ifdef MY_SIGNING_FEATURE -#include "MySigning.h" -#include "MySigningNone.h" -#endif -#include "MyMessage.h" -#ifdef MY_OTA_FIRMWARE_FEATURE -#include "drivers/SPIFlash/SPIFlash.h" -#endif -#include "MyGatewayTransport.h" -#include "MyGatewayTransportSerial.h" +// Include drivers +#include "drivers/SPI/SPI.cpp" -#include -#include +#include "drivers/RF24/RF24.cpp" +#include "drivers/RFM69/RFM69.cpp" -// Set the hardware driver to use (initialized by MySensor-class) -//#if defined __AVR_ATmega328P__ -#if defined(ARDUINO_ARCH_ESP8266) -#include "MyHwESP8266.h" -typedef MyHwESP8266 MyHwDriver; -#elif defined(ARDUINO_ARCH_AVR) -#include "MyHwATMega328.h" -typedef MyHwATMega328 MyHwDriver; -#endif -//#endif +#include "drivers/ATSHA204/ATSHA204.cpp" +#include "drivers/ATSHA204/sha256.cpp" +#include "drivers/SPIFlash/SPIFlash.cpp" -#ifdef MY_DEBUG -#define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__) -#else -#define debug(x,...) -#endif +#include "drivers/Ethernet_W5100/utility/socket.cpp" +#include "drivers/Ethernet_W5100/utility/w5100.cpp" +#include "drivers/Ethernet_W5100/DNS.cpp" +#include "drivers/Ethernet_W5100/Ethernet.cpp" +#include "drivers/Ethernet_W5100/EthernetUdp.cpp" +#include "drivers/Ethernet_W5100/IPAddress.cpp" -#ifdef WITH_LEDS_BLINKING_INVERSE -#define LED_ON 0x1 -#define LED_OFF 0x0 -#else -#define LED_ON 0x0 -#define LED_OFF 0x1 -#endif -// EEPROM start address for mysensors library data -#define EEPROM_START 0 -// EEPROM location of node id -#define EEPROM_NODE_ID_ADDRESS EEPROM_START -// EEPROM location of parent id -#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_START+1) -// EEPROM location of distance to gateway -#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1) -#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes. -#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller) -#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) -#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) -#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) -#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) -#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration +// Include core classes +#include "core/MyHw.cpp" +#include "core/MyHwATMega328.cpp" +#include "core/MyTransport.cpp" +#include "core/MyTransportNRF24.cpp" +#include "core/MyTransportRFM69.cpp" -// Search for a new parent node after this many transmission failures -#define SEARCH_FAILURES 5 +#include "core/MyGatewayTransport.cpp" +#include "core/MyGatewayTransportSerial.cpp" +#include "core/MyMessage.cpp" +#include "core/MySensorCore.cpp" -struct NodeConfig -{ - uint8_t nodeId; // Current node id - uint8_t parentNodeId; // Where this node sends its messages - uint8_t distance; // This nodes distance to sensor net gateway (number of hops) -}; - -struct ControllerConfig { - uint8_t isMetric; -}; - - -// Size of each firmware block -#define FIRMWARE_BLOCK_SIZE 16 -// Number of times a firmware block should be requested before giving up -#define FIRMWARE_MAX_REQUESTS 5 -// Number of times to request a fw block before giving up -#define MY_OTA_RETRY 5 -// Number of millisecons before re-request a fw block -#define MY_OTA_RETRY_DELAY 500 -// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) -#define FIRMWARE_START_OFFSET 10 -// Bootloader version -#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 -#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 -#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) - - -// FW config structure, stored in eeprom -typedef struct { - uint16_t type; - uint16_t version; - uint16_t blocks; - uint16_t crc; -} __attribute__((packed)) NodeFirmwareConfig; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t blocks; - uint16_t crc; - uint16_t BLVersion; -} __attribute__((packed)) RequestFirmwareConfig; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t block; -} __attribute__((packed)) RequestFWBlock; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t block; - uint8_t data[FIRMWARE_BLOCK_SIZE]; -} __attribute__((packed)) ReplyFWBlock; - - -#ifdef __cplusplus -class MySensor -{ - public: - /** - * Constructor - * - * Creates a new instance of Sensor class. - * - */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() -#ifdef MY_SIGNING_FEATURE - , MySigning &signer=*new MySigningNone() -#endif - ); - - /** - * Begin operation of the MySensors library - * - * Call this in setup(), before calling any other sensor net library methods. - * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. - * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. - * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false - * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. - */ - - void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); - - /** - * Return the nodes nodeId. - */ - uint8_t getNodeId(); - - /** - * Each node must present all attached sensors before any values can be handled correctly by the controller. - * It is usually good to present all attached sensors after power-up in setup(). - * - * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. - * @param sensorType The sensor type. See sensor typedef in MyMessage.h. - * @param description A textual description of the sensor. - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * @param description A textual description of the sensor. - */ - void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); - - /** - * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. - * @param name String containing a short Sketch name or NULL if not applicable - * @param version String containing a short Sketch version or NULL if not applicable - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * - */ - void sendSketchInfo(const char *name, const char *version, bool ack=false); - - /** - * Sends a message to gateway or one of the other nodes in the radio network - * - * @param msg Message to send - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * @return true Returns true if message reached the first stop on its way to destination. - */ - bool send(MyMessage &msg, bool ack=false); - - - /** - * Send this nodes battery level to gateway. - * @param level Level between 0-100(%) - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * - */ - void sendBatteryLevel(uint8_t level, bool ack=false); - - /** - * Send a heartbeat message (I'm alive!) to the gateway/controller. - * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on. - */ - void sendHeartbeat(void); - - /** - * Requests a value from gateway or some other sensor in the radio network. - * Make sure to add callback-method in begin-method to handle request responses. - * - * @param childSensorId The unique child id for the different sensors connected to this Arduino. 0-254. - * @param variableType The variableType to fetch - * @param destination The nodeId of other node in radio network. Default is gateway - */ - void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GATEWAY_ADDRESS); - - /** - * Requests time from controller. Answer will be delivered to callback. - * - * @param callback for time request. Incoming argument is seconds since 1970. - */ - void requestTime(void (* timeCallback)(unsigned long)); - - - /** - * Processes incoming messages to this node. If this is a relaying node it will - * Returns true if there is a message addressed for this node just was received. - * Use callback to handle incoming messages. - */ - boolean process(); - - /** - * Returns the most recent node configuration received from controller - */ - ControllerConfig getConfig(); - - /** - * Save a state (in local EEPROM). Good for actuators to "remember" state between - * power cycles. - * - * You have 256 bytes to play with. Note that there is a limitation on the number - * of writes the EEPROM can handle (~100 000 cycles on ATMega328). - * - * @param pos The position to store value in (0-255) - * @param Value to store in position - */ - void saveState(uint8_t pos, uint8_t value); - - /** - * Load a state (from local EEPROM). - * - * @param pos The position to fetch value from (0-255) - * @return Value to store in position - */ - uint8_t loadState(uint8_t pos); - - /** - * Returns the last received message - */ - MyMessage& getLastMessage(void); - - - - /** - * Wait for a specified amount of time to pass. Keeps process()ing. - * This does not power-down the radio nor the Arduino. - * Because this calls process() in a loop, it is a good way to wait - * in your loop() on a repeater node or sensor that listens to messages. - * @param ms Number of milliseconds to sleep. - */ - void wait(unsigned long ms); - - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. - * @param ms Number of milliseconds to sleep. - */ - void sleep(unsigned long ms); - - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. - * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin - * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 - * @param interrupt Interrupt that should trigger the wakeup - * @param mode RISING, FALLING, CHANGE - * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return true if wake up was triggered by pin change and false means timer woke it up. - */ - bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); - - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. - * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin - * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 - * @param interrupt1 First interrupt that should trigger the wakeup - * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) - * @param interrupt2 Second interrupt that should trigger the wakeup - * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) - * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number wake up was triggered by pin change and negative if timer woke it up. - */ - int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); - -#ifdef MY_LEDS_BLINKING_FEATURE - /** - * Blink with LEDs - * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms - */ - void rxBlink(uint8_t cnt); - void txBlink(uint8_t cnt); - void errBlink(uint8_t cnt); -#endif - - boolean sendRoute(MyMessage &message); - - protected: - NodeConfig nc; // Essential settings for node to work - ControllerConfig cc; // Configuration coming from controller -#ifdef MY_OTA_FIRMWARE_FEATURE - NodeFirmwareConfig fc; - bool fwUpdateOngoing; - unsigned long fwLastRequestTime; - uint16_t fwBlock; - uint8_t fwRetry; - SPIFlash flash; -#endif - - bool repeaterMode; - bool autoFindParent; - bool isGateway; - - MyMessage msg; // Buffer for incoming messages. - MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). - -#ifdef MY_LEDS_BLINKING_FEATURE - // these variables don't need to be volatile, since we are not using interrupts - uint8_t countRx; - uint8_t countTx; - uint8_t countErr; - - void handleLedsBlinking(); // do the actual blinking - unsigned long blink_next_time; -#endif - - MyTransport& radio; -#ifdef MY_SIGNING_FEATURE - uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication - MyMessage msgSign; // Buffer for message to sign. - MySigning& signer; -#endif - MyHw& hw; - - boolean sendWrite(uint8_t dest, MyMessage &message); - void processInternalMessages(MyMessage &msg); -#ifdef MY_DEBUG - char convBuf[MAX_PAYLOAD*2+1]; -#endif - uint8_t failedTransmissions; - uint16_t heartbeat; - void (*timeCallback)(unsigned long); // Callback for requested time messages - void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. - -#ifdef MY_OTA_FIRMWARE_FEATURE -// do a crc16 on the whole received firmware - bool isValidFirmware(); -#endif - - private: - - void requestNodeId(); - void setupNode(); - void findParentNode(); - uint8_t crc8Message(MyMessage &message); -}; -#endif - - -class MyGateway : public MySensor -{ -public: - // MyProtocolSerial constructor - MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() -#ifdef MY_SIGNING_FEATURE - , MySigning &signer=*new MySigningNone() -#endif - ); - - - /** - * Begin operation of the MySensors library - * - * Call this in setup(), before calling any other sensor net library methods. - * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. - * @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled - * @param inclusionModeButtonPin Button pin used for enabling inclusion mode - */ - - void begin(void (* msgCallback)(const MyMessage &)=NULL); - - - /** - * See MySensor.h - * - * Overloaded to handle local sensor data sent to controller. - */ - boolean sendRoute(MyMessage &message); - - /** - * Processes incoming messages to this node. - * Returns true if there is a message addressed for this node was received. - * Preferred way of handling incoming messages is to use the callback defined in begin(). - */ - boolean process(); - -private: - - MyGatewayTransport& transport; - -#ifdef MY_INCLUSION_MODE_FEATURE - - void setInclusionMode(bool newMode); - void checkInclusionMode(); - unsigned long inclusionStartTime; - bool inclusionMode; -#endif -}; +// Initialize library +MyTransportRFM69 transport; +MySensor gw; #endif diff --git a/libraries/MySensors/MyGatewayTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.cpp similarity index 100% rename from libraries/MySensors/MyGatewayTransport.cpp rename to libraries/MySensors/core/MyGatewayTransport.cpp diff --git a/libraries/MySensors/MyGatewayTransport.h b/libraries/MySensors/core/MyGatewayTransport.h similarity index 100% rename from libraries/MySensors/MyGatewayTransport.h rename to libraries/MySensors/core/MyGatewayTransport.h diff --git a/libraries/MySensors/MyGatewayTransportEthernet.cpp b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp similarity index 100% rename from libraries/MySensors/MyGatewayTransportEthernet.cpp rename to libraries/MySensors/core/MyGatewayTransportEthernet.cpp diff --git a/libraries/MySensors/MyGatewayTransportEthernet.h b/libraries/MySensors/core/MyGatewayTransportEthernet.h similarity index 100% rename from libraries/MySensors/MyGatewayTransportEthernet.h rename to libraries/MySensors/core/MyGatewayTransportEthernet.h diff --git a/libraries/MySensors/MyGatewayTransportSerial.cpp b/libraries/MySensors/core/MyGatewayTransportSerial.cpp similarity index 100% rename from libraries/MySensors/MyGatewayTransportSerial.cpp rename to libraries/MySensors/core/MyGatewayTransportSerial.cpp diff --git a/libraries/MySensors/MyGatewayTransportSerial.h b/libraries/MySensors/core/MyGatewayTransportSerial.h similarity index 100% rename from libraries/MySensors/MyGatewayTransportSerial.h rename to libraries/MySensors/core/MyGatewayTransportSerial.h diff --git a/libraries/MySensors/MyHw.cpp b/libraries/MySensors/core/MyHw.cpp similarity index 100% rename from libraries/MySensors/MyHw.cpp rename to libraries/MySensors/core/MyHw.cpp diff --git a/libraries/MySensors/MyHw.h b/libraries/MySensors/core/MyHw.h similarity index 100% rename from libraries/MySensors/MyHw.h rename to libraries/MySensors/core/MyHw.h diff --git a/libraries/MySensors/MyHwATMega328.cpp b/libraries/MySensors/core/MyHwATMega328.cpp similarity index 98% rename from libraries/MySensors/MyHwATMega328.cpp rename to libraries/MySensors/core/MyHwATMega328.cpp index ad05033..b20d337 100644 --- a/libraries/MySensors/MyHwATMega328.cpp +++ b/libraries/MySensors/core/MyHwATMega328.cpp @@ -121,7 +121,7 @@ void powerDown(period_t period) { void MyHwATMega328::internalSleep(unsigned long ms) { // Let serial prints finish (debug, log etc) - #ifdef MY_ENABLED_SERIAL + #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif pinIntTrigger = 0; @@ -152,7 +152,7 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { pinTriggeredWakeup = false; } } else { - #ifdef MY_ENABLED_SERIAL + #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif powerDown(SLEEP_FOREVER); @@ -172,7 +172,7 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i retVal = -1; } } else { - #ifdef MY_ENABLED_SERIAL + #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif powerDown(SLEEP_FOREVER); diff --git a/libraries/MySensors/MyHwATMega328.h b/libraries/MySensors/core/MyHwATMega328.h similarity index 99% rename from libraries/MySensors/MyHwATMega328.h rename to libraries/MySensors/core/MyHwATMega328.h index a992ff2..3468db6 100644 --- a/libraries/MySensors/MyHwATMega328.h +++ b/libraries/MySensors/core/MyHwATMega328.h @@ -36,7 +36,6 @@ #ifdef __cplusplus #include -#include #endif #if defined __AVR_ATmega328P__ diff --git a/libraries/MySensors/MyHwESP8266.cpp b/libraries/MySensors/core/MyHwESP8266.cpp similarity index 100% rename from libraries/MySensors/MyHwESP8266.cpp rename to libraries/MySensors/core/MyHwESP8266.cpp diff --git a/libraries/MySensors/MyHwESP8266.h b/libraries/MySensors/core/MyHwESP8266.h similarity index 100% rename from libraries/MySensors/MyHwESP8266.h rename to libraries/MySensors/core/MyHwESP8266.h diff --git a/libraries/MySensors/MyMessage.cpp b/libraries/MySensors/core/MyMessage.cpp similarity index 100% rename from libraries/MySensors/MyMessage.cpp rename to libraries/MySensors/core/MyMessage.cpp diff --git a/libraries/MySensors/MyMessage.h b/libraries/MySensors/core/MyMessage.h similarity index 100% rename from libraries/MySensors/MyMessage.h rename to libraries/MySensors/core/MyMessage.h diff --git a/libraries/MySensors/MyProtocol.cpp b/libraries/MySensors/core/MyProtocol.cpp similarity index 100% rename from libraries/MySensors/MyProtocol.cpp rename to libraries/MySensors/core/MyProtocol.cpp diff --git a/libraries/MySensors/MyProtocol.h b/libraries/MySensors/core/MyProtocol.h similarity index 100% rename from libraries/MySensors/MyProtocol.h rename to libraries/MySensors/core/MyProtocol.h diff --git a/libraries/MySensors/MyProtocolDefault.cpp b/libraries/MySensors/core/MyProtocolDefault.cpp similarity index 100% rename from libraries/MySensors/MyProtocolDefault.cpp rename to libraries/MySensors/core/MyProtocolDefault.cpp diff --git a/libraries/MySensors/MyProtocolDefault.h b/libraries/MySensors/core/MyProtocolDefault.h similarity index 100% rename from libraries/MySensors/MyProtocolDefault.h rename to libraries/MySensors/core/MyProtocolDefault.h diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/core/MySensorCore.cpp similarity index 98% rename from libraries/MySensors/MySensor.cpp rename to libraries/MySensors/core/MySensorCore.cpp index 6a8f96e..32b4e8e 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -19,27 +19,7 @@ -#include "MySensor.h" - - - -#include "drivers/RF24/RF24.cpp" - -#include "drivers/RFM69/RFM69.cpp" - -#include "drivers/ATSHA204/ATSHA204.cpp" -#include "drivers/ATSHA204/sha256.cpp" - -#include "drivers/SPIFlash/SPIFlash.cpp" - - -#include "drivers/Ethernet_W5100/utility/socket.cpp" -#include "drivers/Ethernet_W5100/utility/w5100.cpp" -#include "drivers/Ethernet_W5100/DNS.cpp" -#include "drivers/Ethernet_W5100/Ethernet.cpp" -#include "drivers/Ethernet_W5100/EthernetUdp.cpp" -#include "drivers/Ethernet_W5100/IPAddress.cpp" - +#include "MySensorCore.h" #define DISTANCE_INVALID (0xFF) @@ -168,7 +148,7 @@ void MySensor::errBlink(uint8_t cnt) { #endif void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { - #ifdef MY_ENABLED_SERIAL + #ifndef MY_DISABLED_SERIAL hw_init(); #endif repeaterMode = _repeaterMode; diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h new file mode 100644 index 0000000..5636b29 --- /dev/null +++ b/libraries/MySensors/core/MySensorCore.h @@ -0,0 +1,448 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + + +#ifndef MySensorCore_h +#define MySensorCore_h + +#include "Version.h" // Auto generated by bot +#include "MyConfig.h" +#include "MyHw.h" +#include "MyTransport.h" +#include "MyTransportNRF24.h" +#ifdef MY_SIGNING_FEATURE +#include "MySigning.h" +#include "MySigningNone.h" +#endif +#include "MyMessage.h" +#ifdef MY_OTA_FIRMWARE_FEATURE +#include "drivers/SPIFlash/SPIFlash.h" +#endif + +#include "MyGatewayTransport.h" +#include "MyGatewayTransportSerial.h" + +#include +#include + + +// Set the hardware driver to use (initialized by MySensor-class) +#if defined(ARDUINO_ARCH_ESP8266) +#include "MyHwESP8266.h" +typedef MyHwESP8266 MyHwDriver; +#elif defined(ARDUINO_ARCH_AVR) +#include "MyHwATMega328.h" +typedef MyHwATMega328 MyHwDriver; +#endif + + +#ifdef MY_DEBUG +#define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__) +#else +#define debug(x,...) +#endif + +#ifdef WITH_LEDS_BLINKING_INVERSE +#define LED_ON 0x1 +#define LED_OFF 0x0 +#else +#define LED_ON 0x0 +#define LED_OFF 0x1 +#endif + + +// EEPROM start address for mysensors library data +#define EEPROM_START 0 +// EEPROM location of node id +#define EEPROM_NODE_ID_ADDRESS EEPROM_START +// EEPROM location of parent id +#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_START+1) +// EEPROM location of distance to gateway +#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1) +#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes. +#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller) +#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) +#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) +#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) +#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) +#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration + +// Search for a new parent node after this many transmission failures +#define SEARCH_FAILURES 5 + + +struct NodeConfig +{ + uint8_t nodeId; // Current node id + uint8_t parentNodeId; // Where this node sends its messages + uint8_t distance; // This nodes distance to sensor net gateway (number of hops) +}; + +struct ControllerConfig { + uint8_t isMetric; +}; + + +// Size of each firmware block +#define FIRMWARE_BLOCK_SIZE 16 +// Number of times a firmware block should be requested before giving up +#define FIRMWARE_MAX_REQUESTS 5 +// Number of times to request a fw block before giving up +#define MY_OTA_RETRY 5 +// Number of millisecons before re-request a fw block +#define MY_OTA_RETRY_DELAY 500 +// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#define FIRMWARE_START_OFFSET 10 +// Bootloader version +#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 +#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 +#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) + + +// FW config structure, stored in eeprom +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; +} __attribute__((packed)) NodeFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; + uint16_t BLVersion; +} __attribute__((packed)) RequestFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; +} __attribute__((packed)) RequestFWBlock; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; + uint8_t data[FIRMWARE_BLOCK_SIZE]; +} __attribute__((packed)) ReplyFWBlock; + + +#ifdef __cplusplus +class MySensor +{ + public: + /** + * Constructor + * + * Creates a new instance of Sensor class. + * + */ + MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() +#ifdef MY_SIGNING_FEATURE + , MySigning &signer=*new MySigningNone() +#endif + ); + + /** + * Begin operation of the MySensors library + * + * Call this in setup(), before calling any other sensor net library methods. + * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. + * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. + * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false + * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. + */ + + void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); + + /** + * Return the nodes nodeId. + */ + uint8_t getNodeId(); + + /** + * Each node must present all attached sensors before any values can be handled correctly by the controller. + * It is usually good to present all attached sensors after power-up in setup(). + * + * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. + * @param sensorType The sensor type. See sensor typedef in MyMessage.h. + * @param description A textual description of the sensor. + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * @param description A textual description of the sensor. + */ + void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); + + /** + * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. + * @param name String containing a short Sketch name or NULL if not applicable + * @param version String containing a short Sketch version or NULL if not applicable + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * + */ + void sendSketchInfo(const char *name, const char *version, bool ack=false); + + /** + * Sends a message to gateway or one of the other nodes in the radio network + * + * @param msg Message to send + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * @return true Returns true if message reached the first stop on its way to destination. + */ + bool send(MyMessage &msg, bool ack=false); + + + /** + * Send this nodes battery level to gateway. + * @param level Level between 0-100(%) + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * + */ + void sendBatteryLevel(uint8_t level, bool ack=false); + + /** + * Send a heartbeat message (I'm alive!) to the gateway/controller. + * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on. + */ + void sendHeartbeat(void); + + /** + * Requests a value from gateway or some other sensor in the radio network. + * Make sure to add callback-method in begin-method to handle request responses. + * + * @param childSensorId The unique child id for the different sensors connected to this Arduino. 0-254. + * @param variableType The variableType to fetch + * @param destination The nodeId of other node in radio network. Default is gateway + */ + void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GATEWAY_ADDRESS); + + /** + * Requests time from controller. Answer will be delivered to callback. + * + * @param callback for time request. Incoming argument is seconds since 1970. + */ + void requestTime(void (* timeCallback)(unsigned long)); + + + /** + * Processes incoming messages to this node. If this is a relaying node it will + * Returns true if there is a message addressed for this node just was received. + * Use callback to handle incoming messages. + */ + boolean process(); + + /** + * Returns the most recent node configuration received from controller + */ + ControllerConfig getConfig(); + + /** + * Save a state (in local EEPROM). Good for actuators to "remember" state between + * power cycles. + * + * You have 256 bytes to play with. Note that there is a limitation on the number + * of writes the EEPROM can handle (~100 000 cycles on ATMega328). + * + * @param pos The position to store value in (0-255) + * @param Value to store in position + */ + void saveState(uint8_t pos, uint8_t value); + + /** + * Load a state (from local EEPROM). + * + * @param pos The position to fetch value from (0-255) + * @return Value to store in position + */ + uint8_t loadState(uint8_t pos); + + /** + * Returns the last received message + */ + MyMessage& getLastMessage(void); + + + + /** + * Wait for a specified amount of time to pass. Keeps process()ing. + * This does not power-down the radio nor the Arduino. + * Because this calls process() in a loop, it is a good way to wait + * in your loop() on a repeater node or sensor that listens to messages. + * @param ms Number of milliseconds to sleep. + */ + void wait(unsigned long ms); + + /** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. + * @param ms Number of milliseconds to sleep. + */ + void sleep(unsigned long ms); + + /** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. + * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin + * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 + * @param interrupt Interrupt that should trigger the wakeup + * @param mode RISING, FALLING, CHANGE + * @param ms Number of milliseconds to sleep or 0 to sleep forever + * @return true if wake up was triggered by pin change and false means timer woke it up. + */ + bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); + + /** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. + * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin + * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 + * @param interrupt1 First interrupt that should trigger the wakeup + * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) + * @param interrupt2 Second interrupt that should trigger the wakeup + * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) + * @param ms Number of milliseconds to sleep or 0 to sleep forever + * @return Interrupt number wake up was triggered by pin change and negative if timer woke it up. + */ + int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); + +#ifdef MY_LEDS_BLINKING_FEATURE + /** + * Blink with LEDs + * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms + */ + void rxBlink(uint8_t cnt); + void txBlink(uint8_t cnt); + void errBlink(uint8_t cnt); +#endif + + boolean sendRoute(MyMessage &message); + + protected: + NodeConfig nc; // Essential settings for node to work + ControllerConfig cc; // Configuration coming from controller +#ifdef MY_OTA_FIRMWARE_FEATURE + NodeFirmwareConfig fc; + bool fwUpdateOngoing; + unsigned long fwLastRequestTime; + uint16_t fwBlock; + uint8_t fwRetry; + SPIFlash flash; +#endif + + bool repeaterMode; + bool autoFindParent; + bool isGateway; + + MyMessage msg; // Buffer for incoming messages. + MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). + +#ifdef MY_LEDS_BLINKING_FEATURE + // these variables don't need to be volatile, since we are not using interrupts + uint8_t countRx; + uint8_t countTx; + uint8_t countErr; + + void handleLedsBlinking(); // do the actual blinking + unsigned long blink_next_time; +#endif + + MyTransport& radio; +#ifdef MY_SIGNING_FEATURE + uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication + MyMessage msgSign; // Buffer for message to sign. + MySigning& signer; +#endif + MyHw& hw; + + boolean sendWrite(uint8_t dest, MyMessage &message); + void processInternalMessages(MyMessage &msg); +#ifdef MY_DEBUG + char convBuf[MAX_PAYLOAD*2+1]; +#endif + uint8_t failedTransmissions; + uint16_t heartbeat; + void (*timeCallback)(unsigned long); // Callback for requested time messages + void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. + +#ifdef MY_OTA_FIRMWARE_FEATURE +// do a crc16 on the whole received firmware + bool isValidFirmware(); +#endif + + private: + + void requestNodeId(); + void setupNode(); + void findParentNode(); + uint8_t crc8Message(MyMessage &message); +}; +#endif + + +class MyGateway : public MySensor +{ +public: + // MyProtocolSerial constructor + MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() +#ifdef MY_SIGNING_FEATURE + , MySigning &signer=*new MySigningNone() +#endif + ); + + + /** + * Begin operation of the MySensors library + * + * Call this in setup(), before calling any other sensor net library methods. + * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. + * @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled + * @param inclusionModeButtonPin Button pin used for enabling inclusion mode + */ + + void begin(void (* msgCallback)(const MyMessage &)=NULL); + + + /** + * See MySensor.h + * + * Overloaded to handle local sensor data sent to controller. + */ + boolean sendRoute(MyMessage &message); + + /** + * Processes incoming messages to this node. + * Returns true if there is a message addressed for this node was received. + * Preferred way of handling incoming messages is to use the callback defined in begin(). + */ + boolean process(); + +private: + + MyGatewayTransport& transport; + +#ifdef MY_INCLUSION_MODE_FEATURE + + void setInclusionMode(bool newMode); + void checkInclusionMode(); + unsigned long inclusionStartTime; + bool inclusionMode; +#endif +}; + + +#endif diff --git a/libraries/MySensors/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp similarity index 100% rename from libraries/MySensors/MySigning.cpp rename to libraries/MySensors/core/MySigning.cpp diff --git a/libraries/MySensors/MySigning.h b/libraries/MySensors/core/MySigning.h similarity index 100% rename from libraries/MySensors/MySigning.h rename to libraries/MySensors/core/MySigning.h diff --git a/libraries/MySensors/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp similarity index 100% rename from libraries/MySensors/MySigningAtsha204.cpp rename to libraries/MySensors/core/MySigningAtsha204.cpp diff --git a/libraries/MySensors/MySigningAtsha204.h b/libraries/MySensors/core/MySigningAtsha204.h similarity index 100% rename from libraries/MySensors/MySigningAtsha204.h rename to libraries/MySensors/core/MySigningAtsha204.h diff --git a/libraries/MySensors/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp similarity index 100% rename from libraries/MySensors/MySigningAtsha204Soft.cpp rename to libraries/MySensors/core/MySigningAtsha204Soft.cpp diff --git a/libraries/MySensors/MySigningAtsha204Soft.h b/libraries/MySensors/core/MySigningAtsha204Soft.h similarity index 100% rename from libraries/MySensors/MySigningAtsha204Soft.h rename to libraries/MySensors/core/MySigningAtsha204Soft.h diff --git a/libraries/MySensors/MySigningNone.cpp b/libraries/MySensors/core/MySigningNone.cpp similarity index 100% rename from libraries/MySensors/MySigningNone.cpp rename to libraries/MySensors/core/MySigningNone.cpp diff --git a/libraries/MySensors/MySigningNone.h b/libraries/MySensors/core/MySigningNone.h similarity index 100% rename from libraries/MySensors/MySigningNone.h rename to libraries/MySensors/core/MySigningNone.h diff --git a/libraries/MySensors/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp similarity index 100% rename from libraries/MySensors/MyTransport.cpp rename to libraries/MySensors/core/MyTransport.cpp diff --git a/libraries/MySensors/MyTransport.h b/libraries/MySensors/core/MyTransport.h similarity index 100% rename from libraries/MySensors/MyTransport.h rename to libraries/MySensors/core/MyTransport.h diff --git a/libraries/MySensors/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp similarity index 100% rename from libraries/MySensors/MyTransportNRF24.cpp rename to libraries/MySensors/core/MyTransportNRF24.cpp diff --git a/libraries/MySensors/MyTransportNRF24.h b/libraries/MySensors/core/MyTransportNRF24.h similarity index 100% rename from libraries/MySensors/MyTransportNRF24.h rename to libraries/MySensors/core/MyTransportNRF24.h diff --git a/libraries/MySensors/MyTransportRFM69.cpp b/libraries/MySensors/core/MyTransportRFM69.cpp similarity index 98% rename from libraries/MySensors/MyTransportRFM69.cpp rename to libraries/MySensors/core/MyTransportRFM69.cpp index 757c9a5..ca29585 100644 --- a/libraries/MySensors/MyTransportRFM69.cpp +++ b/libraries/MySensors/core/MyTransportRFM69.cpp @@ -32,7 +32,7 @@ MyTransportRFM69::MyTransportRFM69(uint8_t freqBand, uint8_t networkId, uint8_t bool MyTransportRFM69::init() { // Start up the radio library (_address will be set later by the MySensors library) radio.initialize(_freqBand, _address, _networkId); -#ifdef RFM69_ENABLE_ENCRYPTION +#ifdef MY_RFM69_ENABLE_ENCRYPTION radio.encrypt(RFM69_ENCRYPTKEY); #endif return true; diff --git a/libraries/MySensors/MyTransportRFM69.h b/libraries/MySensors/core/MyTransportRFM69.h similarity index 83% rename from libraries/MySensors/MyTransportRFM69.h rename to libraries/MySensors/core/MyTransportRFM69.h index ea9eaa6..affbb25 100644 --- a/libraries/MySensors/MyTransportRFM69.h +++ b/libraries/MySensors/core/MyTransportRFM69.h @@ -24,13 +24,13 @@ #include "MyTransport.h" #include #include "drivers/RFM69/RFM69.h" -#include +#include "drivers/SPI/SPI.h" class MyTransportRFM69 : public MyTransport { public: - MyTransportRFM69(uint8_t freqBand=RFM69_FREQUENCY, uint8_t networkId=RFM69_NETWORKID, uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM); + MyTransportRFM69(uint8_t freqBand=MY_RFM69_FREQUENCY, uint8_t networkId=MY_RFM69_NETWORKID, uint8_t slaveSelectPin=MY_RF69_SPI_CS, uint8_t interruptPin=MY_RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=MY_RF69_IRQ_NUM); bool init(); void setAddress(uint8_t address); uint8_t getAddress(); diff --git a/libraries/MySensors/Version.h b/libraries/MySensors/core/Version.h similarity index 100% rename from libraries/MySensors/Version.h rename to libraries/MySensors/core/Version.h diff --git a/libraries/DigitalIO/DigitalIO.h b/libraries/MySensors/drivers/DigitalIO/DigitalIO.h similarity index 100% rename from libraries/DigitalIO/DigitalIO.h rename to libraries/MySensors/drivers/DigitalIO/DigitalIO.h diff --git a/libraries/DigitalIO/DigitalPin.h b/libraries/MySensors/drivers/DigitalIO/DigitalPin.h similarity index 100% rename from libraries/DigitalIO/DigitalPin.h rename to libraries/MySensors/drivers/DigitalIO/DigitalPin.h diff --git a/libraries/DigitalIO/I2cConstants.h b/libraries/MySensors/drivers/DigitalIO/I2cConstants.h similarity index 100% rename from libraries/DigitalIO/I2cConstants.h rename to libraries/MySensors/drivers/DigitalIO/I2cConstants.h diff --git a/libraries/DigitalIO/PinIO.cpp b/libraries/MySensors/drivers/DigitalIO/PinIO.cpp similarity index 100% rename from libraries/DigitalIO/PinIO.cpp rename to libraries/MySensors/drivers/DigitalIO/PinIO.cpp diff --git a/libraries/DigitalIO/PinIO.h b/libraries/MySensors/drivers/DigitalIO/PinIO.h similarity index 100% rename from libraries/DigitalIO/PinIO.h rename to libraries/MySensors/drivers/DigitalIO/PinIO.h diff --git a/libraries/DigitalIO/SoftI2cMaster.cpp b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp similarity index 100% rename from libraries/DigitalIO/SoftI2cMaster.cpp rename to libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp diff --git a/libraries/DigitalIO/SoftI2cMaster.h b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h similarity index 100% rename from libraries/DigitalIO/SoftI2cMaster.h rename to libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h diff --git a/libraries/DigitalIO/SoftSPI.h b/libraries/MySensors/drivers/DigitalIO/SoftSPI.h similarity index 100% rename from libraries/DigitalIO/SoftSPI.h rename to libraries/MySensors/drivers/DigitalIO/SoftSPI.h diff --git a/libraries/DigitalIO/attic/ADS7818.h b/libraries/MySensors/drivers/DigitalIO/attic/ADS7818.h similarity index 100% rename from libraries/DigitalIO/attic/ADS7818.h rename to libraries/MySensors/drivers/DigitalIO/attic/ADS7818.h diff --git a/libraries/DigitalIO/attic/MCP320X.h b/libraries/MySensors/drivers/DigitalIO/attic/MCP320X.h similarity index 100% rename from libraries/DigitalIO/attic/MCP320X.h rename to libraries/MySensors/drivers/DigitalIO/attic/MCP320X.h diff --git a/libraries/DigitalIO/attic/MCP355X.h b/libraries/MySensors/drivers/DigitalIO/attic/MCP355X.h similarity index 100% rename from libraries/DigitalIO/attic/MCP355X.h rename to libraries/MySensors/drivers/DigitalIO/attic/MCP355X.h diff --git a/libraries/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino b/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino similarity index 100% rename from libraries/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino rename to libraries/MySensors/drivers/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino diff --git a/libraries/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino b/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino similarity index 100% rename from libraries/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino rename to libraries/MySensors/drivers/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino diff --git a/libraries/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino b/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino similarity index 100% rename from libraries/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino rename to libraries/MySensors/drivers/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino diff --git a/libraries/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino b/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino similarity index 100% rename from libraries/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino rename to libraries/MySensors/drivers/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino diff --git a/libraries/DigitalIO/examples/PinIOBegin/PinIOBegin.ino b/libraries/MySensors/drivers/DigitalIO/examples/PinIOBegin/PinIOBegin.ino similarity index 100% rename from libraries/DigitalIO/examples/PinIOBegin/PinIOBegin.ino rename to libraries/MySensors/drivers/DigitalIO/examples/PinIOBegin/PinIOBegin.ino diff --git a/libraries/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino b/libraries/MySensors/drivers/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino similarity index 100% rename from libraries/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino rename to libraries/MySensors/drivers/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino diff --git a/libraries/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino b/libraries/MySensors/drivers/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino similarity index 100% rename from libraries/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino rename to libraries/MySensors/drivers/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino diff --git a/libraries/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino b/libraries/MySensors/drivers/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino similarity index 100% rename from libraries/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino rename to libraries/MySensors/drivers/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino diff --git a/libraries/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino b/libraries/MySensors/drivers/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino similarity index 100% rename from libraries/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino rename to libraries/MySensors/drivers/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino diff --git a/libraries/DigitalIO/examples/testArduino/testArduino.ino b/libraries/MySensors/drivers/DigitalIO/examples/testArduino/testArduino.ino similarity index 100% rename from libraries/DigitalIO/examples/testArduino/testArduino.ino rename to libraries/MySensors/drivers/DigitalIO/examples/testArduino/testArduino.ino diff --git a/libraries/DigitalIO/examples/testDigitalPin/testDigitalPin.ino b/libraries/MySensors/drivers/DigitalIO/examples/testDigitalPin/testDigitalPin.ino similarity index 100% rename from libraries/DigitalIO/examples/testDigitalPin/testDigitalPin.ino rename to libraries/MySensors/drivers/DigitalIO/examples/testDigitalPin/testDigitalPin.ino diff --git a/libraries/DigitalIO/examples/testFastDigital/testFastDigital.ino b/libraries/MySensors/drivers/DigitalIO/examples/testFastDigital/testFastDigital.ino similarity index 100% rename from libraries/DigitalIO/examples/testFastDigital/testFastDigital.ino rename to libraries/MySensors/drivers/DigitalIO/examples/testFastDigital/testFastDigital.ino diff --git a/libraries/DigitalIO/examples/testPinIO/testPinIO.ino b/libraries/MySensors/drivers/DigitalIO/examples/testPinIO/testPinIO.ino similarity index 100% rename from libraries/DigitalIO/examples/testPinIO/testPinIO.ino rename to libraries/MySensors/drivers/DigitalIO/examples/testPinIO/testPinIO.ino diff --git a/libraries/DigitalIO/examples/testSoftSPI/testSoftSPI.ino b/libraries/MySensors/drivers/DigitalIO/examples/testSoftSPI/testSoftSPI.ino similarity index 100% rename from libraries/DigitalIO/examples/testSoftSPI/testSoftSPI.ino rename to libraries/MySensors/drivers/DigitalIO/examples/testSoftSPI/testSoftSPI.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp b/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp new file mode 100644 index 0000000..d34e8e2 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp @@ -0,0 +1,478 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include +#include +#include "Dhcp.h" +#include "Arduino.h" +#include "utility/util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + _dhcpLeaseTime=0; + _dhcpT1=0; + _dhcpT2=0; + _lastCheck=0; + _timeout = timeout; + _responseTimeout = responseTimeout; + + // zero out _dhcpMacAddr + memset(_dhcpMacAddr, 0, 6); + reset_DHCP_lease(); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + _dhcp_state = STATE_DHCP_START; + return request_DHCP_lease(); +} + +void DhcpClass::reset_DHCP_lease(){ + // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpLocalIp, 0, 20); +} + +//return:0 on error, 1 if request is sent and response is received +int DhcpClass::request_DHCP_lease(){ + + uint8_t messageType = 0; + + + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + _dhcpUdpSocket.stop(); + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(_dhcp_state != STATE_DHCP_LEASED) + { + if(_dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_DISCOVER; + } + else if(_dhcp_state == STATE_DHCP_REREQUEST){ + _dhcpTransactionId++; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + else if(_dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(_dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_ACK) + { + _dhcp_state = STATE_DHCP_LEASED; + result = 1; + //use default lease time if we didn't get it + if(_dhcpLeaseTime == 0){ + _dhcpLeaseTime = DEFAULT_LEASE; + } + //calculate T1 & T2 if we didn't get it + if(_dhcpT1 == 0){ + //T1 should be 50% of _dhcpLeaseTime + _dhcpT1 = _dhcpLeaseTime >> 1; + } + if(_dhcpT2 == 0){ + //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime + _dhcpT2 = _dhcpT1 << 1; + } + _renewInSec = _dhcpT1; + _rebindInSec = _dhcpT2; + } + else if(messageType == DHCP_NAK) + _dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + _dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > _timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); + printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); + printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 30); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() ) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpT1value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1)); + _dhcpT1 = ntohl(_dhcpT1); + break; + + case dhcpT2value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2)); + _dhcpT2 = ntohl(_dhcpT2); + break; + + case dhcpIPaddrLeaseTime : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); + _dhcpLeaseTime = ntohl(_dhcpLeaseTime); + _renewInSec = _dhcpLeaseTime; + break; + + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + + +/* + returns: + 0/DHCP_CHECK_NONE: nothing happened + 1/DHCP_CHECK_RENEW_FAIL: renew failed + 2/DHCP_CHECK_RENEW_OK: renew success + 3/DHCP_CHECK_REBIND_FAIL: rebind fail + 4/DHCP_CHECK_REBIND_OK: rebind success +*/ +int DhcpClass::checkLease(){ + //this uses a signed / unsigned trick to deal with millis overflow + unsigned long now = millis(); + signed long snow = (long)now; + int rc=DHCP_CHECK_NONE; + if (_lastCheck != 0){ + signed long factor; + //calc how many ms past the timeout we are + factor = snow - (long)_secTimeout; + //if on or passed the timeout, reduce the counters + if ( factor >= 0 ){ + //next timeout should be now plus 1000 ms minus parts of second in factor + _secTimeout = snow + 1000 - factor % 1000; + //how many seconds late are we, minimum 1 + factor = factor / 1000 +1; + + //reduce the counters by that mouch + //if we can assume that the cycle time (factor) is fairly constant + //and if the remainder is less than cycle time * 2 + //do it early instead of late + if(_renewInSec < factor*2 ) + _renewInSec = 0; + else + _renewInSec -= factor; + + if(_rebindInSec < factor*2 ) + _rebindInSec = 0; + else + _rebindInSec -= factor; + } + + //if we have a lease but should renew, do it + if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){ + _dhcp_state = STATE_DHCP_REREQUEST; + rc = 1 + request_DHCP_lease(); + } + + //if we have a lease or is renewing but should bind, do it + if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){ + //this should basically restart completely + _dhcp_state = STATE_DHCP_START; + reset_DHCP_lease(); + rc = 3 + request_DHCP_lease(); + } + } + else{ + _secTimeout = snow + 1000; + } + + _lastCheck = now; + return rc; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + +void DhcpClass::printByte(char * buf, uint8_t n ) { + char *str = &buf[1]; + buf[0]='0'; + do { + unsigned long m = n; + n /= 16; + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h b/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h new file mode 100644 index 0000000..01405d7 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h @@ -0,0 +1,178 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "UIPUdp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "ENC28J" +#define DEFAULT_LEASE (900) //default lease time in seconds + +#define DHCP_CHECK_NONE (0) +#define DHCP_CHECK_RENEW_FAIL (1) +#define DHCP_CHECK_RENEW_OK (2) +#define DHCP_CHECK_REBIND_FAIL (3) +#define DHCP_CHECK_REBIND_OK (4) + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + signed long _renewInSec; + signed long _rebindInSec; + signed long _lastCheck; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _secTimeout; + uint8_t _dhcp_state; + UIPUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp b/libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp new file mode 100644 index 0000000..2b97fb7 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp @@ -0,0 +1,422 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "Udp.h" +#include "utility/util.h" + +#include "Dns.h" +#include +//#include +#include "Arduino.h" + + +#define SOCKET_NONE 255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p =aIPAddrString; + while (*p && + ( (*p == '.') || (*p >= '0') || (*p <= '9') )) + { + p++; + } + + if (*p == '\0') + { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + int segment =0; + int segmentValue =0; + while (*p && (segment < 4)) + { + if (*p == '.') + { + // We've reached the end of a segment + if (segmentValue > 255) + { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + segment++; + segmentValue = 0; + } + } + else + { + // Next digit + segmentValue = (segmentValue*10)+(*p - '0'); + } + p++; + } + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) + { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + return 1; + } + } + else + { + return 0; + } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ + int ret =0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) + { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) + { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) + { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) + { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) + { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) + { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) + { + ret = ProcessResponse(5000, aResult); + wait_retries++; + } + } + } + } + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) + { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) + { + end++; + } + + if (end-start > 0) + { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return 1; +} + + +uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) +{ + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) + { + if((millis() - startTime) > aTimeout) + return TIMED_OUT; + delay(50); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || + (iUdp.remotePort() != DNS_PORT) ) + { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) + { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*)&header[2])); + // Check that it's a response to this request + if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || + ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) + { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) + { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*)&header[6])); + if (answerCount == 0 ) + { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) + { + // Skip over the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if (len > 0) + { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i =0; i < 4; i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (uint16_t i =0; i < answerCount; i++) + { + // Skip the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) + { + // It's just a normal label + if (len > 0) + { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + else + { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i =0; i < TTL_SIZE; i++) + { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) + { + if (htons(header_flags) != 4) + { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9;//INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); + return SUCCESS; + } + else + { + // This isn't an answer type we're after, move onto the next one + for (uint16_t i =0; i < htons(header_flags); i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10;//INVALID_RESPONSE; +} + diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dns.h b/libraries/MySensors/drivers/Ethernet_UIP/Dns.h new file mode 100644 index 0000000..4913ca8 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include + +class DNSClient +{ +public: + // ctor + void begin(const IPAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char *aIPAddrString, IPAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + uint16_t BuildRequest(const char* aName); + uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + UIPUDP iUdp; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/README b/libraries/MySensors/drivers/Ethernet_UIP/README new file mode 100644 index 0000000..321b334 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/README @@ -0,0 +1,227 @@ +This is UIPEthernet version 1.09 + +An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS. +Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib! + +UIPEthernet is written as a wrapper around the mature uIP Stack by Adam Dunkels, which provides the low-level implementation for all supported protocols. To overcome the memory-constrains (a 'regular' uIP-application does all processing in RAM) the ENC28J60 internal memory is used for all stream buffers (in and out). Only 400-600 Bytes of Arduinos RAM are used (depending on the number of concurrently open connections). As of Flash-memory a ATmega368-based Arduino is the minimum requirenment. + +This library is written by Norbert Truchsess + +uIP was written by Adam Dunkels of the Networked Embedded Systems group at the Swedish Institute of Computer Science. + +This library was inspired by the SerialIP implementation by Adam Nielsen , actually I took this code as a starting point, but in the latest versions there are very few lines left. + +Installation +------------ + +To install the libraries, you need to place them into your "libraries" folder. You can find it within your Arduino IDE distribution within the "hardware" folder. + + C:\> cd [path to Arduino distribution]\libraries + C:\> git clone https://github.com/ntruchsess/arduino_uip UIPEthernet + +Be sure to restart the IDE if it was running. + +On a Mac, you will want to create a folder named "libraries" in in the "Documents" -> "Arduino" folder within your home directory. Clone the project there (and restart the IDE, if it was running during this process). + + $ cd ~/Documents/Arduino/libraries + $ git clone https://github.com/ntruchsess/arduino_uip UIPEthernet + +Or you download the zipped version of the library from https://github.com/ntruchsess/arduino_uip/releases, and copy the contained directory UIPEthernet to [path to Arduino distribution]\libraries\UIPEthernet. + +If you are running Arduino-IDE 1.5.x use release-version 1.59 or checkout branch 'Arduino_1.5.x' + +Additional information can be found on the Arduino website: http://www.arduino.cc/en/Hacking/Libraries + +Documentation +------------- + +For more information visit: + + - UIPEthernet Repository on github: + https://github.com/ntruchsess/arduino_uip + + - Arduino Ethernet library description + http://arduino.cc/en/Reference/Ethernet + (Arduino_uip uses the same API as that, just include "UIPEthernet.h", "UIPClient.h", "UIPServer.h" and "UIPUDP.h" instead of the stock "Ethernet.h", "EthernetClient.h", "EthernetServer.h " and "EthernetUDP.h") + + - uIP API reference: + http://www.sics.se/~adam/uip/uip-1.0-refman/ + + - Arduino forums + http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl + + - uIP homepage: + http://www.sics.se/~adam/uip/index.php/Main_Page + +Licenses +------------- + +UIPEthernet.h +UIPEthernet.cpp +UIPServer.h +UIPServer.cpp +UIPClient.h +UIPClient.cpp +UIPUdp.h +UIPUdp.cpp +utility/mempool.h +utility/mempool.cpp + +Copyright (c) 2013 Norbert Truchsess +All rights reserved. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +-------------- + +utility/enc28j60.h + +Author : Pascal Stang (c)2005 +Modified by Norbert Truchsess +Copyright: GPL V2 + +-------------- + +utility/Enc28J60Network.h +utility/Enc28J60Network.cpp + +Copyright (c) 2013 Norbert Truchsess +All rights reserved. + +inspired and based on enc28j60.c file from the AVRlib library by Pascal Stang. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +-------------- + +utility/uip.c +utility/uip_arp.h +utility/uip_arp.c +utility/uip_arch.h +utility/uip.h +utility/uipopt.h + +Copyright (c) 2001-2003, Adam Dunkels , . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +-------------- + +uip-conf.h +utility/uip-neighbor.h +utility/uip-neighbor.c +utility/uip_timer.h +utility/uip_timer.c +utility/uip_clock.h + +Author Adam Dunkels Adam Dunkels , +Copyright (c) 2004,2006, Swedish Institute of Computer Science. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +-------------- + +Dhcp.h +Dhcp.cpp + +DHCP Library v0.3 - April 25, 2009 +Author: Jordan Terrell - blog.jordanterrell.com +- as included in Arduinos stock Ethernet-library, no special licence mentioned here + +-------------- + +Dns.h +Dns.cpp + +(c) Copyright 2009-2010 MCQN Ltd. +Released under Apache License, version 2.0 + +-------------- + +clock-arch.h +clock-arch.c + +Copyright (c) 2010 Adam Nielsen +All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp b/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp new file mode 100644 index 0000000..d199cfe --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp @@ -0,0 +1,583 @@ +/* + UIPClient.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +extern "C" +{ +#import "utility/uip-conf.h" +#import "utility/uip.h" +#import "utility/uip_arp.h" +#import "string.h" +} +#include "UIPEthernet.h" +#include "UIPClient.h" +#include "Dns.h" + +#ifdef UIPETHERNET_DEBUG_CLIENT +#include "HardwareSerial.h" +#endif + +#define UIP_TCP_PHYH_LEN UIP_LLH_LEN+UIP_IPTCPH_LEN + +uip_userdata_t UIPClient::all_data[UIP_CONNS]; + +UIPClient::UIPClient() : + data(NULL) +{ +} + +UIPClient::UIPClient(uip_userdata_t* conn_data) : + data(conn_data) +{ +} + +int +UIPClient::connect(IPAddress ip, uint16_t port) +{ + stop(); + uip_ipaddr_t ipaddr; + uip_ip_addr(ipaddr, ip); + struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); + if (conn) + { +#if UIP_CONNECT_TIMEOUT > 0 + int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT; +#endif + while((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) + { + UIPEthernetClass::tick(); + if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) + { + data = (uip_userdata_t*) conn->appstate; +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("connected, state: ")); + Serial.print(data->state); + Serial.print(F(", first packet in: ")); + Serial.println(data->packets_in[0]); +#endif + return 1; + } +#if UIP_CONNECT_TIMEOUT > 0 + if (((int32_t)(millis() - timeout)) > 0) + { + conn->tcpstateflags = UIP_CLOSED; + break; + } +#endif + } + } + return 0; +} + +int +UIPClient::connect(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; +#if UIP_UDP + DNSClient dns; + IPAddress remote_addr; + + dns.begin(UIPEthernetClass::_dnsServerAddress); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } +#endif + return ret; +} + +void +UIPClient::stop() +{ + if (data && data->state) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("before stop(), with data")); + _dumpAllData(); +#endif + _flushBlocks(&data->packets_in[0]); + if (data->state & UIP_CLIENT_REMOTECLOSED) + { + data->state = 0; + } + else + { + data->state |= UIP_CLIENT_CLOSE; + } +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("after stop()")); + _dumpAllData(); +#endif + } +#ifdef UIPETHERNET_DEBUG_CLIENT + else + { + Serial.println(F("stop(), data: NULL")); + } +#endif + data = NULL; + UIPEthernetClass::tick(); +} + +uint8_t +UIPClient::connected() +{ + return (data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; +} + +bool +UIPClient::operator==(const UIPClient& rhs) +{ + return data && rhs.data && (data == rhs.data); +} + +UIPClient::operator bool() +{ + UIPEthernetClass::tick(); + return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); +} + +size_t +UIPClient::write(uint8_t c) +{ + return _write(data, &c, 1); +} + +size_t +UIPClient::write(const uint8_t *buf, size_t size) +{ + return _write(data, buf, size); +} + +size_t +UIPClient::_write(uip_userdata_t* u, const uint8_t *buf, size_t size) +{ + int remain = size; + uint16_t written; +#if UIP_ATTEMPTS_ON_WRITE > 0 + uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; +#endif + repeat: + UIPEthernetClass::tick(); + if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + { + uint8_t p = _currentBlock(&u->packets_out[0]); + if (u->packets_out[p] == NOBLOCK) + { +newpacket: + u->packets_out[p] = Enc28J60Network::allocBlock(UIP_SOCKET_DATALEN); + if (u->packets_out[p] == NOBLOCK) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if ((--attempts)>0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + u->out_pos = 0; + } +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient.write: writePacket(")); + Serial.print(u->packets_out[p]); + Serial.print(F(") pos: ")); + Serial.print(u->out_pos); + Serial.print(F(", buf[")); + Serial.print(size-remain); + Serial.print(F("-")); + Serial.print(remain); + Serial.print(F("]: '")); + Serial.write((uint8_t*)buf+size-remain,remain); + Serial.println(F("'")); +#endif + written = Enc28J60Network::writePacket(u->packets_out[p],u->out_pos,(uint8_t*)buf+size-remain,remain); + remain -= written; + u->out_pos+=written; + if (remain > 0) + { + if (p == UIP_SOCKET_NUMPACKETS-1) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if ((--attempts)>0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + p++; + goto newpacket; + } +ready: +#if UIP_CLIENT_TIMER >= 0 + u->timer = millis()+UIP_CLIENT_TIMER; +#endif + return size-remain; + } + return -1; +} + +int +UIPClient::available() +{ + if (*this) + return _available(data); + return 0; +} + +int +UIPClient::_available(uip_userdata_t *u) +{ + int len = 0; + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + len += Enc28J60Network::blockSize(u->packets_in[i]); + } + return len; +} + +int +UIPClient::read(uint8_t *buf, size_t size) +{ + if (*this) + { + uint16_t remain = size; + if (data->packets_in[0] == NOBLOCK) + return 0; + uint16_t read; + do + { + read = Enc28J60Network::readPacket(data->packets_in[0],0,buf+size-remain,remain); + if (read == Enc28J60Network::blockSize(data->packets_in[0])) + { + remain -= read; + _eatBlock(&data->packets_in[0]); + if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + data->state |= UIP_CLIENT_RESTART; + if (data->packets_in[0] == NOBLOCK) + { + if (data->state & UIP_CLIENT_REMOTECLOSED) + { + data->state = 0; + data = NULL; + } + return size-remain; + } + } + else + { + Enc28J60Network::resizeBlock(data->packets_in[0],read); + break; + } + } + while(remain > 0); + return size; + } + return -1; +} + +int +UIPClient::read() +{ + uint8_t c; + if (read(&c,1) < 0) + return -1; + return c; +} + +int +UIPClient::peek() +{ + if (*this) + { + if (data->packets_in[0] != NOBLOCK) + { + uint8_t c; + Enc28J60Network::readPacket(data->packets_in[0],0,&c,1); + return c; + } + } + return -1; +} + +void +UIPClient::flush() +{ + if (*this) + { + _flushBlocks(&data->packets_in[0]); + } +} + +void +uipclient_appcall(void) +{ + uint16_t send_len = 0; + uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate; + if (!u && uip_connected()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_connected")); + UIPClient::_dumpAllData(); +#endif + u = (uip_userdata_t*) UIPClient::_allocateData(); + if (u) + { + uip_conn->appstate = u; +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient allocated state: ")); + Serial.println(u->state,BIN); +#endif + } +#ifdef UIPETHERNET_DEBUG_CLIENT + else + Serial.println(F("UIPClient allocation failed")); +#endif + } + if (u) + { + if (uip_newdata()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient uip_newdata, uip_len:")); + Serial.println(uip_len); +#endif + if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + { + for (uint8_t i=0; i < UIP_SOCKET_NUMPACKETS; i++) + { + if (u->packets_in[i] == NOBLOCK) + { + u->packets_in[i] = Enc28J60Network::allocBlock(uip_len); + if (u->packets_in[i] != NOBLOCK) + { + Enc28J60Network::copyPacket(u->packets_in[i],0,UIPEthernetClass::in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len); + if (i == UIP_SOCKET_NUMPACKETS-1) + uip_stop(); + goto finish_newdata; + } + } + } + UIPEthernetClass::packetstate &= ~UIPETHERNET_FREEPACKET; + uip_stop(); + } + } +finish_newdata: + if (u->state & UIP_CLIENT_RESTART) + { + u->state &= ~UIP_CLIENT_RESTART; + uip_restart(); + } + // If the connection has been closed, save received but unread data. + if (uip_closed() || uip_timedout()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_closed")); + UIPClient::_dumpAllData(); +#endif + // drop outgoing packets not sent yet: + UIPClient::_flushBlocks(&u->packets_out[0]); + if (u->packets_in[0] != NOBLOCK) + { + ((uip_userdata_closed_t *)u)->lport = uip_conn->lport; + u->state |= UIP_CLIENT_REMOTECLOSED; + } + else + u->state = 0; + // disassociate appdata. +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("after UIPClient uip_closed")); + UIPClient::_dumpAllData(); +#endif + uip_conn->appstate = NULL; + goto finish; + } + if (uip_acked()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_acked")); +#endif + UIPClient::_eatBlock(&u->packets_out[0]); + } + if (uip_poll() || uip_rexmit()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + //Serial.println(F("UIPClient uip_poll")); +#endif + if (u->packets_out[0] != NOBLOCK) + { + if (u->packets_out[1] == NOBLOCK) + { + send_len = u->out_pos; + if (send_len > 0) + { + Enc28J60Network::resizeBlock(u->packets_out[0],0,send_len); + } + } + else + send_len = Enc28J60Network::blockSize(u->packets_out[0]); + if (send_len > 0) + { + UIPEthernetClass::uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf; + UIPEthernetClass::uip_packet = Enc28J60Network::allocBlock(UIPEthernetClass::uip_hdrlen+send_len); + if (UIPEthernetClass::uip_packet != NOBLOCK) + { + Enc28J60Network::copyPacket(UIPEthernetClass::uip_packet,UIPEthernetClass::uip_hdrlen,u->packets_out[0],0,send_len); + UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET; + } + } + goto finish; + } + } + // don't close connection unless all outgoing packets are sent + if (u->state & UIP_CLIENT_CLOSE) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient state UIP_CLIENT_CLOSE")); + UIPClient::_dumpAllData(); +#endif + if (u->packets_out[0] == NOBLOCK) + { + u->state = 0; + uip_conn->appstate = NULL; + uip_close(); +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("no blocks out -> free userdata")); + UIPClient::_dumpAllData(); +#endif + } + else + { + uip_stop(); +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("blocks outstanding transfer -> uip_stop()")); +#endif + } + } + } + finish: + uip_send(uip_appdata,send_len); + uip_len = send_len; +} + +uip_userdata_t * +UIPClient::_allocateData() +{ + for ( uint8_t sock = 0; sock < UIP_CONNS; sock++ ) + { + uip_userdata_t* data = &UIPClient::all_data[sock]; + if (!data->state) + { + data->state = sock | UIP_CLIENT_CONNECTED; + memset(&data->packets_in[0],0,sizeof(uip_userdata_t)-sizeof(data->state)); + return data; + } + } + return NULL; +} + +uint8_t +UIPClient::_currentBlock(memhandle* block) +{ + for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) + { + if (block[i] == NOBLOCK) + return i-1; + } + return UIP_SOCKET_NUMPACKETS-1; +} + +void +UIPClient::_eatBlock(memhandle* block) +{ +#ifdef UIPETHERNET_DEBUG_CLIENT + memhandle* start = block; + Serial.print(F("eatblock(")); + Serial.print(*block); + Serial.print(F("): ")); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Serial.print(start[i]); + Serial.print(F(" ")); + } + Serial.print(F("-> ")); +#endif + Enc28J60Network::freeBlock(block[0]); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS-1; i++) + { + block[i] = block[i+1]; + } + block[UIP_SOCKET_NUMPACKETS-1] = NOBLOCK; +#ifdef UIPETHERNET_DEBUG_CLIENT + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Serial.print(start[i]); + Serial.print(F(" ")); + } + Serial.println(); +#endif +} + +void +UIPClient::_flushBlocks(memhandle* block) +{ + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Enc28J60Network::freeBlock(block[i]); + block[i] = NOBLOCK; + } +} + +#ifdef UIPETHERNET_DEBUG_CLIENT +void +UIPClient::_dumpAllData() { + for (uint8_t i=0; i < UIP_CONNS; i++) + { + Serial.print(F("UIPClient::all_data[")); + Serial.print(i); + Serial.print(F("], state:")); + Serial.println(all_data[i].state, BIN); + Serial.print(F("packets_in: ")); + for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++) + { + Serial.print(all_data[i].packets_in[j]); + Serial.print(F(" ")); + } + Serial.println(); + if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) + { + Serial.print(F("state remote closed, local port: ")); + Serial.println(htons(((uip_userdata_closed_t *)(&all_data[i]))->lport)); + } + else + { + Serial.print(F("packets_out: ")); + for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++) + { + Serial.print(all_data[i].packets_out[j]); + Serial.print(F(" ")); + } + Serial.println(); + Serial.print(F("out_pos: ")); + Serial.println(all_data[i].out_pos); + } + } +} +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h b/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h new file mode 100644 index 0000000..6c0c006 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h @@ -0,0 +1,112 @@ +/* + UIPClient.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPCLIENT_H +#define UIPCLIENT_H + +#include "ethernet_comp.h" +#include "Print.h" +#import "Client.h" +#import "utility/mempool.h" + +extern "C" { + #import "utility/uip.h" +} + +#define UIP_SOCKET_DATALEN UIP_TCP_MSS +//#define UIP_SOCKET_NUMPACKETS UIP_RECEIVE_WINDOW/UIP_TCP_MSS+1 +#ifndef UIP_SOCKET_NUMPACKETS +#define UIP_SOCKET_NUMPACKETS 5 +#endif + +#define UIP_CLIENT_CONNECTED 0x10 +#define UIP_CLIENT_CLOSE 0x20 +#define UIP_CLIENT_REMOTECLOSED 0x40 +#define UIP_CLIENT_RESTART 0x80 +#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | UIP_CLIENT_RESTART) +#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS + +typedef uint8_t uip_socket_ptr; + +typedef struct { + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + uint16_t lport; /**< The local TCP port, in network byte order. */ +} uip_userdata_closed_t; + +typedef struct { + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + memhandle packets_out[UIP_SOCKET_NUMPACKETS]; + memaddress out_pos; +#if UIP_CLIENT_TIMER >= 0 + unsigned long timer; +#endif +} uip_userdata_t; + +class UIPClient : public Client { + +public: + UIPClient(); + int connect(IPAddress ip, uint16_t port); + int connect(const char *host, uint16_t port); + int read(uint8_t *buf, size_t size); + void stop(); + uint8_t connected(); + operator bool(); + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + + size_t write(uint8_t); + size_t write(const uint8_t *buf, size_t size); + int available(); + int read(); + int peek(); + void flush(); + + using Print::write; + +private: + UIPClient(struct uip_conn *_conn); + UIPClient(uip_userdata_t* conn_data); + + uip_userdata_t* data; + + static uip_userdata_t all_data[UIP_CONNS]; + static uip_userdata_t* _allocateData(); + + static size_t _write(uip_userdata_t *,const uint8_t *buf, size_t size); + static int _available(uip_userdata_t *); + + static uint8_t _currentBlock(memhandle* blocks); + static void _eatBlock(memhandle* blocks); + static void _flushBlocks(memhandle* blocks); + +#ifdef UIPETHERNET_DEBUG_CLIENT + static void _dumpAllData(); +#endif + + friend class UIPEthernetClass; + friend class UIPServer; + + friend void uipclient_appcall(void); + +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp b/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp new file mode 100644 index 0000000..91ec70a --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp @@ -0,0 +1,485 @@ +/* + UIPEthernet.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include "UIPEthernet.h" +#include "utility/Enc28J60Network.h" + +#if(defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM) +#include "HardwareSerial.h" +#endif + +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "utility/uip_timer.h" +} + +#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0]) + +memhandle UIPEthernetClass::in_packet(NOBLOCK); +memhandle UIPEthernetClass::uip_packet(NOBLOCK); +uint8_t UIPEthernetClass::uip_hdrlen(0); +uint8_t UIPEthernetClass::packetstate(0); + +IPAddress UIPEthernetClass::_dnsServerAddress; +DhcpClass* UIPEthernetClass::_dhcp(NULL); + +unsigned long UIPEthernetClass::periodic_timer; + +// Because uIP isn't encapsulated within a class we have to use global +// variables, so we can only have one TCP/IP stack per program. + +UIPEthernetClass::UIPEthernetClass() +{ +} + +#if UIP_UDP +int +UIPEthernetClass::begin(const uint8_t* mac) +{ + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + + // Initialise the basic info + init(mac); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP((uint8_t*)mac); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + } + return ret; +} +#endif + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) +{ + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) +{ + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + init(mac); + configure(ip,dns,gateway,subnet); +} + +int UIPEthernetClass::maintain(){ + tick(); + int rc = DHCP_CHECK_NONE; +#if UIP_UDP + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +#endif +} + +IPAddress UIPEthernetClass::localIP() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::subnetMask() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_getnetmask(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::gatewayIP() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_getdraddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +void +UIPEthernetClass::tick() +{ + if (in_packet == NOBLOCK) + { + in_packet = Enc28J60Network::receivePacket(); +#ifdef UIPETHERNET_DEBUG + if (in_packet != NOBLOCK) + { + Serial.print(F("--------------\nreceivePacket: ")); + Serial.println(in_packet); + } +#endif + } + if (in_packet != NOBLOCK) + { + packetstate = UIPETHERNET_FREEPACKET; + uip_len = Enc28J60Network::blockSize(in_packet); + if (uip_len > 0) + { + Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); + if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) + { + uip_packet = in_packet; //required for upper_layer_checksum of in_packet! +#ifdef UIPETHERNET_DEBUG + Serial.print(F("readPacket type IP, uip_len: ")); + Serial.println(uip_len); +#endif + uip_arp_ipin(); + uip_input(); + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } + else if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_ARP)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("readPacket type ARP, uip_len: ")); + Serial.println(uip_len); +#endif + uip_arp_arpin(); + if (uip_len > 0) + { + network_send(); + } + } + } + if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("freeing packet: ")); + Serial.println(in_packet); +#endif + Enc28J60Network::freePacket(); + in_packet = NOBLOCK; + } + } + + unsigned long now = millis(); + +#if UIP_CLIENT_TIMER >= 0 + boolean periodic = (long)( now - periodic_timer ) >= 0; + for (int i = 0; i < UIP_CONNS; i++) + { +#else + if ((long)( now - periodic_timer ) >= 0) + { + periodic_timer = now + UIP_PERIODIC_TIMER; + + for (int i = 0; i < UIP_CONNS; i++) + { +#endif + uip_conn = &uip_conns[i]; +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { +#endif + uip_process(UIP_TIMER); +#if UIP_CLIENT_TIMER >= 0 + } + else + { + if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) + uip_process(UIP_POLL_REQUEST); + else + continue; + } +#endif + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { + periodic_timer = now + UIP_PERIODIC_TIMER; +#endif +#if UIP_UDP + for (int i = 0; i < UIP_UDP_CONNS; i++) + { + uip_udp_periodic(i); + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. */ + if (uip_len > 0) + { + UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate)); + } + } +#endif /* UIP_UDP */ + } +} + +boolean UIPEthernetClass::network_send() +{ + if (packetstate & UIPETHERNET_SENDPACKET) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("Enc28J60Network_send uip_packet: ")); + Serial.print(uip_packet); + Serial.print(F(", hdrlen: ")); + Serial.println(uip_hdrlen); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen); + packetstate &= ~ UIPETHERNET_SENDPACKET; + goto sendandfree; + } + uip_packet = Enc28J60Network::allocBlock(uip_len); + if (uip_packet != NOBLOCK) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("Enc28J60Network_send uip_buf (uip_len): ")); + Serial.print(uip_len); + Serial.print(F(", packet: ")); + Serial.println(uip_packet); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_len); + goto sendandfree; + } + return false; +sendandfree: + Enc28J60Network::sendPacket(uip_packet); + Enc28J60Network::freeBlock(uip_packet); + uip_packet = NOBLOCK; + return true; +} + +void UIPEthernetClass::init(const uint8_t* mac) { + periodic_timer = millis() + UIP_PERIODIC_TIMER; + + Enc28J60Network::init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); + uip_arp_init(); +} + +void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + uip_ipaddr_t ipaddr; + + uip_ip_addr(ipaddr, ip); + uip_sethostaddr(ipaddr); + + uip_ip_addr(ipaddr, gateway); + uip_setdraddr(ipaddr); + + uip_ip_addr(ipaddr, subnet); + uip_setnetmask(ipaddr); + + _dnsServerAddress = dns; +} + +UIPEthernetClass UIPEthernet; + +/*---------------------------------------------------------------------------*/ +uint16_t +UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) +{ + uint16_t t; + const uint8_t *dataptr; + const uint8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +/*---------------------------------------------------------------------------*/ + +uint16_t +UIPEthernetClass::ipchksum(void) +{ + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return (sum == 0) ? 0xffff : htons(sum); +} + +/*---------------------------------------------------------------------------*/ +uint16_t +#if UIP_UDP +UIPEthernetClass::upper_layer_chksum(uint8_t proto) +#else +uip_tcpchksum(void) +#endif +{ + uint16_t upper_layer_len; + uint16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ +#if UIP_UDP + sum = upper_layer_len + proto; +#else + sum = upper_layer_len + UIP_PROTO_TCP; +#endif + /* Sum IP source and destination addresses. */ + sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; +#if UIP_UDP + switch(proto) + { +// case UIP_PROTO_ICMP: +// case UIP_PROTO_ICMP6: +// upper_layer_memlen = upper_layer_len; +// break; + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; + default: +// case UIP_PROTO_TCP: +#endif + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; +#if UIP_UDP + break; + } +#endif + sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print(F("chksum uip_buf[")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN); + Serial.print(F("-")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print(F("]: ")); + Serial.println(htons(sum),HEX); +#endif + if (upper_layer_memlen < upper_layer_len) + { + sum = Enc28J60Network::chksum( + sum, + UIPEthernetClass::uip_packet, + UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, + upper_layer_len - upper_layer_memlen + ); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print(F("chksum uip_packet(")); + Serial.print(uip_packet); + Serial.print(F(")[")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print(F("-")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); + Serial.print(F("]: ")); + Serial.println(htons(sum),HEX); +#endif + } + return (sum == 0) ? 0xffff : htons(sum); +} + +uint16_t +uip_ipchksum(void) +{ + return UIPEthernet.ipchksum(); +} + +#if UIP_UDP +uint16_t +uip_tcpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); + return sum; +} + +uint16_t +uip_udpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); + return sum; +} +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h b/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h new file mode 100644 index 0000000..c68d578 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h @@ -0,0 +1,127 @@ +/* + UIPEthernet.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPETHERNET_H +#define UIPETHERNET_H + +//#define UIPETHERNET_DEBUG +//#define UIPETHERNET_DEBUG_CHKSUM +//#define UIPETHERNET_DEBUG_UDP +//#define UIPETHERNET_DEBUG_CLIENT + +#include "ethernet_comp.h" +#include +#include "Dhcp.h" +#include "IPAddress.h" +#include "utility/Enc28J60Network.h" +#include "UIPClient.h" +#include "UIPServer.h" +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uip_timer.h" +#include "utility/uip.h" +} + +#define UIPETHERNET_FREEPACKET 1 +#define UIPETHERNET_SENDPACKET 2 +#define UIPETHERNET_BUFFERREAD 4 + +#define uip_ip_addr(addr, ip) do { \ + ((u16_t *)(addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \ + ((u16_t *)(addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \ + } while(0) + +#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8 , a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable + +#define uip_seteth_addr(eaddr) do {uip_ethaddr.addr[0] = eaddr[0]; \ + uip_ethaddr.addr[1] = eaddr[1];\ + uip_ethaddr.addr[2] = eaddr[2];\ + uip_ethaddr.addr[3] = eaddr[3];\ + uip_ethaddr.addr[4] = eaddr[4];\ + uip_ethaddr.addr[5] = eaddr[5];} while(0) + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +class UIPEthernetClass +{ +public: + UIPEthernetClass(); + + int begin(const uint8_t* mac); + void begin(const uint8_t* mac, IPAddress ip); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + // maintain() must be called at regular intervals to process the incoming serial + // data and issue IP events to the sketch. It does not return until all IP + // events have been processed. Renews dhcp-lease if required. + int maintain(); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + +private: + static memhandle in_packet; + static memhandle uip_packet; + static uint8_t uip_hdrlen; + static uint8_t packetstate; + + static IPAddress _dnsServerAddress; + static DhcpClass* _dhcp; + + static unsigned long periodic_timer; + + static void init(const uint8_t* mac); + static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + static void tick(); + + static boolean network_send(); + + friend class UIPServer; + + friend class UIPClient; + + friend class UIPUDP; + + static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); + static uint16_t ipchksum(void); +#if UIP_UDP + static uint16_t upper_layer_chksum(uint8_t proto); +#endif + friend uint16_t uip_ipchksum(void); + friend uint16_t uip_tcpchksum(void); + friend uint16_t uip_udpchksum(void); + + friend void uipclient_appcall(void); + friend void uipudp_appcall(void); + +#if UIP_CONF_IPV6 + uint16_t uip_icmp6chksum(void); +#endif /* UIP_CONF_IPV6 */ +}; + +extern UIPEthernetClass UIPEthernet; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp b/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp new file mode 100644 index 0000000..21c7ef5 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp @@ -0,0 +1,63 @@ +/* + UIPServer.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include "UIPEthernet.h" +#include "UIPServer.h" +extern "C" { + #include "utility/uip-conf.h" +} + +UIPServer::UIPServer(uint16_t port) : _port(htons(port)) +{ +} + +UIPClient UIPServer::available() +{ + UIPEthernetClass::tick(); + for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ ) + { + if (data->packets_in[0] != NOBLOCK + && (((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port) + || ((data->state & UIP_CLIENT_REMOTECLOSED) && ((uip_userdata_closed_t *)data)->lport == _port))) + return UIPClient(data); + } + return UIPClient(); +} + +void UIPServer::begin() +{ + uip_listen(_port); + UIPEthernetClass::tick(); +} + +size_t UIPServer::write(uint8_t c) +{ + return write(&c,1); +} + +size_t UIPServer::write(const uint8_t *buf, size_t size) +{ + size_t ret = 0; + for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ ) + { + if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port) + ret += UIPClient::_write(data,buf,size); + } + return ret; +} + diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h b/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h new file mode 100644 index 0000000..0cc0619 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h @@ -0,0 +1,40 @@ +/* + UIPServer.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef UIPSERVER_H +#define UIPSERVER_H + +#include "ethernet_comp.h" +#import "Server.h" +#import "UIPClient.h" + +class UIPServer : public Server { + +public: + UIPServer(uint16_t); + UIPClient available(); + void begin(); + size_t write(uint8_t); + size_t write(const uint8_t *buf, size_t size); + using Print::write; + +private: + uint16_t _port; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp b/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp new file mode 100644 index 0000000..3deb2c4 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp @@ -0,0 +1,383 @@ +/* + UIPUdp.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "UIPEthernet.h" +#include "UIPUdp.h" +#include "Dns.h" + +#ifdef UIPETHERNET_DEBUG_UDP +#include "HardwareSerial.h" +#endif + +extern "C" { +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +} + +#if UIP_UDP +#define UIP_ARPHDRSIZE 42 +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +// Constructor +UIPUDP::UIPUDP() : + _uip_udp_conn(NULL) +{ + memset(&appdata,0,sizeof(appdata)); +} + +// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use +uint8_t +UIPUDP::begin(uint16_t port) +{ + if (!_uip_udp_conn) + { + _uip_udp_conn = uip_udp_new(NULL, 0); + } + if (_uip_udp_conn) + { + uip_udp_bind(_uip_udp_conn,htons(port)); + _uip_udp_conn->appstate = &appdata; + return 1; + } + return 0; +} + +// Finish with the UDP socket +void +UIPUDP::stop() +{ + if (_uip_udp_conn) + { + uip_udp_remove(_uip_udp_conn); + _uip_udp_conn->appstate = NULL; + _uip_udp_conn=NULL; + Enc28J60Network::freeBlock(appdata.packet_in); + Enc28J60Network::freeBlock(appdata.packet_next); + Enc28J60Network::freeBlock(appdata.packet_out); + memset(&appdata,0,sizeof(appdata)); + } +} + +// Sending UDP packets + +// Start building up a packet to send to the remote host specific in ip and port +// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port +int +UIPUDP::beginPacket(IPAddress ip, uint16_t port) +{ + UIPEthernetClass::tick(); + if (ip && port) + { + uip_ipaddr_t ripaddr; + uip_ip_addr(&ripaddr, ip); +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp beginPacket, ")); +#endif + if (_uip_udp_conn) + { + _uip_udp_conn->rport = htons(port); + uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr); + } + else + { + _uip_udp_conn = uip_udp_new(&ripaddr,htons(port)); + if (_uip_udp_conn) + { +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("new connection, ")); +#endif + _uip_udp_conn->appstate = &appdata; + } + else + { +#ifdef UIPETHERNET_DEBUG_UDP + Serial.println(F("failed to allocate new connection")); +#endif + return 0; + } + } +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("rip: ")); + Serial.print(ip); + Serial.print(F(", port: ")); + Serial.println(port); +#endif + } + if (_uip_udp_conn) + { + if (appdata.packet_out == NOBLOCK) + { + appdata.packet_out = Enc28J60Network::allocBlock(UIP_UDP_MAXPACKETSIZE); + appdata.out_pos = UIP_UDP_PHYH_LEN; + if (appdata.packet_out != NOBLOCK) + return 1; +#ifdef UIPETHERNET_DEBUG_UDP + else + Serial.println(F("failed to allocate memory for packet")); +#endif + } +#ifdef UIPETHERNET_DEBUG_UDP + else + Serial.println(F("previous packet on that connection not sent yet")); +#endif + } + return 0; +} + +// Start building up a packet to send to the remote host specific in host and port +// Returns 1 if successful, 0 if there was a problem resolving the hostname or port +int +UIPUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(UIPEthernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + +// Finish off this packet and send it +// Returns 1 if the packet was sent successfully, 0 if there was an error +int +UIPUDP::endPacket() +{ + if (_uip_udp_conn && appdata.packet_out != NOBLOCK) + { + appdata.send = true; + Enc28J60Network::resizeBlock(appdata.packet_out,0,appdata.out_pos); + uip_udp_periodic_conn(_uip_udp_conn); + if (uip_len > 0) + { + _send(&appdata); + return 1; + } + } + return 0; +} + +// Write a single byte into the packet +size_t +UIPUDP::write(uint8_t c) +{ + return write(&c,1); +} + +// Write size bytes from buffer into the packet +size_t +UIPUDP::write(const uint8_t *buffer, size_t size) +{ + if (appdata.packet_out != NOBLOCK) + { + size_t ret = Enc28J60Network::writePacket(appdata.packet_out,appdata.out_pos,(uint8_t*)buffer,size); + appdata.out_pos += ret; + return ret; + } + return 0; +} + +// Start processing the next available incoming packet +// Returns the size of the packet in bytes, or 0 if no packets are available +int +UIPUDP::parsePacket() +{ + UIPEthernetClass::tick(); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F("udp parsePacket freeing previous packet: ")); + Serial.println(appdata.packet_in); + } +#endif + Enc28J60Network::freeBlock(appdata.packet_in); + + appdata.packet_in = appdata.packet_next; + appdata.packet_next = NOBLOCK; + +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F("udp parsePacket received packet: ")); + Serial.print(appdata.packet_in); + } +#endif + int size = Enc28J60Network::blockSize(appdata.packet_in); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F(", size: ")); + Serial.println(size); + } +#endif + return size; +} + +// Number of bytes remaining in the current packet +int +UIPUDP::available() +{ + UIPEthernetClass::tick(); + return Enc28J60Network::blockSize(appdata.packet_in); +} + +// Read a single byte from the current packet +int +UIPUDP::read() +{ + unsigned char c; + if (read(&c,1) > 0) + { + return c; + } + return -1; +} + +// Read up to len bytes from the current packet and place them into buffer +// Returns the number of bytes read, or 0 if none are available +int +UIPUDP::read(unsigned char* buffer, size_t len) +{ + UIPEthernetClass::tick(); + if (appdata.packet_in != NOBLOCK) + { + memaddress read = Enc28J60Network::readPacket(appdata.packet_in,0,buffer,len); + if (read == Enc28J60Network::blockSize(appdata.packet_in)) + { + Enc28J60Network::freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; + } + else + Enc28J60Network::resizeBlock(appdata.packet_in,read); + return read; + } + return 0; +} + +// Return the next byte from the current packet without moving on to the next byte +int +UIPUDP::peek() +{ + UIPEthernetClass::tick(); + if (appdata.packet_in != NOBLOCK) + { + unsigned char c; + if (Enc28J60Network::readPacket(appdata.packet_in,0,&c,1) == 1) + return c; + } + return -1; +} + +// Finish reading the current packet +void +UIPUDP::flush() +{ + UIPEthernetClass::tick(); + Enc28J60Network::freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; +} + +// Return the IP address of the host who sent the current incoming packet +IPAddress +UIPUDP::remoteIP() +{ + return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress(); +} + +// Return the port of the host who sent the current incoming packet +uint16_t +UIPUDP::remotePort() +{ + return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0; +} + +// uIP callback function + +void +uipudp_appcall(void) { + if (uip_udp_userdata_t *data = (uip_udp_userdata_t *)(uip_udp_conn->appstate)) + { + if (uip_newdata()) + { + if (data->packet_next == NOBLOCK) + { + uip_udp_conn->rport = UDPBUF->srcport; + uip_ipaddr_copy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr); + data->packet_next = Enc28J60Network::allocBlock(ntohs(UDPBUF->udplen)-UIP_UDPH_LEN); + //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery + if (data->packet_next != NOBLOCK) + { + //discard Linklevel and IP and udp-header and any trailing bytes: + Enc28J60Network::copyPacket(data->packet_next,0,UIPEthernetClass::in_packet,UIP_UDP_PHYH_LEN,Enc28J60Network::blockSize(data->packet_next)); + #ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_newdata received packet: ")); + Serial.print(data->packet_next); + Serial.print(F(", size: ")); + Serial.println(Enc28J60Network::blockSize(data->packet_next)); + #endif + } + } + } + if (uip_poll() && data->send) + { + //set uip_slen (uip private) by calling uip_udp_send +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_poll preparing packet to send: ")); + Serial.print(data->packet_out); + Serial.print(F(", size: ")); + Serial.println(Enc28J60Network::blockSize(data->packet_out)); +#endif + UIPEthernetClass::uip_packet = data->packet_out; + UIPEthernetClass::uip_hdrlen = UIP_UDP_PHYH_LEN; + uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); + } + } +} + +void +UIPUDP::_send(uip_udp_userdata_t *data) { + uip_arp_out(); //add arp + if (uip_len == UIP_ARPHDRSIZE) + { + UIPEthernetClass::uip_packet = NOBLOCK; + UIPEthernetClass::packetstate &= ~UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + Serial.println(F("udp, uip_poll results in ARP-packet")); +#endif + } + else + //arp found ethaddr for ip (otherwise packet is replaced by arp-request) + { + data->send = false; + data->packet_out = NOBLOCK; + UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_packet to send: ")); + Serial.println(UIPEthernetClass::uip_packet); +#endif + } + UIPEthernetClass::network_send(); +} +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h b/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h new file mode 100644 index 0000000..b007a3c --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h @@ -0,0 +1,126 @@ +/* + UIPUdp.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPUDP_H +#define UIPUDP_H + +#include "ethernet_comp.h" +#include "Arduino.h" +#include +#include "utility/mempool.h" +extern "C" { + #include "utility/uip.h" +} + +#define UIP_UDP_MAXDATALEN 1500 +#define UIP_UDP_PHYH_LEN UIP_LLH_LEN+UIP_IPUDPH_LEN +#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN+UIP_UDP_PHYH_LEN + +typedef struct { + memaddress out_pos; + memhandle packet_next; + memhandle packet_in; + memhandle packet_out; + boolean send; +} uip_udp_userdata_t; + +class UIPUDP : public UDP +{ + +private: + struct uip_udp_conn *_uip_udp_conn; + + uip_udp_userdata_t appdata; + +public: + UIPUDP(); // Constructor + uint8_t + begin(uint16_t);// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + void + stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + int + beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + int + beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + int + endPacket(); + // Write a single byte into the packet + size_t + write(uint8_t); + // Write size bytes from buffer into the packet + size_t + write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + int + parsePacket(); + // Number of bytes remaining in the current packet + int + available(); + // Read a single byte from the current packet + int + read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + int + read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + int + read(char* buffer, size_t len) + { + return read((unsigned char*) buffer, len); + } + ; + // Return the next byte from the current packet without moving on to the next byte + int + peek(); + void + flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + IPAddress + remoteIP(); + + // Return the port of the host who sent the current incoming packet + uint16_t + remotePort(); + +private: + + friend void uipudp_appcall(void); + + friend class UIPEthernetClass; + static void _send(uip_udp_userdata_t *data); + +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h b/libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h new file mode 100644 index 0000000..4cec2ab --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h @@ -0,0 +1,9 @@ +#ifndef ETHERNET_COMP_H +#define ETHERNET_COMP_H + +#define Ethernet UIPEthernet +#define EthernetClient UIPClient +#define EthernetServer UIPServer +#define EthernetUDP UIPUDP + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino new file mode 100644 index 0000000..bc2f094 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -0,0 +1,104 @@ +/* + Advanced Chat Server + + A simple server that distributes any incoming messages to all + connected clients but the client the message comes from. + To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + redesigned to make use of operator== 25 Nov 2013 + by Norbert Truchsess + + */ + +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. + +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,0,6); + +// telnet defaults to port 23 +EthernetServer server(23); + +EthernetClient clients[4]; + +void setup() { + // initialize the ethernet device + Ethernet.begin(mac, ip); + // start listening for clients + server.begin(); + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + if (client) { + + boolean newClient = true; + for (byte i=0;i<4;i++) { + //check whether this client refers to the same socket as one of the existing instances: + if (clients[i]==client) { + newClient = false; + break; + } + } + + if (newClient) { + //check which of the existing clients can be overridden: + for (byte i=0;i<4;i++) { + if (!clients[i] && clients[i]!=client) { + clients[i] = client; + // clead out the input buffer: + client.flush(); + // clead out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + client.print("my IP: "); + client.println(Ethernet.localIP()); + break; + } + } + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to all other connected clients: + for (byte i=0;i<4;i++) { + if (clients[i] && clients[i]!=client) { + clients[i].write(thisChar); + } + } + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } + for (byte i=0;i<4;i++) { + if (!(clients[i].connected())) { + // client.stop() invalidates the internal socket-descriptor, so next use of == will allways return false; + clients[i].stop(); + } + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino new file mode 100644 index 0000000..62d66e4 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino @@ -0,0 +1,58 @@ +/* + * UIPEthernet EchoServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This Hello World example sets up a server at 192.168.1.6 on port 1000. + * Telnet here to access the service. The uIP stack will also respond to + * pings to test if you have successfully established a TCP connection to + * the Arduino. + * + * This example was based upon uIP hello-world by Adam Dunkels + * Ported to the Arduino IDE by Adam Nielsen + * Adaption to Enc28J60 by Norbert Truchsess + */ + +#include +// The connection_data struct needs to be defined in an external file. +#include +#include + +EthernetServer server = EthernetServer(1000); + +void setup() +{ + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + IPAddress myIP(192,168,0,6); + + Ethernet.begin(mac,myIP); + + server.begin(); +} + +void loop() +{ + size_t size; + + if (EthernetClient client = server.available()) + { + if (client) + { + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg,size); + Serial.write(msg,size); + client.write(msg,size); + free(msg); + } + } + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino new file mode 100644 index 0000000..dca685c --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino @@ -0,0 +1,76 @@ +/* + * UIPEthernet TcpClient example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This TcpClient example gets its local ip-address via dhcp and sets + * up a tcp socket-connection to 192.168.0.1 port 5000 every 5 Seconds. + * After sending a message it waits for a response. After receiving the + * response the client disconnects and tries to reconnect after 5 seconds. + * + * Copyright (C) 2013 by Norbert Truchsess + */ + +#include + +EthernetClient client; +signed long next; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + Ethernet.begin(mac); + + Serial.print("localIP: "); + Serial.println(Ethernet.localIP()); + Serial.print("subnetMask: "); + Serial.println(Ethernet.subnetMask()); + Serial.print("gatewayIP: "); + Serial.println(Ethernet.gatewayIP()); + Serial.print("dnsServerIP: "); + Serial.println(Ethernet.dnsServerIP()); + + next = 0; +} + +void loop() { + + if (((signed long)(millis() - next)) > 0) + { + next = millis() + 5000; + Serial.println("Client connect"); + // replace hostname with name of machine running tcpserver.pl +// if (client.connect("server.local",5000)) + if (client.connect(IPAddress(192,168,0,1),5000)) + { + Serial.println("Client connected"); + client.println("DATA from Client"); + while(client.available()==0) + { + if (next - millis() < 0) + goto close; + } + int size; + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg,size); + Serial.write(msg,size); + free(msg); + } +close: + //disconnect client + Serial.println("Client disconnect"); + client.stop(); + } + else + Serial.println("Client connect failed"); + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino new file mode 100644 index 0000000..10512ec --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino @@ -0,0 +1,53 @@ +/* + * UIPEthernet EchoServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This Hello World example sets up a server at 192.168.1.6 on port 1000. + * Telnet here to access the service. The uIP stack will also respond to + * pings to test if you have successfully established a TCP connection to + * the Arduino. + * + * This example was based upon uIP hello-world by Adam Dunkels + * Ported to the Arduino IDE by Adam Nielsen + * Adaption to Enc28J60 by Norbert Truchsess + */ + +#include + +EthernetServer server = EthernetServer(1000); + +void setup() +{ + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + IPAddress myIP(192,168,0,6); + + Ethernet.begin(mac,myIP); + + server.begin(); +} + +void loop() +{ + size_t size; + + if (EthernetClient client = server.available()) + { + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg,size); + Serial.write(msg,size); + free(msg); + } + client.println("DATA from Server!"); + client.stop(); + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino new file mode 100644 index 0000000..aad56b4 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino @@ -0,0 +1,93 @@ +/* + * UIPEthernet UdpClient example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This UdpClient example tries to send a packet via udp to 192.168.0.1 + * on port 5000 every 5 seconds. After successfully sending the packet it + * waits for up to 5 seconds for a response on the local port that has been + * implicitly opened when sending the packet. + * + * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) + */ + +#include + +EthernetUDP udp; +unsigned long next; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + + Ethernet.begin(mac,IPAddress(192,168,0,6)); + + next = millis()+5000; +} + +void loop() { + + int success; + int len = 0; + + if (((signed long)(millis()-next))>0) + { + do + { + success = udp.beginPacket(IPAddress(192,168,0,1),5000); + Serial.print("beginPacket: "); + Serial.println(success ? "success" : "failed"); + //beginPacket fails if remote ethaddr is unknown. In this case an + //arp-request is send out first and beginPacket succeeds as soon + //the arp-response is received. + } + while (!success && ((signed long)(millis()-next))<0); + if (!success ) + goto stop; + + success = udp.write("hello world from arduino"); + + Serial.print("bytes written: "); + Serial.println(success); + + success = udp.endPacket(); + + Serial.print("endPacket: "); + Serial.println(success ? "success" : "failed"); + + do + { + //check for new udp-packet: + success = udp.parsePacket(); + } + while (!success && ((signed long)(millis()-next))<0); + if (!success ) + goto stop; + + Serial.print("received: '"); + do + { + int c = udp.read(); + Serial.write(c); + len++; + } + while ((success = udp.available())>0); + Serial.print("', "); + Serial.print(len); + Serial.println(" bytes"); + + //finish reading this packet: + udp.flush(); + + stop: + udp.stop(); + next = millis()+5000; + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino b/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino new file mode 100644 index 0000000..3b12d75 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino @@ -0,0 +1,88 @@ +/* + * UIPEthernet UdpServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This UdpServer example sets up a udp-server at 192.168.0.6 on port 5000. + * send packet via upd to test + * + * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) + */ + +#include + +EthernetUDP udp; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + + Ethernet.begin(mac,IPAddress(192,168,0,6)); + + int success = udp.begin(5000); + + Serial.print("initialize: "); + Serial.println(success ? "success" : "failed"); + +} + +void loop() { + + //check for new udp-packet: + int size = udp.parsePacket(); + if (size > 0) { + do + { + char* msg = (char*)malloc(size+1); + int len = udp.read(msg,size+1); + msg[len]=0; + Serial.print("received: '"); + Serial.print(msg); + free(msg); + } + while ((size = udp.available())>0); + //finish reading this packet: + udp.flush(); + Serial.println("'"); + int success; + do + { + Serial.print("remote ip: "); + Serial.println(udp.remoteIP()); + Serial.print("remote port: "); + Serial.println(udp.remotePort()); + //send new packet back to ip/port of client. This also + //configures the current connection to ignore packets from + //other clients! + success = udp.beginPacket(udp.remoteIP(),udp.remotePort()); + Serial.print("beginPacket: "); + Serial.println(success ? "success" : "failed"); + //beginPacket fails if remote ethaddr is unknown. In this case an + //arp-request is send out first and beginPacket succeeds as soon + //the arp-response is received. + } + while (!success); + + success = udp.println("hello world from arduino"); + + Serial.print("bytes written: "); + Serial.println(success); + + success = udp.endPacket(); + + Serial.print("endPacket: "); + Serial.println(success ? "success" : "failed"); + + udp.stop(); + //restart with new connection to receive packets from other clients + Serial.print("restart connection: "); + Serial.println (udp.begin(5000) ? "success" : "failed"); + } +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/keywords.txt b/libraries/MySensors/drivers/Ethernet_UIP/keywords.txt new file mode 100644 index 0000000..83ff854 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/keywords.txt @@ -0,0 +1,58 @@ +####################################### +# Syntax Coloring Map for SerialIP +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +UIPEthernet KEYWORD1 +UIPServer KEYWORD1 +UIPClient KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +PSOCK_BEGIN KEYWORD2 +PSOCK_CLOSE KEYWORD2 +PSOCK_END KEYWORD2 +PSOCK_EXIT KEYWORD2 +PSOCK_INIT KEYWORD2 +PSOCK_READBUF KEYWORD2 +PSOCK_READTO KEYWORD2 +PSOCK_SEND KEYWORD2 +PSOCK_SEND_STR KEYWORD2 + +uip_listen KEYWORD2 +uip_unlisten KEYWORD2 +uip_connect KEYWORD2 +uip_outstanding KEYWORD2 +uip_send KEYWORD2 +uip_datalen KEYWORD2 +uip_close KEYWORD2 +uip_abort KEYWORD2 +uip_stop KEYWORD2 +uip_stopped KEYWORD2 +uip_restart KEYWORD2 +uip_acked KEYWORD2 +uip_connected KEYWORD2 +uip_closed KEYWORD2 +uip_aborted KEYWORD2 +uip_timedout KEYWORD2 +uip_rexmit KEYWORD2 +uip_poll KEYWORD2 +uip_initialmss KEYWORD2 +uip_mss KEYWORD2 +uip_ipaddr KEYWORD2 +uip_ipaddr_maskcmp KEYWORD2 +uip_ipaddr_mask KEYWORD2 +HTONS KEYWORD2 +htons KEYWORD2 + +use_device KEYWORD2 +set_uip_callback KEYWORD2 +set_gateway KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/MySensors/drivers/Ethernet_UIP/library.properties b/libraries/MySensors/drivers/Ethernet_UIP/library.properties new file mode 100644 index 0000000..158ae31 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/library.properties @@ -0,0 +1,10 @@ +name=UIPEthernet +author=ntruchsess +email=Norbert Truchsess +sentence=Ethernet library for ENC28J60 +paragraph=implements the same API as stock Ethernet-lib. Just replace the include of Ethernet.h with UIPEthernet.h +url=https://github.com/ntruchsess/arduino_uip +architectures=avr +version=1.04 +dependencies= +core-dependencies=arduino (>=1.5.0) diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl new file mode 100644 index 0000000..e6884dc --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl +#tcpclient.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$client_socket); + +# creating object interface of IO::Socket::INET modules which internally creates +# socket, binds and connects to the TCP server running on the specific port. +$socket = new IO::Socket::INET ( +PeerHost => '192.168.0.6', +PeerPort => '1000', +Proto => 'tcp', +) or die "ERROR in Socket Creation : $!\n"; + +print "TCP Connection Success.\n"; + +# write on the socket to server. +$data = "DATA from Client"; +print $socket "$data\n"; +# we can also send the data through IO::Socket::INET module, +# $socket->send($data); + +# read the socket data sent by server. +$data = <$socket>; +# we can also read from socket through recv() in IO::Socket::INET +# $socket->recv($data,1024); +print "Received from Server : $data\n"; + +sleep (10); +$socket->close(); \ No newline at end of file diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl new file mode 100644 index 0000000..17405a3 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl +#tcpserver.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$client_socket); +my ($peeraddress,$peerport); + +# creating object interface of IO::Socket::INET modules which internally does +# socket creation, binding and listening at the specified port address. +$socket = new IO::Socket::INET ( +LocalHost => '192.168.0.1', +LocalPort => '5000', +Proto => 'tcp', +Listen => 5, +Reuse => 1 +) or die "ERROR in Socket Creation : $!\n"; + +print "SERVER Waiting for client connection on port 5000\n"; + +while(1) +{ + # waiting for new client connection. + $client_socket = $socket->accept(); + + # get the host and port number of newly connected client. + $peer_address = $client_socket->peerhost(); + $peer_port = $client_socket->peerport(); + + print "Accepted New Client Connection From : $peer_address, $peer_port\n "; + + # read operation on the newly accepted client + $data = <$client_socket>; + # we can also read from socket through recv() in IO::Socket::INET + # $client_socket->recv($data,1024); + print "Received from Client : $data\n"; + + # write operation on the newly accepted client. + $data = "DATA from Server"; + print $client_socket "$data\n"; + # we can also send the data through IO::Socket::INET module, + # $client_socket->send($data); + + sleep(1); + + $client_socket->close(); +} + +$socket->close(); + diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl new file mode 100644 index 0000000..bc9e6a2 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +#udpclient.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$data); + +# We call IO::Socket::INET->new() to create the UDP Socket +# and bind with the PeerAddr. +$socket = new IO::Socket::INET ( +PeerAddr => '192.168.0.6:5000', +Proto => 'udp' +) or die "ERROR in Socket Creation : $!\n"; +#send operation +$data = "data from client"; +$socket->send($data); + +#read operation +$data = <$socket>; +print "Data received from socket : $data\n "; + +sleep(10); +$socket->close(); diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl new file mode 100644 index 0000000..e728a46 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl +#udpserver.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$received_data); +my ($peeraddress,$peerport); + +# we call IO::Socket::INET->new() to create the UDP Socket and bound +# to specific port number mentioned in LocalPort and there is no need to provide +# LocalAddr explicitly as in TCPServer. +$socket = new IO::Socket::INET ( +LocalPort => '5000', +Proto => 'udp', +) or die "ERROR in Socket Creation : $!\n"; + +while(1) +{ +# read operation on the socket +$socket->recv($recieved_data,1024); + +#get the peerhost and peerport at which the recent data received. +$peer_address = $socket->peerhost(); +$peer_port = $socket->peerport(); +print "($peer_address , $peer_port) said : $recieved_data\n"; + +#send the data to the client at which the read/write operations done recently. +$data = "data from server\n"; + +$socket->send($data); + +print $socket "$data"; + +} + +$socket->close(); + diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp b/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp new file mode 100644 index 0000000..c7c66fb --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp @@ -0,0 +1,612 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "Enc28J60Network.h" +#include "Arduino.h" + +extern "C" { +#include +#include "enc28j60.h" +#include "uip.h" +} + +#ifdef ENC28J60DEBUG +#include "HardwareSerial.h" +#endif + +// set CS to 0 = active +#define CSACTIVE digitalWrite(ENC28J60_CONTROL_CS, LOW) +// set CS to 1 = passive +#define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH) +// +#define waitspi() while(!(SPSR&(1< ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! + writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); + writeRegPair(EPMM0, 0x303f); + writeRegPair(EPMCSL, 0xf7f9); + // + // + // do bank 2 stuff + // enable MAC receive + // and bring MAC out of reset (writes 0x00 to MACON2) + writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + // enable automatic padding to 60bytes and CRC operations + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + // set inter-frame gap (non-back-to-back) + writeRegPair(MAIPGL, 0x0C12); + // set inter-frame gap (back-to-back) + writeReg(MABBIPG, 0x12); + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + writeRegPair(MAMXFLL, MAX_FRAMELEN); + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + writeReg(MAADR5, macaddr[0]); + writeReg(MAADR4, macaddr[1]); + writeReg(MAADR3, macaddr[2]); + writeReg(MAADR2, macaddr[3]); + writeReg(MAADR1, macaddr[4]); + writeReg(MAADR0, macaddr[5]); + // no loopback of transmitted frames + phyWrite(PHCON2, PHCON2_HDLDIS); + // switch to bank 0 + setBank(ECON1); + // enable interrutps + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); + // enable packet reception + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + //Configure leds + phyWrite(PHLCON,0x476); +} + +memhandle +Enc28J60Network::receivePacket() +{ + uint8_t rxstat; + uint16_t len; + // check if a packet has been received and buffered + //if( !(readReg(EIR) & EIR_PKTIF) ){ + // The above does not work. See Rev. B4 Silicon Errata point 6. + if (readReg(EPKTCNT) != 0) + { + uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-RXSTOP_INIT+RXSTART_INIT : nextPacketPtr+6; + // Set the read pointer to the start of the received packet + writeRegPair(ERDPTL, nextPacketPtr); + // read the next packet pointer + nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); + nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + // read the packet length (see datasheet page 43) + len = readOp(ENC28J60_READ_BUF_MEM, 0); + len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + len -= 4; //remove the CRC count + // read the receive status (see datasheet page 43) + rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); + //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; +#ifdef ENC28J60DEBUG + Serial.print("receivePacket ["); + Serial.print(readPtr,HEX); + Serial.print("-"); + Serial.print((readPtr+len) % (RXSTOP_INIT+1),HEX); + Serial.print("], next: "); + Serial.print(nextPacketPtr,HEX); + Serial.print(", stat: "); + Serial.print(rxstat,HEX); + Serial.print(", count: "); + Serial.print(readReg(EPKTCNT)); + Serial.print(" -> "); + Serial.println((rxstat & 0x80)!=0 ? "OK" : "failed"); +#endif + // decrement the packet counter indicate we are done with this packet + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if ((rxstat & 0x80) != 0) + { + receivePkt.begin = readPtr; + receivePkt.size = len; + return UIP_RECEIVEBUFFERHANDLE; + } + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); + } + return (NOBLOCK); +} + +void +Enc28J60Network::setERXRDPT() +{ + writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr-1); +} + +memaddress +Enc28J60Network::blockSize(memhandle handle) +{ + return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; +} + +void +Enc28J60Network::sendPacket(memhandle handle) +{ + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin-1; + uint16_t end = start + packet->size; + + // backup data at control-byte position + uint8_t data = readByte(start); + // write control-byte (if not 0 anyway) + if (data) + writeByte(start, 0); + +#ifdef ENC28J60DEBUG + Serial.print("sendPacket("); + Serial.print(handle); + Serial.print(") ["); + Serial.print(start,HEX); + Serial.print("-"); + Serial.print(end,HEX); + Serial.print("]: "); + for (uint16_t i=start; i<=end; i++) + { + Serial.print(readByte(i),HEX); + Serial.print(" "); + } + Serial.println(); +#endif + + // TX start + writeRegPair(ETXSTL, start); + // Set the TXND pointer to correspond to the packet size given + writeRegPair(ETXNDL, end); + // send the contents of the transmit buffer onto the network + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. + if( (readReg(EIR) & EIR_TXERIF) ) + { + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + } + + //restore data on control-byte position + if (data) + writeByte(start, data); +} + +uint16_t +Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) +{ + memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && packet->begin + position > RXSTOP_INIT ? packet->begin + position-RXSTOP_INIT+RXSTART_INIT : packet->begin + position; + + writeRegPair(ERDPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + return len; +} + +uint16_t +Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + len = setReadPtr(handle, position, len); + readBuffer(len, buffer); + return len; +} + +uint16_t +Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin + position; + + writeRegPair(EWRPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + writeBuffer(len, buffer); + return len; +} + +uint8_t Enc28J60Network::readByte(uint16_t addr) +{ + writeRegPair(ERDPTL, addr); + + CSACTIVE; + // issue read command + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + CSPASSIVE; + return (SPDR); +} + +void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) +{ + writeRegPair(EWRPTL, addr); + + CSACTIVE; + // issue write command + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + // write data + SPDR = data; + waitspi(); + CSPASSIVE; +} + +void +Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) +{ + memblock *dest = &blocks[dest_pkt]; + memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ? src->begin + src_pos-RXSTOP_INIT+RXSTART_INIT : src->begin + src_pos; + enc28J60_mempool_block_move_callback(dest->begin+dest_pos,start,len); + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); +} + +void +enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) +{ +//void +//Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) +//{ + //as ENC28J60 DMA is unable to copy single bytes: + if (len == 1) + { + Enc28J60Network::writeByte(dest,Enc28J60Network::readByte(src)); + } + else + { + // calculate address of last byte + len += src - 1; + + /* 1. Appropriately program the EDMAST, EDMAND + and EDMADST register pairs. The EDMAST + registers should point to the first byte to copy + from, the EDMAND registers should point to the + last byte to copy and the EDMADST registers + should point to the first byte in the destination + range. The destination range will always be + linear, never wrapping at any values except from + 8191 to 0 (the 8-Kbyte memory boundary). + Extreme care should be taken when + programming the start and end pointers to + prevent a never ending DMA operation which + would overwrite the entire 8-Kbyte buffer. + */ + Enc28J60Network::writeRegPair(EDMASTL, src); + Enc28J60Network::writeRegPair(EDMADSTL, dest); + + if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= (RXSTOP_INIT-RXSTART_INIT); + Enc28J60Network::writeRegPair(EDMANDL, len); + + /* + 2. If an interrupt at the end of the copy process is + desired, set EIE.DMAIE and EIE.INTIE and + clear EIR.DMAIF. + + 3. Verify that ECON1.CSUMEN is clear. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); + + /* 4. Start the DMA copy by setting ECON1.DMAST. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); + + // wait until runnig DMA is completed + while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); + } +} + +void +Enc28J60Network::freePacket() +{ + setERXRDPT(); +} + +uint8_t +Enc28J60Network::readOp(uint8_t op, uint8_t address) +{ + CSACTIVE; + // issue read command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // read data + SPDR = 0x00; + waitspi(); + // do dummy read if needed (for mac and mii, see datasheet page 29) + if(address & 0x80) + { + SPDR = 0x00; + waitspi(); + } + // release CS + CSPASSIVE; + return(SPDR); +} + +void +Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) +{ + CSACTIVE; + // issue write command + SPDR = op | (address & ADDR_MASK); + waitspi(); + // write data + SPDR = data; + waitspi(); + CSPASSIVE; +} + +void +Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) +{ + CSACTIVE; + // issue read command + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + while(len) + { + len--; + // read data + SPDR = 0x00; + waitspi(); + *data = SPDR; + data++; + } + //*data='\0'; + CSPASSIVE; +} + +void +Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) +{ + CSACTIVE; + // issue write command + SPDR = ENC28J60_WRITE_BUF_MEM; + waitspi(); + while(len) + { + len--; + // write data + SPDR = *data; + data++; + waitspi(); + } + CSPASSIVE; +} + +void +Enc28J60Network::setBank(uint8_t address) +{ + // set the bank (if needed) + if((address & BANK_MASK) != bank) + { + // set the bank + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); + bank = (address & BANK_MASK); + } +} + +uint8_t +Enc28J60Network::readReg(uint8_t address) +{ + // set the bank + setBank(address); + // do the read + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void +Enc28J60Network::writeReg(uint8_t address, uint8_t data) +{ + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +void +Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) +{ + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, (data&0xFF)); + writeOp(ENC28J60_WRITE_CTRL_REG, address+1, (data) >> 8); +} + +void +Enc28J60Network::phyWrite(uint8_t address, uint16_t data) +{ + // set the PHY register address + writeReg(MIREGADR, address); + // write the PHY data + writeRegPair(MIWRL, data); + // wait until the PHY write completes + while(readReg(MISTAT) & MISTAT_BUSY){ + delayMicroseconds(15); + } +} + +uint16_t +Enc28J60Network::phyRead(uint8_t address) +{ + writeReg(MIREGADR,address); + writeReg(MICMD, MICMD_MIIRD); + // wait until the PHY read completes + while(readReg(MISTAT) & MISTAT_BUSY){ + delayMicroseconds(15); + } //and MIRDH + writeReg(MICMD, 0); + return (readReg(MIRDL) | readReg(MIRDH) << 8); +} + +void +Enc28J60Network::clkout(uint8_t clk) +{ + //setup clkout: 2 is 12.5MHz: + writeReg(ECOCON, clk & 0x7); +} + +// read the revision of the chip: +uint8_t +Enc28J60Network::getrev(void) +{ + return(readReg(EREVID)); +} + +uint16_t +Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) +{ + uint16_t t; + len = setReadPtr(handle, pos, len)-1; + CSACTIVE; + // issue read command + SPDR = ENC28J60_READ_BUF_MEM; + waitspi(); + uint16_t i; + for (i = 0; i < len; i+=2) + { + // read data + SPDR = 0x00; + waitspi(); + t = SPDR << 8; + SPDR = 0x00; + waitspi(); + t += SPDR; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + if(i == len) { + SPDR = 0x00; + waitspi(); + t = (SPDR << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + CSPASSIVE; + + /* Return sum in host byte order. */ + return sum; +} + +void +Enc28J60Network::powerOff() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +void +Enc28J60Network::powerOn() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + delay(50); +} + +bool +Enc28J60Network::linkStatus() +{ + return (phyRead(PHSTAT2) & 0x0400) > 0; +} + +Enc28J60Network Enc28J60; diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h new file mode 100644 index 0000000..7346e47 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h @@ -0,0 +1,91 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + inspired by enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef Enc28J60Network_H_ +#define Enc28J60Network_H_ + +#include "mempool.h" + +#define ENC28J60_CONTROL_CS SS +#define SPI_MOSI MOSI +#define SPI_MISO MISO +#define SPI_SCK SCK +#define SPI_SS SS + +#define UIP_RECEIVEBUFFERHANDLE 0xff + +//#define ENC28J60DEBUG + +/* + * Empfangen von ip-header, arp etc... + * wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection + */ + +class Enc28J60Network : public MemoryPool +{ + +private: + static uint16_t nextPacketPtr; + static uint8_t bank; + + static struct memblock receivePkt; + + static uint8_t readOp(uint8_t op, uint8_t address); + static void writeOp(uint8_t op, uint8_t address, uint8_t data); + static uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); + static void setERXRDPT(); + static void readBuffer(uint16_t len, uint8_t* data); + static void writeBuffer(uint16_t len, uint8_t* data); + static uint8_t readByte(uint16_t addr); + static void writeByte(uint16_t addr, uint8_t data); + static void setBank(uint8_t address); + static uint8_t readReg(uint8_t address); + static void writeReg(uint8_t address, uint8_t data); + static void writeRegPair(uint8_t address, uint16_t data); + static void phyWrite(uint8_t address, uint16_t data); + static uint16_t phyRead(uint8_t address); + static void clkout(uint8_t clk); + + friend void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +public: + + uint8_t getrev(void); + void powerOn(); + void powerOff(); + bool linkStatus(); + + static void init(uint8_t* macaddr); + static memhandle receivePacket(); + static void freePacket(); + static memaddress blockSize(memhandle handle); + static void sendPacket(memhandle handle); + static uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); + static uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); +}; + +extern Enc28J60Network Enc28J60; +#endif /* Enc28J60NetworkClass_H_ */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c b/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c new file mode 100644 index 0000000..13b886d --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c @@ -0,0 +1,28 @@ +/* + clock-arch.c - Arduino implementation of uIP clock device. + Copyright (c) 2010 Adam Nielsen + All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "clock-arch.h" + +clock_time_t +clock_time(void) +{ + return (clock_time_t) millis(); +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h new file mode 100644 index 0000000..d7a828b --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h @@ -0,0 +1,27 @@ +/* + clock-arch.h - Arduino implementation of uIP clock device. + Copyright (c) 2010 Adam Nielsen + All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef clock_h_ +#define clock_h_ + +typedef unsigned long clock_time_t; +#define CLOCK_CONF_SECOND 1000 + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h new file mode 100644 index 0000000..3a45c59 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h @@ -0,0 +1,257 @@ +/***************************************************************************** +* +* Title : Microchip ENC28J60 Ethernet Interface Driver +* Author : Pascal Stang (c)2005 +* Modified by Norbert Truchsess +* Copyright: GPL V2 +* +*This driver provides initialization and transmit/receive +*functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY. +*This chip is novel in that it is a full MAC+PHY interface all in a 28-pin +*chip, using an SPI interface to the host processor. +* +* +*****************************************************************************/ + +#ifndef ENC28J60_H +#define ENC28J60_H +#include + +// ENC28J60 Control Registers +// Control register definitions are a combination of address, +// bank number, and Ethernet/MAC/PHY indicator bits. +// - Register address (bits 0-4) +// - Bank number (bits 5-6) +// - MAC/PHY indicator (bit 7) +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +// All-bank registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +// Bank 0 registers +#define ERDPTL (0x00|0x00) +#define ERDPTH (0x01|0x00) +#define EWRPTL (0x02|0x00) +#define EWRPTH (0x03|0x00) +#define ETXSTL (0x04|0x00) +#define ETXSTH (0x05|0x00) +#define ETXNDL (0x06|0x00) +#define ETXNDH (0x07|0x00) +#define ERXSTL (0x08|0x00) +#define ERXSTH (0x09|0x00) +#define ERXNDL (0x0A|0x00) +#define ERXNDH (0x0B|0x00) +#define ERXRDPTL (0x0C|0x00) +#define ERXRDPTH (0x0D|0x00) +#define ERXWRPTL (0x0E|0x00) +#define ERXWRPTH (0x0F|0x00) +#define EDMASTL (0x10|0x00) +#define EDMASTH (0x11|0x00) +#define EDMANDL (0x12|0x00) +#define EDMANDH (0x13|0x00) +#define EDMADSTL (0x14|0x00) +#define EDMADSTH (0x15|0x00) +#define EDMACSL (0x16|0x00) +#define EDMACSH (0x17|0x00) +// Bank 1 registers +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCSL (0x10|0x20) +#define EPMCSH (0x11|0x20) +#define EPMOL (0x14|0x20) +#define EPMOH (0x15|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +// Bank 2 registers +#define MACON1 (0x00|0x40|0x80) +#define MACON2 (0x01|0x40|0x80) +#define MACON3 (0x02|0x40|0x80) +#define MACON4 (0x03|0x40|0x80) +#define MABBIPG (0x04|0x40|0x80) +#define MAIPGL (0x06|0x40|0x80) +#define MAIPGH (0x07|0x40|0x80) +#define MACLCON1 (0x08|0x40|0x80) +#define MACLCON2 (0x09|0x40|0x80) +#define MAMXFLL (0x0A|0x40|0x80) +#define MAMXFLH (0x0B|0x40|0x80) +#define MAPHSUP (0x0D|0x40|0x80) +#define MICON (0x11|0x40|0x80) +#define MICMD (0x12|0x40|0x80) +#define MIREGADR (0x14|0x40|0x80) +#define MIWRL (0x16|0x40|0x80) +#define MIWRH (0x17|0x40|0x80) +#define MIRDL (0x18|0x40|0x80) +#define MIRDH (0x19|0x40|0x80) +// Bank 3 registers +#define MAADR1 (0x00|0x60|0x80) +#define MAADR0 (0x01|0x60|0x80) +#define MAADR3 (0x02|0x60|0x80) +#define MAADR2 (0x03|0x60|0x80) +#define MAADR5 (0x04|0x60|0x80) +#define MAADR4 (0x05|0x60|0x80) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCSL (0x08|0x60) +#define EBSTCSH (0x09|0x60) +#define MISTAT (0x0A|0x60|0x80) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUSL (0x18|0x60) +#define EPAUSH (0x19|0x60) +// PHY registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +// ENC28J60 ERXFCON Register Bit Definitions +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 +// ENC28J60 EIE Register Bit Definitions +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +#define EIE_WOLIE 0x04 +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +// ENC28J60 EIR Register Bit Definitions +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +#define EIR_WOLIF 0x04 +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +// ENC28J60 ESTAT Register Bit Definitions +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +// ENC28J60 ECON2 Register Bit Definitions +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +// ENC28J60 ECON1 Register Bit Definitions +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +// ENC28J60 MACON1 Register Bit Definitions +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +// ENC28J60 MACON2 Register Bit Definitions +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +// ENC28J60 MACON3 Register Bit Definitions +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +// ENC28J60 MICMD Register Bit Definitions +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +// ENC28J60 MISTAT Register Bit Definitions +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 +// ENC28J60 PHY PHCON1 Register Bit Definitions +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +// ENC28J60 PHY PHSTAT1 Register Bit Definitions +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +// ENC28J60 PHY PHCON2 Register Bit Definitions +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 + +// ENC28J60 Packet Control Byte Bit Definitions +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +// SPI operation codes +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + + +// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata +// buffer boundaries applied to internal 8K ram +// the entire available packet buffer space is allocated +// +// start with recbuf at 0/ +#define RXSTART_INIT 0x0 +// receive buffer end. make sure this is an odd value ( See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)') +#define RXSTOP_INIT (0x1FFF-0x1800) +// start TX buffer RXSTOP_INIT+1 +#define TXSTART_INIT (RXSTOP_INIT+1) +// stp TX buffer at end of mem +#define TXSTOP_INIT 0x1FFF +// +// max frame length which the conroller will accept: +#define MAX_FRAMELEN 1500 // (note: maximum ethernet frame length would be 1518) +//#define MAX_FRAMELEN 600 + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp new file mode 100644 index 0000000..c2f7abf --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp @@ -0,0 +1,168 @@ +/* + mempool.cpp - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "mempool.h" +#include + +#define POOLOFFSET 1 + +struct memblock MemoryPool::blocks[MEMPOOL_NUM_MEMBLOCKS+1]; + +void +MemoryPool::init() +{ + memset(&blocks[0], 0, sizeof(blocks)); + blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS; + blocks[POOLSTART].size = 0; + blocks[POOLSTART].nextblock = NOBLOCK; +} + +memhandle +MemoryPool::allocBlock(memaddress size) +{ + memblock* best = NULL; + memhandle cur = POOLSTART; + memblock* block = &blocks[POOLSTART]; + memaddress bestsize = MEMPOOL_SIZE + 1; + + do + { + memhandle next = block->nextblock; + memaddress freesize = ( next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) - block->begin - block->size; + if (freesize == size) + { + best = &blocks[cur]; + goto found; + } + if (freesize > size && freesize < bestsize) + { + bestsize = freesize; + best = &blocks[cur]; + } + if (next == NOBLOCK) + { + if (best) + goto found; + else + goto collect; + } + block = &blocks[next]; + cur = next; + } + while (true); + + collect: + { + cur = POOLSTART; + block = &blocks[POOLSTART]; + memhandle next; + while ((next = block->nextblock) != NOBLOCK) + { + memaddress dest = block->begin + block->size; + memblock* nextblock = &blocks[next]; + memaddress* src = &nextblock->begin; + if (dest != *src) + { +#ifdef MEMPOOL_MEMBLOCK_MV + MEMPOOL_MEMBLOCK_MV(dest,*src,nextblock->size); +#endif + *src = dest; + } + block = nextblock; + } + if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size) + best = block; + else + goto notfound; + } + + found: + { + block = &blocks[POOLOFFSET]; + for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) + { + if (block->size) + { + block++; + continue; + } + memaddress address = best->begin + best->size; +#ifdef MEMBLOCK_ALLOC + MEMBLOCK_ALLOC(address,size); +#endif + block->begin = address; + block->size = size; + block->nextblock = best->nextblock; + best->nextblock = cur; + return cur; + } + } + + notfound: return NOBLOCK; +} + +void +MemoryPool::freeBlock(memhandle handle) +{ + if (handle == NOBLOCK) + return; + memblock *b = &blocks[POOLSTART]; + + do + { + memhandle next = b->nextblock; + if (next == handle) + { + memblock *f = &blocks[next]; +#ifdef MEMBLOCK_FREE + MEMBLOCK_FREE(f->begin,f->size); +#endif + b->nextblock = f->nextblock; + f->size = 0; + f->nextblock = NOBLOCK; + return; + } + if (next == NOBLOCK) + return; + b = &blocks[next]; + } + while (true); +} + +void +MemoryPool::resizeBlock(memhandle handle, memaddress position) +{ + memblock * block = &blocks[handle]; + block->begin += position; + block->size -= position; +} + +void +MemoryPool::resizeBlock(memhandle handle, memaddress position, memaddress size) +{ + memblock * block = &blocks[handle]; + block->begin += position; + block->size = size; +} + +memaddress +MemoryPool::blockSize(memhandle handle) +{ + return blocks[handle].size; +} diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h new file mode 100644 index 0000000..2a1db21 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h @@ -0,0 +1,54 @@ +/* + mempool.h - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#include + +#define POOLSTART 0 +#define NOBLOCK 0 + +#include "mempool_conf.h" + +struct memblock +{ + memaddress begin; + memaddress size; + memhandle nextblock; +}; + +class MemoryPool +{ +#ifdef MEMPOOLTEST_H + friend class MemoryPoolTest; +#endif + +protected: + static struct memblock blocks[MEMPOOL_NUM_MEMBLOCKS+1]; + +public: + static void init(); + static memhandle allocBlock(memaddress); + static void freeBlock(memhandle); + static void resizeBlock(memhandle handle, memaddress position); + static void resizeBlock(memhandle handle, memaddress position, memaddress size); + static memaddress blockSize(memhandle); +}; +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h new file mode 100644 index 0000000..9615f92 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h @@ -0,0 +1,34 @@ +#ifndef MEMPOOLCONF_H +#define MEMPOOLCONF_H +#include "uipethernet-conf.h" +extern "C" { + #include "uipopt.h" + #include "enc28j60.h" +} +#include + +typedef uint16_t memaddress; +typedef uint8_t memhandle; + +#if UIP_SOCKET_NUMPACKETS and UIP_CONNS +#define NUM_TCP_MEMBLOCKS (UIP_SOCKET_NUMPACKETS*2)*UIP_CONNS +#else +#define NUM_TCP_MEMBLOCKS 0 +#endif + +#if UIP_UDP and UIP_UDP_CONNS +#define NUM_UDP_MEMBLOCKS 3*UIP_UDP_CONNS +#else +#define NUM_UDP_MEMBLOCKS 0 +#endif + +#define MEMPOOL_NUM_MEMBLOCKS (NUM_TCP_MEMBLOCKS+NUM_UDP_MEMBLOCKS) + +#define MEMPOOL_STARTADDRESS TXSTART_INIT+1 +#define MEMPOOL_SIZE TXSTOP_INIT-TXSTART_INIT + +void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +#define MEMPOOL_MEMBLOCK_MV(dest,src,size) enc28J60_mempool_block_move_callback(dest,src,size) + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h new file mode 100644 index 0000000..814aeb9 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h @@ -0,0 +1,185 @@ +/** + * UIPEthernet Project-specific configuration options + * Copyright (c) 2013 Norbert Truchsess + * @{ + * + * uIP has a number of configuration options that can be overridden + * for each project. These are kept in a project-specific uip-conf.h + * file and all configuration names have the prefix UIP_CONF. + */ + +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + */ + +#ifndef __UIP_CONF_H__ +#define __UIP_CONF_H__ + +#include +#include "uipethernet-conf.h" + +/** + * 8 bit datatype + * + * This typedef defines the 8-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint8_t u8_t; + +/** + * 16 bit datatype + * + * This typedef defines the 16-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint16_t u16_t; + +/** + * Statistics datatype + * + * This typedef defines the dataype used for keeping statistics in + * uIP. + * + * \hideinitializer + */ +typedef unsigned short uip_stats_t; + +/** + * Maximum number of TCP connections. + * (see uipethernet-conf.h) + * \hideinitializer + * + * #define UIP_CONF_MAX_CONNECTIONS 4 + */ + +/** + * Maximum number of listening TCP ports. + * + * \hideinitializer + */ +#define UIP_CONF_MAX_LISTENPORTS 4 + +/** + * uIP buffer size. + * + * \hideinitializer + */ +#define UIP_CONF_BUFFER_SIZE 98 +//#define UIP_CONF_BUFFER_SIZE 118 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ + +#define UIP_CONF_TCP_MSS 512 + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#define UIP_CONF_RECEIVE_WINDOW 512 + +/** + * CPU byte order. + * + * \hideinitializer + */ +#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN + +/** + * Logging on or off + * + * \hideinitializer + */ +#define UIP_CONF_LOGGING 0 + +/** + * UDP support on or off + * (see uipethernet-conf.h) + * \hideinitializer + * + * #define UIP_CONF_UDP 1 + * + * #define UIP_CONF_UDP_CONNS 4 + */ + +/** + * UDP checksums on or off + * + * \hideinitializer + */ +#define UIP_CONF_UDP_CHECKSUMS 1 + +/** + * UDP Broadcast (receive) on or off + * (see uipethernet-conf.h) + * \hideinitializer + * #define UIP_CONF_BROADCAST 1 + */ + + +/** + * uIP statistics on or off + * + * \hideinitializer + */ +#define UIP_CONF_STATISTICS 0 + +// SLIP +//#define UIP_CONF_LLH_LEN 0 + +typedef void* uip_tcp_appstate_t; + +void uipclient_appcall(void); + +#define UIP_APPCALL uipclient_appcall + +typedef void* uip_udp_appstate_t; + +void uipudp_appcall(void); + +#define UIP_UDP_APPCALL uipudp_appcall + +#define CC_REGISTER_ARG register + +#define UIP_ARCH_CHKSUM 1 + +#endif /* __UIP_CONF_H__ */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c new file mode 100644 index 0000000..84ea8c3 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c @@ -0,0 +1,1897 @@ +#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/ + +/** + * \defgroup uip The uIP TCP/IP stack + * @{ + * + * uIP is an implementation of the TCP/IP protocol stack intended for + * small 8-bit and 16-bit microcontrollers. + * + * uIP provides the necessary protocols for Internet communication, + * with a very small code footprint and RAM requirements - the uIP + * code size is on the order of a few kilobytes and RAM usage is on + * the order of a few hundred bytes. + */ + +/** + * \file + * The uIP TCP/IP stack code. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $ + * + */ + +/* + * uIP is a small implementation of the IP, UDP and TCP protocols (as + * well as some basic ICMP stuff). The implementation couples the IP, + * UDP, TCP and the application layers very tightly. To keep the size + * of the compiled code down, this code frequently uses the goto + * statement. While it would be possible to break the uip_process() + * function into many smaller functions, this would increase the code + * size because of the overhead of parameter passing and the fact that + * the optimier would not be as efficient. + * + * The principle is that we have a small buffer, called the uip_buf, + * in which the device driver puts an incoming packet. The TCP/IP + * stack parses the headers in the packet, and calls the + * application. If the remote host has sent data to the application, + * this data is present in the uip_buf and the application read the + * data from there. It is up to the application to put this data into + * a byte stream if needed. The application will not be fed with data + * that is out of sequence. + * + * If the application whishes to send data to the peer, it should put + * its data into the uip_buf. The uip_appdata pointer points to the + * first available byte. The TCP/IP stack will calculate the + * checksums, and fill in the necessary header fields and finally send + * the packet back to the peer. +*/ + +#include "uip.h" +#include "uipopt.h" +#include "uip_arch.h" + +#if UIP_CONF_IPV6 +#include "uip-neighbor.h" +#endif /* UIP_CONF_IPV6 */ + +#include + +/*---------------------------------------------------------------------------*/ +/* Variable definitions. */ + + +/* The IP address of this host. If it is defined to be fixed (by + setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set + here. Otherwise, the address */ +#if UIP_FIXEDADDR > 0 +const uip_ipaddr_t uip_hostaddr = + {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1), + HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)}; +const uip_ipaddr_t uip_draddr = + {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1), + HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)}; +const uip_ipaddr_t uip_netmask = + {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1), + HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)}; +#else +uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask; +#endif /* UIP_FIXEDADDR */ + +static const uip_ipaddr_t all_ones_addr = +#if UIP_CONF_IPV6 + {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; +#else /* UIP_CONF_IPV6 */ + {0xffff,0xffff}; +#endif /* UIP_CONF_IPV6 */ +static const uip_ipaddr_t all_zeroes_addr = +#if UIP_CONF_IPV6 + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; +#else /* UIP_CONF_IPV6 */ + {0x0000,0x0000}; +#endif /* UIP_CONF_IPV6 */ + + +#if UIP_FIXEDETHADDR +const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0, + UIP_ETHADDR1, + UIP_ETHADDR2, + UIP_ETHADDR3, + UIP_ETHADDR4, + UIP_ETHADDR5}}; +#else +struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +#endif + +#ifndef UIP_CONF_EXTERNAL_BUFFER +u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains + incoming packets. */ +#endif /* UIP_CONF_EXTERNAL_BUFFER */ + +void *uip_appdata; /* The uip_appdata pointer points to + application data. */ +void *uip_sappdata; /* The uip_appdata pointer points to + the application data which is to + be sent. */ +#if UIP_URGDATA > 0 +void *uip_urgdata; /* The uip_urgdata pointer points to + urgent data (out-of-band data), if + present. */ +u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + +u16_t uip_len, uip_slen; + /* The uip_len is either 8 or 16 bits, + depending on the maximum packet + size. */ + +u8_t uip_flags; /* The uip_flags variable is used for + communication between the TCP/IP stack + and the application program. */ +struct uip_conn *uip_conn; /* uip_conn always points to the current + connection. */ + +struct uip_conn uip_conns[UIP_CONNS]; + /* The uip_conns array holds all TCP + connections. */ +u16_t uip_listenports[UIP_LISTENPORTS]; + /* The uip_listenports list all currently + listning ports. */ +#if UIP_UDP +struct uip_udp_conn *uip_udp_conn; +struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +static u16_t ipid; /* Ths ipid variable is an increasing + number that is used for the IP ID + field. */ + +void uip_setipid(u16_t id) { ipid = id; } + +static u8_t iss[4]; /* The iss variable is used for the TCP + initial sequence number. */ + +#if UIP_ACTIVE_OPEN +static u16_t lastport; /* Keeps track of the last port used for + a new connection. */ +#endif /* UIP_ACTIVE_OPEN */ + +/* Temporary variables. */ +u8_t uip_acc32[4]; +static u8_t c, opt; +static u16_t tmp16; + +/* Structures and definitions. */ +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_CTL 0x3f + +#define TCP_OPT_END 0 /* End of TCP options list */ +#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */ +#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */ + +#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */ + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 + +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 +#define ICMP6_NEIGHBOR_SOLICITATION 135 +#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 + +#define ICMP6_FLAG_S (1 << 6) + +#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 +#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 + + +/* Macros. */ +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) +#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +#if UIP_LOGGING == 1 +#include +void uip_log(char *msg); +#define UIP_LOG(m) uip_log(m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if ! UIP_ARCH_ADD32 +void +uip_add32(u8_t *op32, u16_t op16) +{ + uip_acc32[3] = op32[3] + (op16 & 0xff); + uip_acc32[2] = op32[2] + (op16 >> 8); + uip_acc32[1] = op32[1]; + uip_acc32[0] = op32[0]; + + if(uip_acc32[2] < (op16 >> 8)) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + + + if(uip_acc32[3] < (op16 & 0xff)) { + ++uip_acc32[2]; + if(uip_acc32[2] == 0) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + } +} + +#endif /* UIP_ARCH_ADD32 */ + +#if ! UIP_ARCH_CHKSUM +/*---------------------------------------------------------------------------*/ +static u16_t +chksum(u16_t sum, const u8_t *data, u16_t len) +{ + u16_t t; + const u8_t *dataptr; + const u8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} +/*---------------------------------------------------------------------------*/ +u16_t +uip_chksum(u16_t *data, u16_t len) +{ + return htons(chksum(0, (u8_t *)data, len)); +} +/*---------------------------------------------------------------------------*/ +#ifndef UIP_ARCH_IPCHKSUM +u16_t +uip_ipchksum(void) +{ + u16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum); + return (sum == 0) ? 0xffff : htons(sum); +} +#endif +/*---------------------------------------------------------------------------*/ +static u16_t +upper_layer_chksum(u8_t proto) +{ + u16_t upper_layer_len; + u16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + /* Sum TCP header and data. */ + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], + upper_layer_len); + + return (sum == 0) ? 0xffff : htons(sum); +} +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_IPV6 +u16_t +uip_icmp6chksum(void) +{ + return upper_layer_chksum(UIP_PROTO_ICMP6); + +} +#endif /* UIP_CONF_IPV6 */ +/*---------------------------------------------------------------------------*/ +u16_t +uip_tcpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_TCP); +} +/*---------------------------------------------------------------------------*/ +#if UIP_UDP_CHECKSUMS +u16_t +uip_udpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_UDP); +} +#endif /* UIP_UDP_CHECKSUMS */ +#endif /* UIP_ARCH_CHKSUM */ +/*---------------------------------------------------------------------------*/ +void +uip_init(void) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + uip_listenports[c] = 0; + } + for(c = 0; c < UIP_CONNS; ++c) { + uip_conns[c].tcpstateflags = UIP_CLOSED; + } +#if UIP_ACTIVE_OPEN + lastport = 1024; +#endif /* UIP_ACTIVE_OPEN */ + +#if UIP_UDP + for(c = 0; c < UIP_UDP_CONNS; ++c) { + uip_udp_conns[c].lport = 0; + } +#endif /* UIP_UDP */ + + + /* IPv4 initialization. */ +#if UIP_FIXEDADDR == 0 + /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/ +#endif /* UIP_FIXEDADDR */ + +} +/*---------------------------------------------------------------------------*/ +#if UIP_ACTIVE_OPEN +struct uip_conn * +uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_conn *conn, *cconn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + /* Check if this port is already in use, and if so try to find + another one. */ + for(c = 0; c < UIP_CONNS; ++c) { + conn = &uip_conns[c]; + if(conn->tcpstateflags != UIP_CLOSED && + conn->lport == htons(lastport)) { + goto again; + } + } + + conn = 0; + for(c = 0; c < UIP_CONNS; ++c) { + cconn = &uip_conns[c]; + if(cconn->tcpstateflags == UIP_CLOSED) { + conn = cconn; + break; + } + if(cconn->tcpstateflags == UIP_TIME_WAIT) { + if(conn == 0 || + cconn->timer > conn->timer) { + conn = cconn; + } + } + } + + if(conn == 0) { + return 0; + } + + conn->tcpstateflags = UIP_SYN_SENT; + + conn->snd_nxt[0] = iss[0]; + conn->snd_nxt[1] = iss[1]; + conn->snd_nxt[2] = iss[2]; + conn->snd_nxt[3] = iss[3]; + + conn->initialmss = conn->mss = UIP_TCP_MSS; + + conn->len = 1; /* TCP length of the SYN is one. */ + conn->nrtx = 0; + conn->timer = 1; /* Send the SYN next time around. */ + conn->rto = UIP_RTO; + conn->sa = 0; + conn->sv = 16; /* Initial value of the RTT variance. */ + conn->lport = htons(lastport); + conn->rport = rport; + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + + return conn; +} +#endif /* UIP_ACTIVE_OPEN */ +/*---------------------------------------------------------------------------*/ +#if UIP_UDP +struct uip_udp_conn * +uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_udp_conn *conn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == htons(lastport)) { + goto again; + } + } + + + conn = 0; + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == 0) { + conn = &uip_udp_conns[c]; + break; + } + } + + if(conn == 0) { + return 0; + } + + conn->lport = HTONS(lastport); + conn->rport = rport; + if(ripaddr == NULL) { + memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + } else { + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + } + conn->ttl = UIP_TTL; + + return conn; +} +#endif /* UIP_UDP */ +/*---------------------------------------------------------------------------*/ +void +uip_unlisten(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == port) { + uip_listenports[c] = 0; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_listen(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == 0) { + uip_listenports[c] = port; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +/* XXX: IP fragment reassembly: not well-tested. */ + +#if UIP_REASSEMBLY && !UIP_CONF_IPV6 +#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) +static u8_t uip_reassbuf[UIP_REASS_BUFSIZE]; +static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01}; +static u16_t uip_reasslen; +static u8_t uip_reassflags; +#define UIP_REASS_FLAG_LASTFRAG 0x01 +static u8_t uip_reasstmr; + +#define IP_MF 0x20 + +static u8_t +uip_reass(void) +{ + u16_t offset, len; + u16_t i; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if(uip_reasstmr == 0) { + memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + /* Clear the bitmap. */ + memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] && + BUF->srcipaddr[1] == FBUF->srcipaddr[1] && + BUF->destipaddr[0] == FBUF->destipaddr[0] && + BUF->destipaddr[1] == FBUF->destipaddr[1] && + BUF->ipid[0] == FBUF->ipid[0] && + BUF->ipid[1] == FBUF->ipid[1]) { + + len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; + offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if(offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], + (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), + len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if((BUF->ipoffset[0] & IP_MF) == 0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if(uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if(uip_reassbitmap[uip_reasslen / (8 * 8)] != + (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + memcpy(BUF, FBUF, uip_reasslen); + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + BUF->len[0] = uip_reasslen >> 8; + BUF->len[1] = uip_reasslen & 0xff; + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + + return uip_reasslen; + } + } + + nullreturn: + return 0; +} +#endif /* UIP_REASSEMBLY */ +/*---------------------------------------------------------------------------*/ +static void +uip_add_rcv_nxt(u16_t n) +{ + uip_add32(uip_conn->rcv_nxt, n); + uip_conn->rcv_nxt[0] = uip_acc32[0]; + uip_conn->rcv_nxt[1] = uip_acc32[1]; + uip_conn->rcv_nxt[2] = uip_acc32[2]; + uip_conn->rcv_nxt[3] = uip_acc32[3]; +} +/*---------------------------------------------------------------------------*/ +void +uip_process(u8_t flag) +{ + register struct uip_conn *uip_connr = uip_conn; + +#if UIP_UDP + if(flag == UIP_UDP_SEND_CONN) { + goto udp_send; + } +#endif /* UIP_UDP */ + + uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; + + /* Check if we were invoked because of a poll request for a + particular connection. */ + if(flag == UIP_POLL_REQUEST) { + if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && + !uip_outstanding(uip_connr)) { + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + goto drop; + + /* Check if we were invoked because of the perodic timer fireing. */ + } else if(flag == UIP_TIMER) { +#if UIP_REASSEMBLY + if(uip_reasstmr != 0) { + --uip_reasstmr; + } +#endif /* UIP_REASSEMBLY */ + /* Increase the initial sequence number. */ + if(++iss[3] == 0) { + if(++iss[2] == 0) { + if(++iss[1] == 0) { + ++iss[0]; + } + } + } + + /* Reset the length variables. */ + uip_len = 0; + uip_slen = 0; + + /* Check if the connection is in a state in which we simply wait + for the connection to time out. If so, we increase the + connection's timer and remove the connection if it times + out. */ + if(uip_connr->tcpstateflags == UIP_TIME_WAIT || + uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { + ++(uip_connr->timer); + if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { + uip_connr->tcpstateflags = UIP_CLOSED; + } + } else if(uip_connr->tcpstateflags != UIP_CLOSED) { + /* If the connection has outstanding data, we increase the + connection's timer and see if it has reached the RTO value + in which case we retransmit. */ + if(uip_outstanding(uip_connr)) { + if(uip_connr->timer-- == 0) { + if(uip_connr->nrtx == UIP_MAXRTX || + ((uip_connr->tcpstateflags == UIP_SYN_SENT || + uip_connr->tcpstateflags == UIP_SYN_RCVD) && + uip_connr->nrtx == UIP_MAXSYNRTX)) { + uip_connr->tcpstateflags = UIP_CLOSED; + + /* We call UIP_APPCALL() with uip_flags set to + UIP_TIMEDOUT to inform the application that the + connection has timed out. */ + uip_flags = UIP_TIMEDOUT; + UIP_APPCALL(); + + /* We also send a reset packet to the remote host. */ + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + /* Exponential backoff. */ + uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? + 4: + uip_connr->nrtx); + ++(uip_connr->nrtx); + + /* Ok, so we need to retransmit. We do this differently + depending on which state we are in. In ESTABLISHED, we + call upon the application so that it may prepare the + data for the retransmit. In SYN_RCVD, we resend the + SYNACK that we sent earlier and in LAST_ACK we have to + retransmit our FINACK. */ + UIP_STAT(++uip_stat.tcp.rexmit); + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + case UIP_SYN_RCVD: + /* In the SYN_RCVD state, we should retransmit our + SYNACK. */ + goto tcp_send_synack; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application + to do the actual retransmit after which we jump into + the code for sending out the packet (the apprexmit + label). */ + uip_flags = UIP_REXMIT; + UIP_APPCALL(); + goto apprexmit; + + case UIP_FIN_WAIT_1: + case UIP_CLOSING: + case UIP_LAST_ACK: + /* In all these states we should retransmit a FINACK. */ + goto tcp_send_finack; + + } + } + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { + /* If there was no need for a retransmission, we poll the + application for new data. */ + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + } + goto drop; + } +#if UIP_UDP + if(flag == UIP_UDP_TIMER) { + if(uip_udp_conn->lport != 0) { + uip_conn = NULL; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_slen = 0; + uip_flags = UIP_POLL; + UIP_UDP_APPCALL(); + goto udp_send; + } else { + goto drop; + } + } +#endif + + /* This is where the input processing starts. */ + UIP_STAT(++uip_stat.ip.recv); + + /* Start of IP input header processing code. */ + +#if UIP_CONF_IPV6 + /* Check validity of the IP header. */ + if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ipv6: invalid version."); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* Check validity of the IP header. */ + if(BUF->vhl != 0x45) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ip: invalid version or header length."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + /* Check the size of the packet. If the size reported to us in + uip_len is smaller the size reported in the IP header, we assume + that the packet has been corrupted in transit. If the size of + uip_len is larger than the size reported in the IP packet header, + the packet has been padded and we set uip_len to the correct + value.. */ + + if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) { + uip_len = (BUF->len[0] << 8) + BUF->len[1]; +#if UIP_CONF_IPV6 + uip_len += 40; /* The length reported in the IPv6 header is the + length of the payload that follows the + header. However, uIP uses the uip_len variable + for holding the size of the entire packet, + including the IP header. For IPv4 this is not a + problem as the length field in the IPv4 header + contains the length of the entire packet. But + for IPv6 we need to add the size of the IPv6 + header (40 bytes). */ +#endif /* UIP_CONF_IPV6 */ + } else { + UIP_LOG("ip: packet shorter than reported in IP header."); + goto drop; + } + +#if !UIP_CONF_IPV6 + /* Check the fragment flag. */ + if((BUF->ipoffset[0] & 0x3f) != 0 || + BUF->ipoffset[1] != 0) { +#if UIP_REASSEMBLY + uip_len = uip_reass(); + if(uip_len == 0) { + goto drop; + } +#else /* UIP_REASSEMBLY */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.fragerr); + UIP_LOG("ip: fragment dropped."); + goto drop; +#endif /* UIP_REASSEMBLY */ + } +#endif /* UIP_CONF_IPV6 */ + + if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) { + /* If we are configured to use ping IP address configuration and + hasn't been assigned an IP address yet, we accept all ICMP + packets. */ +#if UIP_PINGADDRCONF && !UIP_CONF_IPV6 + if(BUF->proto == UIP_PROTO_ICMP) { + UIP_LOG("ip: possible ping config packet received."); + goto icmp_input; + } else { + UIP_LOG("ip: packet dropped since no address assigned."); + goto drop; + } +#endif /* UIP_PINGADDRCONF */ + + } else { + /* If IP broadcast support is configured, we check for a broadcast + UDP packet, which may be destined to us. */ +#if UIP_BROADCAST + DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum()); + if(BUF->proto == UIP_PROTO_UDP && + uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) + /*&& + uip_ipchksum() == 0xffff*/) { + goto udp_input; + } +#endif /* UIP_BROADCAST */ + + /* Check if the packet is destined for our IP address. */ +#if !UIP_CONF_IPV6 + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* For IPv6, packet reception is a little trickier as we need to + make sure that we listen to certain multicast addresses (all + hosts multicast address, and the solicited-node multicast + address) as well. However, we will cheat here and accept all + multicast packets that are sent to the ff02::/16 addresses. */ + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && + BUF->destipaddr[0] != HTONS(0xff02)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + } + +#if !UIP_CONF_IPV6 + if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header + checksum. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_LOG("ip: bad checksum."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so, + proceed with TCP input + processing. */ + goto tcp_input; + } + +#if UIP_UDP + if(BUF->proto == UIP_PROTO_UDP) { + goto udp_input; + } +#endif /* UIP_UDP */ + +#if !UIP_CONF_IPV6 + /* ICMPv4 processing code follows. */ + if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp."); + goto drop; + } + +#if UIP_PINGADDRCONF + icmp_input: +#endif /* UIP_PINGADDRCONF */ + UIP_STAT(++uip_stat.icmp.recv); + + /* ICMP echo (i.e., ping) processing. This is simple, we only change + the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP + checksum before we return the packet. */ + if(ICMPBUF->type != ICMP_ECHO) { + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: not icmp echo."); + goto drop; + } + + /* If we are configured to use ping IP address assignment, we use + the destination IP address of this ping packet and assign it to + ourself. */ +#if UIP_PINGADDRCONF + if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) { + uip_hostaddr[0] = BUF->destipaddr[0]; + uip_hostaddr[1] = BUF->destipaddr[1]; + } +#endif /* UIP_PINGADDRCONF */ + + ICMPBUF->type = ICMP_ECHO_REPLY; + + if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1; + } else { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8); + } + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + + /* End of IPv4 input header processing code. */ +#else /* !UIP_CONF_IPV6 */ + + /* This is IPv6 ICMPv6 processing code. */ + DEBUG_PRINTF("icmp6_input: length %d\n", uip_len); + + if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp6."); + goto drop; + } + + UIP_STAT(++uip_stat.icmp.recv); + + /* If we get a neighbor solicitation for our address we should send + a neighbor advertisement message back. */ + if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) { + if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) { + + if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { + /* Save the sender's address in our neighbor list. */ + uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2])); + } + + /* We should now send a neighbor advertisement back to where the + neighbor solicication came from. */ + ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT; + ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */ + + ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0; + + uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr); + uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr); + ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; + ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ + memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + goto send; + + } + goto drop; + } else if(ICMPBUF->type == ICMP6_ECHO) { + /* ICMP echo (i.e., ping) processing. This is simple, we only + change the ICMP type from ECHO to ECHO_REPLY and update the + ICMP checksum before we return the packet. */ + + ICMPBUF->type = ICMP6_ECHO_REPLY; + + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + } else { + DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type); + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: unknown ICMP message."); + goto drop; + } + + /* End of IPv6 ICMP processing. */ + +#endif /* !UIP_CONF_IPV6 */ + +#if UIP_UDP + /* UDP input processing. */ + udp_input: + /* UDP processing is really just a hack. We don't do anything to the + UDP/IP headers, but let the UDP application do all the hard + work. If the application sets uip_slen, it has a packet to + send. */ +#if UIP_UDP_CHECKSUMS + uip_len = uip_len - UIP_IPUDPH_LEN; + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) { + UIP_STAT(++uip_stat.udp.drop); + UIP_STAT(++uip_stat.udp.chkerr); + UIP_LOG("udp: bad checksum."); + goto drop; + } +#else /* UIP_UDP_CHECKSUMS */ + uip_len = uip_len - UIP_IPUDPH_LEN; +#endif /* UIP_UDP_CHECKSUMS */ + + /* Demultiplex this UDP packet between the UDP "connections". */ + for(uip_udp_conn = &uip_udp_conns[0]; + uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; + ++uip_udp_conn) { + /* If the local UDP port is non-zero, the connection is considered + to be used. If so, the local port number is checked against the + destination port number in the received packet. If the two port + numbers match, the remote port number is checked if the + connection is bound to a remote port. Finally, if the + connection is bound to a remote IP address, the source IP + address of the packet is checked. */ + if(uip_udp_conn->lport != 0 && + UDPBUF->destport == uip_udp_conn->lport && + (uip_udp_conn->rport == 0 || + UDPBUF->srcport == uip_udp_conn->rport) && + (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) || + uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || + uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) { + goto udp_found; + } + } + UIP_LOG("udp: no matching connection found"); + goto drop; + + udp_found: + uip_conn = NULL; + uip_flags = UIP_NEWDATA; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_slen = 0; + UIP_UDP_APPCALL(); + udp_send: + if(uip_slen == 0) { + goto drop; + } + uip_len = uip_slen + UIP_IPUDPH_LEN; + +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->ttl = uip_udp_conn->ttl; + BUF->proto = UIP_PROTO_UDP; + + UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN); + UDPBUF->udpchksum = 0; + + BUF->srcport = uip_udp_conn->lport; + BUF->destport = uip_udp_conn->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr); + + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; + +#if UIP_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + UDPBUF->udpchksum = ~(uip_udpchksum()); + if(UDPBUF->udpchksum == 0) { + UDPBUF->udpchksum = 0xffff; + } +#endif /* UIP_UDP_CHECKSUMS */ + + goto ip_send_nolen; +#endif /* UIP_UDP */ + + /* TCP input processing. */ + tcp_input: + UIP_STAT(++uip_stat.tcp.recv); + + /* Start of TCP input header processing code. */ + + if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP + checksum. */ + UIP_STAT(++uip_stat.tcp.drop); + UIP_STAT(++uip_stat.tcp.chkerr); + UIP_LOG("tcp: bad checksum."); + goto drop; + } + + + /* Demultiplex this segment. */ + /* First check any active connections. */ + for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; + ++uip_connr) { + if(uip_connr->tcpstateflags != UIP_CLOSED && + BUF->destport == uip_connr->lport && + BUF->srcport == uip_connr->rport && + uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) { + goto found; + } + } + + /* If we didn't find and active connection that expected the packet, + either this packet is an old duplicate, or this is a SYN packet + destined for a connection in LISTEN. If the SYN flag isn't set, + it is an old packet and we send a RST. */ + if((BUF->flags & TCP_CTL) != TCP_SYN) { + goto reset; + } + + tmp16 = BUF->destport; + /* Next, check listening connections. */ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(tmp16 == uip_listenports[c]) + goto found_listen; + } + + /* No matching connection found, so we send a RST packet. */ + UIP_STAT(++uip_stat.tcp.synrst); + reset: + + /* We do not send resets in response to resets. */ + if(BUF->flags & TCP_RST) { + goto drop; + } + + UIP_STAT(++uip_stat.tcp.rst); + + BUF->flags = TCP_RST | TCP_ACK; + uip_len = UIP_IPTCPH_LEN; + BUF->tcpoffset = 5 << 4; + + /* Flip the seqno and ackno fields in the TCP header. */ + c = BUF->seqno[3]; + BUF->seqno[3] = BUF->ackno[3]; + BUF->ackno[3] = c; + + c = BUF->seqno[2]; + BUF->seqno[2] = BUF->ackno[2]; + BUF->ackno[2] = c; + + c = BUF->seqno[1]; + BUF->seqno[1] = BUF->ackno[1]; + BUF->ackno[1] = c; + + c = BUF->seqno[0]; + BUF->seqno[0] = BUF->ackno[0]; + BUF->ackno[0] = c; + + /* We also have to increase the sequence number we are + acknowledging. If the least significant byte overflowed, we need + to propagate the carry to the other bytes as well. */ + if(++BUF->ackno[3] == 0) { + if(++BUF->ackno[2] == 0) { + if(++BUF->ackno[1] == 0) { + ++BUF->ackno[0]; + } + } + } + + /* Swap port numbers. */ + tmp16 = BUF->srcport; + BUF->srcport = BUF->destport; + BUF->destport = tmp16; + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + /* And send out the RST packet! */ + goto tcp_send_noconn; + + /* This label will be jumped to if we matched the incoming packet + with a connection in LISTEN. In that case, we should create a new + connection and send a SYNACK in return. */ + found_listen: + /* First we check if there are any connections avaliable. Unused + connections are kept in the same table as used connections, but + unused ones have the tcpstate set to CLOSED. Also, connections in + TIME_WAIT are kept track of and we'll use the oldest one if no + CLOSED connections are found. Thanks to Eddie C. Dost for a very + nice algorithm for the TIME_WAIT search. */ + uip_connr = 0; + for(c = 0; c < UIP_CONNS; ++c) { + if(uip_conns[c].tcpstateflags == UIP_CLOSED) { + uip_connr = &uip_conns[c]; + break; + } + if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { + if(uip_connr == 0 || + uip_conns[c].timer > uip_connr->timer) { + uip_connr = &uip_conns[c]; + } + } + } + + if(uip_connr == 0) { + /* All connections are used already, we drop packet and hope that + the remote end will retransmit the packet at a time when we + have more spare connections. */ + UIP_STAT(++uip_stat.tcp.syndrop); + UIP_LOG("tcp: found no unused connections."); + goto drop; + } + uip_conn = uip_connr; + + /* Fill in the necessary fields for the new connection. */ + uip_connr->rto = uip_connr->timer = UIP_RTO; + uip_connr->sa = 0; + uip_connr->sv = 4; + uip_connr->nrtx = 0; + uip_connr->lport = BUF->destport; + uip_connr->rport = BUF->srcport; + uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); + uip_connr->tcpstateflags = UIP_SYN_RCVD; + + uip_connr->snd_nxt[0] = iss[0]; + uip_connr->snd_nxt[1] = iss[1]; + uip_connr->snd_nxt[2] = iss[2]; + uip_connr->snd_nxt[3] = iss[3]; + uip_connr->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_add_rcv_nxt(1); + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = uip_connr->mss = + tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + + /* Our response will be a SYNACK. */ +#if UIP_ACTIVE_OPEN + tcp_send_synack: + BUF->flags = TCP_ACK; + + tcp_send_syn: + BUF->flags |= TCP_SYN; +#else /* UIP_ACTIVE_OPEN */ + tcp_send_synack: + BUF->flags = TCP_SYN | TCP_ACK; +#endif /* UIP_ACTIVE_OPEN */ + + /* We send out the TCP Maximum Segment Size option with our + SYNACK. */ + BUF->optdata[0] = TCP_OPT_MSS; + BUF->optdata[1] = TCP_OPT_MSS_LEN; + BUF->optdata[2] = (UIP_TCP_MSS) / 256; + BUF->optdata[3] = (UIP_TCP_MSS) & 255; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; + goto tcp_send; + + /* This label will be jumped to if we found an active connection. */ + found: + uip_conn = uip_connr; + uip_flags = 0; + /* We do a very naive form of TCP reset processing; we just accept + any RST and kill our connection. We should in fact check if the + sequence number of this reset is wihtin our advertised window + before we accept the reset. */ + if(BUF->flags & TCP_RST) { + uip_connr->tcpstateflags = UIP_CLOSED; + UIP_LOG("tcp: got reset, aborting connection."); + uip_flags = UIP_ABORT; + UIP_APPCALL(); + goto drop; + } + /* Calculated the length of the data, if the application has sent + any data to us. */ + c = (BUF->tcpoffset >> 4) << 2; + /* uip_len will contain the length of the actual TCP data. This is + calculated by subtracing the length of the TCP header (in + c) and the length of the IP header (20 bytes). */ + uip_len = uip_len - c - UIP_IPH_LEN; + + /* First, check if the sequence number of the incoming packet is + what we're expecting next. If not, we send out an ACK with the + correct numbers in. */ + if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && + ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) { + if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && + (BUF->seqno[0] != uip_connr->rcv_nxt[0] || + BUF->seqno[1] != uip_connr->rcv_nxt[1] || + BUF->seqno[2] != uip_connr->rcv_nxt[2] || + BUF->seqno[3] != uip_connr->rcv_nxt[3])) { + goto tcp_send_ack; + } + } + + /* Next, check if the incoming segment acknowledges any outstanding + data. If so, we update the sequence number, reset the length of + the outstanding data, calculate RTT estimations, and reset the + retransmission timer. */ + if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { + uip_add32(uip_connr->snd_nxt, uip_connr->len); + + if(BUF->ackno[0] == uip_acc32[0] && + BUF->ackno[1] == uip_acc32[1] && + BUF->ackno[2] == uip_acc32[2] && + BUF->ackno[3] == uip_acc32[3]) { + /* Update sequence number. */ + uip_connr->snd_nxt[0] = uip_acc32[0]; + uip_connr->snd_nxt[1] = uip_acc32[1]; + uip_connr->snd_nxt[2] = uip_acc32[2]; + uip_connr->snd_nxt[3] = uip_acc32[3]; + + + /* Do RTT estimation, unless we have done retransmissions. */ + if(uip_connr->nrtx == 0) { + signed char m; + m = uip_connr->rto - uip_connr->timer; + /* This is taken directly from VJs original code in his paper */ + m = m - (uip_connr->sa >> 3); + uip_connr->sa += m; + if(m < 0) { + m = -m; + } + m = m - (uip_connr->sv >> 2); + uip_connr->sv += m; + uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; + + } + /* Set the acknowledged flag. */ + uip_flags = UIP_ACKDATA; + /* Reset the retransmission timer. */ + uip_connr->timer = uip_connr->rto; + + /* Reset length of outstanding data. */ + uip_connr->len = 0; + } + + } + + /* Do different things depending on in what state the connection is. */ + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not + implemented, since we force the application to close when the + peer sends a FIN (hence the application goes directly from + ESTABLISHED to LAST_ACK). */ + case UIP_SYN_RCVD: + /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and + we are waiting for an ACK that acknowledges the data we sent + out the last time. Therefore, we want to have the UIP_ACKDATA + flag set. If so, we enter the ESTABLISHED state. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_flags = UIP_CONNECTED; + uip_connr->len = 0; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + goto drop; +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In SYN_SENT, we wait for a SYNACK that is sent in response to + our SYN. The rcv_nxt is set to sequence number in the SYNACK + plus one, and we send an ACK. We move into the ESTABLISHED + state. */ + if((uip_flags & UIP_ACKDATA) && + (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = + uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_add_rcv_nxt(1); + uip_flags = UIP_CONNECTED | UIP_NEWDATA; + uip_connr->len = 0; + uip_len = 0; + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + /* Inform the application that the connection failed */ + uip_flags = UIP_ABORT; + UIP_APPCALL(); + /* The connection is closed after we send the RST */ + uip_conn->tcpstateflags = UIP_CLOSED; + goto reset; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application to feed + data into the uip_buf. If the UIP_ACKDATA flag is set, the + application should put new data into the buffer, otherwise we are + retransmitting an old segment, and the application should put that + data into the buffer. + + If the incoming packet is a FIN, we should close the connection on + this side as well, and we send out a FIN and enter the LAST_ACK + state. We require that there is no outstanding data; otherwise the + sequence numbers will be screwed up. */ + + if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + if(uip_outstanding(uip_connr)) { + goto drop; + } + uip_add_rcv_nxt(1 + uip_len); + uip_flags |= UIP_CLOSE; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + } + UIP_APPCALL(); + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_LAST_ACK; + uip_connr->nrtx = 0; + tcp_send_finack: + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* Check the URG flag. If this is set, the segment carries urgent + data that we must pass to the application. */ + if((BUF->flags & TCP_URG) != 0) { +#if UIP_URGDATA > 0 + uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1]; + if(uip_urglen > uip_len) { + /* There is more urgent data in the next segment to come. */ + uip_urglen = uip_len; + } + uip_add_rcv_nxt(uip_urglen); + uip_len -= uip_urglen; + uip_urgdata = uip_appdata; + uip_appdata += uip_urglen; + } else { + uip_urglen = 0; +#else /* UIP_URGDATA > 0 */ + uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); + uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +#endif /* UIP_URGDATA > 0 */ + } + + /* If uip_len > 0 we have TCP data in the packet, and we flag this + by setting the UIP_NEWDATA flag and update the sequence number + we acknowledge. If the application has stopped the dataflow + using uip_stop(), we must not accept any data packets from the + remote host. */ + if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + + /* Check if the available buffer space advertised by the other end + is smaller than the initial MSS for this connection. If so, we + set the current MSS to the window size to ensure that the + application does not send more data than the other end can + handle. + + If the remote host advertises a zero window, we set the MSS to + the initial MSS so that the application will send an entire MSS + of data. This data will not be acknowledged by the receiver, + and the application will retransmit it. This is called the + "persistent timer" and uses the retransmission mechanim. + */ + tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1]; + if(tmp16 > uip_connr->initialmss || + tmp16 == 0) { + tmp16 = uip_connr->initialmss; + } + uip_connr->mss = tmp16; + + /* If this packet constitutes an ACK for outstanding data (flagged + by the UIP_ACKDATA flag, we should call the application since it + might want to send more data. If the incoming packet had data + from the peer (as flagged by the UIP_NEWDATA flag), the + application must also be notified. + + When the application is called, the global variable uip_len + contains the length of the incoming data. The application can + access the incoming data through the global pointer + uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN + bytes into the uip_buf array. + + If the application wishes to send any data, this data should be + put into the uip_appdata and the length of the data should be + put into uip_len. If the application don't have any data to + send, uip_len must be set to 0. */ + if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { + uip_slen = 0; + UIP_APPCALL(); + + appsend: + + if(uip_flags & UIP_ABORT) { + uip_slen = 0; + uip_connr->tcpstateflags = UIP_CLOSED; + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + if(uip_flags & UIP_CLOSE) { + uip_slen = 0; + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_FIN_WAIT_1; + uip_connr->nrtx = 0; + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* If uip_slen > 0, the application has data to be sent. */ + if(uip_slen > 0) { + + /* If the connection has acknowledged data, the contents of + the ->len variable should be discarded. */ + if((uip_flags & UIP_ACKDATA) != 0) { + uip_connr->len = 0; + } + + /* If the ->len variable is non-zero the connection has + already data in transit and cannot send anymore right + now. */ + if(uip_connr->len == 0) { + + /* The application cannot send more than what is allowed by + the mss (the minumum of the MSS and the available + window). */ + if(uip_slen > uip_connr->mss) { + uip_slen = uip_connr->mss; + } + + /* Remember how much data we send out now so that we know + when everything has been acknowledged. */ + uip_connr->len = uip_slen; + } else { + + /* If the application already had unacknowledged data, we + make sure that the application does not send (i.e., + retransmit) out more than it previously sent out. */ + uip_slen = uip_connr->len; + } + } + uip_connr->nrtx = 0; + apprexmit: + uip_appdata = uip_sappdata; + + /* If the application has data to be sent, or if the incoming + packet had new data in it, we must send out a packet. */ + if(uip_slen > 0 && uip_connr->len > 0) { + /* Add the length of the IP and TCP headers. */ + uip_len = uip_connr->len + UIP_TCPIP_HLEN; + /* We always set the ACK flag in response packets. */ + BUF->flags = TCP_ACK | TCP_PSH; + /* Send the packet. */ + goto tcp_send_noopts; + } + /* If there is no data to send, just send out a pure ACK if + there is newdata. */ + if(uip_flags & UIP_NEWDATA) { + uip_len = UIP_TCPIP_HLEN; + BUF->flags = TCP_ACK; + goto tcp_send_noopts; + } + } + goto drop; + case UIP_LAST_ACK: + /* We can close this connection if the peer has acknowledged our + FIN. This is indicated by the UIP_ACKDATA flag. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_CLOSED; + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + } + break; + + case UIP_FIN_WAIT_1: + /* The application has closed the connection, but the remote host + hasn't closed its end yet. Thus we do nothing but wait for a + FIN from the other side. */ + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_connr->len = 0; + } else { + uip_connr->tcpstateflags = UIP_CLOSING; + } + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } else if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_FIN_WAIT_2; + uip_connr->len = 0; + goto drop; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_FIN_WAIT_2: + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_TIME_WAIT: + goto tcp_send_ack; + + case UIP_CLOSING: + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + } + } + goto drop; + + + /* We jump here when we are ready to send the packet, and just want + to set the appropriate TCP sequence numbers in the TCP header. */ + tcp_send_ack: + BUF->flags = TCP_ACK; + tcp_send_nodata: + uip_len = UIP_IPTCPH_LEN; + tcp_send_noopts: + BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; + tcp_send: + /* We're done with the input processing. We are now ready to send a + reply. Our job is to fill in all the fields of the TCP and IP + headers before calculating the checksum and finally send the + packet. */ + BUF->ackno[0] = uip_connr->rcv_nxt[0]; + BUF->ackno[1] = uip_connr->rcv_nxt[1]; + BUF->ackno[2] = uip_connr->rcv_nxt[2]; + BUF->ackno[3] = uip_connr->rcv_nxt[3]; + + BUF->seqno[0] = uip_connr->snd_nxt[0]; + BUF->seqno[1] = uip_connr->snd_nxt[1]; + BUF->seqno[2] = uip_connr->snd_nxt[2]; + BUF->seqno[3] = uip_connr->snd_nxt[3]; + + BUF->proto = UIP_PROTO_TCP; + + BUF->srcport = uip_connr->lport; + BUF->destport = uip_connr->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr); + + if(uip_connr->tcpstateflags & UIP_STOPPED) { + /* If the connection has issued uip_stop(), we advertise a zero + window so that the remote host will stop sending data. */ + BUF->wnd[0] = BUF->wnd[1] = 0; + } else { + BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); + BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); + } + + tcp_send_noconn: + BUF->ttl = UIP_TTL; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->urgp[0] = BUF->urgp[1] = 0; + + /* Calculate TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + + ip_send_nolen: + +#if UIP_CONF_IPV6 + BUF->vtc = 0x60; + BUF->tcflow = 0x00; + BUF->flow = 0x00; +#else /* UIP_CONF_IPV6 */ + BUF->vhl = 0x45; + BUF->tos = 0; + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + ++ipid; + BUF->ipid[0] = ipid >> 8; + BUF->ipid[1] = ipid & 0xff; + /* Calculate IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + + UIP_STAT(++uip_stat.tcp.sent); + send: + DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len, + (BUF->len[0] << 8) | BUF->len[1]); + + UIP_STAT(++uip_stat.ip.sent); + /* Return and let the caller do the actual transmission. */ + uip_flags = 0; + return; + drop: + uip_len = 0; + uip_flags = 0; + return; +} +/*---------------------------------------------------------------------------*/ +u16_t +htons(u16_t val) +{ + return HTONS(val); +} +/*---------------------------------------------------------------------------*/ +void +uip_send(const void *data, int len) +{ + uip_slen = len; + if(len > 0) { + if(data != uip_sappdata) { + memcpy(uip_sappdata, (data), uip_slen); + } + } +} +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h new file mode 100644 index 0000000..4fc0452 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h @@ -0,0 +1,1601 @@ + +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $ + * + */ + +#ifndef __UIP_H__ +#define __UIP_H__ + +#include "uipopt.h" + +/** + * Repressentation of an IP address. + * + */ +typedef u16_t uip_ip4addr_t[2]; +typedef u16_t uip_ip6addr_t[8]; +#if UIP_CONF_IPV6 +typedef uip_ip6addr_t uip_ipaddr_t; +#else /* UIP_CONF_IPV6 */ +typedef uip_ip4addr_t uip_ipaddr_t; +#endif /* UIP_CONF_IPV6 */ + +/*---------------------------------------------------------------------------*/ +/* First, the functions that should be called from the + * system. Initialization, the periodic timer and incoming packets are + * handled by the following three functions. + */ + +/** + * \defgroup uipconffunc uIP configuration functions + * @{ + * + * The uIP configuration functions are used for setting run-time + * parameters in uIP such as IP addresses. + */ + +/** + * Set the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + + uip_ipaddr_t addr; + + uip_ipaddr(&addr, 192,168,1,2); + uip_sethostaddr(&addr); + + \endcode + * \param addr A pointer to an IP address of type uip_ipaddr_t; + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_sethostaddr(addr) uip_ipaddr_copy(uip_hostaddr, (addr)) + +/** + * Get the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + uip_ipaddr_t hostaddr; + + uip_gethostaddr(&hostaddr); + \endcode + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the currently configured IP address. + * + * \hideinitializer + */ +#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), uip_hostaddr) + +/** + * Set the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the default router. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setdraddr(addr) uip_ipaddr_copy(uip_draddr, (addr)) + +/** + * Set the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the netmask. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setnetmask(addr) uip_ipaddr_copy(uip_netmask, (addr)) + + +/** + * Get the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address of the default router. + * + * \hideinitializer + */ +#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr) + +/** + * Get the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the value of the netmask. + * + * \hideinitializer + */ +#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask) + +/** @} */ + +/** + * \defgroup uipinit uIP initialization functions + * @{ + * + * The uIP initialization functions are used for booting uIP. + */ + +/** + * uIP initialization function. + * + * This function should be called at boot up to initilize the uIP + * TCP/IP stack. + */ +void uip_init(void); + +/** + * uIP initialization function. + * + * This function may be used at boot time to set the initial ip_id. + */ +void uip_setipid(u16_t id); + +/** @} */ + +/** + * \defgroup uipdevfunc uIP device driver functions + * @{ + * + * These functions are used by a network device driver for interacting + * with uIP. + */ + +/** + * Process an incoming packet. + * + * This function should be called when the device driver has received + * a packet from the network. The packet from the device driver must + * be present in the uip_buf buffer, and the length of the packet + * should be placed in the uip_len variable. + * + * When the function returns, there may be an outbound packet placed + * in the uip_buf packet buffer. If so, the uip_len variable is set to + * the length of the packet. If no packet is to be sent out, the + * uip_len variable is set to 0. + * + * The usual way of calling the function is presented by the source + * code below. + \code + uip_len = devicedriver_poll(); + if(uip_len > 0) { + uip_input(); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uIP ARP code before calling + * this function: + \code + #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + uip_len = ethernet_devicedrver_poll(); + if(uip_len > 0) { + if(BUF->type == HTONS(UIP_ETHTYPE_IP)) { + uip_arp_ipin(); + uip_input(); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + if(uip_len > 0) { + ethernet_devicedriver_send(); + } + } + \endcode + * + * \hideinitializer + */ +#define uip_input() uip_process(UIP_DATA) + +/** + * Periodic processing for a connection identified by its number. + * + * This function does the necessary periodic processing (timers, + * polling) for a uIP TCP conneciton, and should be called when the + * periodic uIP timer goes off. It should be called for every + * connection, regardless of whether they are open of closed. + * + * When the function returns, it may have an outbound packet waiting + * for service in the uIP packet buffer, and if so the uip_len + * variable is set to a value larger than zero. The device driver + * should be called to send out the packet. + * + * The ususal way of calling the function is through a for() loop like + * this: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uip_arp_out() function before + * calling the device driver: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the connection which is to be periodically polled. + * + * \hideinitializer + */ +#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \ + uip_process(UIP_TIMER); } while (0) + +/** + * + * + */ +#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED) + +/** + * Perform periodic processing for a connection identified by a pointer + * to its structure. + * + * Same as uip_periodic() but takes a pointer to the actual uip_conn + * struct instead of an integer as its argument. This function can be + * used to force periodic processing of a specific connection. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_periodic_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_TIMER); } while (0) + +/** + * Reuqest that a particular connection should be polled. + * + * Similar to uip_periodic_conn() but does not perform any timer + * processing. The application is polled for new data. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_poll_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_POLL_REQUEST); } while (0) + + +#if UIP_UDP +/** + * Periodic processing for a UDP connection identified by its number. + * + * This function is essentially the same as uip_periodic(), but for + * UDP connections. It is called in a similar fashion as the + * uip_periodic() function: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note As for the uip_periodic() function, special care has to be + * taken when using uIP together with ARP and Ethernet: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the UDP connection to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \ + uip_process(UIP_UDP_TIMER); } while (0) + +/** + * Periodic processing for a UDP connection identified by a pointer to + * its structure. + * + * Same as uip_udp_periodic() but takes a pointer to the actual + * uip_conn struct instead of an integer as its argument. This + * function can be used to force periodic processing of a specific + * connection. + * + * \param conn A pointer to the uip_udp_conn struct for the connection + * to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \ + uip_process(UIP_UDP_TIMER); } while (0) + + +#endif /* UIP_UDP */ + +/** + * The uIP packet buffer. + * + * The uip_buf array is used to hold incoming and outgoing + * packets. The device driver should place incoming data into this + * buffer. When sending data, the device driver should read the link + * level headers and the TCP/IP headers from this buffer. The size of + * the link level headers is configured by the UIP_LLH_LEN define. + * + * \note The application data need not be placed in this buffer, so + * the device driver must read it from the place pointed to by the + * uip_appdata pointer as illustrated by the following example: + \code + void + devicedriver_send(void) + { + hwsend(&uip_buf[0], UIP_LLH_LEN); + if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { + hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN); + } else { + hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN); + hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN); + } + } + \endcode + */ +extern u8_t uip_buf[UIP_BUFSIZE+2]; + +/** @} */ + +/*---------------------------------------------------------------------------*/ +/* Functions that are used by the uIP application program. Opening and + * closing connections, sending and receiving data, etc. is all + * handled by the functions below. +*/ +/** + * \defgroup uipappfunc uIP application functions + * @{ + * + * Functions used by an application running of top of uIP. + */ + +/** + * Start listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_listen(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_listen(u16_t port); + +/** + * Stop listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_unlisten(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_unlisten(u16_t port); + +/** + * Connect to a remote host using TCP. + * + * This function is used to start a new connection to the specified + * port on the specied host. It allocates a new connection identifier, + * sets the connection to the SYN_SENT state and sets the + * retransmission timer to 0. This will cause a TCP SYN segment to be + * sent out the next time this connection is periodically processed, + * which usually is done within 0.5 seconds after the call to + * uip_connect(). + * + * \note This function is avaliable only if support for active open + * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h. + * + * \note Since this function requires the port number to be in network + * byte order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_ipaddr_t ipaddr; + + uip_ipaddr(&ipaddr, 192,168,1,2); + uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param ripaddr The IP address of the remote hot. + * + * \param port A 16-bit port number in network byte order. + * + * \return A pointer to the uIP connection identifier for the new connection, + * or NULL if no connection could be allocated. + * + */ +struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port); + + + +/** + * \internal + * + * Check if a connection has outstanding (i.e., unacknowledged) data. + * + * \param conn A pointer to the uip_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_outstanding(conn) ((conn)->len) + +/** + * Send data on the current connection. + * + * This function is used to send out a single segment of TCP + * data. Only applications that have been invoked by uIP for event + * processing can send data. + * + * The amount of data that actually is sent out after a call to this + * funcion is determined by the maximum amount of data TCP allows. uIP + * will automatically crop the data so that only the appropriate + * amount of data is sent. The function uip_mss() can be used to query + * uIP for the amount of data that actually will be sent. + * + * \note This function does not guarantee that the sent data will + * arrive at the destination. If the data is lost in the network, the + * application will be invoked with the uip_rexmit() event being + * set. The application will then have to resend the data using this + * function. + * + * \param data A pointer to the data which is to be sent. + * + * \param len The maximum amount of data bytes to be sent. + * + * \hideinitializer + */ +void uip_send(const void *data, int len); + +/** + * The length of any incoming data that is currently avaliable (if avaliable) + * in the uip_appdata buffer. + * + * The test function uip_data() must first be used to check if there + * is any data available at all. + * + * \hideinitializer + */ +/*void uip_datalen(void);*/ +#define uip_datalen() uip_len + +/** + * The length of any out-of-band data (urgent data) that has arrived + * on the connection. + * + * \note The configuration parameter UIP_URGDATA must be set for this + * function to be enabled. + * + * \hideinitializer + */ +#define uip_urgdatalen() uip_urglen + +/** + * Close the current connection. + * + * This function will close the current connection in a nice way. + * + * \hideinitializer + */ +#define uip_close() (uip_flags = UIP_CLOSE) + +/** + * Abort the current connection. + * + * This function will abort (reset) the current connection, and is + * usually used when an error has occured that prevents using the + * uip_close() function. + * + * \hideinitializer + */ +#define uip_abort() (uip_flags = UIP_ABORT) + +/** + * Tell the sending host to stop sending data. + * + * This function will close our receiver's window so that we stop + * receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED) + +/** + * Find out if the current connection has been previously stopped with + * uip_stop(). + * + * \hideinitializer + */ +#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED) + +/** + * Restart the current connection, if is has previously been stopped + * with uip_stop(). + * + * This function will open the receiver's window again so that we + * start receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_restart() do { uip_flags |= UIP_NEWDATA; \ + uip_conn->tcpstateflags &= ~UIP_STOPPED; \ + } while(0) + + +/* uIP tests that can be made to determine in what state the current + connection is, and what the application function should do. */ + +/** + * Is the current connection a UDP connection? + * + * This function checks whether the current connection is a UDP connection. + * + * \hideinitializer + * + */ +#define uip_udpconnection() (uip_conn == NULL) + +/** + * Is new incoming data available? + * + * Will reduce to non-zero if there is new data for the application + * present at the uip_appdata pointer. The size of the data is + * avaliable through the uip_len variable. + * + * \hideinitializer + */ +#define uip_newdata() (uip_flags & UIP_NEWDATA) + +/** + * Has previously sent data been acknowledged? + * + * Will reduce to non-zero if the previously sent data has been + * acknowledged by the remote host. This means that the application + * can send new data. + * + * \hideinitializer + */ +#define uip_acked() (uip_flags & UIP_ACKDATA) + +/** + * Has the connection just been connected? + * + * Reduces to non-zero if the current connection has been connected to + * a remote host. This will happen both if the connection has been + * actively opened (with uip_connect()) or passively opened (with + * uip_listen()). + * + * \hideinitializer + */ +#define uip_connected() (uip_flags & UIP_CONNECTED) + +/** + * Has the connection been closed by the other end? + * + * Is non-zero if the connection has been closed by the remote + * host. The application may then do the necessary clean-ups. + * + * \hideinitializer + */ +#define uip_closed() (uip_flags & UIP_CLOSE) + +/** + * Has the connection been aborted by the other end? + * + * Non-zero if the current connection has been aborted (reset) by the + * remote host. + * + * \hideinitializer + */ +#define uip_aborted() (uip_flags & UIP_ABORT) + +/** + * Has the connection timed out? + * + * Non-zero if the current connection has been aborted due to too many + * retransmissions. + * + * \hideinitializer + */ +#define uip_timedout() (uip_flags & UIP_TIMEDOUT) + +/** + * Do we need to retransmit previously data? + * + * Reduces to non-zero if the previously sent data has been lost in + * the network, and the application should retransmit it. The + * application should send the exact same data as it did the last + * time, using the uip_send() function. + * + * \hideinitializer + */ +#define uip_rexmit() (uip_flags & UIP_REXMIT) + +/** + * Is the connection being polled by uIP? + * + * Is non-zero if the reason the application is invoked is that the + * current connection has been idle for a while and should be + * polled. + * + * The polling event can be used for sending data without having to + * wait for the remote host to send data. + * + * \hideinitializer + */ +#define uip_poll() (uip_flags & UIP_POLL) + +/** + * Get the initial maxium segment size (MSS) of the current + * connection. + * + * \hideinitializer + */ +#define uip_initialmss() (uip_conn->initialmss) + +/** + * Get the current maxium segment size that can be sent on the current + * connection. + * + * The current maxiumum segment size that can be sent on the + * connection is computed from the receiver's window and the MSS of + * the connection (which also is available by calling + * uip_initialmss()). + * + * \hideinitializer + */ +#define uip_mss() (uip_conn->mss) + +/** + * Set up a new UDP connection. + * + * This function sets up a new UDP connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * uip_udp_bind() call, after the uip_udp_new() function has been + * called. + * + * Example: + \code + uip_ipaddr_t addr; + struct uip_udp_conn *c; + + uip_ipaddr(&addr, 192,168,2,1); + c = uip_udp_new(&addr, HTONS(12345)); + if(c != NULL) { + uip_udp_bind(c, HTONS(12344)); + } + \endcode + * \param ripaddr The IP address of the remote host. + * + * \param rport The remote port number in network byte order. + * + * \return The uip_udp_conn structure for the new connection or NULL + * if no connection could be allocated. + */ +struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport); + +/** + * Removed a UDP connection. + * + * \param conn A pointer to the uip_udp_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_udp_remove(conn) (conn)->lport = 0 + +/** + * Bind a UDP connection to a local port. + * + * \param conn A pointer to the uip_udp_conn structure for the + * connection. + * + * \param port The local port number, in network byte order. + * + * \hideinitializer + */ +#define uip_udp_bind(conn, port) (conn)->lport = port + +/** + * Send a UDP datagram of length len on the current connection. + * + * This function can only be called in response to a UDP event (poll + * or newdata). The data must be present in the uip_buf buffer, at the + * place pointed to by the uip_appdata pointer. + * + * \param len The length of the data in the uip_buf buffer. + * + * \hideinitializer + */ +#define uip_udp_send(len) uip_send((char *)uip_appdata, len) + +/** @} */ + +/* uIP convenience and converting functions. */ + +/** + * \defgroup uipconvfunc uIP conversion functions + * @{ + * + * These functions can be used for converting between different data + * formats used by uIP. + */ + +/** + * Construct an IP address from four bytes. + * + * This function constructs an IP address of the type that uIP handles + * internally from four bytes. The function is handy for specifying IP + * addresses to use with e.g. the uip_connect() function. + * + * Example: + \code + uip_ipaddr_t ipaddr; + struct uip_conn *c; + + uip_ipaddr(&ipaddr, 192,168,1,2); + c = uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address. + * + * \param addr0 The first octet of the IP address. + * \param addr1 The second octet of the IP address. + * \param addr2 The third octet of the IP address. + * \param addr3 The forth octet of the IP address. + * + * \hideinitializer + */ +#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \ + ((u16_t *)(addr))[0] = HTONS(((addr0) << 8) | (addr1)); \ + ((u16_t *)(addr))[1] = HTONS(((addr2) << 8) | (addr3)); \ + } while(0) + +/** + * Construct an IPv6 address from eight 16-bit words. + * + * This function constructs an IPv6 address. + * + * \hideinitializer + */ +#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \ + ((u16_t *)(addr))[0] = HTONS((addr0)); \ + ((u16_t *)(addr))[1] = HTONS((addr1)); \ + ((u16_t *)(addr))[2] = HTONS((addr2)); \ + ((u16_t *)(addr))[3] = HTONS((addr3)); \ + ((u16_t *)(addr))[4] = HTONS((addr4)); \ + ((u16_t *)(addr))[5] = HTONS((addr5)); \ + ((u16_t *)(addr))[6] = HTONS((addr6)); \ + ((u16_t *)(addr))[7] = HTONS((addr7)); \ + } while(0) + +/** + * Copy an IP address to another IP address. + * + * Copies an IP address from one place to another. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr_copy(&ipaddr2, &ipaddr1); + \endcode + * + * \param dest The destination for the copy. + * \param src The source from where to copy. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_copy(dest, src) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1]; \ + } while(0) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t)) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses + * + * Compares two IP addresses. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \ + ((u16_t *)addr1)[1] == ((u16_t *)addr2)[1]) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses with netmasks + * + * Compares two IP addresses with netmasks. The masks are used to mask + * out the bits that are to be compared. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, mask; + + uip_ipaddr(&mask, 255,255,255,0); + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&ipaddr2, 192,16,1,3); + if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_maskcmp(addr1, addr2, mask) \ + (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \ + (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \ + ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \ + (((u16_t *)addr2)[1] & ((u16_t *)mask)[1]))) + + +/** + * Mask out the network part of an IP address. + * + * Masks out the network part of an IP address, given the address and + * the netmask. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, netmask; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&netmask, 255,255,255,0); + uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask); + \endcode + * + * In the example above, the variable "ipaddr2" will contain the IP + * address 192.168.1.0. + * + * \param dest Where the result is to be placed. + * \param src The IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_mask(dest, src, mask) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \ + } while(0) + +/** + * Pick the first octet of an IP address. + * + * Picks out the first octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr1(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 1. + * + * \hideinitializer + */ +#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8) + +/** + * Pick the second octet of an IP address. + * + * Picks out the second octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr2(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 2. + * + * \hideinitializer + */ +#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff) + +/** + * Pick the third octet of an IP address. + * + * Picks out the third octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr3(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 3. + * + * \hideinitializer + */ +#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8) + +/** + * Pick the fourth octet of an IP address. + * + * Picks out the fourth octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr4(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 4. + * + * \hideinitializer + */ +#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff) + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the htons() function instead. + * + * \hideinitializer + */ +#ifndef HTONS +# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN +# define HTONS(n) (n) +# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) +# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +#else +#error "HTONS already defined!" +#endif /* HTONS */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the HTONS() macro instead. + */ +#ifndef htons +u16_t htons(u16_t val); +#endif /* htons */ +#ifndef ntohs +#define ntohs htons +#endif + +/** @} */ + +/** + * Pointer to the application data in the packet buffer. + * + * This pointer points to the application data when the application is + * called. If the application wishes to send data, the application may + * use this space to write the data into before calling uip_send(). + */ +extern void *uip_appdata; + +#if UIP_URGDATA > 0 +/* u8_t *uip_urgdata: + * + * This pointer points to any urgent data that has been received. Only + * present if compiled with support for urgent data (UIP_URGDATA). + */ +extern void *uip_urgdata; +#endif /* UIP_URGDATA > 0 */ + + +/** + * \defgroup uipdrivervars Variables used in uIP device drivers + * @{ + * + * uIP has a few global variables that are used in device drivers for + * uIP. + */ + +/** + * The length of the packet in the uip_buf buffer. + * + * The global variable uip_len holds the length of the packet in the + * uip_buf buffer. + * + * When the network device driver calls the uIP input function, + * uip_len should be set to the length of the packet in the uip_buf + * buffer. + * + * When sending packets, the device driver should use the contents of + * the uip_len variable to determine the length of the outgoing + * packet. + * + */ +extern u16_t uip_len; + +/** @} */ + +#if UIP_URGDATA > 0 +extern u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + + +/** + * Representation of a uIP TCP connection. + * + * The uip_conn structure is used for identifying a connection. All + * but one field in the structure are to be considered read-only by an + * application. The only exception is the appstate field whos purpose + * is to let the application store application-specific state (e.g., + * file pointers) for the connection. The type of this field is + * configured in the "uipopt.h" header file. + */ +struct uip_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */ + + u16_t lport; /**< The local TCP port, in network byte order. */ + u16_t rport; /**< The local remote TCP port, in network byte + order. */ + + u8_t rcv_nxt[4]; /**< The sequence number that we expect to + receive next. */ + u8_t snd_nxt[4]; /**< The sequence number that was last sent by + us. */ + u16_t len; /**< Length of the data that was previously sent. */ + u16_t mss; /**< Current maximum segment size for the + connection. */ + u16_t initialmss; /**< Initial maximum segment size for the + connection. */ + u8_t sa; /**< Retransmission time-out calculation state + variable. */ + u8_t sv; /**< Retransmission time-out calculation state + variable. */ + u8_t rto; /**< Retransmission time-out. */ + u8_t tcpstateflags; /**< TCP state and flags. */ + u8_t timer; /**< The retransmission timer. */ + u8_t nrtx; /**< The number of retransmissions for the last + segment sent. */ + + /** The application state. */ + uip_tcp_appstate_t appstate; +}; + + +/** + * Pointer to the current TCP connection. + * + * The uip_conn pointer can be used to access the current TCP + * connection. + */ +extern struct uip_conn *uip_conn; +/* The array containing all uIP connections. */ +extern struct uip_conn uip_conns[UIP_CONNS]; +/** + * \addtogroup uiparch + * @{ + */ + +/** + * 4-byte array used for the 32-bit sequence number calculations. + */ +extern u8_t uip_acc32[4]; + +/** @} */ + + +#if UIP_UDP +/** + * Representation of a uIP UDP connection. + */ +struct uip_udp_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */ + u16_t lport; /**< The local port number in network byte order. */ + u16_t rport; /**< The remote port number in network byte order. */ + u8_t ttl; /**< Default time-to-live. */ + + /** The application state. */ + uip_udp_appstate_t appstate; +}; + +/** + * The current UDP connection. + */ +extern struct uip_udp_conn *uip_udp_conn; +extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +/** + * The structure holding the TCP/IP statistics that are gathered if + * UIP_STATISTICS is set to 1. + * + */ +struct uip_stats { + struct { + uip_stats_t drop; /**< Number of dropped packets at the IP + layer. */ + uip_stats_t recv; /**< Number of received packets at the IP + layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP + layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong + IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong + IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong + IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they + were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP + checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they + were neither ICMP, UDP nor TCP. */ + } ip; /**< IP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped ICMP packets. */ + uip_stats_t recv; /**< Number of received ICMP packets. */ + uip_stats_t sent; /**< Number of sent ICMP packets. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong + type. */ + } icmp; /**< ICMP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped TCP segments. */ + uip_stats_t recv; /**< Number of recived TCP segments. */ + uip_stats_t sent; /**< Number of sent TCP segments. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad + checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK + number. */ + uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ + uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few + connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, + triggering a RST. */ + } tcp; /**< TCP statistics. */ +#if UIP_UDP + struct { + uip_stats_t drop; /**< Number of dropped UDP segments. */ + uip_stats_t recv; /**< Number of recived UDP segments. */ + uip_stats_t sent; /**< Number of sent UDP segments. */ + uip_stats_t chkerr; /**< Number of UDP segments with a bad + checksum. */ + } udp; /**< UDP statistics. */ +#endif /* UIP_UDP */ +}; + +/** + * The uIP TCP/IP statistics. + * + * This is the variable in which the uIP TCP/IP statistics are gathered. + */ +extern struct uip_stats uip_stat; + + +/*---------------------------------------------------------------------------*/ +/* All the stuff below this point is internal to uIP and should not be + * used directly by an application or by a device driver. + */ +/*---------------------------------------------------------------------------*/ +/* u8_t uip_flags: + * + * When the application is called, uip_flags will contain the flags + * that are defined in this file. Please read below for more + * infomation. + */ +extern u8_t uip_flags; + +/* The following flags may be set in the global variable uip_flags + before calling the application callback. The UIP_ACKDATA, + UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time, + whereas the others are mutualy exclusive. Note that these flags + should *NOT* be accessed directly, but only through the uIP + functions/macros. */ + +#define UIP_ACKDATA 1 /* Signifies that the outstanding data was + acked and the application should send + out new data instead of retransmitting + the last data. */ +#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent + us new data. */ +#define UIP_REXMIT 4 /* Tells the application to retransmit the + data that was last sent. */ +#define UIP_POLL 8 /* Used for polling the application, to + check if the application has data that + it wants to send. */ +#define UIP_CLOSE 16 /* The remote host has closed the + connection, thus the connection has + gone away. Or the application signals + that it wants to close the + connection. */ +#define UIP_ABORT 32 /* The remote host has aborted the + connection, thus the connection has + gone away. Or the application signals + that it wants to abort the + connection. */ +#define UIP_CONNECTED 64 /* We have got a connection from a remote + host and have set up a new connection + for it, or an active connection has + been successfully established. */ + +#define UIP_TIMEDOUT 128 /* The connection has been aborted due to + too many retransmissions. */ + +/* uip_process(flag): + * + * The actual uIP function which does all the work. + */ +void uip_process(u8_t flag); + +/* The following flags are passed as an argument to the uip_process() + function. They are used to distinguish between the two cases where + uip_process() is called. It can be called either because we have + incoming data that should be processed, or because the periodic + timer has fired. These values are never used directly, but only in + the macrose defined in this file. */ + +#define UIP_DATA 1 /* Tells uIP that there is incoming + data in the uip_buf buffer. The + length of the data is stored in the + global variable uip_len. */ +#define UIP_TIMER 2 /* Tells uIP that the periodic timer + has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should + be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram + should be constructed in the + uip_buf buffer. */ +#if UIP_UDP +#define UIP_UDP_TIMER 5 +#endif /* UIP_UDP */ + +/* The TCP states used in the uip_conn->tcpstateflags. */ +#define UIP_CLOSED 0 +#define UIP_SYN_RCVD 1 +#define UIP_SYN_SENT 2 +#define UIP_ESTABLISHED 3 +#define UIP_FIN_WAIT_1 4 +#define UIP_FIN_WAIT_2 5 +#define UIP_CLOSING 6 +#define UIP_TIME_WAIT 7 +#define UIP_LAST_ACK 8 +#define UIP_TS_MASK 15 + +#define UIP_STOPPED 16 + +/* The TCP and IP headers. */ +struct uip_tcpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcflow; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* TCP header. */ + u16_t srcport, + destport; + u8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +/* The ICMP and IP headers. */ +struct uip_icmpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* ICMP (echo) header. */ + u8_t type, icode; + u16_t icmpchksum; +#if !UIP_CONF_IPV6 + u16_t id, seqno; +#else /* !UIP_CONF_IPV6 */ + u8_t flags, reserved1, reserved2, reserved3; + u8_t icmp6data[16]; + u8_t options[1]; +#endif /* !UIP_CONF_IPV6 */ +}; + + +/* The UDP and IP headers. */ +struct uip_udpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* UDP header. */ + u16_t srcport, + destport; + u16_t udplen; + u16_t udpchksum; +}; + + + +/** + * The buffer size available for user data in the \ref uip_buf buffer. + * + * This macro holds the available size for user data in the \ref + * uip_buf buffer. The macro is intended to be used for checking + * bounds of available user data. + * + * Example: + \code + snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i); + \endcode + * + * \hideinitializer + */ +#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) + + +#define UIP_PROTO_ICMP 1 +#define UIP_PROTO_TCP 6 +#define UIP_PROTO_UDP 17 +#define UIP_PROTO_ICMP6 58 + +/* Header sizes. */ +#if UIP_CONF_IPV6 +#define UIP_IPH_LEN 40 +#else /* UIP_CONF_IPV6 */ +#define UIP_IPH_LEN 20 /* Size of IP header */ +#endif /* UIP_CONF_IPV6 */ +#define UIP_UDPH_LEN 8 /* Size of UDP header */ +#define UIP_TCPH_LEN 20 /* Size of TCP header */ +#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP + + UDP + header */ +#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP + + TCP + header */ +#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN + + +#if UIP_FIXEDADDR +extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#else /* UIP_FIXEDADDR */ +extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#endif /* UIP_FIXEDADDR */ + + + +/** + * Representation of a 48-bit Ethernet address. + */ +struct uip_eth_addr { + u8_t addr[6]; +}; + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +/** + * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. + * + * The UDP checksum is the Internet checksum of data contents of the + * UDP segment, and a pseudo-header as defined in RFC768. + * + * \return The UDP checksum of the UDP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_udpchksum(void); + + +#endif /* __UIP_H__ */ + + +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h new file mode 100644 index 0000000..71fd84b --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h @@ -0,0 +1,138 @@ +/** + * \addtogroup uip + * {@ + */ + +/** + * \defgroup uiparch Architecture specific uIP functions + * @{ + * + * The functions in the architecture specific module implement the IP + * check sum and 32-bit additions. + * + * The IP checksum calculation is the most computationally expensive + * operation in the TCP/IP stack and it therefore pays off to + * implement this in efficient assembler. The purpose of the uip-arch + * module is to let the checksum functions to be implemented in + * architecture specific assembler. + * + */ + +/** + * \file + * Declarations of architecture specific functions. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arch.h,v 1.2 2006/06/07 09:15:19 adam Exp $ + * + */ + +#ifndef __UIP_ARCH_H__ +#define __UIP_ARCH_H__ + +#include "uip.h" + +/** + * Carry out a 32-bit addition. + * + * Because not all architectures for which uIP is intended has native + * 32-bit arithmetic, uIP uses an external C function for doing the + * required 32-bit additions in the TCP protocol processing. This + * function should add the two arguments and place the result in the + * global variable uip_acc32. + * + * \note The 32-bit integer pointed to by the op32 parameter and the + * result in the uip_acc32 variable are in network byte order (big + * endian). + * + * \param op32 A pointer to a 4-byte array representing a 32-bit + * integer in network byte order (big endian). + * + * \param op16 A 16-bit integer in host byte order. + */ +void uip_add32(u8_t *op32, u16_t op16); + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \note This function is not called in the current version of uIP, + * but future versions might make use of it. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \note The uip_appdata pointer that points to the packet data may + * point anywhere in memory, so it is not possible to simply calculate + * the Internet checksum of the contents of the uip_buf buffer. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +u16_t uip_udpchksum(void); + +/** @} */ +/** @} */ + +#endif /* __UIP_ARCH_H__ */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c new file mode 100644 index 0000000..44ca7c4 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c @@ -0,0 +1,423 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uiparp uIP Address Resolution Protocol + * @{ + * + * The Address Resolution Protocol ARP is used for mapping between IP + * addresses and link level addresses such as the Ethernet MAC + * addresses. ARP uses broadcast queries to ask for the link level + * address of a known IP address and the host which is configured with + * the IP address for which the query was meant, will respond with its + * link level address. + * + * \note This ARP implementation only supports Ethernet. + */ + +/** + * \file + * Implementation of the ARP Address Resolution Protocol. + * \author Adam Dunkels + * + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $ + * + */ + + +#include "uip_arp.h" + +#include + +struct arp_hdr { + struct uip_eth_hdr ethhdr; + u16_t hwtype; + u16_t protocol; + u8_t hwlen; + u8_t protolen; + u16_t opcode; + struct uip_eth_addr shwaddr; + u16_t sipaddr[2]; + struct uip_eth_addr dhwaddr; + u16_t dipaddr[2]; +}; + +struct ethip_hdr { + struct uip_eth_hdr ethhdr; + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +}; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +struct arp_entry { + u16_t ipaddr[2]; + struct uip_eth_addr ethaddr; + u8_t time; +}; + +static const struct uip_eth_addr broadcast_ethaddr = + {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff}; + +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; +static u16_t ipaddr[2]; +static u8_t i, c; + +static u8_t arptime; +static u8_t tmpage; + +#define BUF ((struct arp_hdr *)&uip_buf[0]) +#define IPBUF ((struct ethip_hdr *)&uip_buf[0]) +/*-----------------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_init(void) +{ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + memset(arp_table[i].ipaddr, 0, 4); + } +} +/*-----------------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_timer(void) +{ + struct arp_entry *tabptr; + + ++arptime; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && + arptime - tabptr->time >= UIP_ARP_MAXAGE) { + memset(tabptr->ipaddr, 0, 4); + } + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr) +{ + register struct arp_entry *tabptr; + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + + tabptr = &arp_table[i]; + /* Only check those entries that are actually in use. */ + if(tabptr->ipaddr[0] != 0 && + tabptr->ipaddr[1] != 0) { + + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(ipaddr[0] == tabptr->ipaddr[0] && + ipaddr[1] == tabptr->ipaddr[1]) { + + /* An old entry found, update this and return. */ + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; + + return; + } + } + } + + /* If we get here, no existing ARP table entry was found, so we + create one. */ + + /* First, we try to find an unused entry in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(tabptr->ipaddr[0] == 0 && + tabptr->ipaddr[1] == 0) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == UIP_ARPTAB_SIZE) { + tmpage = 0; + c = 0; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(arptime - tabptr->time > tmpage) { + tmpage = arptime - tabptr->time; + c = i; + } + } + i = c; + tabptr = &arp_table[i]; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + memcpy(tabptr->ipaddr, ipaddr, 4); + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; +} +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming IP packets + * + * This function should be called by the device driver when an IP + * packet has been received. The function will check if the address is + * in the ARP cache, and if so the ARP cache entry will be + * refreshed. If no ARP cache entry was found, a new one is created. + * + * This function expects an IP packet with a prepended Ethernet header + * in the uip_buf[] buffer, and the length of the packet in the global + * variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +//#if 0 +void +uip_arp_ipin(void) +{ + uip_len -= sizeof(struct uip_eth_hdr); + + /* Only insert/update an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + if((IPBUF->srcipaddr[0] & uip_netmask[0]) != + (uip_hostaddr[0] & uip_netmask[0])) { + return; + } + if((IPBUF->srcipaddr[1] & uip_netmask[1]) != + (uip_hostaddr[1] & uip_netmask[1])) { + return; + } + uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); + + return; +} +//#endif /* 0 */ +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming ARP packets. + * + * This function should be called by the device driver when an ARP + * packet has been received. The function will act differently + * depending on the ARP packet type: if it is a reply for a request + * that we previously sent out, the ARP cache will be filled in with + * the values from the ARP reply. If the incoming ARP packet is an ARP + * request for our IP address, an ARP reply packet is created and put + * into the uip_buf[] buffer. + * + * When the function returns, the value of the global variable uip_len + * indicates whether the device driver should send out a packet or + * not. If uip_len is zero, no packet should be sent. If uip_len is + * non-zero, it contains the length of the outbound packet that is + * present in the uip_buf[] buffer. + * + * This function expects an ARP packet with a prepended Ethernet + * header in the uip_buf[] buffer, and the length of the packet in the + * global variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_arpin(void) +{ + + if(uip_len < sizeof(struct arp_hdr)) { + uip_len = 0; + return; + } + uip_len = 0; + + switch(BUF->opcode) { + case HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + reply. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + /* First, we register the one who made the request in our ARP + table, since it is likely that we will do more communication + with this host in the future. */ + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + + /* The reply opcode is 2. */ + BUF->opcode = HTONS(2); + + memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); + + BUF->dipaddr[0] = BUF->sipaddr[0]; + BUF->dipaddr[1] = BUF->sipaddr[1]; + BUF->sipaddr[0] = uip_hostaddr[0]; + BUF->sipaddr[1] = uip_hostaddr[1]; + + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + uip_len = sizeof(struct arp_hdr); + } + break; + case HTONS(ARP_REPLY): + /* ARP reply. We insert or update the ARP table if it was meant + for us. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + } + break; + } + + return; +} +/*-----------------------------------------------------------------------------------*/ +/** + * Prepend Ethernet header to an outbound IP packet and see if we need + * to send out an ARP request. + * + * This function should be called before sending out an IP packet. The + * function checks the destination IP address of the IP packet to see + * what Ethernet MAC address that should be used as a destination MAC + * address on the Ethernet. + * + * If the destination IP address is in the local network (determined + * by logical ANDing of netmask and our IP address), the function + * checks the ARP cache to see if an entry for the destination IP + * address is found. If so, an Ethernet header is prepended and the + * function returns. If no ARP cache entry is found for the + * destination IP address, the packet in the uip_buf[] is replaced by + * an ARP request packet for the IP address. The IP packet is dropped + * and it is assumed that they higher level protocols (e.g., TCP) + * eventually will retransmit the dropped packet. + * + * If the destination IP address is not on the local network, the IP + * address of the default router is used instead. + * + * When the function returns, a packet is present in the uip_buf[] + * buffer, and the length of the packet is in the global variable + * uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_out(void) +{ + struct arp_entry *tabptr; + + /* Find the destination IP address in the ARP table and construct + the Ethernet header. If the destination IP addres isn't on the + local network, we use the default router's IP address instead. + + If not ARP table entry is found, we overwrite the original IP + packet with an ARP request for the IP address. */ + + /* First check if destination is a local broadcast. */ + if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { + memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); + } else { + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ipaddr_copy(ipaddr, uip_draddr); + } else { + /* Else, we use the destination IP address. */ + uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); + } + + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { + break; + } + } + + if(i == UIP_ARPTAB_SIZE) { + /* The destination address was not in our ARP table, so we + overwrite the IP packet with an ARP request. */ + + memset(BUF->ethhdr.dest.addr, 0xff, 6); + memset(BUF->dhwaddr.addr, 0x00, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + + uip_ipaddr_copy(BUF->dipaddr, ipaddr); + uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); + BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ + BUF->hwtype = HTONS(ARP_HWTYPE_ETH); + BUF->protocol = HTONS(UIP_ETHTYPE_IP); + BUF->hwlen = 6; + BUF->protolen = 4; + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + + uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; + + uip_len = sizeof(struct arp_hdr); + return; + } + + /* Build an ethernet header. */ + memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); + } + memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + + IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); + + uip_len += sizeof(struct uip_eth_hdr); +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h new file mode 100644 index 0000000..ef93054 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h @@ -0,0 +1,144 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \addtogroup uiparp + * @{ + */ + +/** + * \file + * Macros and definitions for the ARP module. + * \author Adam Dunkels + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.h,v 1.5 2006/06/11 21:46:39 adam Exp $ + * + */ + +#ifndef __UIP_ARP_H__ +#define __UIP_ARP_H__ + +#include "uip.h" + + +extern struct uip_eth_addr uip_ethaddr; + +/** + * The Ethernet header. + */ +struct uip_eth_hdr { + struct uip_eth_addr dest; + struct uip_eth_addr src; + u16_t type; +}; + +#define UIP_ETHTYPE_ARP 0x0806 +#define UIP_ETHTYPE_IP 0x0800 +#define UIP_ETHTYPE_IP6 0x86dd + + +/* The uip_arp_init() function must be called before any of the other + ARP functions. */ +void uip_arp_init(void); + +/* The uip_arp_ipin() function should be called whenever an IP packet + arrives from the Ethernet. This function refreshes the ARP table or + inserts a new mapping if none exists. The function assumes that an + IP packet with an Ethernet header is present in the uip_buf buffer + and that the length of the packet is in the uip_len variable. */ +void uip_arp_ipin(void); +//#define uip_arp_ipin() + +/* The uip_arp_arpin() should be called when an ARP packet is received + by the Ethernet driver. This function also assumes that the + Ethernet frame is present in the uip_buf buffer. When the + uip_arp_arpin() function returns, the contents of the uip_buf + buffer should be sent out on the Ethernet if the uip_len variable + is > 0. */ +void uip_arp_arpin(void); + +/* The uip_arp_out() function should be called when an IP packet + should be sent out on the Ethernet. This function creates an + Ethernet header before the IP header in the uip_buf buffer. The + Ethernet header will have the correct Ethernet MAC destination + address filled in if an ARP table entry for the destination IP + address (or the IP address of the default router) is present. If no + such table entry is found, the IP packet is overwritten with an ARP + request and we rely on TCP to retransmit the packet that was + overwritten. In any case, the uip_len variable holds the length of + the Ethernet frame that should be transmitted. */ +void uip_arp_out(void); + +/* The uip_arp_timer() function should be called every ten seconds. It + is responsible for flushing old entries in the ARP table. */ +void uip_arp_timer(void); + +/** @} */ + +/** + * \addtogroup uipconffunc + * @{ + */ + + +/** + * Specifiy the Ethernet MAC address. + * + * The ARP code needs to know the MAC address of the Ethernet card in + * order to be able to respond to ARP queries and to generate working + * Ethernet headers. + * + * \note This macro only specifies the Ethernet MAC address to the ARP + * code. It cannot be used to change the MAC address of the Ethernet + * card. + * + * \param eaddr A pointer to a struct uip_eth_addr containing the + * Ethernet MAC address of the Ethernet card. + * + * \hideinitializer + */ +#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \ + uip_ethaddr.addr[1] = eaddr.addr[1];\ + uip_ethaddr.addr[2] = eaddr.addr[2];\ + uip_ethaddr.addr[3] = eaddr.addr[3];\ + uip_ethaddr.addr[4] = eaddr.addr[4];\ + uip_ethaddr.addr[5] = eaddr.addr[5];} while(0) + +/** @} */ +/** @} */ + +#endif /* __UIP_ARP_H__ */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h new file mode 100644 index 0000000..6dd72be --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h @@ -0,0 +1,88 @@ +/** + * \defgroup clock Clock interface + * + * The clock interface is the interface between the \ref timer "timer library" + * and the platform specific clock functionality. The clock + * interface must be implemented for each platform that uses the \ref + * timer "timer library". + * + * The clock interface does only one this: it measures time. The clock + * interface provides a macro, CLOCK_SECOND, which corresponds to one + * second of system time. + * + * \sa \ref timer "Timer library" + * + * @{ + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: clock.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __UIP_CLOCK_H__ +#define __UIP_CLOCK_H__ + +#include "clock-arch.h" + +/** + * Initialize the clock library. + * + * This function initializes the clock library and should be called + * from the main() function of the system. + * + */ +void uip_clock_init(void); + +/** + * Get the current clock time. + * + * This function returns the current system clock time. + * + * \return The current clock time, measured in system ticks. + */ +clock_time_t clock_time(void); + +/** + * A second, measured in system clock time. + * + * \hideinitializer + */ +#ifdef CLOCK_CONF_SECOND +#define CLOCK_SECOND CLOCK_CONF_SECOND +#else +#define CLOCK_SECOND (clock_time_t)32 +#endif + +#endif /* __CLOCK_H__ */ + +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp new file mode 100644 index 0000000..444bd0e --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +extern "C" { + #import "utility/uip.h" +} + +struct uip_conn con[UIP_CONNS]; + +void +UIPDebug::uip_debug_printconns() +{ + for(uint8_t i=0;iripaddr,rhs->ripaddr)) + { + Serial.print(" ripaddr: "); + uip_debug_printbytes((const uint8_t *)lhs->ripaddr,4); + Serial.print(" -> "); + uip_debug_printbytes((const uint8_t *)rhs->ripaddr,4); + Serial.println(); + uip_ipaddr_copy(lhs->ripaddr,rhs->ripaddr); + changed = true; + } + if (lhs->lport != rhs->lport) + { + Serial.print(" lport: "); + Serial.print(htons(lhs->lport)); + Serial.print(" -> "); + Serial.println(htons(rhs->lport)); + lhs->lport = rhs->lport; + changed = true; + } + if (lhs->rport != rhs->rport) + { + Serial.print(" rport: "); + Serial.print(htons(lhs->rport)); + Serial.print(" -> "); + Serial.println(htons(rhs->rport)); + lhs->rport = rhs->rport; + changed = true; + } + if ((uint32_t)lhs->rcv_nxt[0] != (uint32_t)rhs->rcv_nxt[0]) + { + Serial.print(" rcv_nxt: "); + uip_debug_printbytes(lhs->rcv_nxt,4); + Serial.print(" -> "); + uip_debug_printbytes(rhs->rcv_nxt,4); + *((uint32_t *)&lhs->rcv_nxt[0]) = (uint32_t)rhs->rcv_nxt[0]; + Serial.println(); + changed = true; + } + if ((uint32_t)lhs->snd_nxt[0] != (uint32_t)rhs->snd_nxt[0]) + { + Serial.print(" snd_nxt: "); + uip_debug_printbytes(lhs->snd_nxt,4); + Serial.print(" -> "); + uip_debug_printbytes(rhs->snd_nxt,4); + *((uint32_t *)&lhs->snd_nxt[0]) = (uint32_t)rhs->snd_nxt[0]; + Serial.println(); + changed = true; + } + if (lhs->len != rhs->len) + { + Serial.print(" len: "); + Serial.print(lhs->len); + Serial.print(" -> "); + Serial.println(rhs->len); + lhs->len = rhs->len; + changed = true; + } + if (lhs->mss != rhs->mss) + { + Serial.print(" mss: "); + Serial.print(lhs->mss); + Serial.print(" -> "); + Serial.println(rhs->mss); + lhs->mss = rhs->mss; + changed = true; + } + if (lhs->initialmss != rhs->initialmss) + { + Serial.print(" initialmss: "); + Serial.print(lhs->initialmss); + Serial.print(" -> "); + Serial.println(rhs->initialmss); + lhs->initialmss = rhs->initialmss; + changed = true; + } + if (lhs->sa != rhs->sa) + { + Serial.print(" sa: "); + Serial.print(lhs->sa); + Serial.print(" -> "); + Serial.println(rhs->sa); + lhs->sa = rhs->sa; + changed = true; + } + if (lhs->sv != rhs->sv) + { + Serial.print(" sv: "); + Serial.print(lhs->sv); + Serial.print(" -> "); + Serial.println(rhs->sv); + lhs->sv = rhs->sv; + changed = true; + } + if (lhs->rto != rhs->rto) + { + Serial.print(" rto: "); + Serial.print(lhs->rto); + Serial.print(" -> "); + Serial.println(rhs->rto); + lhs->rto = rhs->rto; + changed = true; + } + if (lhs->tcpstateflags != rhs->tcpstateflags) + { + Serial.print(" tcpstateflags: "); + Serial.print(lhs->tcpstateflags); + Serial.print(" -> "); + Serial.println(rhs->tcpstateflags); + lhs->tcpstateflags = rhs->tcpstateflags; + changed = true; + } + if (lhs->timer != rhs->timer) + { + Serial.print(" timer: "); + Serial.print(lhs->timer); + Serial.print(" -> "); + Serial.println(rhs->timer); + lhs->timer = rhs->timer; + changed = true; + } + if (lhs->nrtx != rhs->nrtx) + { + Serial.print(" nrtx: "); + Serial.print(lhs->nrtx); + Serial.print(" -> "); + Serial.println(rhs->nrtx); + lhs->nrtx = rhs->nrtx; + changed = true; + } + return changed; +} + +void +UIPDebug::uip_debug_printbytes(const uint8_t *data, uint8_t len) +{ + for(uint8_t i=0;i + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include "uip_clock.h" +#include "uip_timer.h" + +/*---------------------------------------------------------------------------*/ +/** + * Set a timer. + * + * This function is used to set a timer for a time sometime in the + * future. The function timer_expired() will evaluate to true after + * the timer has expired. + * + * \param t A pointer to the timer + * \param interval The interval before the timer expires. + * + */ +void +uip_timer_set(struct uip_timer *t, clock_time_t interval) +{ + t->interval = interval; + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Reset the timer with the same interval. + * + * This function resets the timer with the same interval that was + * given to the timer_set() function. The start point of the interval + * is the exact time that the timer last expired. Therefore, this + * function will cause the timer to be stable over time, unlike the + * timer_rester() function. + * + * \param t A pointer to the timer. + * + * \sa timer_restart() + */ +void +uip_timer_reset(struct uip_timer *t) +{ + t->start += t->interval; +} +/*---------------------------------------------------------------------------*/ +/** + * Restart the timer from the current point in time + * + * This function restarts a timer with the same interval that was + * given to the timer_set() function. The timer will start at the + * current time. + * + * \note A periodic timer will drift if this function is used to reset + * it. For preioric timers, use the timer_reset() function instead. + * + * \param t A pointer to the timer. + * + * \sa timer_reset() + */ +void +uip_timer_restart(struct uip_timer *t) +{ + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Check if a timer has expired. + * + * This function tests if a timer has expired and returns true or + * false depending on its status. + * + * \param t A pointer to the timer + * + * \return Non-zero if the timer has expired, zero otherwise. + * + */ +int +uip_timer_expired(struct uip_timer *t) +{ + return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h new file mode 100644 index 0000000..f260349 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h @@ -0,0 +1,86 @@ +/** + * \defgroup timer Timer library + * + * The timer library provides functions for setting, resetting and + * restarting timers, and for checking if a timer has expired. An + * application must "manually" check if its timers have expired; this + * is not done automatically. + * + * A timer is declared as a \c struct \c timer and all access to the + * timer is made by a pointer to the declared timer. + * + * \note The timer library uses the \ref clock "Clock library" to + * measure time. Intervals should be specified in the format used by + * the clock library. + * + * @{ + */ + + +/** + * \file + * Timer library header file. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __UIP_TIMER_H__ +#define __UIP_TIMER_H__ + +#include "uip_clock.h" + +/** + * A timer. + * + * This structure is used for declaring a timer. The timer must be set + * with timer_set() before it can be used. + * + * \hideinitializer + */ +struct uip_timer { + clock_time_t start; + clock_time_t interval; +}; + +void uip_timer_set(struct uip_timer *t, clock_time_t interval); +void uip_timer_reset(struct uip_timer *t); +void uip_timer_restart(struct uip_timer *t); +int uip_timer_expired(struct uip_timer *t); + +#endif /* __UIP_TIMER_H__ */ + +/** @} */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h new file mode 100644 index 0000000..b9c8d73 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h @@ -0,0 +1,29 @@ +#ifndef UIPETHERNET_CONF_H +#define UIPETHERNET_CONF_H + +/* for TCP */ +#define UIP_SOCKET_NUMPACKETS 5 +#define UIP_CONF_MAX_CONNECTIONS 1 + +/* for UDP + * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */ +#define UIP_CONF_UDP 0 +#define UIP_CONF_BROADCAST 1 +#define UIP_CONF_UDP_CONNS 4 + +/* number of attempts on write before returning number of bytes sent so far + * set to -1 to block until connection is closed by timeout */ +#define UIP_ATTEMPTS_ON_WRITE -1 + +/* timeout after which UIPClient::connect gives up. The timeout is specified in seconds. + * if set to a number <= 0 connect will timeout when uIP does (which might be longer than you expect...) */ +#define UIP_CONNECT_TIMEOUT -1 + +/* periodic timer for uip (in ms) */ +#define UIP_PERIODIC_TIMER 250 + +/* timer to poll client for data after last write (in ms) + * set to -1 to disable fast polling and rely on periodic only (saves 100 bytes flash) */ +#define UIP_CLIENT_TIMER 10 + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h new file mode 100644 index 0000000..42badf8 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h @@ -0,0 +1,543 @@ +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * uipopt.h. This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + * + * \note Most of the configuration options in the uipopt.h should not + * be changed, but rather the per-project uip-conf.h file. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uipopt.h,v 1.4 2006/06/12 08:00:31 adam Exp $ + * + */ + +#ifndef __UIPOPT_H__ +#define __UIPOPT_H__ + +#ifndef UIP_LITTLE_ENDIAN +#define UIP_LITTLE_ENDIAN 3412 +#endif /* UIP_LITTLE_ENDIAN */ +#ifndef UIP_BIG_ENDIAN +#define UIP_BIG_ENDIAN 1234 +#endif /* UIP_BIG_ENDIAN */ + +#include "uip-conf.h" + +/*------------------------------------------------------------------------------*/ + +/** + * \name Static configuration options + * @{ + * + * These configuration options can be used for setting the IP address + * settings statically, but only if UIP_FIXEDADDR is set to 1. The + * configuration options for a specific node includes IP address, + * netmask and default router as well as the Ethernet address. The + * netmask, default router and Ethernet address are appliciable only + * if uIP should be run over Ethernet. + * + * All of these should be changed to suit your project. +*/ + +/** + * Determines if uIP should use a fixed IP address or not. + * + * If uIP should use a fixed IP address, the settings are set in the + * uipopt.h file. If not, the macros uip_sethostaddr(), + * uip_setdraddr() and uip_setnetmask() should be used instead. + * + * \hideinitializer + */ +#define UIP_FIXEDADDR 0 + +/** + * Ping IP address asignment. + * + * uIP uses a "ping" packets for setting its own IP address if this + * option is set. If so, uIP will start with an empty IP address and + * the destination IP address of the first incoming "ping" (ICMP echo) + * packet will be used for setting the hosts IP address. + * + * \note This works only if UIP_FIXEDADDR is 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_PINGADDRCONF +#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF +#else /* UIP_CONF_PINGADDRCONF */ +#define UIP_PINGADDRCONF 0 +#endif /* UIP_CONF_PINGADDRCONF */ + + +/** + * Specifies if the uIP ARP module should be compiled with a fixed + * Ethernet MAC address or not. + * + * If this configuration option is 0, the macro uip_setethaddr() can + * be used to specify the Ethernet address at run-time. + * + * \hideinitializer + */ +#define UIP_FIXEDETHADDR 0 + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name IP configuration options + * @{ + * + */ +/** + * The IP TTL (time to live) of IP packets sent by uIP. + * + * This should normally not be changed. + */ +#define UIP_TTL 64 + +/** + * Turn on support for IP packet reassembly. + * + * uIP supports reassembly of fragmented IP packets. This features + * requires an additonal amount of RAM to hold the reassembly buffer + * and the reassembly code size is approximately 700 bytes. The + * reassembly buffer is of the same size as the uip_buf buffer + * (configured by UIP_BUFSIZE). + * + * \note IP packet reassembly is not heavily tested. + * + * \hideinitializer + */ +#define UIP_REASSEMBLY 0 + +/** + * The maximum time an IP fragment should wait in the reassembly + * buffer before it is dropped. + * + */ +#define UIP_REASS_MAXAGE 40 + +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \name UDP configuration options + * @{ + */ + +/** + * Toggles wether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP +#define UIP_UDP UIP_CONF_UDP +#else /* UIP_CONF_UDP */ +#define UIP_UDP 0 +#endif /* UIP_CONF_UDP */ + +/** + * Toggles if UDP checksums should be used or not. + * + * \note Support for UDP checksums is currently not included in uIP, + * so this option has no function. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CHECKSUMS +#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS +#else +#define UIP_UDP_CHECKSUMS 0 +#endif + +/** + * The maximum amount of concurrent UDP connections. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CONNS +#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS +#else /* UIP_CONF_UDP_CONNS */ +#define UIP_UDP_CONNS 10 +#endif /* UIP_CONF_UDP_CONNS */ + +/** + * The name of the function that should be called when UDP datagrams arrive. + * + * \hideinitializer + */ + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name TCP configuration options + * @{ + */ + +/** + * Determines if support for opening connections from uIP should be + * compiled in. + * + * If the applications that are running on top of uIP for this project + * do not need to open outgoing TCP connections, this configration + * option can be turned off to reduce the code size of uIP. + * + * \hideinitializer + */ +#define UIP_ACTIVE_OPEN 1 + +/** + * The maximum number of simultaneously open TCP connections. + * + * Since the TCP connections are statically allocated, turning this + * configuration knob down results in less RAM used. Each TCP + * connection requires approximatly 30 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_CONNECTIONS +#define UIP_CONNS 10 +#else /* UIP_CONF_MAX_CONNECTIONS */ +#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS +#endif /* UIP_CONF_MAX_CONNECTIONS */ + + +/** + * The maximum number of simultaneously listening TCP ports. + * + * Each listening TCP port requires 2 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_LISTENPORTS +#define UIP_LISTENPORTS 20 +#else /* UIP_CONF_MAX_LISTENPORTS */ +#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS +#endif /* UIP_CONF_MAX_LISTENPORTS */ + +/** + * Determines if support for TCP urgent data notification should be + * compiled in. + * + * Urgent data (out-of-band data) is a rarely used TCP feature that + * very seldom would be required. + * + * \hideinitializer + */ +#define UIP_URGDATA 0 + +/** + * The initial retransmission timeout counted in timer pulses. + * + * This should not be changed. + */ +#define UIP_RTO 3 + +/** + * The maximum number of times a segment should be retransmitted + * before the connection should be aborted. + * + * This should not be changed. + */ +#define UIP_MAXRTX 8 + +/** + * The maximum number of times a SYN segment should be retransmitted + * before a connection request should be deemed to have been + * unsuccessful. + * + * This should not need to be changed. + */ +#define UIP_MAXSYNRTX 5 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ +#ifndef UIP_CONF_TCP_MSS +#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) +#else +#define UIP_TCP_MSS UIP_CONF_TCP_MSS +#endif + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#ifndef UIP_CONF_RECEIVE_WINDOW +#define UIP_RECEIVE_WINDOW UIP_TCP_MSS +#else +#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW +#endif + +/** + * How long a connection should stay in the TIME_WAIT state. + * + * This configiration option has no real implication, and it should be + * left untouched. + */ +#define UIP_TIME_WAIT_TIMEOUT 120 + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name ARP configuration options + * @{ + */ + +/** + * The size of the ARP table. + * + * This option should be set to a larger value if this uIP node will + * have many connections from the local network. + * + * \hideinitializer + */ +#ifdef UIP_CONF_ARPTAB_SIZE +#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE +#else +#define UIP_ARPTAB_SIZE 8 +#endif + +/** + * The maxium age of ARP table entries measured in 10ths of seconds. + * + * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD + * default). + */ +#define UIP_ARP_MAXAGE 120 + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \name General configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1500 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#ifndef UIP_CONF_BUFFER_SIZE +#define UIP_BUFSIZE 400 +#else /* UIP_CONF_BUFFER_SIZE */ +#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE +#endif /* UIP_CONF_BUFFER_SIZE */ + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#ifndef UIP_CONF_STATISTICS +#define UIP_STATISTICS 0 +#else /* UIP_CONF_STATISTICS */ +#define UIP_STATISTICS UIP_CONF_STATISTICS +#endif /* UIP_CONF_STATISTICS */ + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#ifndef UIP_CONF_LOGGING +#define UIP_LOGGING 0 +#else /* UIP_CONF_LOGGING */ +#define UIP_LOGGING UIP_CONF_LOGGING +#endif /* UIP_CONF_LOGGING */ + +/** + * Broadcast support. + * + * This flag configures IP broadcast support. This is useful only + * together with UDP. + * + * \hideinitializer + * + */ +#if UIP_UDP && UIP_CONF_BROADCAST +#define UIP_BROADCAST UIP_CONF_BROADCAST +#else /* UIP_CONF_BROADCAST */ +#define UIP_BROADCAST 0 +#endif /* UIP_CONF_BROADCAST */ + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void uip_log(char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_LLH_LEN +#define UIP_LLH_LEN UIP_CONF_LLH_LEN +#else /* UIP_CONF_LLH_LEN */ +#define UIP_LLH_LEN 14 +#endif /* UIP_CONF_LLH_LEN */ + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either BIG_ENDIAN (Motorola byte order) or + * LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifdef UIP_CONF_BYTE_ORDER +#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER +#else /* UIP_CONF_BYTE_ORDER */ +#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN +#endif /* UIP_CONF_BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ + +/** + * \name Appication specific configurations + * @{ + * + * An uIP application is implemented using a single application + * function that is called by uIP whenever a TCP/IP event occurs. The + * name of this function must be registered with uIP at compile time + * using the UIP_APPCALL definition. + * + * uIP applications can store the application state within the + * uip_conn structure by specifying the type of the application + * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t. + * + * The file containing the definitions must be included in the + * uipopt.h file. + * + * The following example illustrates how this can look. + \code + +void httpd_appcall(void); +#define UIP_APPCALL httpd_appcall + +struct httpd_state { + u8_t state; + u16_t count; + char *dataptr; + char *script; +}; +typedef struct httpd_state uip_tcp_appstate_t + \endcode + */ + +/** + * \var #define UIP_APPCALL + * + * The name of the application function that uIP should call in + * response to TCP/IP events. + * + */ + +/** + * \var typedef uip_tcp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ + +/** + * \var typedef uip_udp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ +/** @} */ +/** @} */ + +#endif /* __UIPOPT_H__ */ diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/util.h b/libraries/MySensors/drivers/Ethernet_UIP/utility/util.h new file mode 100644 index 0000000..5042e82 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_UIP/utility/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Client.h b/libraries/MySensors/drivers/Ethernet_W5100/Client.h new file mode 100644 index 0000000..b8e5d93 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Client.h @@ -0,0 +1,45 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp b/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp new file mode 100644 index 0000000..040e126 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp @@ -0,0 +1,471 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include "utility/w5100.h" + +#include +#include +#include "Dhcp.h" +#include "Arduino.h" +#include "utility/util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + _dhcpLeaseTime=0; + _dhcpT1=0; + _dhcpT2=0; + _timeout = timeout; + _responseTimeout = responseTimeout; + + // zero out _dhcpMacAddr + memset(_dhcpMacAddr, 0, 6); + reset_DHCP_lease(); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + _dhcp_state = STATE_DHCP_START; + return request_DHCP_lease(); +} + +void DhcpClass::reset_DHCP_lease(){ + // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpLocalIp, 0, 20); +} + +//return:0 on error, 1 if request is sent and response is received +int DhcpClass::request_DHCP_lease(){ + + uint8_t messageType = 0; + + + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + _dhcpUdpSocket.stop(); + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(_dhcp_state != STATE_DHCP_LEASED) + { + if(_dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_DISCOVER; + } + else if(_dhcp_state == STATE_DHCP_REREQUEST){ + _dhcpTransactionId++; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + else if(_dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(_dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_ACK) + { + _dhcp_state = STATE_DHCP_LEASED; + result = 1; + //use default lease time if we didn't get it + if(_dhcpLeaseTime == 0){ + _dhcpLeaseTime = DEFAULT_LEASE; + } + // Calculate T1 & T2 if we didn't get it + if(_dhcpT1 == 0){ + // T1 should be 50% of _dhcpLeaseTime + _dhcpT1 = _dhcpLeaseTime >> 1; + } + if(_dhcpT2 == 0){ + // T2 should be 87.5% (7/8ths) of _dhcpLeaseTime + _dhcpT2 = _dhcpLeaseTime - (_dhcpLeaseTime >> 3); + } + _renewInSec = _dhcpT1; + _rebindInSec = _dhcpT2; + } + else if(messageType == DHCP_NAK) + _dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + _dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > _timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + _lastCheckLeaseMillis = millis(); + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); + printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); + printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 30); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if ((_dhcpDhcpServerIp[0] == 0 && _dhcpDhcpServerIp[1] == 0 && + _dhcpDhcpServerIp[2] == 0 && _dhcpDhcpServerIp[3] == 0) || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpT1value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1)); + _dhcpT1 = ntohl(_dhcpT1); + break; + + case dhcpT2value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2)); + _dhcpT2 = ntohl(_dhcpT2); + break; + + case dhcpIPaddrLeaseTime : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); + _dhcpLeaseTime = ntohl(_dhcpLeaseTime); + _renewInSec = _dhcpLeaseTime; + break; + + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + + +/* + returns: + 0/DHCP_CHECK_NONE: nothing happened + 1/DHCP_CHECK_RENEW_FAIL: renew failed + 2/DHCP_CHECK_RENEW_OK: renew success + 3/DHCP_CHECK_REBIND_FAIL: rebind fail + 4/DHCP_CHECK_REBIND_OK: rebind success +*/ +int DhcpClass::checkLease(){ + int rc = DHCP_CHECK_NONE; + + unsigned long now = millis(); + unsigned long elapsed = now - _lastCheckLeaseMillis; + + // if more then one sec passed, reduce the counters accordingly + if (elapsed >= 1000) { + // set the new timestamps + _lastCheckLeaseMillis = now - (elapsed % 1000); + elapsed = elapsed / 1000; + + // decrease the counters by elapsed seconds + // we assume that the cycle time (elapsed) is fairly constant + // if the remainder is less than cycle time * 2 + // do it early instead of late + if (_renewInSec < elapsed * 2) + _renewInSec = 0; + else + _renewInSec -= elapsed; + + if (_rebindInSec < elapsed * 2) + _rebindInSec = 0; + else + _rebindInSec -= elapsed; + } + + // if we have a lease but should renew, do it + if (_renewInSec == 0 &&_dhcp_state == STATE_DHCP_LEASED) { + _dhcp_state = STATE_DHCP_REREQUEST; + rc = 1 + request_DHCP_lease(); + } + + // if we have a lease or is renewing but should bind, do it + if (_rebindInSec == 0 && (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START)) { + // this should basically restart completely + _dhcp_state = STATE_DHCP_START; + reset_DHCP_lease(); + rc = 3 + request_DHCP_lease(); + } + return rc; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + +void DhcpClass::printByte(char * buf, uint8_t n ) { + char *str = &buf[1]; + buf[0]='0'; + do { + unsigned long m = n; + n /= 16; + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); +} diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h b/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h new file mode 100644 index 0000000..aeadfbd --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h @@ -0,0 +1,177 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "EthernetUdp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "WIZnet" +#define DEFAULT_LEASE (900) //default lease time in seconds + +#define DHCP_CHECK_NONE (0) +#define DHCP_CHECK_RENEW_FAIL (1) +#define DHCP_CHECK_RENEW_OK (2) +#define DHCP_CHECK_REBIND_FAIL (3) +#define DHCP_CHECK_REBIND_OK (4) + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct __attribute__((packed)) _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + unsigned long _renewInSec; + unsigned long _rebindInSec; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _lastCheckLeaseMillis; + uint8_t _dhcp_state; + EthernetUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp b/libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp new file mode 100644 index 0000000..62e36f8 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp @@ -0,0 +1,423 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "utility/w5100.h" +#include "EthernetUdp.h" +#include "utility/util.h" + +#include "Dns.h" +#include +//#include +#include "Arduino.h" + + +#define SOCKET_NONE 255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p =aIPAddrString; + while (*p && + ( (*p == '.') || (*p >= '0') || (*p <= '9') )) + { + p++; + } + + if (*p == '\0') + { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + int segment =0; + int segmentValue =0; + while (*p && (segment < 4)) + { + if (*p == '.') + { + // We've reached the end of a segment + if (segmentValue > 255) + { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + segment++; + segmentValue = 0; + } + } + else + { + // Next digit + segmentValue = (segmentValue*10)+(*p - '0'); + } + p++; + } + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) + { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + return 1; + } + } + else + { + return 0; + } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ + int ret =0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) + { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) + { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) + { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) + { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) + { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) + { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) + { + ret = ProcessResponse(5000, aResult); + wait_retries++; + } + } + } + } + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) + { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) + { + end++; + } + + if (end-start > 0) + { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return 1; +} + + +uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) +{ + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) + { + if((millis() - startTime) > aTimeout) + return TIMED_OUT; + delay(50); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || + (iUdp.remotePort() != DNS_PORT) ) + { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) + { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*)&header[2])); + // Check that it's a response to this request + if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || + ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) + { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) + { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*)&header[6])); + if (answerCount == 0 ) + { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) + { + // Skip over the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if (len > 0) + { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i =0; i < 4; i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (uint16_t i =0; i < answerCount; i++) + { + // Skip the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) + { + // It's just a normal label + if (len > 0) + { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + else + { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i =0; i < TTL_SIZE; i++) + { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) + { + if (htons(header_flags) != 4) + { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9;//INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); + return SUCCESS; + } + else + { + // This isn't an answer type we're after, move onto the next one + for (uint16_t i =0; i < htons(header_flags); i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10;//INVALID_RESPONSE; +} + diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dns.h b/libraries/MySensors/drivers/Ethernet_W5100/Dns.h new file mode 100644 index 0000000..abe0262 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include "EthernetUdp.h" + +class DNSClient +{ +public: + // ctor + void begin(const IPAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char *aIPAddrString, IPAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + uint16_t BuildRequest(const char* aName); + uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + EthernetUDP iUdp; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp b/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp new file mode 100644 index 0000000..3eea69a --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp @@ -0,0 +1,136 @@ +#include "utility/w5100.h" +#include "Ethernet.h" +#include "Dhcp.h" + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { + 0, 0, 0, 0 }; +uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { + 0, 0, 0, 0 }; + +int EthernetClass::begin(uint8_t *mac_address) +{ + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + + + // Initialise the basic info + W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac_address); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + SPI.endTransaction(); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(mac_address, local_ip, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(mac_address, local_ip, dns_server, gateway); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, dns_server, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); + W5100.setIPAddress(local_ip.raw_address()); + W5100.setGatewayIp(gateway.raw_address()); + W5100.setSubnetMask(subnet.raw_address()); + SPI.endTransaction(); + _dnsServerAddress = dns_server; +} + +int EthernetClass::maintain(){ + int rc = DHCP_CHECK_NONE; + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getIPAddress(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getSubnetMask(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getGatewayIp(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +EthernetClass Ethernet; diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h b/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h new file mode 100644 index 0000000..2a07ff3 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h @@ -0,0 +1,41 @@ +#ifndef ethernet_h +#define ethernet_h + +#include +//#include "w5100.h" +#include "IPAddress.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dhcp.h" + +#define MAX_SOCK_NUM 4 + +class EthernetClass { +private: + IPAddress _dnsServerAddress; + DhcpClass* _dhcp; +public: + static uint8_t _state[MAX_SOCK_NUM]; + static uint16_t _server_port[MAX_SOCK_NUM]; + // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + int maintain(); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + + friend class EthernetClient; + friend class EthernetServer; +}; + +extern EthernetClass Ethernet; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp b/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp new file mode 100644 index 0000000..75765e5 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp @@ -0,0 +1,177 @@ +#include "utility/w5100.h" +#include "utility/socket.h" + +extern "C" { + #include "string.h" +} + +#include "Arduino.h" + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dns.h" + +uint16_t EthernetClient::_srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 + +EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) { +} + +EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) { +} + +int EthernetClient::connect(const char* host, uint16_t port) { + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } else { + return ret; + } +} + +int EthernetClient::connect(IPAddress ip, uint16_t port) { + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = socketStatus(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + _srcport++; + if (_srcport == 0) _srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 + socket(_sock, SnMR::TCP, _srcport, 0); + + if (!::connect(_sock, rawIPAddress(ip), port)) { + _sock = MAX_SOCK_NUM; + return 0; + } + + while (status() != SnSR::ESTABLISHED) { + delay(1); + if (status() == SnSR::CLOSED) { + _sock = MAX_SOCK_NUM; + return 0; + } + } + + return 1; +} + +size_t EthernetClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t EthernetClient::write(const uint8_t *buf, size_t size) { + if (_sock == MAX_SOCK_NUM) { + setWriteError(); + return 0; + } + if (!send(_sock, buf, size)) { + setWriteError(); + return 0; + } + return size; +} + +int EthernetClient::available() { + if (_sock != MAX_SOCK_NUM) + return recvAvailable(_sock); + return 0; +} + +int EthernetClient::read() { + uint8_t b; + if ( recv(_sock, &b, 1) > 0 ) + { + // recv worked + return b; + } + else + { + // No data available + return -1; + } +} + +int EthernetClient::read(uint8_t *buf, size_t size) { + return recv(_sock, buf, size); +} + +int EthernetClient::peek() { + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must + if (!available()) + return -1; + ::peek(_sock, &b); + return b; +} + +void EthernetClient::flush() { + ::flush(_sock); +} + +void EthernetClient::stop() { + if (_sock == MAX_SOCK_NUM) + return; + + // attempt to close the connection gracefully (send a FIN to other side) + disconnect(_sock); + unsigned long start = millis(); + + // wait up to a second for the connection to close + uint8_t s; + do { + s = status(); + if (s == SnSR::CLOSED) + break; // exit the loop + delay(1); + } while (millis() - start < 1000); + + // if it hasn't closed, close it forcefully + if (s != SnSR::CLOSED) + close(_sock); + + EthernetClass::_server_port[_sock] = 0; + _sock = MAX_SOCK_NUM; +} + +uint8_t EthernetClient::connected() { + if (_sock == MAX_SOCK_NUM) return 0; + + uint8_t s = status(); + return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT || + (s == SnSR::CLOSE_WAIT && !available())); +} + +uint8_t EthernetClient::status() { + if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; + return socketStatus(_sock); +} + +// the next function allows us to use the client returned by +// EthernetServer::available() as the condition in an if-statement. + +EthernetClient::operator bool() { + return _sock != MAX_SOCK_NUM; +} + +bool EthernetClient::operator==(const EthernetClient& rhs) { + return _sock == rhs._sock && _sock != MAX_SOCK_NUM && rhs._sock != MAX_SOCK_NUM; +} + +uint8_t EthernetClient::getSocketNumber() { + return _sock; +} diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h b/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h new file mode 100644 index 0000000..52a3b8f --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h @@ -0,0 +1,42 @@ +#ifndef ethernetclient_h +#define ethernetclient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class EthernetClient : public Client { + +public: + EthernetClient(); + EthernetClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + uint8_t getSocketNumber(); + + friend class EthernetServer; + + using Print::write; + +private: + static uint16_t _srcport; + uint8_t _sock; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp b/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp new file mode 100644 index 0000000..cfa813e --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp @@ -0,0 +1,92 @@ +#include "utility/w5100.h" +#include "utility/socket.h" +extern "C" { +#include "string.h" +} + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" + +EthernetServer::EthernetServer(uint16_t port) +{ + _port = port; +} + +void EthernetServer::begin() +{ + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + if (client.status() == SnSR::CLOSED) { + socket(sock, SnMR::TCP, _port, 0); + listen(sock); + EthernetClass::_server_port[sock] = _port; + break; + } + } +} + +void EthernetServer::accept() +{ + int listening = 0; + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + + if (EthernetClass::_server_port[sock] == _port) { + if (client.status() == SnSR::LISTEN) { + listening = 1; + } + else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) { + client.stop(); + } + } + } + + if (!listening) { + begin(); + } +} + +EthernetClient EthernetServer::available() +{ + accept(); + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + if (EthernetClass::_server_port[sock] == _port) { + uint8_t s = client.status(); + if (s == SnSR::ESTABLISHED || s == SnSR::CLOSE_WAIT) { + if (client.available()) { + // XXX: don't always pick the lowest numbered socket. + return client; + } + } + } + } + + return EthernetClient(MAX_SOCK_NUM); +} + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + + accept(); + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + + if (EthernetClass::_server_port[sock] == _port && + client.status() == SnSR::ESTABLISHED) { + n += client.write(buffer, size); + } + } + + return n; +} diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h b/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h new file mode 100644 index 0000000..86ccafe --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h @@ -0,0 +1,22 @@ +#ifndef ethernetserver_h +#define ethernetserver_h + +#include "Server.h" + +class EthernetClient; + +class EthernetServer : +public Server { +private: + uint16_t _port; + void accept(); +public: + EthernetServer(uint16_t); + EthernetClient available(); + virtual void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + using Print::write; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp b/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp new file mode 100644 index 0000000..2baee82 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp @@ -0,0 +1,252 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#include "utility/w5100.h" +#include "utility/socket.h" +#include "Ethernet.h" +#include "Udp.h" +#include "Dns.h" + +/* Constructor */ +EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} + +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::begin(uint16_t port) { + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = socketStatus(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + _port = port; + _remaining = 0; + socket(_sock, SnMR::UDP, _port, 0); + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int EthernetUDP::available() { + return _remaining; +} + +/* Release any resources being used by this EthernetUDP instance */ +void EthernetUDP::stop() +{ + if (_sock == MAX_SOCK_NUM) + return; + + close(_sock); + + EthernetClass::_server_port[_sock] = 0; + _sock = MAX_SOCK_NUM; +} + +int EthernetUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + +int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) +{ + _offset = 0; + return startUDP(_sock, rawIPAddress(ip), port); +} + +int EthernetUDP::endPacket() +{ + return sendUDP(_sock); +} + +size_t EthernetUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t EthernetUDP::write(const uint8_t *buffer, size_t size) +{ + uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); + _offset += bytes_written; + return bytes_written; +} + +int EthernetUDP::parsePacket() +{ + // discard any remaining bytes in the last packet + flush(); + + if (recvAvailable(_sock) > 0) + { + //HACK - hand-parse the UDP packet using TCP recv method + uint8_t tmpBuf[8]; + int ret =0; + //read 8 header bytes and get IP and port from it + ret = recv(_sock,tmpBuf,8); + if (ret > 0) + { + _remoteIP = tmpBuf; + _remotePort = tmpBuf[4]; + _remotePort = (_remotePort << 8) + tmpBuf[5]; + _remaining = tmpBuf[6]; + _remaining = (_remaining << 8) + tmpBuf[7]; + + // When we get here, any remaining bytes are the data + ret = _remaining; + } + return ret; + } + // There aren't any packets available + return 0; +} + +int EthernetUDP::read() +{ + uint8_t byte; + + if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) + { + // We read things without any problems + _remaining--; + return byte; + } + + // If we get here, there's no data available + return -1; +} + +int EthernetUDP::read(unsigned char* buffer, size_t len) +{ + + if (_remaining > 0) + { + + int got; + + if (_remaining <= len) + { + // data should fit in the buffer + got = recv(_sock, buffer, _remaining); + } + else + { + // too much data for the buffer, + // grab as much as will fit + got = recv(_sock, buffer, len); + } + + if (got > 0) + { + _remaining -= got; + return got; + } + + } + + // If we get here, there's no data available or recv failed + return -1; + +} + +int EthernetUDP::peek() +{ + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must. + // If the user hasn't called parsePacket yet then return nothing otherwise they + // may get the UDP header + if (!_remaining) + return -1; + ::peek(_sock, &b); + return b; +} + +void EthernetUDP::flush() +{ + // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? + // should only occur if recv fails after telling us the data is there, lets + // hope the w5100 always behaves :) + + while (_remaining) + { + read(); + } +} + +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::beginMulticast(IPAddress ip, uint16_t port) +{ + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = W5100.readSnSR(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + // Calculate MAC address from Multicast IP Address + byte mac[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; + + mac[3] = ip[1] & 0x7F; + mac[4] = ip[2]; + mac[5] = ip[3]; + + W5100.writeSnDIPR(_sock, rawIPAddress(ip)); //239.255.0.1 + W5100.writeSnDPORT(_sock, port); + W5100.writeSnDHAR(_sock,mac); + + _remaining = 0; + socket(_sock, SnMR::UDP, port, SnMR::MULTI); + return 1; +} + + diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h b/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h new file mode 100644 index 0000000..549e355 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h @@ -0,0 +1,102 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef ethernetudp_h +#define ethernetudp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: + uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent + +protected: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: + EthernetUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() { return _remotePort; }; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp b/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp new file mode 100644 index 0000000..175ba75 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp @@ -0,0 +1,74 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "IPAddress.h" + +IPAddress::IPAddress() +{ + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for (int i =0; i < 3; i++) + { + n += p.print(_address.bytes[i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[3], DEC); + return n; +} + diff --git a/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h b/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h new file mode 100644 index 0000000..94acdc4 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h @@ -0,0 +1,75 @@ +/* + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef IPAddress_h +#define IPAddress_h + +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress : public Printable { +private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address.bytes; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address.bytes[index]; }; + uint8_t& operator[](int index) { return _address.bytes[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +const IPAddress INADDR_NONE(0,0,0,0); + + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Server.h b/libraries/MySensors/drivers/Ethernet_W5100/Server.h new file mode 100644 index 0000000..69e3e39 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/Server.h @@ -0,0 +1,30 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef server_h +#define server_h + +#include "Print.h" + +class Server : public Print { +public: + virtual void begin() =0; +}; + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp b/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp new file mode 100644 index 0000000..9254b74 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp @@ -0,0 +1,469 @@ +#include "w5100.h" +#include "socket.h" + +static uint16_t local_port; + +/** + * @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it. + * @return 1 for success else 0. + */ +uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) +{ + if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) + { + close(s); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnMR(s, protocol | flag); + if (port != 0) { + W5100.writeSnPORT(s, port); + } + else { + local_port++; // if don't set the source port, set local_port number. + W5100.writeSnPORT(s, local_port); + } + + W5100.execCmdSn(s, Sock_OPEN); + SPI.endTransaction(); + return 1; + } + + return 0; +} + + +uint8_t socketStatus(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + uint8_t status = W5100.readSnSR(s); + SPI.endTransaction(); + return status; +} + + +/** + * @brief This function close the socket and parameter is "s" which represent the socket number + */ +void close(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_CLOSE); + W5100.writeSnIR(s, 0xFF); + SPI.endTransaction(); +} + + +/** + * @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer. + * @return 1 for success else 0. + */ +uint8_t listen(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + if (W5100.readSnSR(s) != SnSR::INIT) { + SPI.endTransaction(); + return 0; + } + W5100.execCmdSn(s, Sock_LISTEN); + SPI.endTransaction(); + return 1; +} + + +/** + * @brief This function established the connection for the channel in Active (client) mode. + * This function waits for the untill the connection is established. + * + * @return 1 for success else 0. + */ +uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) +{ + if + ( + ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) || + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + (port == 0x00) + ) + return 0; + + // set destination IP + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + W5100.execCmdSn(s, Sock_CONNECT); + SPI.endTransaction(); + + return 1; +} + + + +/** + * @brief This function used for disconnect the socket and parameter is "s" which represent the socket number + * @return 1 for success else 0. + */ +void disconnect(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_DISCON); + SPI.endTransaction(); +} + + +/** + * @brief This function used to send the data in TCP mode + * @return 1 for success else 0. + */ +uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) +{ + uint8_t status=0; + uint16_t ret=0; + uint16_t freesize=0; + + if (len > W5100.SSIZE) + ret = W5100.SSIZE; // check size not to exceed MAX size. + else + ret = len; + + // if freebuf is available, start. + do + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + freesize = W5100.getTXFreeSize(s); + status = W5100.readSnSR(s); + SPI.endTransaction(); + if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) + { + ret = 0; + break; + } + yield(); + } + while (freesize < ret); + + // copy data + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + /* m2008.01 [bj] : reduce code */ + if ( W5100.readSnSR(s) == SnSR::CLOSED ) + { + SPI.endTransaction(); + close(s); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + return ret; +} + + +/** + * @brief This function is an application I/F function which is used to receive the data in TCP mode. + * It continues to wait for data as much as the application wants to receive. + * + * @return received data size for success else -1. + */ +int16_t recv(SOCKET s, uint8_t *buf, int16_t len) +{ + // Check how much data is available + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + int16_t ret = W5100.getRXReceivedSize(s); + if ( ret == 0 ) + { + // No data available. + uint8_t status = W5100.readSnSR(s); + if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT ) + { + // The remote end has closed its side of the connection, so this is the eof state + ret = 0; + } + else + { + // The connection is still up, but there's no data waiting to be read + ret = -1; + } + } + else if (ret > len) + { + ret = len; + } + + if ( ret > 0 ) + { + W5100.recv_data_processing(s, buf, ret); + W5100.execCmdSn(s, Sock_RECV); + } + SPI.endTransaction(); + return ret; +} + + +int16_t recvAvailable(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + int16_t ret = W5100.getRXReceivedSize(s); + SPI.endTransaction(); + return ret; +} + + +/** + * @brief Returns the first byte in the receive queue (no checking) + * + * @return + */ +uint16_t peek(SOCKET s, uint8_t *buf) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.recv_data_processing(s, buf, 1, 1); + SPI.endTransaction(); + return 1; +} + + +/** + * @brief This function is an application I/F function which is used to send the data for other then TCP mode. + * Unlike TCP transmission, The peer's destination address and the port is needed. + * + * @return This function return send data size for success else -1. + */ +uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port) +{ + uint16_t ret=0; + + if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size. + else ret = len; + + if + ( + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + ((port == 0x00)) ||(ret == 0) + ) + { + /* +2008.01 [bj] : added return value */ + ret = 0; + } + else + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + + // copy data + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ + SPI.endTransaction(); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + } + return ret; +} + + +/** + * @brief This function is an application I/F function which is used to receive the data in other then + * TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well. + * + * @return This function return received data size for success else -1. + */ +uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port) +{ + uint8_t head[8]; + uint16_t data_len=0; + uint16_t ptr=0; + + if ( len > 0 ) + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + ptr = W5100.readSnRX_RD(s); + switch (W5100.readSnMR(s) & 0x07) + { + case SnMR::UDP : + W5100.read_data(s, ptr, head, 0x08); + ptr += 8; + // read peer's IP address, port number. + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + *port = head[4]; + *port = (*port << 8) + head[5]; + data_len = head[6]; + data_len = (data_len << 8) + head[7]; + + W5100.read_data(s, ptr, buf, data_len); // data copy. + ptr += data_len; + + W5100.writeSnRX_RD(s, ptr); + break; + + case SnMR::IPRAW : + W5100.read_data(s, ptr, head, 0x06); + ptr += 6; + + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + data_len = head[4]; + data_len = (data_len << 8) + head[5]; + + W5100.read_data(s, ptr, buf, data_len); // data copy. + ptr += data_len; + + W5100.writeSnRX_RD(s, ptr); + break; + + case SnMR::MACRAW: + W5100.read_data(s, ptr, head, 2); + ptr+=2; + data_len = head[0]; + data_len = (data_len<<8) + head[1] - 2; + + W5100.read_data(s, ptr, buf, data_len); + ptr += data_len; + W5100.writeSnRX_RD(s, ptr); + break; + + default : + break; + } + W5100.execCmdSn(s, Sock_RECV); + SPI.endTransaction(); + } + return data_len; +} + +/** + * @brief Wait for buffered transmission to complete. + */ +void flush(SOCKET s) { + // TODO +} + +uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) +{ + uint16_t ret=0; + + if (len > W5100.SSIZE) + ret = W5100.SSIZE; // check size not to exceed MAX size. + else + ret = len; + + if (ret == 0) + return 0; + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* in case of igmp, if send fails, then socket closed */ + /* if you want change, remove this code. */ + SPI.endTransaction(); + close(s); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + return ret; +} + +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) +{ + uint16_t ret =0; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + if (len > W5100.getTXFreeSize(s)) + { + ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. + } + else + { + ret = len; + } + W5100.send_data_processing_offset(s, offset, buf, ret); + SPI.endTransaction(); + return ret; +} + +int startUDP(SOCKET s, uint8_t* addr, uint16_t port) +{ + if + ( + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + ((port == 0x00)) + ) + { + return 0; + } + else + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + SPI.endTransaction(); + return 1; + } +} + +int sendUDP(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); + SPI.endTransaction(); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + + /* Sent ok */ + return 1; +} + diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h b/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h new file mode 100644 index 0000000..6a88bce --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h @@ -0,0 +1,44 @@ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + +#include "w5100.h" + +extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) +extern uint8_t socketStatus(SOCKET s); +extern void close(SOCKET s); // Close socket +extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) +extern void disconnect(SOCKET s); // disconnect the connection +extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection) +extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) +extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP) +extern int16_t recvAvailable(SOCKET s); +extern uint16_t peek(SOCKET s, uint8_t *buf); +extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) +extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) +extern void flush(SOCKET s); // Wait for transmission to complete + +extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); + +// Functions to allow buffered UDP send (i.e. where the UDP datagram is built up over a +// number of calls before being sent +/* + @brief This function sets up a UDP datagram, the data for which will be provided by one + or more calls to bufferData and then finally sent with sendUDP. + @return 1 if the datagram was successfully set up, or 0 if there was an error +*/ +extern int startUDP(SOCKET s, uint8_t* addr, uint16_t port); +/* + @brief This function copies up to len bytes of data from buf into a UDP datagram to be + sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. + @return Number of bytes successfully buffered +*/ +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len); +/* + @brief Send a UDP datagram built up from a sequence of startUDP followed by one or more + calls to bufferData. + @return 1 if the datagram was successfully sent, or 0 if there was an error +*/ +int sendUDP(SOCKET s); + +#endif +/* _SOCKET_H_ */ diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/util.h b/libraries/MySensors/drivers/Ethernet_W5100/utility/util.h new file mode 100644 index 0000000..33d32a9 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/utility/util.h @@ -0,0 +1,14 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( ((x)<< 8 & 0xFF00) | \ + ((x)>> 8 & 0x00FF) ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp b/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp new file mode 100644 index 0000000..48409e0 --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2010 by Arduino LLC. All rights reserved. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include +#include + +#include "w5100.h" + +// W5100 controller instance +W5100Class W5100; + +#define TX_RX_MAX_BUF_SIZE 2048 +#define TX_BUF 0x1100 +#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) + +#define TXBUF_BASE 0x4000 +#define RXBUF_BASE 0x6000 + +void W5100Class::init(void) +{ + delay(300); + +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + SPI.begin(); + initSS(); +#else + SPI.begin(SPI_CS); + // Set clock to 4Mhz (W5100 should support up to about 14Mhz) + SPI.setClockDivider(SPI_CS, 21); + SPI.setDataMode(SPI_CS, SPI_MODE0); +#endif + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + writeMR(1< SSIZE) + { + // Wrap around circular buffer + uint16_t size = SSIZE - offset; + write(dstAddr, data, size); + write(SBASE[s], data + size, len - size); + } + else { + write(dstAddr, data, len); + } + + ptr += len; + writeSnTX_WR(s, ptr); +} + + +void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) +{ + uint16_t ptr; + ptr = readSnRX_RD(s); + read_data(s, ptr, data, len); + if (!peek) + { + ptr += len; + writeSnRX_RD(s, ptr); + } +} + +void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len) +{ + uint16_t size; + uint16_t src_mask; + uint16_t src_ptr; + + src_mask = src & RMASK; + src_ptr = RBASE[s] + src_mask; + + if( (src_mask + len) > RSIZE ) + { + size = RSIZE - src_mask; + read(src_ptr, (uint8_t *)dst, size); + dst += size; + read(RBASE[s], (uint8_t *) dst, len - size); + } + else + read(src_ptr, (uint8_t *) dst, len); +} + + +uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) +{ +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + SPI.transfer(_data); + resetSS(); +#else + SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + SPI.transfer(SPI_CS, _data); +#endif + return 1; +} + +uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) +{ + for (uint16_t i=0; i<_len; i++) + { +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + SPI.transfer(_buf[i]); + resetSS(); +#else + SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + SPI.transfer(SPI_CS, _buf[i]); + _addr++; +#endif + } + return _len; +} + +uint8_t W5100Class::read(uint16_t _addr) +{ +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + uint8_t _data = SPI.transfer(0); + resetSS(); +#else + SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + uint8_t _data = SPI.transfer(SPI_CS, 0); +#endif + return _data; +} + +uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) +{ + for (uint16_t i=0; i<_len; i++) + { +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + _buf[i] = SPI.transfer(0); + resetSS(); +#else + SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + _buf[i] = SPI.transfer(SPI_CS, 0); + _addr++; +#endif + } + return _len; +} + +void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { + // Send command to socket + writeSnCR(s, _cmd); + // Wait for command to complete + while (readSnCR(s)) + ; +} diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h b/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h new file mode 100644 index 0000000..358e25c --- /dev/null +++ b/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2010 by Arduino LLC. All rights reserved. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef W5100_H_INCLUDED +#define W5100_H_INCLUDED + +#include "drivers/SPI/SPI.h" + +#define ETHERNET_SHIELD_SPI_CS 10 + +#define MAX_SOCK_NUM 4 + +typedef uint8_t SOCKET; + +#define IDM_OR 0x8000 +#define IDM_AR0 0x8001 +#define IDM_AR1 0x8002 +#define IDM_DR 0x8003 +/* +class MR { +public: + static const uint8_t RST = 0x80; + static const uint8_t PB = 0x10; + static const uint8_t PPPOE = 0x08; + static const uint8_t LB = 0x04; + static const uint8_t AI = 0x02; + static const uint8_t IND = 0x01; +}; +*/ +/* +class IR { +public: + static const uint8_t CONFLICT = 0x80; + static const uint8_t UNREACH = 0x40; + static const uint8_t PPPoE = 0x20; + static const uint8_t SOCK0 = 0x01; + static const uint8_t SOCK1 = 0x02; + static const uint8_t SOCK2 = 0x04; + static const uint8_t SOCK3 = 0x08; + static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); }; +}; +*/ + +class SnMR { +public: + static const uint8_t CLOSE = 0x00; + static const uint8_t TCP = 0x01; + static const uint8_t UDP = 0x02; + static const uint8_t IPRAW = 0x03; + static const uint8_t MACRAW = 0x04; + static const uint8_t PPPOE = 0x05; + static const uint8_t ND = 0x20; + static const uint8_t MULTI = 0x80; +}; + +enum SockCMD { + Sock_OPEN = 0x01, + Sock_LISTEN = 0x02, + Sock_CONNECT = 0x04, + Sock_DISCON = 0x08, + Sock_CLOSE = 0x10, + Sock_SEND = 0x20, + Sock_SEND_MAC = 0x21, + Sock_SEND_KEEP = 0x22, + Sock_RECV = 0x40 +}; + +/*class SnCmd { +public: + static const uint8_t OPEN = 0x01; + static const uint8_t LISTEN = 0x02; + static const uint8_t CONNECT = 0x04; + static const uint8_t DISCON = 0x08; + static const uint8_t CLOSE = 0x10; + static const uint8_t SEND = 0x20; + static const uint8_t SEND_MAC = 0x21; + static const uint8_t SEND_KEEP = 0x22; + static const uint8_t RECV = 0x40; +}; +*/ + +class SnIR { +public: + static const uint8_t SEND_OK = 0x10; + static const uint8_t TIMEOUT = 0x08; + static const uint8_t RECV = 0x04; + static const uint8_t DISCON = 0x02; + static const uint8_t CON = 0x01; +}; + +class SnSR { +public: + static const uint8_t CLOSED = 0x00; + static const uint8_t INIT = 0x13; + static const uint8_t LISTEN = 0x14; + static const uint8_t SYNSENT = 0x15; + static const uint8_t SYNRECV = 0x16; + static const uint8_t ESTABLISHED = 0x17; + static const uint8_t FIN_WAIT = 0x18; + static const uint8_t CLOSING = 0x1A; + static const uint8_t TIME_WAIT = 0x1B; + static const uint8_t CLOSE_WAIT = 0x1C; + static const uint8_t LAST_ACK = 0x1D; + static const uint8_t UDP = 0x22; + static const uint8_t IPRAW = 0x32; + static const uint8_t MACRAW = 0x42; + static const uint8_t PPPOE = 0x5F; +}; + +class IPPROTO { +public: + static const uint8_t IP = 0; + static const uint8_t ICMP = 1; + static const uint8_t IGMP = 2; + static const uint8_t GGP = 3; + static const uint8_t TCP = 6; + static const uint8_t PUP = 12; + static const uint8_t UDP = 17; + static const uint8_t IDP = 22; + static const uint8_t ND = 77; + static const uint8_t RAW = 255; +}; + +class W5100Class { + +public: + void init(); + + /** + * @brief This function is being used for copy the data form Receive buffer of the chip to application buffer. + * + * It calculate the actual physical address where one has to read + * the data from Receive buffer. Here also take care of the condition while it exceed + * the Rx memory uper-bound of socket. + */ + void read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len); + + /** + * @brief This function is being called by send() and sendto() function also. + * + * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer + * register. User should read upper byte first and lower byte later to get proper value. + */ + void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); + /** + * @brief A copy of send_data_processing that uses the provided ptr for the + * write offset. Only needed for the "streaming" UDP API, where + * a single UDP packet is built up over a number of calls to + * send_data_processing_ptr, because TX_WR doesn't seem to get updated + * correctly in those scenarios + * @param ptr value to use in place of TX_WR. If 0, then the value is read + * in from TX_WR + * @return New value for ptr, to be used in the next call + */ +// FIXME Update documentation + void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); + + /** + * @brief This function is being called by recv() also. + * + * This function read the Rx read pointer register + * and after copy the data from receive buffer update the Rx write pointer register. + * User should read upper byte first and lower byte later to get proper value. + */ + void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); + + inline void setGatewayIp(uint8_t *_addr); + inline void getGatewayIp(uint8_t *_addr); + + inline void setSubnetMask(uint8_t *_addr); + inline void getSubnetMask(uint8_t *_addr); + + inline void setMACAddress(uint8_t * addr); + inline void getMACAddress(uint8_t * addr); + + inline void setIPAddress(uint8_t * addr); + inline void getIPAddress(uint8_t * addr); + + inline void setRetransmissionTime(uint16_t timeout); + inline void setRetransmissionCount(uint8_t _retry); + + void execCmdSn(SOCKET s, SockCMD _cmd); + + uint16_t getTXFreeSize(SOCKET s); + uint16_t getRXReceivedSize(SOCKET s); + + + // W5100 Registers + // --------------- +private: + static uint8_t write(uint16_t _addr, uint8_t _data); + static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); + static uint8_t read(uint16_t addr); + static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); + +#define __GP_REGISTER8(name, address) \ + static inline void write##name(uint8_t _data) { \ + write(address, _data); \ + } \ + static inline uint8_t read##name() { \ + return read(address); \ + } +#define __GP_REGISTER16(name, address) \ + static void write##name(uint16_t _data) { \ + write(address, _data >> 8); \ + write(address+1, _data & 0xFF); \ + } \ + static uint16_t read##name() { \ + uint16_t res = read(address); \ + res = (res << 8) + read(address + 1); \ + return res; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static uint16_t write##name(uint8_t *_buff) { \ + return write(address, _buff, size); \ + } \ + static uint16_t read##name(uint8_t *_buff) { \ + return read(address, _buff, size); \ + } + +public: + __GP_REGISTER8 (MR, 0x0000); // Mode + __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address + __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address + __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address + __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address + __GP_REGISTER8 (IR, 0x0015); // Interrupt + __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask + __GP_REGISTER16(RTR, 0x0017); // Timeout address + __GP_REGISTER8 (RCR, 0x0019); // Retry count + __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size + __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size + __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode + __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer + __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number + __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode + __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + + // W5100 Socket registers + // ---------------------- +private: + static inline uint8_t readSn(SOCKET _s, uint16_t _addr); + static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); + static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + + static const uint16_t CH_BASE = 0x0400; + static const uint16_t CH_SIZE = 0x0100; + +#define __SOCKET_REGISTER8(name, address) \ + static inline void write##name(SOCKET _s, uint8_t _data) { \ + writeSn(_s, address, _data); \ + } \ + static inline uint8_t read##name(SOCKET _s) { \ + return readSn(_s, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static void write##name(SOCKET _s, uint16_t _data) { \ + writeSn(_s, address, _data >> 8); \ + writeSn(_s, address+1, _data & 0xFF); \ + } \ + static uint16_t read##name(SOCKET _s) { \ + uint16_t res = readSn(_s, address); \ + uint16_t res2 = readSn(_s,address + 1); \ + res = res << 8; \ + res2 = res2 & 0xFF; \ + res = res | res2; \ + return res; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ + return writeSn(_s, address, _buff, size); \ + } \ + static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ + return readSn(_s, address, _buff, size); \ + } + +public: + __SOCKET_REGISTER8(SnMR, 0x0000) // Mode + __SOCKET_REGISTER8(SnCR, 0x0001) // Command + __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt + __SOCKET_REGISTER8(SnSR, 0x0003) // Status + __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port + __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr + __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr + __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port + __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size + __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode + __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS + __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL + __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size + __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer + __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer + __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size + __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer + __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + + +private: + static const uint8_t RST = 7; // Reset BIT + + static const int SOCKETS = 4; + static const uint16_t SMASK = 0x07FF; // Tx buffer MASK + static const uint16_t RMASK = 0x07FF; // Rx buffer MASK +public: + static const uint16_t SSIZE = 2048; // Max Tx buffer size +private: + static const uint16_t RSIZE = 2048; // Max Rx buffer size + uint16_t SBASE[SOCKETS]; // Tx buffer base address + uint16_t RBASE[SOCKETS]; // Rx buffer base address + +private: +#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING) + #define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0) + #if defined(ARDUINO_ARCH_AVR) + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + inline static void initSS() { DDRB |= _BV(4); }; + inline static void setSS() { PORTB &= ~_BV(4); }; + inline static void resetSS() { PORTB |= _BV(4); }; + #elif defined(__AVR_ATmega32U4__) + inline static void initSS() { DDRB |= _BV(6); }; + inline static void setSS() { PORTB &= ~_BV(6); }; + inline static void resetSS() { PORTB |= _BV(6); }; + #elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__) + inline static void initSS() { DDRB |= _BV(0); }; + inline static void setSS() { PORTB &= ~_BV(0); }; + inline static void resetSS() { PORTB |= _BV(0); }; + #else + inline static void initSS() { DDRB |= _BV(2); }; + inline static void setSS() { PORTB &= ~_BV(2); }; + inline static void resetSS() { PORTB |= _BV(2); }; + #endif + #else + inline static void initSS() { + *portModeRegister(digitalPinToPort(ETHERNET_SHIELD_SPI_CS)) |= digitalPinToBitMask(ETHERNET_SHIELD_SPI_CS); + } + inline static void setSS() { + *portOutputRegister(digitalPinToPort(ETHERNET_SHIELD_SPI_CS)) &= ~digitalPinToBitMask(ETHERNET_SHIELD_SPI_CS); + } + inline static void resetSS() { + *portOutputRegister(digitalPinToPort(ETHERNET_SHIELD_SPI_CS)) |= digitalPinToBitMask(ETHERNET_SHIELD_SPI_CS); + } + #endif +#else + #define SPI_ETHERNET_SETTINGS ETHERNET_SHIELD_SPI_CS,SPISettings(4000000, MSBFIRST, SPI_MODE0) + // initSS(), setSS(), resetSS() not needed with EXTENDED_CS_PIN_HANDLING +#endif +}; + +extern W5100Class W5100; + +uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) { + return read(CH_BASE + _s * CH_SIZE + _addr); +} + +uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { + return write(CH_BASE + _s * CH_SIZE + _addr, _data); +} + +uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +void W5100Class::getGatewayIp(uint8_t *_addr) { + readGAR(_addr); +} + +void W5100Class::setGatewayIp(uint8_t *_addr) { + writeGAR(_addr); +} + +void W5100Class::getSubnetMask(uint8_t *_addr) { + readSUBR(_addr); +} + +void W5100Class::setSubnetMask(uint8_t *_addr) { + writeSUBR(_addr); +} + +void W5100Class::getMACAddress(uint8_t *_addr) { + readSHAR(_addr); +} + +void W5100Class::setMACAddress(uint8_t *_addr) { + writeSHAR(_addr); +} + +void W5100Class::getIPAddress(uint8_t *_addr) { + readSIPR(_addr); +} + +void W5100Class::setIPAddress(uint8_t *_addr) { + writeSIPR(_addr); +} + +void W5100Class::setRetransmissionTime(uint16_t _timeout) { + writeRTR(_timeout); +} + +void W5100Class::setRetransmissionCount(uint8_t _retry) { + writeRCR(_retry); +} + +#endif diff --git a/libraries/MySensors/drivers/RF24/RF24.h b/libraries/MySensors/drivers/RF24/RF24.h index 235fb71..a0ae93b 100644 --- a/libraries/MySensors/drivers/RF24/RF24.h +++ b/libraries/MySensors/drivers/RF24/RF24.h @@ -47,8 +47,8 @@ typedef enum { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 } rf24_crclength_e class RF24 { private: -#ifdef SOFTSPI - SoftSPI spi; +#ifdef MY_SOFTSPI + SoftSPI spi; #elif defined (SPI_UART) SPIUARTClass uspi; #endif diff --git a/libraries/MySensors/drivers/RF24/RF24_config.h b/libraries/MySensors/drivers/RF24/RF24_config.h index d38ac88..d8c8016 100644 --- a/libraries/MySensors/drivers/RF24/RF24_config.h +++ b/libraries/MySensors/drivers/RF24/RF24_config.h @@ -11,7 +11,7 @@ #ifndef __RF24_CONFIG_H__ #define __RF24_CONFIG_H__ - #include + #include "MyConfig.h" #if ARDUINO < 100 #include @@ -38,17 +38,19 @@ #if defined SPI_UART #include #define _SPI uspi - #elif defined SOFTSPI - // change these pins to your liking - //const uint8_t SOFT_SPI_MISO_PIN = 16; // <-- Moved to MyConfig.h - //const uint8_t SOFT_SPI_MOSI_PIN = 15; // <-- Moved to MyConfig.h - //const uint8_t SOFT_SPI_SCK_PIN = 14; // <-- Moved to MyConfig.h + #elif defined MY_SOFTSPI + #include "drivers/DigitalIO/DigitalIO.h" - const uint8_t SPI_MODE = 0; - #define _SPI spi + // change these pins to your liking + const uint8_t SOFT_SPI_MISO_PIN = MY_SOFT_SPI_MOSI_PIN; + const uint8_t SOFT_SPI_MOSI_PIN = MY_SOFT_SPI_MISO_PIN; + const uint8_t SOFT_SPI_SCK_PIN = MY_SOFT_SPI_SCK_PIN; + + const uint8_t SPI_MODE = 0; + #define _SPI spi #else - #include + #include "drivers/SPI/SPI.h" #define _SPI SPI #endif #endif diff --git a/libraries/MySensors/drivers/RFM69/RFM69.cpp b/libraries/MySensors/drivers/RFM69/RFM69.cpp index 56e47e5..f7e63e7 100644 --- a/libraries/MySensors/drivers/RFM69/RFM69.cpp +++ b/libraries/MySensors/drivers/RFM69/RFM69.cpp @@ -31,7 +31,7 @@ // ********************************************************************************** #include "RFM69.h" #include "RFM69registers.h" -#include +#include "drivers/SPI/SPI.h" volatile byte RFM69::DATA[RF69_MAX_DATA_LEN]; volatile byte RFM69::_mode; // current transceiver state diff --git a/libraries/MySensors/drivers/SPI/SPI.cpp b/libraries/MySensors/drivers/SPI/SPI.cpp new file mode 100644 index 0000000..af14e07 --- /dev/null +++ b/libraries/MySensors/drivers/SPI/SPI.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "SPI.h" + +SPIClass SPI; + +uint8_t SPIClass::initialized = 0; +uint8_t SPIClass::interruptMode = 0; +uint8_t SPIClass::interruptMask = 0; +uint8_t SPIClass::interruptSave = 0; +#ifdef SPI_TRANSACTION_MISMATCH_LED +uint8_t SPIClass::inTransactionFlag = 0; +#endif + +void SPIClass::begin() +{ + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + if (!initialized) { + // Set SS to high so a connected chip will be "deselected" by default + uint8_t port = digitalPinToPort(SS); + uint8_t bit = digitalPinToBitMask(SS); + volatile uint8_t *reg = portModeRegister(port); + + // if the SS pin is not already configured as an output + // then set it high (to enable the internal pull-up resistor) + if(!(*reg & bit)){ + digitalWrite(SS, HIGH); + } + + // When the SS pin is set as OUTPUT, it can be used as + // a general purpose output port (it doesn't influence + // SPI operations). + pinMode(SS, OUTPUT); + + // Warning: if the SS pin ever becomes a LOW INPUT then SPI + // automatically switches to Slave, so the data direction of + // the SS pin MUST be kept as OUTPUT. + SPCR |= _BV(MSTR); + SPCR |= _BV(SPE); + + // Set direction register for SCK and MOSI pin. + // MISO pin automatically overrides to INPUT. + // By doing this AFTER enabling SPI, we avoid accidentally + // clocking in a single bit since the lines go directly + // from "input" to SPI control. + // http://code.google.com/p/arduino/issues/detail?id=888 + pinMode(SCK, OUTPUT); + pinMode(MOSI, OUTPUT); + } + initialized++; // reference count + SREG = sreg; +} + +void SPIClass::end() { + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + // Decrease the reference counter + if (initialized) + initialized--; + // If there are no more references disable SPI + if (!initialized) { + SPCR &= ~_BV(SPE); + interruptMode = 0; + #ifdef SPI_TRANSACTION_MISMATCH_LED + inTransactionFlag = 0; + #endif + } + SREG = sreg; +} + +// mapping of interrupt numbers to bits within SPI_AVR_EIMSK +#if defined(__AVR_ATmega32U4__) + #define SPI_INT0_MASK (1< + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +#define SPI_HAS_NOTUSINGINTERRUPT 1 + +// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. +// This way when there is a bug fix you can check this define to alert users +// of your code if it uses better version of this library. +// This also implies everything that SPI_HAS_TRANSACTION as documented above is +// available too. +#define SPI_ATOMIC_VERSION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn +// on if any mismatch is ever detected. +//#define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR + +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) + #define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) + #define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) + #define SPI_AVR_EIMSK GIMSK +#endif + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + // Clock settings are defined as follows. Note that this shows SPI2X + // inverted, so the bits form increasing numbers. Also note that + // fosc/64 appears twice + // SPR1 SPR0 ~SPI2X Freq + // 0 0 0 fosc/2 + // 0 0 1 fosc/4 + // 0 1 0 fosc/8 + // 0 1 1 fosc/16 + // 1 0 0 fosc/32 + // 1 0 1 fosc/64 + // 1 1 0 fosc/64 + // 1 1 1 fosc/128 + + // We find the fastest clock that is less than or equal to the + // given clock rate. The clock divider that results in clock_setting + // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the + // slowest (128 == 2 ^^ 7, so clock_div = 6). + uint8_t clockDiv; + + // When the clock is known at compiletime, use this if-then-else + // cascade, which the compiler knows how to completely optimize + // away. When clock is not known, use a loop instead, which generates + // shorter code. + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) { + clockDiv = 0; + } else if (clock >= F_CPU / 4) { + clockDiv = 1; + } else if (clock >= F_CPU / 8) { + clockDiv = 2; + } else if (clock >= F_CPU / 16) { + clockDiv = 3; + } else if (clock >= F_CPU / 32) { + clockDiv = 4; + } else if (clock >= F_CPU / 64) { + clockDiv = 5; + } else { + clockDiv = 6; + } + } else { + uint32_t clockSetting = F_CPU / 2; + clockDiv = 0; + while (clockDiv < 6 && clock < clockSetting) { + clockSetting /= 2; + clockDiv++; + } + } + + // Compensate for the duplicate fosc/64 + if (clockDiv == 6) + clockDiv = 7; + + // Invert the SPI2X bit + clockDiv ^= 0x1; + + // Pack into the SPISettings class + spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | + (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); + spsr = clockDiv & SPI_2XCLOCK_MASK; + } + uint8_t spcr; + uint8_t spsr; + friend class SPIClass; +}; + + +class SPIClass { +public: + // Initialize the SPI library + static void begin(); + + // If SPI is used from within an interrupt, this function registers + // that interrupt with the SPI library, so beginTransaction() can + // prevent conflicts. The input interruptNumber is the number used + // with attachInterrupt. If SPI is used from a different interrupt + // (eg, a timer), interruptNumber should be 255. + static void usingInterrupt(uint8_t interruptNumber); + // And this does the opposite. + static void notUsingInterrupt(uint8_t interruptNumber); + // Note: the usingInterrupt and notUsingInterrupt functions should + // not to be called from ISR context or inside a transaction. + // For details see: + // https://github.com/arduino/Arduino/pull/2381 + // https://github.com/arduino/Arduino/pull/2449 + + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + inline static void beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + uint8_t sreg = SREG; + noInterrupts(); + + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + SREG = sreg; + } else + #endif + { + interruptSave = sreg; + } + } + + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 1; + #endif + + SPCR = settings.spcr; + SPSR = settings.spsr; + } + + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + inline static uint8_t transfer(uint8_t data) { + SPDR = data; + /* + * The following NOP introduces a small delay that can prevent the wait + * loop form iterating when running at the maximum speed. This gives + * about 10% more speed, even if it seems counter-intuitive. At lower + * speeds it is unnoticed. + */ + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; // wait + return SPDR; + } + inline static uint16_t transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; + in.val = data; + if (!(SPCR & _BV(DORD))) { + SPDR = in.msb; + asm volatile("nop"); // See transfer(uint8_t) function + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + } else { + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + SPDR = in.msb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + } + return out.val; + } + inline static void transfer(void *buf, size_t count) { + if (count == 0) return; + uint8_t *p = (uint8_t *)buf; + SPDR = *p; + while (--count > 0) { + uint8_t out = *(p + 1); + while (!(SPSR & _BV(SPIF))) ; + uint8_t in = SPDR; + SPDR = out; + *p++ = in; + } + while (!(SPSR & _BV(SPIF))) ; + *p = SPDR; + } + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + inline static void endTransaction(void) { + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (!inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 0; + #endif + + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + uint8_t sreg = SREG; + #endif + noInterrupts(); + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + SREG = sreg; + } else + #endif + { + SREG = interruptSave; + } + } + } + + // Disable the SPI bus + static void end(); + + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setBitOrder(uint8_t bitOrder) { + if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); + else SPCR &= ~(_BV(DORD)); + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setDataMode(uint8_t dataMode) { + SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setClockDivider(uint8_t clockDiv) { + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); + } + // These undocumented functions should not be used. SPI.transfer() + // polls the hardware flag which is automatically cleared as the + // AVR responds to SPI's interrupt + inline static void attachInterrupt() { SPCR |= _BV(SPIE); } + inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } + +private: + static uint8_t initialized; + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state + #ifdef SPI_TRANSACTION_MISMATCH_LED + static uint8_t inTransactionFlag; + #endif +}; + +extern SPIClass SPI; + +#endif diff --git a/libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..df73ade --- /dev/null +++ b/libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return (result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + diff --git a/libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 0000000..c7afcc0 --- /dev/null +++ b/libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 10 (SS pin) + * SDI - to digital pin 11 (MOSI pin) + * CLK - to digital pin 13 (SCK pin) + + created 10 Aug 2010 + by Tom Igoe + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// inslude the SPI library: +#include + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { + // set the slaveSelectPin as an output: + pinMode(slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +void digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin, LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin, HIGH); +} diff --git a/libraries/MySensors/drivers/SPI/keywords.txt b/libraries/MySensors/drivers/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/libraries/MySensors/drivers/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/libraries/MySensors/drivers/SPI/library.properties b/libraries/MySensors/drivers/SPI/library.properties new file mode 100644 index 0000000..2964aec --- /dev/null +++ b/libraries/MySensors/drivers/SPI/library.properties @@ -0,0 +1,9 @@ +name=SPI +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. +paragraph= +url=http://www.arduino.cc/en/Reference/SPI +architectures=avr + diff --git a/libraries/MySensors/drivers/SPIFlash/SPIFlash.h b/libraries/MySensors/drivers/SPIFlash/SPIFlash.h index a308760..e6e1d04 100644 --- a/libraries/MySensors/drivers/SPIFlash/SPIFlash.h +++ b/libraries/MySensors/drivers/SPIFlash/SPIFlash.h @@ -42,7 +42,7 @@ #include "pins_arduino.h" #endif -#include +#include "drivers/SPI/SPI.h" /// IMPORTANT: NAND FLASH memory requires erase before write, because /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s @@ -120,4 +120,4 @@ protected: #endif }; -#endif \ No newline at end of file +#endif diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 7b6adaa..c5e10a4 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -56,37 +56,24 @@ * */ -#include // This include can be removed when using UIPEthernet module -#include - -//#include -//#include -//#include -//#include -//#include -//#include - #define MY_WITH_LEDS_BLINKING #define MY_INCLUSION_MODE_FEATURE #define MY_INCLUSION_BUTTON_FEATURE - #define MY_DEFAULT_LED_BLINK_PERIOD 300 #define MY_INCLUSION_MODE_DURATION 60 // Number of minutes inclusion mode is enabled #define MY_INCLUSION_MODE_BUTTON_PIN 3 // Digital pin used for inclusion mode button #define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin -#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin -#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED +#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin +#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED -#define RADIO_CE_PIN 5 // radio chip enable -#define RADIO_SPI_SS_PIN 6 // radio SPI serial select +#define MY_RADIO_CE_PIN 5 // radio chip enable +#define MY_RADIO_SPI_SS_PIN 6 // radio SPI serial select #include -#include -#include #define MY_IP_PORT 5003 // The port you want to open diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index 0c9179b..a0d734b 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -27,18 +27,20 @@ * */ -#include -#include +//#define MY_DEBUG + +#include "MySensor.h" unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) #define CHILD_ID 1 // Id of the sensor child -MySensor gw; // Initialize motion message MyMessage msg(CHILD_ID, V_TRIPPED); + + void setup() { gw.begin(); From 6a42e2d5553d5fd98b47eb7d994d5fc95d88a761 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 12 Sep 2015 00:36:32 +0200 Subject: [PATCH 248/660] Disable RFM69 temporarily --- libraries/MySensors/MySensor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 94f7e45..7071221 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -49,7 +49,7 @@ #include "core/MyHwATMega328.cpp" #include "core/MyTransport.cpp" #include "core/MyTransportNRF24.cpp" -#include "core/MyTransportRFM69.cpp" +//#include "core/MyTransportRFM69.cpp" #include "core/MyGatewayTransport.cpp" #include "core/MyGatewayTransportSerial.cpp" @@ -58,7 +58,7 @@ // Initialize library -MyTransportRFM69 transport; +//MyTransportRFM69 transport; MySensor gw; From f8ee37623074086767715d92bfb8ff2ada8e5079 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 13 Sep 2015 11:59:09 +0200 Subject: [PATCH 249/660] C:ifying continues.. --- libraries/MySensors/MyConfig.h | 92 +- libraries/MySensors/MySensor.h | 168 +- .../MySensors/core/MyGatewayTransport.cpp | 25 - libraries/MySensors/core/MyGatewayTransport.h | 47 - .../core/MyGatewayTransportEthernet.cpp | 120 +- .../core/MyGatewayTransportEthernet.h | 59 +- .../MySensors/core/MyGatewayTransportSerial.h | 1 - libraries/MySensors/core/MyHw.cpp | 23 - libraries/MySensors/core/MyHw.h | 54 - libraries/MySensors/core/MyHwATMega328.cpp | 94 +- libraries/MySensors/core/MyHwATMega328.h | 51 +- libraries/MySensors/core/MyHwESP8266.cpp | 74 +- libraries/MySensors/core/MyHwESP8266.h | 41 +- libraries/MySensors/core/MySensorCore.cpp | 1891 +++++++++-------- libraries/MySensors/core/MySensorCore.h | 427 ++-- libraries/MySensors/core/MyTransportNRF24.cpp | 9 +- libraries/MySensors/core/MyTransportNRF24.h | 4 +- libraries/MySensors/core/MyTransportRFM69.cpp | 8 +- libraries/MySensors/core/MyTransportRFM69.h | 4 +- .../MySensors/drivers/DigitalIO/DigitalIO.h | 12 +- .../MySensors/drivers/DigitalIO/PinIO.cpp | 4 +- .../drivers/DigitalIO/SoftI2cMaster.cpp | 2 +- .../drivers/DigitalIO/SoftI2cMaster.h | 4 +- .../MySensors/drivers/DigitalIO/SoftSPI.h | 2 +- libraries/MySensors/drivers/RF24/RF24.cpp | 2 +- .../MySensors/drivers/RF24/RF24_config.h | 2 +- .../EthernetGateway/EthernetGateway.ino | 100 +- .../examples/MotionSensor/MotionSensor.ino | 18 +- 28 files changed, 1541 insertions(+), 1797 deletions(-) delete mode 100644 libraries/MySensors/core/MyGatewayTransport.cpp delete mode 100644 libraries/MySensors/core/MyGatewayTransport.h delete mode 100644 libraries/MySensors/core/MyHw.cpp delete mode 100644 libraries/MySensors/core/MyHw.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 71d87c0..c8323be 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -22,33 +22,53 @@ #define MyConfig_h #include -// Enable debug flag for debug prints. This will add a lot to the size of the final sketch but good -// to see what is actually is happening when developing +// Enables this in sketch to show debug prints. This option will add a lot to the size of the +// final sketch but is helpful to see what is actually is happening during development //#define MY_DEBUG -// Enable this line, If you are using TX(1), RX(0) as normal I/O pin -// #define MY_DISABLED_SERIAL +// Enable this in sketch if you want to use TX(1), RX(0) as normal I/O pin +//#define MY_DISABLED_SERIAL + +// Turn off debug if serial pins is used for other stuff +#ifdef MY_DISABLED_SERIAL +#undef MY_DEBUG +#endif // Serial output baud rate (for debug prints and serial gateway) #ifndef MY_BAUD_RATE #define MY_BAUD_RATE 115200 #endif +// Node id defaults to AUTO (tries to fetch id from controller) +#ifndef MY_NODE_ID +#define MY_NODE_ID AUTO +#endif + +// Node parent defaults to AUTO (tries to find a parent automatically) +#ifndef MY_PARENT_NODE_ID +#define MY_PARENT_NODE_ID AUTO +#endif + +// Enables repeater functionality (relays messages from other nodes) +// #define MY_REPEATER_FEATURE + /********************************** * Over the air firmware updates ***********************************/ -// The following define enables the safe over-the-air firmware update feature -// which requires external flash and the DualOptiBoot bootloader. +// Enable MY_OTA_FIRMWARE_FEATURE in sketch to allow safe over-the-air firmware updates. +// This feature requires external flash and the DualOptiBoot bootloader. // Note: You can still have OTA FW updates without external flash but it // requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE //#define MY_OTA_FIRMWARE_FEATURE + // Slave select pin for external flash -#ifdef MY_OTA_FLASH_SS +#ifndef MY_OTA_FLASH_SS #define MY_OTA_FLASH_SS 8 #endif + // Flash jdecid -#ifdef MY_OTA_FLASH_JDECID +#ifndef MY_OTA_FLASH_JDECID #define MY_OTA_FLASH_JDECID 0x1F65 #endif @@ -112,8 +132,10 @@ /********************************** * Message Signing Settings ***********************************/ -// Disable to completely disable signing functionality in library -//#define MY_SIGNING_FEATURE + +// Enable one of these in sketch to use signing functionality +//#define MY_SIGNING_ATSHA204 +//#define MY_SIGNING_SOFT // Define a suitable timeout for a signature verification session // Consider the turn-around from a nonce being generated to a signed message being received @@ -151,18 +173,30 @@ /********************************** * NRF24L01 Driver Defaults ***********************************/ -#define RF24_CE_PIN 9 -#define RF24_CS_PIN 10 -#define RF24_PA_LEVEL RF24_PA_MAX -#define RF24_PA_LEVEL_GW RF24_PA_LOW -// RF channel for the sensor net, 0-127 -#define RF24_CHANNEL 76 -//RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps -#define RF24_DATARATE RF24_250KBPS -// This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. -#define RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) +#ifndef MY_RF24_CE_PIN +#define MY_RF24_CE_PIN 9 +#endif +#ifndef MY_RF24_CS_PIN +#define MY_RF24_CS_PIN 10 +#endif -// Enable SOFTSPI for NRF24L01 when using the W5100 Ethernet module +#ifndef MY_RF24_PA_LEVEL +#define MY_RF24_PA_LEVEL RF24_PA_MAX +#endif +// RF channel for the sensor net, 0-127 +#ifndef MY_RF24_CHANNEL +#define MY_RF24_CHANNEL 76 +#endif +//RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps +#ifndef MY_RF24_DATARATE +#define MY_RF24_DATARATE RF24_250KBPS +#endif +// This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. +#ifndef MY_RF24_BASE_RADIO_ID +#define MY_RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL) +#endif + +// Enable SOFTSPI for NRF24L01, useful for the W5100 Ethernet module //#define MY_SOFTSPI #ifndef MY_SOFT_SPI_SCK_PIN @@ -186,6 +220,11 @@ //#define MY_RFM69_FREQUENCY RF69_915MHZ #endif +// Enable this if you're running the RFM69HW model +#ifndef MY_IS_RFM69HW +#define MY_IS_RFM69HW false +#endif + // Default network id. Use the same for all nodes that will talk to each other #ifndef MY_RFM69_NETWORKID #define MY_RFM69_NETWORKID 100 @@ -210,9 +249,16 @@ * Gateway Transport Ethernet Defaults ***************************************/ // Enable to use DHCP for getting IP address. If not defined, static IP is expected -//#define IP_ADDRESS_DHCP +//#define MY_IP_ADDRESS_VIA_DHCP +#ifndef MY_IP_RENEWAL_INTERVAL +#define MY_IP_RENEWAL_INTERVAL 60000 +#endif + +#ifndef MY_MAC_ADDRESS +#define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +#endif // Enable to use UDP instead of plain Ethernet -#define MY_USE_UDP +//#define MY_USE_UDP #endif diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 7071221..e9d4e75 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -16,50 +16,164 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - - #ifndef MySensor_h #define MySensor_h +#define VALUE_TO_STRING(x) #x +#define VALUE(x) VALUE_TO_STRING(x) +#define VAR_NAME_VALUE(var) #var "=" VALUE(var) +// #pragma message(VAR_NAME_VALUE(MY_GATEWAY_FEATURE)) + #include "MyConfig.h" -// Include drivers +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100_CLIENT) || defined(MY_GATEWAY_W5100_SERVER) + #define MY_GATEWAY_FEATURE + #define MY_NODE_TYPE "gateway" +#elif defined(MY_REPEATER_FEATURE) + #define MY_NODE_TYPE "repeater" +#else + #define MY_NODE_TYPE "sensor" +#endif + +// CORE #include "drivers/SPI/SPI.cpp" -#include "drivers/RF24/RF24.cpp" -#include "drivers/RFM69/RFM69.cpp" +// HARDWARE +#if defined(ARDUINO_ARCH_ESP8266) + #include "core/MyHwESP8266.cpp" +#elif defined(ARDUINO_ARCH_AVR) + #include "core/MyHwATMega328.cpp" +#endif -#include "drivers/ATSHA204/ATSHA204.cpp" -#include "drivers/ATSHA204/sha256.cpp" +// SIGNING +#if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) + #include "MySigning.cpp" + #define MY_SIGNING_FEATURE + #if defined(MY_SIGNING_ATSHA204) + #include "MySigningAtsha204.cpp" + #include "drivers/ATSHA204/ATSHA204.cpp" + MySigningAtsha204 signer; + #elif defined(MY_SIGNING_SOFT) + #include "MySigningAtsha204Soft.cpp" + #include "drivers/ATSHA204/sha256.cpp" + MySigningAtsha204Soft signer; + #endif +#endif -#include "drivers/SPIFlash/SPIFlash.cpp" +// RADIO +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) + #define MY_RADIO_FEATURE + // SOFTSPI + #ifdef MY_SOFTSPI + #include "drivers/DigitalIO/SoftI2cMaster.cpp" + #include "drivers/DigitalIO/PinIO.cpp" + #endif -#include "drivers/Ethernet_W5100/utility/socket.cpp" -#include "drivers/Ethernet_W5100/utility/w5100.cpp" -#include "drivers/Ethernet_W5100/DNS.cpp" -#include "drivers/Ethernet_W5100/Ethernet.cpp" -#include "drivers/Ethernet_W5100/EthernetUdp.cpp" -#include "drivers/Ethernet_W5100/IPAddress.cpp" + // FLASH + #ifdef MY_OTA_FIRMWARE_FEATURE + SPIFlash flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); + #include "drivers/SPIFlash/SPIFlash.cpp" + #endif + + #include "core/MyTransport.cpp" + #if defined(MY_RADIO_NRF24) + #include "drivers/RF24/RF24.cpp" + #include "core/MyTransportNRF24.cpp" + MyTransportNRF24 transport; + + #elif defined(MY_RADIO_RFM69) + #include "drivers/RFM69/RFM69.cpp" + #include "core/MyTransportRFM69.cpp" + MyTransportRFM69 transport; + #endif +#endif +// GATEWAY - TRANSPORT +#if defined(MY_GATEWAY_FEATURE) + // GATEWAY - PROTOCOL + #include "core/MyProtocol.cpp" + #if defined(MY_GATEWAY_PROTOCOL_DEFAULT) + #include "core/MyProtocolDefault.cpp" + MyProtocolDefault _protocol; + #else + #error No gateway protocol specified! + #endif + #if defined(MY_RADIO_FEATURE) + // We assume that a gateway having a radio also should act as repeater + #define MY_REPEATER_FEATURE + #endif + #if defined(MY_GATEWAY_W5100_CLIENT) || defined(MY_GATEWAY_W5100_SERVER) + #include "drivers/Ethernet_W5100/utility/socket.cpp" + #include "drivers/Ethernet_W5100/utility/w5100.cpp" + #include "drivers/Ethernet_W5100/DNS.cpp" + #include "drivers/Ethernet_W5100/Ethernet.cpp" + #include "drivers/Ethernet_W5100/EthernetUdp.cpp" + #include "drivers/Ethernet_W5100/IPAddress.cpp" + #if !defined(MY_PORT) + #error You must define MY_PORT + #endif + #if !defined(USE_UDP) + #include "drivers/Ethernet_W5100/EthernetServer.cpp" + #endif + #if defined(MY_GATEWAY_W5100_CLIENT) && !defined(MY_CONTROLLER_IP_ADDRESS) + #error You must define MY_CONTROLLER_IP_ADDRESS when acting as client + #endif + + #if defined(MY_GATEWAY_W5100_CLIENT) + #include "drivers/Ethernet_W5100/EthernetClient.cpp" + #include "core/MyGatewayTransportEthernet.cpp" + #endif + #elif defined(MY_GATEWAY_SERIAL) + #include "core/MyGatewayTransportSerial.cpp" + MyGatewayTransportSerial gwTransport(protocol); + #endif +#else + #undef MY_GATEWAY_FEATURE +#endif + +// Make sure to disable child features when parent feature is disabled +#if !defined(MY_RADIO_FEATURE) + #undef MY_OTA_FIRMWARE_FEATURE + #undef MY_REPEATER_FEATURE + #undef MY_SECURE_NODE_WHITELISTING + #undef MY_SIGNING_FEATURE +#endif + +#if !defined(MY_GATEWAY_FEATURE) + #undef MY_INCLUSION_MODE_FEATURE + #undef MY_INCLUSION_BUTTON_FEATURE +#endif + +// Defines used in code for if-statements +#if defined(MY_REPEATER_FEATURE) + #define MY_IS_REPEATER true +#else + #define MY_IS_REPEATER false +#endif + +#if defined(MY_GATEWAY_FEATURE) + #define MY_IS_GATEWAY true +#else + #define MY_IS_GATEWAY false +#endif -// Include core classes -#include "core/MyHw.cpp" -#include "core/MyHwATMega328.cpp" -#include "core/MyTransport.cpp" -#include "core/MyTransportNRF24.cpp" -//#include "core/MyTransportRFM69.cpp" -#include "core/MyGatewayTransport.cpp" -#include "core/MyGatewayTransportSerial.cpp" #include "core/MyMessage.cpp" #include "core/MySensorCore.cpp" +extern void setup(); +extern void loop(); -// Initialize library -//MyTransportRFM69 transport; -MySensor gw; - - +// Initialize library and call sketch functions +int main() { + begin(); + setup(); + while(1) { + // We handle incoming message processing here + process(); + loop(); + } +} #endif diff --git a/libraries/MySensors/core/MyGatewayTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.cpp deleted file mode 100644 index 2306d5f..0000000 --- a/libraries/MySensors/core/MyGatewayTransport.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include "MyGatewayTransport.h" - - -MyGatewayTransport::MyGatewayTransport(MyProtocol &_protocol) : protocol(_protocol) { - -} diff --git a/libraries/MySensors/core/MyGatewayTransport.h b/libraries/MySensors/core/MyGatewayTransport.h deleted file mode 100644 index da03ff5..0000000 --- a/libraries/MySensors/core/MyGatewayTransport.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#ifndef MyGatewayTransport_h -#define MyGatewayTransport_h - -#include "MyMessage.h" -#include "MyProtocol.h" -#include "MyProtocolDefault.h" - -class MyGatewayTransport -{ -public: - // MyProtocol constructor - MyGatewayTransport(MyProtocol &protocol = *new MyProtocolDefault()); - - // initialize the transport driver - virtual bool begin() = 0; - - // Send message to controller - virtual bool send(MyMessage &message) = 0; - - // Check if a new message is available from controller - virtual bool available() = 0; - - // Pick up last message received from controller - virtual MyMessage& receive() = 0; -protected: - MyProtocol& protocol; -}; -#endif diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp index 7b9083d..b2b21ee 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp @@ -19,39 +19,28 @@ #include "MyGatewayTransportEthernet.h" -MyGatewayTransportEthernet::MyGatewayTransportEthernet( - MyProtocol &protocol, - uint8_t *gw_mac -#ifndef IP_ADDRESS_DHCP - , IPAddress gw_ip -#endif /* not IP_ADDRESS_DHCP */ - , uint16_t gw_port -#ifdef IP_ADDRESS_DHCP - , unsigned long ip_renew_interval -#endif /* IP_ADDRESS_DHCP */ - , IPAddress controller_IP - , uint16_t controller_port) : - MyGatewayTransport(protocol), - gatewayMAC(gw_mac), -#ifndef IP_ADDRESS_DHCP - gatewayIP(gw_ip), -#endif /* not IP_ADDRESS_DHCP */ - gatewayPort(gw_port), -#ifdef IP_ADDRESS_DHCP - ip_renewal_period(ip_renew_interval), -#endif /* IP_ADDRESS_DHCP */ - controllerIP(controller_IP), - controllerPort(controller_port) -{ - ; -} +IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); +IPAddress _ethernetGatewayIP(MY_IP_ADDRESS); +byte _ethernetGatewayMAC[] = { MY_MAC_ADDRESS }; +uint16_t _ethernetGatewayPort = MY_PORT; +char _ethernetInputBuffer[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface +MyMessage _ethernetMsg; -bool MyGatewayTransportEthernet::begin() { -#ifdef IP_ADDRESS_DHCP - // Get IP address from DHCP - Ethernet.begin(gatewayMAC); +#ifdef MY_USE_UDP + EthernetUDP _ethernetServer; #else - Ethernet.begin(gatewayMAC, gatewayIP); + // we have to use pointers due to the constructor of EthernetServer + EthernetServer _ethernetServer(_ethernetGatewayPort); + uint8_t _ethernetInputPos; +#endif /* USE_UDP */ + + +bool gatewayTransportBegin() { +#ifdef MY_IP_ADDRESS + Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP); +#else + // Get IP address from DHCP + Ethernet.begin(_ethernetGatewayMAC); #endif /* IP_ADDRESS_DHCP */ // give the Ethernet interface a second to initialize @@ -59,34 +48,32 @@ bool MyGatewayTransportEthernet::begin() { delay(1000); #ifdef MY_USE_UDP - server = new EthernetUDP(); - server->begin(gatewayPort); + _ethernetServer.begin(_ethernetGatewayPort); #else // we have to use pointers due to the constructor of EthernetServer - server = new EthernetServer(gatewayPort); - server->begin(); + _ethernetServer.begin(); #endif /* USE_UDP */ } -bool MyGatewayTransportEthernet::send(MyMessage &message) +bool gatewayTransportSend(MyMessage &message) { - char *msg = NULL; + char *_ethernetMsg = NULL; - if (controllerIP == INADDR_NONE) { + if (_ethernetControllerIP == INADDR_NONE) { // no controller IP address set! return false; } else { - msg = protocol.format(message); + _ethernetMsg = _protocol.format(message); #ifdef MY_USE_UDP - server->beginPacket(controllerIP, controllerPort); - server->write(msg, strlen(msg)); + _ethernetServer.beginPacket(_ethernetControllerIP, MY_CONTROLLER_PORT); + _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); // returns 1 if the packet was sent successfully - return server->endPacket(); + return _ethernetServer.endPacket(); #else EthernetClient client; - if (client.connect(controllerIP, controllerPort)) { - client.write(msg, strlen(msg)); + if (client.connect(_ethernetControllerIP, MY_CONTROLLER_PORT)) { + client.write(_ethernetMsg, strlen(_ethernetMsg)); client.stop(); return true; } @@ -98,71 +85,64 @@ bool MyGatewayTransportEthernet::send(MyMessage &message) } } -bool MyGatewayTransportEthernet::available() +bool gatewayTransportAvailable() { bool available = false; -#ifdef IP_ADDRESS_DHCP +#ifndef MY_IP_ADDRESS // renew IP address using DHCP - renewIP(); + gatewayTransportRenewIP(); #endif #ifdef MY_USE_UDP - int packet_size = server->parsePacket(); + int packet_size = _ethernetServer.parsePacket(); - if (server->available()) { - server->read(inputBuffer, MAX_RECEIVE_LENGTH); + if (_ethernetServer.available()) { + _ethernetServer.read(_ethernetInputBuffer, MAX_RECEIVE_LENGTH); available = true; } #else // if an incoming client connects, there will be // bytes available to read via the client object - EthernetClient client = server->available(); + EthernetClient client = _ethernetServer.available(); if (client) { while (client.available()) { // read the bytes incoming from the client char inChar = client.read(); - if (inputPos < MAX_RECEIVE_LENGTH - 1) { + if (_ethernetInputPos < MAX_RECEIVE_LENGTH - 1) { // if newline then command is complete if (inChar == '\n') { - inputBuffer[inputPos] = 0; + _ethernetInputBuffer[_ethernetInputPos] = 0; available = true; } else { - inputBuffer[inputPos] = inChar; - inputPos++; + _ethernetInputBuffer[_ethernetInputPos] = inChar; + _ethernetInputPos++; } } } } - inputPos = 0; + _ethernetInputPos = 0; #endif if (available) { // Parse message and return parse result - available = protocol.parse(msg, inputBuffer); + available = _protocol.parse(_ethernetMsg, _ethernetInputBuffer); } return available; } -MyMessage& MyGatewayTransportEthernet::receive() +MyMessage& gatewayTransportReceive() { // Return the last parsed message - return msg; + return _ethernetMsg; } -void MyGatewayTransportEthernet::setControllerIPPort(const IPAddress& addr, const uint16_t port) { - controllerIP = addr; - /* set the port if some legal value passed */ - if (port > 0) - controllerPort = port; -} - -#ifdef IP_ADDRESS_DHCP -void MyGatewayTransportEthernet::renewIP() +#ifndef MY_IP_ADDRES +void gatewayTransportRenewIP() { /* renew/rebind IP address 0 - nothing happened @@ -172,7 +152,7 @@ void MyGatewayTransportEthernet::renewIP() 4 - rebind success */ // TODO: Use millis from MyHw ?? - static unsigned long next_time = millis() + ip_renewal_period; + static unsigned long next_time = millis() + MY_IP_RENEWAL_INTERVAL; unsigned long now = millis(); // http://playground.arduino.cc/Code/TimingRollover @@ -184,6 +164,6 @@ void MyGatewayTransportEthernet::renewIP() return; } - next_time = now + ip_renewal_period; + next_time = now + MY_IP_RENEWAL_INTERVAL; } #endif /* IP_ADDRESS_DHCP */ diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.h b/libraries/MySensors/core/MyGatewayTransportEthernet.h index 7256b1a..da1abc1 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.h +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.h @@ -23,7 +23,6 @@ #include "MyConfig.h" #include "MyMessage.h" #include "MyProtocol.h" -#include "MyGatewayTransport.h" #include "MyProtocolDefault.h" #include "drivers/Ethernet_W5100/IPAddress.h" @@ -43,58 +42,20 @@ #define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller -class MyGatewayTransportEthernet : public MyGatewayTransport -{ - public: - MyGatewayTransportEthernet(MyProtocol &protocol, - uint8_t *gw_mac -#ifndef IP_ADDRESS_DHCP - , IPAddress gw_ip -#endif /* not IP_ADDRESS_DHCP */ - , uint16_t gw_port -#ifdef IP_ADDRESS_DHCP - , unsigned long ip_renew_interval -#endif /* IP_ADDRESS_DHCP */ - , IPAddress controller_IP - , uint16_t controller_port - ); +// initialize the driver +bool gatewayTransportBegin(); - // initialize the driver - bool begin(); +// Send message to controller +bool gatewayTransportSend(MyMessage &message); - // Send message to controller - bool send(MyMessage &message); +// Check if a new message is available from controller +bool gatewayTransportAvailable(); - // Check if a new message is available from controller - bool available(); +// Pick up last message received from controller +MyMessage& gatewayTransportReceive(); - // Pick up last message received from controller - MyMessage& receive(); - - // Set the controller IP and Port - void setControllerIPPort(const IPAddress& addr, const uint16_t port); - -protected: - IPAddress controllerIP; - uint16_t controllerPort; - -#ifdef IP_ADDRESS_DHCP - void renewIP(); - unsigned long ip_renewal_period; -#endif /* IP_ADDRESS_DHCP */ - uint8_t *gatewayMAC; - IPAddress gatewayIP; - uint16_t gatewayPort; - -#ifdef MY_USE_UDP - EthernetUDP *server; -#else - EthernetServer *server; - uint8_t inputPos; +#ifndef MY_IP_ADDRESS + void gatewayTransportRenewIP(); #endif - char inputBuffer[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface - MyMessage msg; -}; - #endif /* MyGatewayTransportEthernet_h */ diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.h b/libraries/MySensors/core/MyGatewayTransportSerial.h index 44434cf..302a06c 100644 --- a/libraries/MySensors/core/MyGatewayTransportSerial.h +++ b/libraries/MySensors/core/MyGatewayTransportSerial.h @@ -22,7 +22,6 @@ #include "MyMessage.h" #include "MyProtocol.h" -#include "MyGatewayTransport.h" #include "MyProtocolDefault.h" #define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller diff --git a/libraries/MySensors/core/MyHw.cpp b/libraries/MySensors/core/MyHw.cpp deleted file mode 100644 index 3016a6b..0000000 --- a/libraries/MySensors/core/MyHw.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include "MyHw.h" - -MyHw::MyHw() { -} diff --git a/libraries/MySensors/core/MyHw.h b/libraries/MySensors/core/MyHw.h deleted file mode 100644 index 506648b..0000000 --- a/libraries/MySensors/core/MyHw.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#ifndef MyHw_h -#define MyHw_h - -#include -#include -#include "MyConfig.h" - -/** - * The Hw contains all hardware specific details of the platform - */ - -class MyHw -{ -public: - // MyHw constructor - MyHw(); -/* // The following is defined as macros to save space - virtual void init() = 0; - virtual void watchdogReset() = 0; - virtual void reboot() = 0; - virtual unsigned long millisec() = 0; - virtual uint8_t readConfig(uint8_t pos) = 0; - virtual void writeConfig(uint8_t pos, uint8_t value) = 0; - virtual void readConfigBlock(void* buf, void * pos, size_t length) = 0; - virtual void writeConfigBlock(void* pos, void* buf, uint16_t length) = 0; */ - virtual void sleep(unsigned long ms) = 0; - virtual bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) = 0; - virtual uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) = 0; - #ifdef MY_DEBUG - virtual void debugPrint(bool isGW, const char *fmt, ... ) = 0; - #endif - -}; - -#endif diff --git a/libraries/MySensors/core/MyHwATMega328.cpp b/libraries/MySensors/core/MyHwATMega328.cpp index b20d337..38e16fe 100644 --- a/libraries/MySensors/core/MyHwATMega328.cpp +++ b/libraries/MySensors/core/MyHwATMega328.cpp @@ -19,7 +19,6 @@ #ifdef ARDUINO_ARCH_AVR -#include "MyHw.h" #include "MyHwATMega328.h" int8_t pinIntTrigger = 0; @@ -40,51 +39,10 @@ ISR (WDT_vect) wdt_disable(); } -MyHwATMega328::MyHwATMega328() : MyHw() -{ -} -/* -// The following was redifined as macros to save space - -inline uint8_t MyHwATMega328::readConfig(uint8_t pos) { - return eeprom_read_byte((uint8_t*)pos); -} - -inline void MyHwATMega328::writeConfig(uint8_t pos, uint8_t value) { - eeprom_update_byte((uint8_t*)pos, value); -} - -inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { - eeprom_read_block(buf, (void*)pos, length); -} - -inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { - eeprom_write_block((void*)pos, (void*)buf, length); -} - - -inline void MyHwATMega328::init() { - Serial.begin(BAUD_RATE); -} - -inline void MyHwATMega328::watchdogReset() { - wdt_reset(); -} - -inline void MyHwATMega328::reboot() { - wdt_enable(WDTO_15MS); for (;;); -} - -inline unsigned long MyHwATMega328::millis() { - return ::millis(); -} -*/ - - -void powerDown(period_t period) { +void hwPowerDown(period_t period) { ADCSRA &= ~(1 << ADEN); @@ -119,35 +77,35 @@ void powerDown(period_t period) { ADCSRA |= (1 << ADEN); } -void MyHwATMega328::internalSleep(unsigned long ms) { +void hwInternalSleep(unsigned long ms) { // Let serial prints finish (debug, log etc) #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif pinIntTrigger = 0; - while (!pinIntTrigger && ms >= 8000) { powerDown(SLEEP_8S); ms -= 8000; } - if (!pinIntTrigger && ms >= 4000) { powerDown(SLEEP_4S); ms -= 4000; } - if (!pinIntTrigger && ms >= 2000) { powerDown(SLEEP_2S); ms -= 2000; } - if (!pinIntTrigger && ms >= 1000) { powerDown(SLEEP_1S); ms -= 1000; } - if (!pinIntTrigger && ms >= 500) { powerDown(SLEEP_500MS); ms -= 500; } - if (!pinIntTrigger && ms >= 250) { powerDown(SLEEP_250MS); ms -= 250; } - if (!pinIntTrigger && ms >= 125) { powerDown(SLEEP_120MS); ms -= 120; } - if (!pinIntTrigger && ms >= 64) { powerDown(SLEEP_60MS); ms -= 60; } - if (!pinIntTrigger && ms >= 32) { powerDown(SLEEP_30MS); ms -= 30; } - if (!pinIntTrigger && ms >= 16) { powerDown(SLEEP_15Ms); ms -= 15; } + while (!pinIntTrigger && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; } + if (!pinIntTrigger && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; } + if (!pinIntTrigger && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; } + if (!pinIntTrigger && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; } + if (!pinIntTrigger && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; } + if (!pinIntTrigger && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; } + if (!pinIntTrigger && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; } + if (!pinIntTrigger && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; } + if (!pinIntTrigger && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; } + if (!pinIntTrigger && ms >= 16) { hwPowerDown(SLEEP_15Ms); ms -= 15; } } -void MyHwATMega328::sleep(unsigned long ms) { - internalSleep(ms); +void hwSleep(unsigned long ms) { + hwInternalSleep(ms); } -bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { +bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { pinIntTrigger = 0; - internalSleep(ms); + hwInternalSleep(ms); if (0 == pinIntTrigger) { pinTriggeredWakeup = false; } @@ -155,19 +113,19 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif - powerDown(SLEEP_FOREVER); + hwPowerDown(SLEEP_FOREVER); } detachInterrupt(interrupt); return pinTriggeredWakeup; } -inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { +uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { int8_t retVal = 1; attachInterrupt(interrupt1, wakeUp, mode1); attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { pinIntTrigger = 0; - internalSleep(ms); + hwInternalSleep(ms); if (0 == pinIntTrigger) { retVal = -1; } @@ -175,7 +133,7 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i #ifndef MY_DISABLED_SERIAL Serial.flush(); #endif - powerDown(SLEEP_FOREVER); + hwPowerDown(SLEEP_FOREVER); } detachInterrupt(interrupt1); detachInterrupt(interrupt2); @@ -191,24 +149,24 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i #ifdef MY_DEBUG -void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) { +void hwDebugPrint(const char *fmt, ... ) { char fmtBuffer[300]; - if (isGW) { + #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); Serial.print(fmtBuffer); - } + #endif va_list args; va_start (args, fmt ); va_end (args); - if (isGW) { + #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf_P(fmtBuffer, 60, fmt, args); fmtBuffer[59] = '\n'; fmtBuffer[60] = '\0'; - } else { + #else vsnprintf_P(fmtBuffer, 299, fmt, args); - } + #endif va_end (args); Serial.print(fmtBuffer); Serial.flush(); diff --git a/libraries/MySensors/core/MyHwATMega328.h b/libraries/MySensors/core/MyHwATMega328.h index 3468db6..90ea09b 100644 --- a/libraries/MySensors/core/MyHwATMega328.h +++ b/libraries/MySensors/core/MyHwATMega328.h @@ -22,7 +22,6 @@ #ifdef ARDUINO_ARCH_AVR -#include "MyHw.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -42,7 +41,7 @@ #ifndef sleep_bod_disable #define sleep_bod_disable() \ do { \ - unsigned char tempreg; \ + unsigned char tempreg; \ __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ "ori %[tempreg], %[bods_bodse]" "\n\t" \ "out %[mcucr], %[tempreg]" "\n\t" \ @@ -59,22 +58,22 @@ do { \ // Define these as macros to save valuable space -#define hw_digitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hw_init() Serial.begin(MY_BAUD_RATE) -#define hw_watchdogReset() wdt_reset() -#define hw_reboot() wdt_enable(WDTO_15MS); while (1) -#define hw_millis() millis() -#define hw_readConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) +#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) +#define hwInit() Serial.begin(MY_BAUD_RATE) +#define hwWatchdogReset() wdt_reset() +#define hwReboot() wdt_enable(WDTO_15MS); while (1) +#define hwMillis() millis() +#define hwReadConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) #ifndef eeprom_update_byte - #define hw_writeConfig(loc, val) if((uint8_t)(val) != eeprom_read_byte((uint8_t*)(loc))) { eeprom_write_byte((uint8_t*)(loc), (val)); } + #define hwWriteConfig(loc, val) if((uint8_t)(val) != eeprom_read_byte((uint8_t*)(loc))) { eeprom_write_byte((uint8_t*)(loc), (val)); } #else - #define hw_writeConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) + #define hwWriteConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) #endif // -#define hw_readConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) -#define hw_writeConfigBlock(__pos, __buf, __length) (eeprom_write_block((void*)(__pos), (void*)__buf, (__length))) +#define hwReadConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) +#define hwWriteConfigBlock(__pos, __buf, __length) (eeprom_write_block((void*)(__pos), (void*)__buf, (__length))) @@ -93,28 +92,14 @@ enum period_t SLEEP_FOREVER }; -class MyHwATMega328 : public MyHw -{ -public: - MyHwATMega328(); -/* void init(); - void watchdogReset(); - void reboot(); - unsigned long millis(); - uint8_t readConfig(uint8_t pos); - void writeConfig(uint8_t pos, uint8_t value); - void readConfigBlock(void* buf, void * pos, size_t length); - void writeConfigBlock(void* pos, void* buf, size_t length); */ - - void sleep(unsigned long ms); - bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms); - uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +void hwSleep(unsigned long ms); +bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); +uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); #ifdef MY_DEBUG - void debugPrint(bool isGW, const char *fmt, ... ); -#endif -private: - void internalSleep(unsigned long ms); -}; + void hwDebugPrint(const char *fmt, ... ); #endif +void hwInternalSleep(unsigned long ms); + #endif // #ifdef ARDUINO_ARCH_AVR +#endif diff --git a/libraries/MySensors/core/MyHwESP8266.cpp b/libraries/MySensors/core/MyHwESP8266.cpp index fa36ebf..5a0eb64 100644 --- a/libraries/MySensors/core/MyHwESP8266.cpp +++ b/libraries/MySensors/core/MyHwESP8266.cpp @@ -19,7 +19,6 @@ #ifdef ARDUINO_ARCH_ESP8266 -#include "MyHw.h" #include "MyHwESP8266.h" #include @@ -43,7 +42,7 @@ ISR (WDT_vect) } */ -static void hw_initConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ ) +static void hwInitConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ ) { static bool initDone = false; if (!initDone) @@ -53,7 +52,7 @@ static void hw_initConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes* } } -void hw_readConfigBlock(void* buf, void* adr, size_t length) +void hwReadConfigBlock(void* buf, void* adr, size_t length) { hw_initConfigBlock(); uint8_t* dst = static_cast(buf); @@ -64,7 +63,7 @@ void hw_readConfigBlock(void* buf, void* adr, size_t length) } } -void hw_writeConfigBlock(void* buf, void* adr, size_t length) +void hwWriteConfigBlock(void* buf, void* adr, size_t length) { hw_initConfigBlock(); uint8_t* src = static_cast(buf); @@ -76,14 +75,14 @@ void hw_writeConfigBlock(void* buf, void* adr, size_t length) EEPROM.commit(); } -uint8_t hw_readConfig(int adr) +uint8_t hwReadConfig(int adr) { uint8_t value; hw_readConfigBlock(&value, reinterpret_cast(adr), 1); return value; } -void hw_writeConfig(int adr, uint8_t value) +void hwWriteConfig(int adr, uint8_t value) { uint8_t curr = hw_readConfig(adr); if (curr != value) @@ -94,85 +93,40 @@ void hw_writeConfig(int adr, uint8_t value) -MyHwESP8266::MyHwESP8266() : MyHw() -{ -} - -/* - -// The following was redifined as macros to save space - -inline uint8_t MyHwATMega328::readConfig(uint8_t pos) { - return eeprom_read_byte((uint8_t*)pos); -} - -inline void MyHwATMega328::writeConfig(uint8_t pos, uint8_t value) { - eeprom_update_byte((uint8_t*)pos, value); -} - -inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) { - eeprom_read_block(buf, (void*)pos, length); -} - -inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) { - eeprom_write_block((void*)pos, (void*)buf, length); -} - - -inline void MyHwATMega328::init() { - Serial.begin(BAUD_RATE); -} - -inline void MyHwATMega328::watchdogReset() { - wdt_reset(); -} - -inline void MyHwATMega328::reboot() { - wdt_enable(WDTO_15MS); for (;;); -} - -inline unsigned long MyHwATMega328::millis() { - return ::millis(); -} -*/ - - -void MyHwESP8266::sleep(unsigned long ms) { +void hwSleep(unsigned long ms) { // TODO: Not supported! } -bool MyHwESP8266::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { +bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // TODO: Not supported! return false; } -inline uint8_t MyHwESP8266::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { +uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { // TODO: Not supported! return 0; } - - #ifdef MY_DEBUG -void MyHwESP8266::debugPrint(bool isGW, const char *fmt, ... ) { +void hwDebugPrint(bool isGW, const char *fmt, ... ) { char fmtBuffer[300]; - if (isGW) { + #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); Serial.print(fmtBuffer); - } + #endif va_list args; va_start (args, fmt ); va_end (args); - if (isGW) { + #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf_P(fmtBuffer, 60, fmt, args); fmtBuffer[59] = '\n'; fmtBuffer[60] = '\0'; - } else { + #else vsnprintf_P(fmtBuffer, 299, fmt, args); - } + #endif va_end (args); Serial.print(fmtBuffer); Serial.flush(); diff --git a/libraries/MySensors/core/MyHwESP8266.h b/libraries/MySensors/core/MyHwESP8266.h index 03f47c3..6f99201 100644 --- a/libraries/MySensors/core/MyHwESP8266.h +++ b/libraries/MySensors/core/MyHwESP8266.h @@ -22,7 +22,6 @@ #ifndef MyHwESP8266_h #define MyHwESP8266_h -#include "MyHw.h" #include "MyConfig.h" #include "MyMessage.h" @@ -34,16 +33,16 @@ // Define these as macros to save valuable space -#define hw_digitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hw_init() Serial.begin(BAUD_RATE) -#define hw_watchdogReset() wdt_reset() -#define hw_reboot() wdt_enable(WDTO_15MS); while (1) -#define hw_millis() millis() +#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) +#define hwInit() Serial.begin(BAUD_RATE) +#define hwWatchdogReset() wdt_reset() +#define hwReboot() wdt_enable(WDTO_15MS); while (1) +#define hwMillis() millis() -void hw_readConfigBlock(void* buf, void* adr, size_t length); -void hw_writeConfigBlock(void* buf, void* adr, size_t length); -void hw_writeConfig(int adr, uint8_t value); -uint8_t hw_readConfig(int adr); +void hwReadConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfig(int adr, uint8_t value); +uint8_t hwReadConfig(int adr); enum period_t { @@ -60,27 +59,13 @@ enum period_t SLEEP_FOREVER }; -class MyHwESP8266 : public MyHw -{ -public: - MyHwESP8266(); -/* void init(); - void watchdogReset(); - void reboot(); - unsigned long millis(); - uint8_t readConfig(uint8_t pos); - void writeConfig(uint8_t pos, uint8_t value); - void readConfigBlock(void* buf, void * pos, size_t length); - void writeConfigBlock(void* pos, void* buf, size_t length); */ - void sleep(unsigned long ms); - bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms); - uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +void hwSleep(unsigned long ms); +bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); +uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); #ifdef MY_DEBUG - void debugPrint(bool isGW, const char *fmt, ... ); -#endif -}; + void hwDebugPrint(const char *fmt, ... ); #endif #endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index 32b4e8e..05121cf 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -21,17 +21,58 @@ #include "MySensorCore.h" + +NodeConfig _nc; // Essential settings for node to work +ControllerConfig _cc; // Configuration coming from controller +#ifdef MY_OTA_FIRMWARE_FEATURE +NodeFirmwareConfig _fc; +bool _fwUpdateOngoing; +unsigned long _fwLastRequestTime; +uint16_t _fwBlock; +uint8_t _fwRetry; +#endif + +#ifdef MY_RADIO_FEATURE +bool _autoFindParent; +uint8_t _failedTransmissions; +#endif + +MyMessage _msg; // Buffer for incoming messages. +MyMessage _msgTmp ; // Buffer for temporary messages (acks and nonces among others). + +#ifdef MY_LEDS_BLINKING_FEATURE +// these variables don't need to be volatile, since we are not using interrupts +uint8_t _countRx; +uint8_t _countTx; +uint8_t _countErr; +unsigned long _blink_next_time; +#endif + +#ifdef MY_SIGNING_FEATURE +uint16_t _doSign[16]; // Bitfield indicating which sensors require signed communication +MyMessage _msgSign; // Buffer for message to sign. +#endif + +#ifdef MY_DEBUG + char convBuf[MAX_PAYLOAD*2+1]; +#endif + +uint16_t _heartbeat; +void (*_timeCallback)(unsigned long); // Callback for requested time messages +void (*_msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. + + #define DISTANCE_INVALID (0xFF) #ifdef MY_SIGNING_FEATURE // Macros for manipulating signing requirement table -#define DO_SIGN(node) (node == 0 ? (~doSign[0]&1) : (~doSign[node>>4]&(node%16))) -#define SET_SIGN(node) (node == 0 ? (doSign[0]&=~1) : (doSign[node>>4]&=~(node%16))) -#define CLEAR_SIGN(node) (node == 0 ? (doSign[0]|=1) : (doSign[node>>4]|=(node%16))) +#define DO_SIGN(node) (node == 0 ? (~_doSign[0]&1) : (~_doSign[node>>4]&(node%16))) +#define SET_SIGN(node) (node == 0 ? (_doSign[0]&=~1) : (_doSign[node>>4]&=~(node%16))) +#define CLEAR_SIGN(node) (node == 0 ? (_doSign[0]|=1) : (_doSign[node>>4]|=(node%16))) #endif // Inline function and macros -static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { +static inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { msg.sender = sender; msg.destination = destination; msg.sensor = sensor; @@ -42,858 +83,6 @@ static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destinat return msg; } -static inline bool isValidParent( const uint8_t parent ) { - return parent != AUTO; -} -static inline bool isValidDistance( const uint8_t distance ) { - return distance != DISTANCE_INVALID; -} - - -MySensor::MySensor(MyTransport &_radio, MyHw &_hw -#ifdef MY_SIGNING_FEATURE - , MySigning &_signer -#endif - ) - : - radio(_radio), -#ifdef MY_SIGNING_FEATURE - signer(_signer), -#endif -#ifdef MY_OTA_FIRMWARE_FEATURE - flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID), -#endif - hw(_hw) -{ -} - - -#ifdef MY_OTA_FIRMWARE_FEATURE - -// do a crc16 on the whole received firmware -bool MySensor::isValidFirmware() { - // init crc - uint16_t crc = ~0; - for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - crc ^= flash.readByte(i + FIRMWARE_START_OFFSET); - for (int8_t j = 0; j < 8; ++j) { - if (crc & 1) - crc = (crc >> 1) ^ 0xA001; - else - crc = (crc >> 1); - } - } - return crc == fc.crc; -} - -#endif - -#ifdef MY_LEDS_BLINKING_FEATURE -void MySensor::handleLedsBlinking() { - static unsigned long next_time = hw_millis() + MY_DEFAULT_LED_BLINK_PERIOD; - - // Just return if it is not the time... - // http://playground.arduino.cc/Code/TimingRollover - if ((long)(hw_millis() - blink_next_time) < 0) - return; - else - blink_next_time = hw_millis() + ledBlinkPeriod; - - // do the actual blinking - if(countRx && countRx != 255) { - // switch led on - hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON); - } - else if(!countRx) { - // switching off - hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); - } - if(countRx != 255) - --countRx; - - if(countTx && countTx != 255) { - // switch led on - hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON); - } - else if(!countTx) { - // switching off - hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); - } - if(countTx != 255) - --countTx; - - if(countErr && countErr != 255) { - // switch led on - hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON); - } - else if(!countErr) { - // switching off - hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); - } - if(countErr != 255) - --countErr; -} - -void MySensor::rxBlink(uint8_t cnt) { - if(countRx == 255) { countRx = cnt; } -} - -void MySensor::txBlink(uint8_t cnt) { - if(countTx == 255) { countTx = cnt; } -} - -void MySensor::errBlink(uint8_t cnt) { - if(countErr == 255) { countErr = cnt; } -} -#endif - -void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) { - #ifndef MY_DISABLED_SERIAL - hw_init(); - #endif - repeaterMode = _repeaterMode; - msgCallback = _msgCallback; - failedTransmissions = 0; - - // Only gateway should use node id 0! - isGateway = _nodeId == GATEWAY_ADDRESS; - - // Setup radio - if (!radio.init()) { - debug(PSTR("radio init fail\n")); - while(1); // Nothing more we can do - } - -#ifdef MY_SIGNING_FEATURE - // Read out the signing requirements from EEPROM - hw_readConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); -#endif - -#ifdef MY_LEDS_BLINKING_FEATURE - // Setup led pins - pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); - pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); - pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); - - // Set initial state of leds - hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); - hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); - hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); - - // initialize counters - countRx = 0; - countTx = 0; - countErr = 0; -#endif - - if (isGateway) { - // Set configuration for gateway - nc.parentNodeId = GATEWAY_ADDRESS; - nc.distance = 0; - nc.nodeId = GATEWAY_ADDRESS; - } else { - // Read settings from eeprom - hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); - // Read latest received controller configuration from EEPROM - hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); -#ifdef MY_OTA_FIRMWARE_FEATURE - // Read firmware config from EEPROM, i.e. type, version, CRC, blocks - hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); -#endif - - if (cc.isMetric == 0xff) { - // Eeprom empty, set default to metric - cc.isMetric = 0x01; - } - - autoFindParent = _parentNodeId == AUTO; - if (!autoFindParent) { - nc.parentNodeId = _parentNodeId; - // Save static parent id in eeprom (used by bootloader) - hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _parentNodeId); - // We don't actually know the distance to gw here. Let's pretend it is 1. - // If the current node is also repeater, be aware of this. - nc.distance = 1; - } else if (!isValidParent(nc.parentNodeId)) { - // Auto find parent, but parent in eeprom is invalid. Try find one. - findParentNode(); - } - - if (_nodeId != AUTO) { - // Set static id - nc.nodeId = _nodeId; - // Save static id in eeprom - hw_writeConfig(EEPROM_NODE_ID_ADDRESS, _nodeId); - } else if (nc.nodeId == AUTO && isValidParent(nc.parentNodeId)) { - // Try to fetch node-id from gateway - requestNodeId(); - } - } - - setupNode(); - debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), isGateway?"gateway":(repeaterMode?"repeater":"sensor"), nc.nodeId, nc.parentNodeId, nc.distance); -} - - -uint8_t MySensor::getNodeId() { - return nc.nodeId; -} - -ControllerConfig MySensor::getConfig() { - return cc; -} - -void MySensor::requestNodeId() { - debug(PSTR("req id\n")); - radio.setAddress(nc.nodeId); - build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); - sendWrite(nc.parentNodeId, msg); - wait(2000); -} - -void MySensor::setupNode() { - // Open reading pipe for messages directed to this node (set write pipe to same) - radio.setAddress(nc.nodeId); - - // Present node and request config - if (!isGateway && nc.nodeId != AUTO) { -#ifdef MY_SIGNING_FEATURE - // Notify gateway (and possibly controller) about the signing preferences of this node - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); - - // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages - if (signer.requestSignatures()) { - wait(2000); - } -#endif - - // Send presentation for this radio node (attach - present(NODE_SENSOR_ID, repeaterMode? S_ARDUINO_REPEATER_NODE : S_ARDUINO_NODE); - - // Send a configuration exchange request to controller - // Node sends parent node. Controller answers with latest node configuration - // which is picked up in process() - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(nc.parentNodeId)); - - // Wait configuration reply. - wait(2000); - -#ifdef MY_OTA_FIRMWARE_FEATURE - RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)msg.data; - mSetLength(msg, sizeof(RequestFirmwareConfig)); - mSetCommand(msg, C_STREAM); - mSetPayloadType(msg,P_CUSTOM); - // copy node settings to reqFWConfig - memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig)); - // add bootloader information - reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; - fwUpdateOngoing = false; - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); -#endif - - - } -} - -void MySensor::findParentNode() { - static boolean findingParentNode = false; - - if (findingParentNode) - return; - findingParentNode = true; - - failedTransmissions = 0; - - // Set distance to max - nc.distance = 255; - - // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) - debug(PSTR("find parent\n")); - - build(msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); - // Write msg, but suppress recursive parent search - sendWrite(BROADCAST_ADDRESS, msg); - - // Wait for ping response. - wait(2000); - findingParentNode = false; -} - -boolean MySensor::sendRoute(MyMessage &message) { - uint8_t sender = message.sender; - uint8_t dest = message.destination; - uint8_t last = message.last; - bool ok; - - // If we still don't have any parent id, re-request and skip this message. - if (nc.parentNodeId == AUTO) { - findParentNode(); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - - // If we still don't have any node id, re-request and skip this message. - if (nc.nodeId == AUTO) { - requestNodeId(); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - - mSetVersion(message, PROTOCOL_VERSION); - -#ifdef MY_SIGNING_FEATURE - // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message - if (DO_SIGN(message.destination) && message.sender == nc.nodeId && !mGetAck(message) && mGetLength(message) && - (mGetCommand(message) != C_INTERNAL || - (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && - message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && - message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { - bool signOk = false; - // Send nonce-request - if (!sendRoute(build(tmpMsg, nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { - debug(PSTR("nonce tr err\n")); - return false; - } - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hw_millis(); - msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (hw_millis() - enter < MY_VERIFICATION_TIMEOUT_MS) { - if (process()) { - if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - if (signer.putNonce(getLastMessage()) && signer.signMsg(msgSign)) { - message = msgSign; // Write the signed message back - signOk = true; - } - break; - } - } - } - if (hw_millis() - enter > MY_VERIFICATION_TIMEOUT_MS) { - debug(PSTR("nonce tmo\n")); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - if (!signOk) { - debug(PSTR("sign fail\n")); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, - // or signature will become invalid and the message rejected by the receiver - } else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned -#endif - - if (dest == GATEWAY_ADDRESS || !repeaterMode) { - // Store this address in routing table (if repeater) - if (repeaterMode) { - hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - // If destination is the gateway or if we aren't a repeater, let - // our parent take care of the message - ok = sendWrite(nc.parentNodeId, message); - } else { - // Relay the message - uint8_t route = hw_readConfig(EEPROM_ROUTES_ADDRESS+dest); - if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { - // This message should be forwarded to a child node. If we send message - // to this nodes pipe then all children will receive it because the are - // all listening to this nodes pipe. - // - // +----B - // -A - // +----C------D - // - // We're node C, Message comes from A and has destination D - // - // Message destination is not gateway and is in routing table for this node. - // Send it downstream - return sendWrite(route, message); - } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { - // Node has not yet received any id. We need to send it - // by doing a broadcast sending, - return sendWrite(BROADCAST_ADDRESS, message); - } else if (isGateway) { - // Destination isn't in our routing table and isn't a broadcast address - // Nothing to do here - return false; - } else { - // A message comes from a child node and we have no - // route for it. - // - // +----B - // -A - // +----C------D <-- Message comes from D - // - // We're node C - // - // Message should be passed to node A (this nodes relay) - - // This message should be routed back towards sensor net gateway - ok = sendWrite(nc.parentNodeId, message); - // Add this child to our "routing table" if it not already exist - hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - } - - if (!ok) { - // Failure when sending to parent node. The parent node might be down and we - // need to find another route to gateway. -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - failedTransmissions++; - if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { - findParentNode(); - } - } else { - failedTransmissions = 0; - } - return ok; -} - -boolean MySensor::sendWrite(uint8_t to, MyMessage &message) { - mSetVersion(message, PROTOCOL_VERSION); - uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); - message.last = nc.nodeId; -#ifdef MY_LEDS_BLINKING_FEATURE - txBlink(1); -#endif - bool ok = radio.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - - debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), - message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); - - return ok; -} - -bool MySensor::send(MyMessage &message, bool enableAck) { - message.sender = nc.nodeId; - mSetCommand(message,C_SET); - mSetRequestAck(message,enableAck); - return sendRoute(message); -} - -void MySensor::sendBatteryLevel(uint8_t value, bool enableAck) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); -} - -void MySensor::sendHeartbeat(void) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT, false).set(heartbeat++)); - -} - -void MySensor::present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); -} - -void MySensor::sendSketchInfo(const char *name, const char *version, bool enableAck) { - if (name != NULL) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); - } - if (version != NULL) { - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); - } -} - -void MySensor::request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { - sendRoute(build(msg, nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); -} - -void MySensor::requestTime(void (* _timeCallback)(unsigned long)) { - timeCallback = _timeCallback; - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); -} - -boolean MySensor::process() { - hw_watchdogReset(); - -#ifdef MY_LEDS_BLINKING_FEATURE - handleLedsBlinking(); -#endif - - uint8_t to = 0; - if (!radio.available(&to)) - { -#ifdef MY_OTA_FIRMWARE_FEATURE - unsigned long enter = hw_millis(); - if (fwUpdateOngoing && (enter - fwLastRequestTime > MY_OTA_RETRY_DELAY)) { - if (!fwRetry) { - debug(PSTR("fw upd fail\n")); - // Give up. We have requested MY_OTA_RETRY times without any packet in return. - fwUpdateOngoing = false; -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - fwRetry--; - fwLastRequestTime = enter; - // Time to (re-)request firmware block from controller - RequestFWBlock *firmwareRequest = (RequestFWBlock *)msg.data; - mSetLength(msg, sizeof(RequestFWBlock)); - firmwareRequest->type = fc.type; - firmwareRequest->version = fc.version; - firmwareRequest->block = (fwBlock - 1); - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); - } -#endif - return false; - } - -#ifdef MY_SIGNING_FEATURE - (void)signer.checkTimer(); // Manage signing timeout -#endif - - uint8_t len = radio.receive((uint8_t *)&msg); - (void)len; //until somebody makes use of 'len' -#ifdef MY_LEDS_BLINKING_FEATURE - rxBlink(1); -#endif - -#ifdef MY_SIGNING_FEATURE - // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) - // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) - if (signer.requestSignatures() && msg.destination == nc.nodeId && mGetLength(msg) && !mGetAck(msg) && - (mGetCommand(msg) != C_INTERNAL || - (msg.type != I_GET_NONCE_RESPONSE && msg.type != I_GET_NONCE && msg.type != I_REQUEST_SIGNING && - msg.type != I_ID_REQUEST && msg.type != I_ID_RESPONSE && - msg.type != I_FIND_PARENT && msg.type != I_FIND_PARENT_RESPONSE))) { - if (!mGetSigned(msg)) { - // Got unsigned message that should have been signed - debug(PSTR("no sign\n")); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - else if (!signer.verifyMsg(msg)) { - debug(PSTR("verify fail\n")); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; // This signed message has been tampered with! - } - } -#endif - - // Add string termination, good if we later would want to print it. - msg.data[mGetLength(msg)] = '\0'; - debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - msg.sender, msg.last, msg.destination, msg.sensor, mGetCommand(msg), msg.type, mGetPayloadType(msg), mGetLength(msg), mGetSigned(msg), msg.getString(convBuf)); - mSetSigned(msg,0); // Clear the sign-flag now as verification (and debug printing) is completed - - if(!(mGetVersion(msg) == PROTOCOL_VERSION)) { - debug(PSTR("ver mismatch\n")); -#ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); -#endif - return false; - } - - uint8_t command = mGetCommand(msg); - uint8_t type = msg.type; - uint8_t sender = msg.sender; - uint8_t last = msg.last; - uint8_t destination = msg.destination; - - if (destination == nc.nodeId) { - // This message is addressed to this node - - if (repeaterMode && last != nc.parentNodeId) { - // Message is from one of the child nodes. Add it to routing table. - hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - - // Check if sender requests an ack back. - if (mGetRequestAck(msg)) { - // Copy message - tmpMsg = msg; - mSetRequestAck(tmpMsg,false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(tmpMsg,true); - tmpMsg.sender = nc.nodeId; - tmpMsg.destination = msg.sender; - sendRoute(tmpMsg); - } - - if (command == C_INTERNAL) { - if (type == I_FIND_PARENT_RESPONSE) { - if (autoFindParent) { - // We've received a reply to a FIND_PARENT message. Check if the distance is - // shorter than we already have. - uint8_t distance = msg.getByte(); - if (isValidDistance(distance)) - { - // Distance to gateway is one more for us w.r.t. parent - distance++; - if (isValidDistance(distance) && (distance < nc.distance)) { - // Found a neighbor closer to GW than previously found - nc.distance = distance; - nc.parentNodeId = msg.sender; - hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); - hw_writeConfig(EEPROM_DISTANCE_ADDRESS, nc.distance); - debug(PSTR("parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); - } - } - } - return false; -#ifdef MY_SIGNING_FEATURE - } else if (type == I_GET_NONCE) { - if (signer.getNonce(msg)) { - sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); - } - return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_REQUEST_SIGNING) { - if (msg.getBool()) { - // We received an indicator that the sender require us to sign all messages we send to it - SET_SIGN(msg.sender); - } else { - // We received an indicator that the sender does not require us to sign all messages we send to it - CLEAR_SIGN(msg.sender); - } - // Save updated table - hw_writeConfigBlock((void*)doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(doSign)); - - // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing - // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages - if (isGateway) { - if (signer.requestSignatures() && DO_SIGN(msg.sender)) - sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); - else - sendRoute(build(msg, nc.nodeId, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); - } - return false; // Signing request is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_GET_NONCE_RESPONSE) { - return true; // Just pass along nonce silently (no need to call callback for these) -#endif - } else if (sender == GATEWAY_ADDRESS) { - if (type == I_ID_RESPONSE && nc.nodeId == AUTO) { - nc.nodeId = msg.getByte(); - if (nc.nodeId == AUTO) { - // sensor net gateway will return max id if all sensor id are taken - debug(PSTR("full\n")); - while (1); // Wait here. Nothing else we can do... - } - setupNode(); - // Write id to EEPROM - hw_writeConfig(EEPROM_NODE_ID_ADDRESS, nc.nodeId); - debug(PSTR("id=%d\n"), nc.nodeId); - } else { - processInternalMessages(msg); - } - return false; - } - } -#ifdef MY_OTA_FIRMWARE_FEATURE - else if (command == C_STREAM) { - if (type == ST_FIRMWARE_CONFIG_RESPONSE) { - NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)msg.data; - // compare with current node configuration, if they differ, start fw fetch process - if (memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { - debug(PSTR("fw update\n")); - // copy new FW config - memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); - // Init flash - if (!flash.initialize()) { - debug(PSTR("flash init fail\n")); - fwUpdateOngoing = false; - } else { - // erase lower 32K -> max flash size for ATMEGA328 - flash.blockErase32K(0); - // wait until flash erased - while ( flash.busy() ); - fwBlock = fc.blocks; - fwUpdateOngoing = true; - // reset flags - fwRetry = MY_OTA_RETRY+1; - fwLastRequestTime = 0; - } - return false; - } else debug(PSTR("fw update skipped\n")); - } else if (type == ST_FIRMWARE_RESPONSE) { - if (fwUpdateOngoing) { - // Save block to flash - debug(PSTR("fw block %d\n"), fwBlock); - // extract FW block - ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data; - // write to flash - flash.writeBytes( ((fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); - // wait until flash written - while ( flash.busy() ); - fwBlock--; - if (!fwBlock) { - // We're finished! Do a checksum and reboot. - fwUpdateOngoing = false; - if (isValidFirmware()) { - debug(PSTR("fw checksum ok\n")); - // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - uint16_t fwsize = FIRMWARE_BLOCK_SIZE * fc.blocks; - uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; - flash.writeBytes(0, OTAbuffer, 10); - // Write the new firmware config to eeprom - hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); - hw_reboot(); - } else { - debug(PSTR("fw checksum fail\n")); - } - } - // reset flags - fwRetry = MY_OTA_RETRY+1; - fwLastRequestTime = 0; - } else { - debug(PSTR("No fw update ongoing\n")); - } - return false; - } - - } -#endif - // Call incoming message callback if available - if (msgCallback != NULL) { - msgCallback(msg); - } - // Return true if message was addressed for this node... - return true; - } else if (repeaterMode && nc.nodeId != AUTO) { - // If this node have an id, relay the message - - if (command == C_INTERNAL && type == I_FIND_PARENT) { - if (sender != nc.parentNodeId) { - if (nc.distance == DISTANCE_INVALID) - findParentNode(); - - if (nc.distance != DISTANCE_INVALID) { - // Relaying nodes should always answer ping messages - // Wait a random delay of 0-2 seconds to minimize collision - // between ping ack messages from other relaying nodes - wait(hw_millis() & 0x3ff); - sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); - } - } - } else if (to == nc.nodeId) { - // We should try to relay this message to another node - sendRoute(msg); - } - } - return false; -} - - -void MySensor::processInternalMessages(MyMessage &msg) { - bool isMetric; - uint8_t type = msg.type; - - if (type == I_REBOOT) { - // Requires MySensors or other bootloader with watchdogs enabled - hw_reboot(); - } else if (type == I_CONFIG) { - // Pick up configuration from controller (currently only metric/imperial) - // and store it in eeprom if changed - isMetric = msg.getString()[0] == 'M' ; - cc.isMetric = isMetric; - hw_writeConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); - } else if (type == I_CHILDREN) { - if (repeaterMode && msg.getString()[0] == 'C') { - // Clears child relay data for this node - debug(PSTR("clear\n")); - uint8_t i = 255; - do { - hw_writeConfig(EEPROM_ROUTES_ADDRESS+i, 0xff); - } while (i--); - // Clear parent node id & distance to gw - hw_writeConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); - hw_writeConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); - // Find parent node - findParentNode(); - sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); - } - } else if (type == I_TIME) { - if (timeCallback != NULL) { - // Deliver time to callback - timeCallback(msg.getULong()); - } - } -} - - -MyMessage& MySensor::getLastMessage() { - return msg; -} - -void MySensor::saveState(uint8_t pos, uint8_t value) { - hw_writeConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); -} -uint8_t MySensor::loadState(uint8_t pos) { - return hw_readConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos); -} - -void MySensor::wait(unsigned long ms) { - unsigned long enter = hw_millis(); - while (hw_millis() - enter < ms) { - process(); - } -} - -void MySensor::sleep(unsigned long ms) { -#ifdef MY_OTA_FIRMWARE_FEATURE - if (fwUpdateOngoing) { - // Do not sleep node while fw update is ongoing - process(); - } else { -#endif - radio.powerDown(); - hw.sleep(ms); -#ifdef MY_OTA_FIRMWARE_FEATURE - } -#endif -} - -bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { -#ifdef MY_OTA_FIRMWARE_FEATURE - if (fwUpdateOngoing) { - // Do not sleep node while fw update is ongoing - process(); - return false; - } else { -#endif - radio.powerDown(); - return hw.sleep(interrupt, mode, ms) ; -#ifdef MY_OTA_FIRMWARE_FEATURE - } -#endif -} - -int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { -#ifdef MY_OTA_FIRMWARE_FEATURE - if (fwUpdateOngoing) { - // Do not sleep node while fw update is ongoing - process(); - return -1; - } else { -#endif - radio.powerDown(); - return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ; -#ifdef MY_OTA_FIRMWARE_FEATURE - } -#endif -} - - - - - -// Inline function and macros static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { msg.sender = GATEWAY_ADDRESS; msg.destination = GATEWAY_ADDRESS; @@ -905,120 +94,954 @@ static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { return msg; } -MyGateway::MyGateway(MyGatewayTransport &_transport, MyTransport &_radio, - MyHw &_hw -#ifdef MY_SIGNING_FEATURE - , MySigning &_signer -#endif - ) : - transport(_transport), MySensor(_radio, _hw -#ifdef MY_SIGNING_FEATURE - , _signer -#endif - ) -{ -#ifdef MY_INCLUSION_MODE_FEATURE - inclusionMode = false; -#endif +static inline bool isValidParent( const uint8_t parent ) { + return parent != AUTO; +} +static inline bool isValidDistance( const uint8_t distance ) { + return distance != DISTANCE_INVALID; +} + + + +#ifdef MY_OTA_FIRMWARE_FEATURE +// do a crc16 on the whole received firmware +bool isValidFirmware() { + // init crc + uint16_t crc = ~0; + for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { + crc ^= flash.readByte(i + FIRMWARE_START_OFFSET); + for (int8_t j = 0; j < 8; ++j) { + if (crc & 1) + crc = (crc >> 1) ^ 0xA001; + else + crc = (crc >> 1); + } + } + return crc == _fc.crc; } -void MyGateway::begin(void (*_msgCallback)(const MyMessage &)) { - // Setup digital in that triggers inclusion mode -#ifdef MY_INCLUSION_MODE_FEATURE -#ifdef MY_INCLUSION_BUTTON_FEATURE - pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); - digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); -#endif #endif - // initialize the transport driver - if (!transport.begin()) { - debug(PSTR("transport driver init fail\n")); - while(1); // Nothing more we can do +#ifdef MY_LEDS_BLINKING_FEATURE +void handleLedsBlinking() { + static unsigned long next_time = hwMillis() + MY_DEFAULT_LED_BLINK_PERIOD; + + // Just return if it is not the time... + // http://playground.arduino.cc/Code/TimingRollover + if ((long)(hwMillis() - _blink_next_time) < 0) + return; + else + _blink_next_time = hwMillis() + ledBlinkPeriod; + + // do the actual blinking + if(_countRx && _countRx != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON); + } + else if(!_countRx) { + // switching off + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); + } + if(_countRx != 255) + --_countRx; + + if(_countTx && _countTx != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON); + } + else if(!_countTx) { + // switching off + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); + } + if(_countTx != 255) + --_countTx; + + if(_countErr && _countErr != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON); + } + else if(!_countErr) { + // switching off + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); + } + if(_countErr != 255) + --_countErr; +} + +void rxBlink(uint8_t cnt) { + if(_countRx == 255) { _countRx = cnt; } +} + +void txBlink(uint8_t cnt) { + if(_countTx == 255) { _countTx = cnt; } +} + +void errBlink(uint8_t cnt) { + if(_countErr == 255) { _countErr = cnt; } +} +#endif + + +void dataCallback(void (*msgCallback)(const MyMessage &)) { + _msgCallback = msgCallback; +} + +void begin() { + + #if defined(MY_INCLUSION_MODE_FEATURE) + inclusionMode = false; + #endif + + #ifndef MY_DISABLED_SERIAL + hwInit(); + #endif + + #ifdef MY_GATEWAY_FEATURE + #if defined(MY_INCLUSION_MODE_FEATURE) && defined(MY_INCLUSION_BUTTON_FEATURE) + // Setup digital in that triggers inclusion mode + pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); + digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); + #endif + // initialize the transport driver + if (!gatewayTransportBegin()) { + debug(PSTR("transport driver init fail\n")); + while(1); // Nothing more we can do + } + #endif + + #if defined(MY_GATEWAY_FEATURE) + gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); + #endif + + #if defined(MY_RADIO_FEATURE) + _failedTransmissions = 0; + + // Setup radio + if (!transport.init()) { + debug(PSTR("radio init fail\n")); + while(1); // Nothing more we can do + } + #endif + + #ifdef MY_SIGNING_FEATURE + // Read out the signing requirements from EEPROM + hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); + #endif + +#ifdef MY_LEDS_BLINKING_FEATURE + // Setup led pins + pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); + pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); + pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); + + // Set initial state of leds + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); + + // initialize counters + _countRx = 0; + _countTx = 0; + _countErr = 0; +#endif + + // Read latest received controller configuration from EEPROM + hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + if (_cc.isMetric == 0xff) { + // Eeprom empty, set default to metric + _cc.isMetric = 0x01; } - // Start MySensors in repeater mode - MySensor::begin(_msgCallback, GATEWAY_ADDRESS, true, GATEWAY_ADDRESS); + #if defined(MY_GATEWAY_FEATURE) + // Set configuration for gateway + _nc.parentNodeId = GATEWAY_ADDRESS; + _nc.distance = 0; + _nc.nodeId = GATEWAY_ADDRESS; + #else + // Read settings from eeprom + hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + // Read latest received controller configuration from EEPROM + hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + #ifdef MY_OTA_FIRMWARE_FEATURE + // Read firmware config from EEPROM, i.e. type, version, CRC, blocks + hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + #endif - // Startup complete - transport.send(buildGw(msg, I_GATEWAY_READY).set("Gateway startup complete.")); + _autoFindParent = MY_PARENT_NODE_ID == AUTO; + if (!_autoFindParent) { + _nc.parentNodeId = MY_PARENT_NODE_ID; + // Save static parent id in eeprom (used by bootloader) + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); + // We don't actually know the distance to gw here. Let's pretend it is 1. + // If the current node is also repeater, be aware of this. + _nc.distance = 1; + } else if (!isValidParent(_nc.parentNodeId)) { + // Auto find parent, but parent in eeprom is invalid. Try find one. + findParentNode(); + } + if (MY_NODE_ID != AUTO) { + // Set static id + _nc.nodeId = MY_NODE_ID; + // Save static id in eeprom + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); + } else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) { + // Try to fetch node-id from gateway + requestNodeId(); + } + #endif + + #if defined(MY_RADIO_FEATURE) + setupNode(); + #endif + debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), MY_NODE_TYPE, _nc.nodeId, _nc.parentNodeId, _nc.distance); } -boolean MyGateway::sendRoute(MyMessage &message) { - if (message.destination == GATEWAY_ADDRESS) { - // This is a message sent from a sensor attached on the gateway node. - // Pass it directly to the gateway transport layer. - transport.send(message); - } else { - MySensor::sendRoute(message); - } + + + +uint8_t getNodeId() { + return _nc.nodeId; } -boolean MyGateway::process() { -#ifdef MY_INCLUSION_MODE_FEATURE - checkInclusionMode(); +ControllerConfig getConfig() { + return _cc; +} + +#if defined(MY_RADIO_FEATURE) +void requestNodeId() { + debug(PSTR("req id\n")); + transport.setAddress(_nc.nodeId); + build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); + sendWrite(_nc.parentNodeId, _msg); + wait(2000); +} #endif - bool newMessage = false; - if (transport.available()) { - MyMessage &gmsg = transport.receive(); - if (msg.destination == GATEWAY_ADDRESS) { - // Check if sender requests an ack back. - if (mGetRequestAck(gmsg)) { - // Copy message - tmpMsg = gmsg; - mSetRequestAck(tmpMsg, false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(tmpMsg, true); - tmpMsg.sender = nc.nodeId; - tmpMsg.destination = msg.sender; - transport.send(tmpMsg); + +#if defined(MY_RADIO_FEATURE) + + +void setupNode() { + // Open reading pipe for messages directed to this node (set write pipe to same) + transport.setAddress(_nc.nodeId); + // Present node and request config + #ifndef MY_GATEWAY_FEATURE + if (_nc.nodeId != AUTO) { + #ifdef MY_SIGNING_FEATURE + // Notify gateway (and possibly controller) about the signing preferences of this node + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); + + // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages + if (signer.requestSignatures()) { + wait(2000); + } + #endif + + // Send presentation for this radio node + #ifdef MY_REPEATER_FEATURE + present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + #else + present(NODE_SENSOR_ID, S_ARDUINO_NODE); + #endif + // Send a configuration exchange request to controller + // Node sends parent node. Controller answers with latest node configuration + // which is picked up in process() + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + + // Wait configuration reply. + wait(2000); + + #ifdef MY_OTA_FIRMWARE_FEATURE + RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msg.data; + mSetLength(_msg, sizeof(RequestFirmwareConfig)); + mSetCommand(_msg, C_STREAM); + mSetPayloadType(_msg,P_CUSTOM); + // copy node settings to reqFWConfig + memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig)); + // add bootloader information + reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; + _fwUpdateOngoing = false; + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + #endif + } + #endif +} +#endif + +#if defined(MY_RADIO_FEATURE) +void findParentNode() { + static boolean findingParentNode = false; + + if (findingParentNode) + return; + findingParentNode = true; + + _failedTransmissions = 0; + + // Set distance to max + _nc.distance = 255; + + // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) + debug(PSTR("find parent\n")); + + build(_msg, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); + // Write msg, but suppress recursive parent search + sendWrite(BROADCAST_ADDRESS, _msg); + + // Wait for ping response. + wait(2000); + findingParentNode = false; +} +#endif + + + +boolean sendRoute(MyMessage &message) { + + #if defined(MY_GATEWAY_FEATURE) + if (message.destination == _nc.nodeId) { + // This is a message sent from a sensor attached on the gateway node. + // Pass it directly to the gateway transport layer. + #ifdef MY_LEDS_BLINKING_FEATURE + txBlink(1); + #endif + return gatewayTransportSend(message); + } + #endif + + + #if defined(MY_RADIO_FEATURE) + uint8_t sender = message.sender; + uint8_t dest = message.destination; + uint8_t last = message.last; + bool ok; + + // If we still don't have any parent id, re-request and skip this message. + if (_nc.parentNodeId == AUTO) { + findParentNode(); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return false; + } + + // If we still don't have any node id, re-request and skip this message. + if (_nc.nodeId == AUTO) { + requestNodeId(); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return false; + } + + mSetVersion(message, PROTOCOL_VERSION); + + #ifdef MY_SIGNING_FEATURE + // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message + if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && mGetLength(message) && + (mGetCommand(message) != C_INTERNAL || + (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && + message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && + message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { + bool signOk = false; + // Send nonce-request + if (!sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + debug(PSTR("nonce tr err\n")); + return false; } - if (mGetCommand(gmsg) == C_INTERNAL) { - if (msg.type == I_VERSION) { - // Request for version. Create the response - transport.send(buildGw(msg, I_VERSION).set(LIBRARY_VERSION)); -#ifdef MY_INCLUSION_MODE_FEATURE - } else if (msg.type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(msg.data) == 1); + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust process() takes care of them + unsigned long enter = hwMillis(); + _msgSign = message; // Copy the message to sign since message buffer might be touched in process() + while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS) { + if (process()) { + if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + if (signer.putNonce(getLastMessage()) && signer.signMsg(_msgSign)) { + message = _msgSign; // Write the signed message back + signOk = true; + } + break; + } + } + } + if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { + debug(PSTR("nonce tmo\n")); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return false; + } + if (!signOk) { + debug(PSTR("sign fail\n")); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return false; + } + // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, + // or signature will become invalid and the message rejected by the receiver + } else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned + #endif + + if (dest == GATEWAY_ADDRESS || !MY_IS_REPEATER) { + // Store this address in routing table (if repeater) + #if defined (MY_IS_REPEATER) + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + #endif + // If destination is the gateway or if we aren't a repeater, let + // our parent take care of the message + ok = sendWrite(_nc.parentNodeId, message); + } else { + // Relay the message + uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); + if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { + // This message should be forwarded to a child node. If we send message + // to this nodes pipe then all children will receive it because the are + // all listening to this nodes pipe. + // + // +----B + // -A + // +----C------D + // + // We're node C, Message comes from A and has destination D + // + // Message destination is not gateway and is in routing table for this node. + // Send it downstream + return sendWrite(route, message); + } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { + // Node has not yet received any id. We need to send it + // by doing a broadcast sending, + return sendWrite(BROADCAST_ADDRESS, message); + } else if (MY_IS_GATEWAY) { + // Destination isn't in our routing table and isn't a broadcast address + // Nothing to do here + return false; + } else { + // A message comes from a child node and we have no + // route for it. + // + // +----B + // -A + // +----C------D <-- Message comes from D + // + // We're node C + // + // Message should be passed to node A (this nodes relay) + + // This message should be routed back towards sensor net gateway + ok = sendWrite(_nc.parentNodeId, message); + // Add this child to our "routing table" if it not already exist + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + } + } + + if (!ok) { + // Failure when sending to parent node. The parent node might be down and we + // need to find another route to gateway. + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + _failedTransmissions++; + if (_autoFindParent && _failedTransmissions > SEARCH_FAILURES) { + findParentNode(); + } + } else { + _failedTransmissions = 0; + } + return ok; + #else + return false; + #endif +} + +#ifdef MY_RADIO_FEATURE +boolean sendWrite(uint8_t to, MyMessage &message) { + mSetVersion(message, PROTOCOL_VERSION); + uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); + message.last = _nc.nodeId; + #ifdef MY_LEDS_BLINKING_FEATURE + txBlink(1); + #endif + bool ok = transport.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); + + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), + message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, + mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); + + return ok; +} #endif + +bool send(MyMessage &message, bool enableAck) { + message.sender = _nc.nodeId; + mSetCommand(message,C_SET); + mSetRequestAck(message,enableAck); + return sendRoute(message); +} + +void sendBatteryLevel(uint8_t value, bool enableAck) { + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); +} + +void sendHeartbeat(void) { + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT, false).set(_heartbeat++)); + +} + +void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); +} + +void sendSketchInfo(const char *name, const char *version, bool enableAck) { + if (name != NULL) { + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); + } + if (version != NULL) { + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); + } +} + +void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { + sendRoute(build(_msg, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); +} + +void requestTime(void (* timeCallback)(unsigned long)) { + _timeCallback = timeCallback; + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); +} + +void process() { + hwWatchdogReset(); + + #ifdef MY_LEDS_BLINKING_FEATURE + handleLedsBlinking(); + #endif + + #ifdef MY_INCLUSION_MODE_FEATURE + checkInclusionMode(); + #endif + + #if defined (MY_GATEWAY_FEATURE) + if (gatewayTransportAvailable()) { + MyMessage &_msg = gatewayTransportReceive(); + if (_msg.destination == GATEWAY_ADDRESS) { + // Check if sender requests an ack back. + if (mGetRequestAck(_msg)) { + // Copy message + _msgTmp = _msg; + mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(_msgTmp, true); + _msgTmp.sender = _nc.nodeId; + _msgTmp.destination = _msg.sender; + gatewayTransportSend(_msgTmp); + } + if (mGetCommand(_msg) == C_INTERNAL) { + if (_msg.type == I_VERSION) { + // Request for version. Create the response + gatewayTransportSend(buildGw(_msg, I_VERSION).set(LIBRARY_VERSION)); + #ifdef MY_INCLUSION_MODE_FEATURE + } else if (_msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + setInclusionMode(atoi(_msg.data) == 1); + #endif } else { - processInternalMessages(gmsg); + processInternalMessages(); } } else { // Call incoming message callback if available - if (msgCallback != NULL) { - msgCallback(msg); + if (_msgCallback != NULL) { + _msgCallback(_msg); } - newMessage = true; } } } + #endif - // new message from sensor node - if (MySensor::process()) { - MyMessage &msg = MySensor::getLastMessage(); - newMessage = true; - transport.send(msg); + #if defined(MY_RADIO_FEATURE) + uint8_t to = 0; + if (!transport.available(&to)) + { + #ifdef MY_OTA_FIRMWARE_FEATURE + unsigned long enter = hwMillis(); + if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { + if (!_fwRetry) { + debug(PSTR("fw upd fail\n")); + // Give up. We have requested MY_OTA_RETRY times without any packet in return. + _fwUpdateOngoing = false; + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return; + } + _fwRetry--; + _fwLastRequestTime = enter; + // Time to (re-)request firmware block from controller + RequestFWBlock *firmwareRequest = (RequestFWBlock *)_msg.data; + mSetLength(_msg, sizeof(RequestFWBlock)); + firmwareRequest->type = _fc.type; + firmwareRequest->version = _fc.version; + firmwareRequest->block = (_fwBlock - 1); + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); + } + #endif + return; } - return newMessage; + #ifdef MY_SIGNING_FEATURE + (void)signer.checkTimer(); // Manage signing timeout + #endif + + uint8_t len = transport.receive((uint8_t *)&_msg); + (void)len; //until somebody makes use of 'len' + #ifdef MY_LEDS_BLINKING_FEATURE + rxBlink(1); + #endif + + #ifdef MY_SIGNING_FEATURE + // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) + // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) + if (signer.requestSignatures() && _msg.destination == _nc.nodeId && mGetLength(_msg) && !mGetAck(_msg) && + (mGetCommand(_msg) != C_INTERNAL || + (_msg.type != I_GET_NONCE_RESPONSE && _msg.type != I_GET_NONCE && _msg.type != I_REQUEST_SIGNING && + _msg.type != I_ID_REQUEST && _msg.type != I_ID_RESPONSE && + _msg.type != I_FIND_PARENT && _msg.type != I_FIND_PARENT_RESPONSE))) { + if (!mGetSigned(_msg)) { + // Got unsigned message that should have been signed + debug(PSTR("no sign\n")); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return; + } + else if (!signer.verifyMsg(_msg)) { + debug(PSTR("verify fail\n")); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return; // This signed message has been tampered with! + } + } + #endif + + // Add string termination, good if we later would want to print it. + _msg.data[mGetLength(_msg)] = '\0'; + debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), + _msg.sender, _msg.last, _msg.destination, _msg.sensor, mGetCommand(_msg), _msg.type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(convBuf)); + mSetSigned(_msg,0); // Clear the sign-flag now as verification (and debug printing) is completed + + if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) { + debug(PSTR("ver mismatch\n")); + #ifdef MY_LEDS_BLINKING_FEATURE + errBlink(1); + #endif + return; + } + + uint8_t command = mGetCommand(_msg); + uint8_t type = _msg.type; + uint8_t sender = _msg.sender; + uint8_t last = _msg.last; + uint8_t destination = _msg.destination; + + if (destination == _nc.nodeId) { + // This message is addressed to this node + + if (MY_IS_REPEATER && last != _nc.parentNodeId) { + // Message is from one of the child nodes. Add it to routing table. + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + } + + // Check if sender requests an ack back. + if (mGetRequestAck(_msg)) { + // Copy message + _msgTmp = _msg; + mSetRequestAck(_msgTmp,false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(_msgTmp,true); + _msgTmp.sender = _nc.nodeId; + _msgTmp.destination = _msg.sender; + sendRoute(_msgTmp); + } + + if (command == C_INTERNAL) { + if (type == I_FIND_PARENT_RESPONSE) { + if (_autoFindParent) { + // We've received a reply to a FIND_PARENT message. Check if the distance is + // shorter than we already have. + uint8_t distance = _msg.getByte(); + if (isValidDistance(distance)) + { + // Distance to gateway is one more for us w.r.t. parent + distance++; + if (isValidDistance(distance) && (distance < _nc.distance)) { + // Found a neighbor closer to GW than previously found + _nc.distance = distance; + _nc.parentNodeId = _msg.sender; + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _nc.parentNodeId); + hwWriteConfig(EEPROM_DISTANCE_ADDRESS, _nc.distance); + debug(PSTR("parent=%d, d=%d\n"), _nc.parentNodeId, _nc.distance); + } + } + } + return; + #ifdef MY_SIGNING_FEATURE + } else if (type == I_GET_NONCE) { + if (signer.getNonce(_msg)) { + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); + } + return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this + } else if (type == I_REQUEST_SIGNING) { + if (_msg.getBool()) { + // We received an indicator that the sender require us to sign all messages we send to it + SET_SIGN(_msg.sender); + } else { + // We received an indicator that the sender does not require us to sign all messages we send to it + CLEAR_SIGN(_msg.sender); + } + // Save updated table + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); + + // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing + // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node + // to sign it's messages + if (MY_GATEWAY_FEATURE) { + if (signer.requestSignatures() && DO_SIGN(_msg.sender)) + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); + else + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + } + return; // Signing request is an internal MySensor protocol message, no need to inform caller about this + } else if (type == I_GET_NONCE_RESPONSE) { + return; // Just pass along nonce silently (no need to call callback for these) + #endif + } else if (sender == GATEWAY_ADDRESS) { + if (type == I_ID_RESPONSE && _nc.nodeId == AUTO) { + _nc.nodeId = _msg.getByte(); + if (_nc.nodeId == AUTO) { + // sensor net gateway will return max id if all sensor id are taken + debug(PSTR("full\n")); + while (1); // Wait here. Nothing else we can do... + } + setupNode(); + // Write id to EEPROM + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, _nc.nodeId); + debug(PSTR("id=%d\n"), _nc.nodeId); + } else { + processInternalMessages(); + } + return; + } + } + #ifdef MY_OTA_FIRMWARE_FEATURE + else if (command == C_STREAM) { + if (type == ST_FIRMWARE_CONFIG_RESPONSE) { + NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; + // compare with current node configuration, if they differ, start fw fetch process + if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + debug(PSTR("fw update\n")); + // copy new FW config + memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); + // Init flash + if (!flash.initialize()) { + debug(PSTR("flash init fail\n")); + _fwUpdateOngoing = false; + } else { + // erase lower 32K -> max flash size for ATMEGA328 + flash.blockErase32K(0); + // wait until flash erased + while ( flash.busy() ); + _fwBlock = _fc.blocks; + _fwUpdateOngoing = true; + // reset flags + _fwRetry = MY_OTA_RETRY+1; + _fwLastRequestTime = 0; + } + return ; + } else debug(PSTR("fw update skipped\n")); + } else if (type == ST_FIRMWARE_RESPONSE) { + if (_fwUpdateOngoing) { + // Save block to flash + debug(PSTR("fw block %d\n"), _fwBlock); + // extract FW block + ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; + // write to flash + flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + // wait until flash written + while ( flash.busy() ); + _fwBlock--; + if (!_fwBlock) { + // We're finished! Do a checksum and reboot. + _fwUpdateOngoing = false; + if (isValidFirmware()) { + debug(PSTR("fw checksum ok\n")); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; + uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; + flash.writeBytes(0, OTAbuffer, 10); + // Write the new firmware config to eeprom + hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hwReboot(); + } else { + debug(PSTR("fw checksum fail\n")); + } + } + // reset flags + _fwRetry = MY_OTA_RETRY+1; + _fwLastRequestTime = 0; + } else { + debug(PSTR("No fw update ongoing\n")); + } + return; + } + + } + #endif + // Call incoming message callback if available + if (_msgCallback != NULL) { + _msgCallback(_msg); + } + return; + } else if (MY_IS_REPEATER && _nc.nodeId != AUTO) { + // If this node have an id, relay the message + if (command == C_INTERNAL && type == I_FIND_PARENT) { + if (sender != _nc.parentNodeId) { + if (_nc.distance == DISTANCE_INVALID) + findParentNode(); + + if (_nc.distance != DISTANCE_INVALID) { + // Relaying nodes should always answer ping messages + // Wait a random delay of 0-2 seconds to minimize collision + // between ping ack messages from other relaying nodes + wait(hwMillis() & 0x3ff); + sendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + } + } + } else if (to == _nc.nodeId) { + // We should try to relay this message to another node + sendRoute(_msg); + } + } + #endif } + +void processInternalMessages() { + bool isMetric; + uint8_t type = _msg.type; + + if (type == I_REBOOT) { + // Requires MySensors or other bootloader with watchdogs enabled + hwReboot(); + } else if (type == I_CONFIG) { + // Pick up configuration from controller (currently only metric/imperial) + // and store it in eeprom if changed + isMetric = _msg.getString()[0] == 'M' ; + _cc.isMetric = isMetric; + hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); + } else if (type == I_CHILDREN) { + if (MY_IS_REPEATER && _msg.getString()[0] == 'C') { + // Clears child relay data for this node + debug(PSTR("clear\n")); + uint8_t i = 255; + do { + hwWriteConfig(EEPROM_ROUTES_ADDRESS+i, 0xff); + } while (i--); + // Clear parent node id & distance to gw + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); + hwWriteConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); + // Find parent node + findParentNode(); + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); + } + } else if (type == I_TIME) { + if (_timeCallback != NULL) { + // Deliver time to callback + _timeCallback(_msg.getULong()); + } + } +} + + +#if defined (MY_REPEATER_FEATURE) +void saveState(uint8_t pos, uint8_t value) { + hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); +} +uint8_t loadState(uint8_t pos) { + return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos); +} +#endif + +void wait(unsigned long ms) { + unsigned long enter = hwMillis(); + while (hwMillis() - enter < ms) { + process(); + } +} + +void sleep(unsigned long ms) { + #if defined(MY_OTA_FIRMWARE_FEATURE) + if (_fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + } else { + #endif + #if defined(MY_RADIO_FEATURE) + transport.powerDown(); + #endif + hwSleep(ms); + #if defined(MY_OTA_FIRMWARE_FEATURE) + } + #endif +} + +bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { + #if defined(MY_OTA_FIRMWARE_FEATURE) + if (_fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + return false; + } else { + #endif + #if defined(MY_RADIO_FEATURE) + transport.powerDown(); + #endif + return hwSleep(interrupt, mode, ms) ; + #if defined(MY_OTA_FIRMWARE_FEATURE) + } + #endif +} + +int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { + #if defined(MY_OTA_FIRMWARE_FEATURE) + if (_fwUpdateOngoing) { + // Do not sleep node while fw update is ongoing + process(); + return -1; + } else { + #endif + #if defined(MY_RADIO_FEATURE) + transport.powerDown(); + #endif + return hwSleep(interrupt1, mode1, interrupt2, mode2, ms) ; + #if defined(MY_OTA_FIRMWARE_FEATURE) + } + #endif +} + + #ifdef MY_INCLUSION_MODE_FEATURE -void MyGateway::setInclusionMode(boolean newMode) { +void setInclusionMode(boolean newMode) { if (newMode != inclusionMode) { inclusionMode = newMode; // Send back mode change to controller - transport.send(buildGw(msg, I_INCLUSION_MODE).set(inclusionMode?1:0)); + gatewayTransportSend(buildGw(_msg, I_INCLUSION_MODE).set(inclusionMode?1:0)); if (inclusionMode) { - inclusionStartTime = hw_millis(); + inclusionStartTime = hwMillis(); } } } -void MyGateway::checkInclusionMode() { - +void checkInclusionMode() { #ifdef MY_INCLUSION_BUTTON_FEATURE if (!inclusionMode && digitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == LOW) { // Start inclusion mode @@ -1026,7 +1049,7 @@ void MyGateway::checkInclusionMode() { } #endif - if (inclusionMode && hw_millis()-inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) { + if (inclusionMode && hwMillis()-inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) { // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode setInclusionMode(false); } diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index 5636b29..6deb634 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -23,9 +23,7 @@ #include "Version.h" // Auto generated by bot #include "MyConfig.h" -#include "MyHw.h" #include "MyTransport.h" -#include "MyTransportNRF24.h" #ifdef MY_SIGNING_FEATURE #include "MySigning.h" #include "MySigningNone.h" @@ -35,25 +33,14 @@ #include "drivers/SPIFlash/SPIFlash.h" #endif -#include "MyGatewayTransport.h" -#include "MyGatewayTransportSerial.h" - #include #include -// Set the hardware driver to use (initialized by MySensor-class) -#if defined(ARDUINO_ARCH_ESP8266) -#include "MyHwESP8266.h" -typedef MyHwESP8266 MyHwDriver; -#elif defined(ARDUINO_ARCH_AVR) -#include "MyHwATMega328.h" -typedef MyHwATMega328 MyHwDriver; -#endif #ifdef MY_DEBUG -#define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__) +#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) #else #define debug(x,...) #endif @@ -146,179 +133,165 @@ typedef struct { } __attribute__((packed)) ReplyFWBlock; -#ifdef __cplusplus -class MySensor -{ - public: - /** - * Constructor - * - * Creates a new instance of Sensor class. - * - */ - MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() -#ifdef MY_SIGNING_FEATURE - , MySigning &signer=*new MySigningNone() -#endif - ); - /** - * Begin operation of the MySensors library - * - * Call this in setup(), before calling any other sensor net library methods. - * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. - * @param nodeId The unique id (1-254) for this sensor. Default is AUTO(255) which means sensor tries to fetch an id from controller. - * @param repeaterMode Activate repeater mode. This node will forward messages to other nodes in the radio network. Make sure to call process() regularly. Default in false - * @param parentNodeId Use this to force node to always communicate with a certain parent node. Default is AUTO which means node automatically tries to find a parent. - */ - - void begin(void (* msgCallback)(const MyMessage &)=NULL, uint8_t nodeId=AUTO, boolean repeaterMode=false, uint8_t parentNodeId=AUTO); - - /** - * Return the nodes nodeId. - */ - uint8_t getNodeId(); - - /** - * Each node must present all attached sensors before any values can be handled correctly by the controller. - * It is usually good to present all attached sensors after power-up in setup(). - * - * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. - * @param sensorType The sensor type. See sensor typedef in MyMessage.h. - * @param description A textual description of the sensor. - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * @param description A textual description of the sensor. - */ - void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); - - /** - * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. - * @param name String containing a short Sketch name or NULL if not applicable - * @param version String containing a short Sketch version or NULL if not applicable - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * - */ - void sendSketchInfo(const char *name, const char *version, bool ack=false); - - /** - * Sends a message to gateway or one of the other nodes in the radio network - * - * @param msg Message to send - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * @return true Returns true if message reached the first stop on its way to destination. - */ - bool send(MyMessage &msg, bool ack=false); +/** +* Begin operation of the MySensors library +* +* Call this in setup(), before calling any other sensor net library methods. +* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. +*/ - /** - * Send this nodes battery level to gateway. - * @param level Level between 0-100(%) - * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. - * - */ - void sendBatteryLevel(uint8_t level, bool ack=false); +void dataCallback(void (* msgCallback)(const MyMessage &)=NULL); - /** - * Send a heartbeat message (I'm alive!) to the gateway/controller. - * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on. - */ - void sendHeartbeat(void); +/** + * Return the nodes nodeId. + */ +uint8_t getNodeId(); - /** - * Requests a value from gateway or some other sensor in the radio network. - * Make sure to add callback-method in begin-method to handle request responses. - * - * @param childSensorId The unique child id for the different sensors connected to this Arduino. 0-254. - * @param variableType The variableType to fetch - * @param destination The nodeId of other node in radio network. Default is gateway - */ - void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GATEWAY_ADDRESS); +/** +* Each node must present all attached sensors before any values can be handled correctly by the controller. +* It is usually good to present all attached sensors after power-up in setup(). +* +* @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254. +* @param sensorType The sensor type. See sensor typedef in MyMessage.h. +* @param description A textual description of the sensor. +* @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. +* @param description A textual description of the sensor. +*/ +void present(uint8_t sensorId, uint8_t sensorType, const char *description="", bool ack=false); - /** - * Requests time from controller. Answer will be delivered to callback. - * - * @param callback for time request. Incoming argument is seconds since 1970. - */ - void requestTime(void (* timeCallback)(unsigned long)); +/** + * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. + * @param name String containing a short Sketch name or NULL if not applicable + * @param version String containing a short Sketch version or NULL if not applicable + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * + */ +void sendSketchInfo(const char *name, const char *version, bool ack=false); + +/** +* Sends a message to gateway or one of the other nodes in the radio network +* +* @param msg Message to send +* @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. +* @return true Returns true if message reached the first stop on its way to destination. +*/ +bool send(MyMessage &msg, bool ack=false); - /** - * Processes incoming messages to this node. If this is a relaying node it will - * Returns true if there is a message addressed for this node just was received. - * Use callback to handle incoming messages. - */ - boolean process(); +/** + * Send this nodes battery level to gateway. + * @param level Level between 0-100(%) + * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack. + * + */ +void sendBatteryLevel(uint8_t level, bool ack=false); - /** - * Returns the most recent node configuration received from controller - */ - ControllerConfig getConfig(); +/** + * Send a heartbeat message (I'm alive!) to the gateway/controller. + * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on. + */ +void sendHeartbeat(void); - /** - * Save a state (in local EEPROM). Good for actuators to "remember" state between - * power cycles. - * - * You have 256 bytes to play with. Note that there is a limitation on the number - * of writes the EEPROM can handle (~100 000 cycles on ATMega328). - * - * @param pos The position to store value in (0-255) - * @param Value to store in position - */ - void saveState(uint8_t pos, uint8_t value); +/** +* Requests a value from gateway or some other sensor in the radio network. +* Make sure to add callback-method in begin-method to handle request responses. +* +* @param childSensorId The unique child id for the different sensors connected to this Arduino. 0-254. +* @param variableType The variableType to fetch +* @param destination The nodeId of other node in radio network. Default is gateway +*/ +void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GATEWAY_ADDRESS); - /** - * Load a state (from local EEPROM). - * - * @param pos The position to fetch value from (0-255) - * @return Value to store in position - */ - uint8_t loadState(uint8_t pos); - - /** - * Returns the last received message - */ - MyMessage& getLastMessage(void); +/** + * Requests time from controller. Answer will be delivered to callback. + * + * @param callback for time request. Incoming argument is seconds since 1970. + */ +void requestTime(void (* timeCallback)(unsigned long)); - /** - * Wait for a specified amount of time to pass. Keeps process()ing. - * This does not power-down the radio nor the Arduino. - * Because this calls process() in a loop, it is a good way to wait - * in your loop() on a repeater node or sensor that listens to messages. - * @param ms Number of milliseconds to sleep. - */ - void wait(unsigned long ms); +/** + * Returns the most recent node configuration received from controller + */ +ControllerConfig getConfig(); - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. - * @param ms Number of milliseconds to sleep. - */ - void sleep(unsigned long ms); +/** + * Save a state (in local EEPROM). Good for actuators to "remember" state between + * power cycles. + * + * You have 256 bytes to play with. Note that there is a limitation on the number + * of writes the EEPROM can handle (~100 000 cycles on ATMega328). + * + * @param pos The position to store value in (0-255) + * @param Value to store in position + */ +void saveState(uint8_t pos, uint8_t value); - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. - * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin - * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 - * @param interrupt Interrupt that should trigger the wakeup - * @param mode RISING, FALLING, CHANGE - * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return true if wake up was triggered by pin change and false means timer woke it up. - */ - bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); +/** + * Load a state (from local EEPROM). + * + * @param pos The position to fetch value from (0-255) + * @return Value to store in position + */ +uint8_t loadState(uint8_t pos); - /** - * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. - * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin - * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 - * @param interrupt1 First interrupt that should trigger the wakeup - * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) - * @param interrupt2 Second interrupt that should trigger the wakeup - * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) - * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number wake up was triggered by pin change and negative if timer woke it up. - */ - int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); +/** +* Returns the last received message +*/ +MyMessage& getLastMessage(void); + + + +/** + * Wait for a specified amount of time to pass. Keeps process()ing. + * This does not power-down the radio nor the Arduino. + * Because this calls process() in a loop, it is a good way to wait + * in your loop() on a repeater node or sensor that listens to messages. + * @param ms Number of milliseconds to sleep. + */ +void wait(unsigned long ms); + +/** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. + * @param ms Number of milliseconds to sleep. + */ +void sleep(unsigned long ms); + +/** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. + * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin + * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 + * @param interrupt Interrupt that should trigger the wakeup + * @param mode RISING, FALLING, CHANGE + * @param ms Number of milliseconds to sleep or 0 to sleep forever + * @return true if wake up was triggered by pin change and false means timer woke it up. + */ +bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); + +/** + * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. + * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin + * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 + * @param interrupt1 First interrupt that should trigger the wakeup + * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) + * @param interrupt2 Second interrupt that should trigger the wakeup + * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) + * @param ms Number of milliseconds to sleep or 0 to sleep forever + * @return Interrupt number wake up was triggered by pin change and negative if timer woke it up. + */ +int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); + + + +/****** PRIVATE ********/ +void begin(); + +void process(void); + +void processInternalMessages(); #ifdef MY_LEDS_BLINKING_FEATURE /** @@ -328,121 +301,31 @@ class MySensor void rxBlink(uint8_t cnt); void txBlink(uint8_t cnt); void errBlink(uint8_t cnt); -#endif - - boolean sendRoute(MyMessage &message); - - protected: - NodeConfig nc; // Essential settings for node to work - ControllerConfig cc; // Configuration coming from controller -#ifdef MY_OTA_FIRMWARE_FEATURE - NodeFirmwareConfig fc; - bool fwUpdateOngoing; - unsigned long fwLastRequestTime; - uint16_t fwBlock; - uint8_t fwRetry; - SPIFlash flash; -#endif - - bool repeaterMode; - bool autoFindParent; - bool isGateway; - - MyMessage msg; // Buffer for incoming messages. - MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others). - -#ifdef MY_LEDS_BLINKING_FEATURE - // these variables don't need to be volatile, since we are not using interrupts - uint8_t countRx; - uint8_t countTx; - uint8_t countErr; - void handleLedsBlinking(); // do the actual blinking - unsigned long blink_next_time; #endif - MyTransport& radio; -#ifdef MY_SIGNING_FEATURE - uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication - MyMessage msgSign; // Buffer for message to sign. - MySigning& signer; -#endif - MyHw& hw; - - boolean sendWrite(uint8_t dest, MyMessage &message); - void processInternalMessages(MyMessage &msg); -#ifdef MY_DEBUG - char convBuf[MAX_PAYLOAD*2+1]; -#endif - uint8_t failedTransmissions; - uint16_t heartbeat; - void (*timeCallback)(unsigned long); // Callback for requested time messages - void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. - #ifdef MY_OTA_FIRMWARE_FEATURE -// do a crc16 on the whole received firmware - bool isValidFirmware(); + // do a crc16 on the whole received firmware + bool isValidFirmware(); #endif - private: - - void requestNodeId(); - void setupNode(); - void findParentNode(); - uint8_t crc8Message(MyMessage &message); -}; -#endif - - -class MyGateway : public MySensor -{ -public: - // MyProtocolSerial constructor - MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver() -#ifdef MY_SIGNING_FEATURE - , MySigning &signer=*new MySigningNone() -#endif - ); - - - /** - * Begin operation of the MySensors library - * - * Call this in setup(), before calling any other sensor net library methods. - * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. - * @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled - * @param inclusionModeButtonPin Button pin used for enabling inclusion mode - */ - - void begin(void (* msgCallback)(const MyMessage &)=NULL); - - - /** - * See MySensor.h - * - * Overloaded to handle local sensor data sent to controller. - */ - boolean sendRoute(MyMessage &message); - - /** - * Processes incoming messages to this node. - * Returns true if there is a message addressed for this node was received. - * Preferred way of handling incoming messages is to use the callback defined in begin(). - */ - boolean process(); - -private: - - MyGatewayTransport& transport; #ifdef MY_INCLUSION_MODE_FEATURE - void setInclusionMode(bool newMode); void checkInclusionMode(); unsigned long inclusionStartTime; bool inclusionMode; #endif -}; + + +boolean sendRoute(MyMessage &message); +#if defined(MY_RADIO_FEATURE) + boolean sendWrite(uint8_t dest, MyMessage &message); + void requestNodeId(); + void setupNode(); + void findParentNode(); +#endif + #endif diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index d11545d..5affb12 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -20,11 +20,10 @@ #include "MyTransport.h" #include "MyTransportNRF24.h" -MyTransportNRF24::MyTransportNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) +MyTransportNRF24::MyTransportNRF24() : MyTransport(), - rf24(ce, cs), - _paLevel(paLevel) + rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN) { } @@ -38,9 +37,9 @@ bool MyTransportNRF24::init() { rf24.setAutoAck(1); rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast rf24.enableAckPayload(); - rf24.setChannel(RF24_CHANNEL); + rf24.setChannel(MY_RF24_CHANNEL); rf24.setPALevel(_paLevel); - rf24.setDataRate(RF24_DATARATE); + rf24.setDataRate(MY_RF24_DATARATE); rf24.setRetries(5,15); rf24.setCRCLength(RF24_CRC_16); rf24.enableDynamicPayloads(); diff --git a/libraries/MySensors/core/MyTransportNRF24.h b/libraries/MySensors/core/MyTransportNRF24.h index 535186d..d8a7b81 100644 --- a/libraries/MySensors/core/MyTransportNRF24.h +++ b/libraries/MySensors/core/MyTransportNRF24.h @@ -26,7 +26,7 @@ #include "drivers/RF24/RF24.h" #include "drivers/RF24/RF24_config.h" -#define TO_ADDR(x) (RF24_BASE_RADIO_ID + x) +#define TO_ADDR(x) (MY_RF24_BASE_RADIO_ID + x) #define WRITE_PIPE ((uint8_t)0) #define CURRENT_NODE_PIPE ((uint8_t)1) @@ -35,7 +35,7 @@ class MyTransportNRF24 : public MyTransport { public: - MyTransportNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); + MyTransportNRF24(); bool init(); void setAddress(uint8_t address); uint8_t getAddress(); diff --git a/libraries/MySensors/core/MyTransportRFM69.cpp b/libraries/MySensors/core/MyTransportRFM69.cpp index ca29585..30e923e 100644 --- a/libraries/MySensors/core/MyTransportRFM69.cpp +++ b/libraries/MySensors/core/MyTransportRFM69.cpp @@ -20,18 +20,16 @@ #include "MyTransport.h" #include "MyTransportRFM69.h" -MyTransportRFM69::MyTransportRFM69(uint8_t freqBand, uint8_t networkId, uint8_t slaveSelectPin, uint8_t interruptPin, bool isRFM69HW, uint8_t interruptNum) +MyTransportRFM69::MyTransportRFM69() : MyTransport(), - radio(slaveSelectPin, interruptPin, isRFM69HW, interruptNum), - _freqBand(freqBand), - _networkId(networkId) + radio(MY_RF69_SPI_CS, MY_RF69_IRQ_PIN, MY_IS_RFM69HW, MY_RF69_IRQ_NUM) { } bool MyTransportRFM69::init() { // Start up the radio library (_address will be set later by the MySensors library) - radio.initialize(_freqBand, _address, _networkId); + radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID); #ifdef MY_RFM69_ENABLE_ENCRYPTION radio.encrypt(RFM69_ENCRYPTKEY); #endif diff --git a/libraries/MySensors/core/MyTransportRFM69.h b/libraries/MySensors/core/MyTransportRFM69.h index affbb25..1336d1e 100644 --- a/libraries/MySensors/core/MyTransportRFM69.h +++ b/libraries/MySensors/core/MyTransportRFM69.h @@ -30,7 +30,7 @@ class MyTransportRFM69 : public MyTransport { public: - MyTransportRFM69(uint8_t freqBand=MY_RFM69_FREQUENCY, uint8_t networkId=MY_RFM69_NETWORKID, uint8_t slaveSelectPin=MY_RF69_SPI_CS, uint8_t interruptPin=MY_RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=MY_RF69_IRQ_NUM); + MyTransportRFM69(); bool init(); void setAddress(uint8_t address); uint8_t getAddress(); @@ -41,8 +41,6 @@ public: private: RFM69 radio; uint8_t _address; - uint8_t _freqBand; - uint8_t _networkId; }; #endif diff --git a/libraries/MySensors/drivers/DigitalIO/DigitalIO.h b/libraries/MySensors/drivers/DigitalIO/DigitalIO.h index 8f47bf1..f984ef8 100644 --- a/libraries/MySensors/drivers/DigitalIO/DigitalIO.h +++ b/libraries/MySensors/drivers/DigitalIO/DigitalIO.h @@ -28,9 +28,9 @@ /** DigitalPin version YYYYMMDD */ #define DIGITAL_IO_VERSION 20140217 //------------------------------------------------------------------------------ -#include -#include -#include -#include -#include -#endif // DigitalIO_h \ No newline at end of file +#include "DigitalPin.h" +#include "I2cConstants.h" +#include "PinIO.h" +#include "SoftI2cMaster.h" +#include "SoftSPI.h" +#endif // DigitalIO_h diff --git a/libraries/MySensors/drivers/DigitalIO/PinIO.cpp b/libraries/MySensors/drivers/DigitalIO/PinIO.cpp index b0367b7..5f1ff52 100644 --- a/libraries/MySensors/drivers/DigitalIO/PinIO.cpp +++ b/libraries/MySensors/drivers/DigitalIO/PinIO.cpp @@ -25,7 +25,7 @@ * @details Two Wire Interface library. * @{ */ -#include +#include "PinIO.h" #include #include //============================================================================== @@ -65,4 +65,4 @@ void PinIO::config(bool mode, bool data) { writeI(data); } } -/** @} */ \ No newline at end of file +/** @} */ diff --git a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp index a698636..d02b2bb 100644 --- a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp +++ b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp @@ -25,7 +25,7 @@ * @details Software Two Wire Interface library. * @{ */ -#include +#include "SoftI2cMaster.h" //------------------------------------------------------------------------------ /** * Start an I2C transfer with possible continuation. diff --git a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h index 7bf3c00..33e11fc 100644 --- a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h +++ b/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h @@ -33,8 +33,8 @@ #include #endif // ARDUINO #include -#include -#include +#include "DigitalPin.h" +#include "I2cConstants.h" //------------------------------------------------------------------------------ // State codes. diff --git a/libraries/MySensors/drivers/DigitalIO/SoftSPI.h b/libraries/MySensors/drivers/DigitalIO/SoftSPI.h index 036fad6..f51f210 100644 --- a/libraries/MySensors/drivers/DigitalIO/SoftSPI.h +++ b/libraries/MySensors/drivers/DigitalIO/SoftSPI.h @@ -28,7 +28,7 @@ #ifndef SoftSPI_h #define SoftSPI_h -#include +#include "DigitalPin.h" //------------------------------------------------------------------------------ /** Nop for timing. */ #define nop asm volatile ("nop\n\t") diff --git a/libraries/MySensors/drivers/RF24/RF24.cpp b/libraries/MySensors/drivers/RF24/RF24.cpp index 16bff15..d78c875 100644 --- a/libraries/MySensors/drivers/RF24/RF24.cpp +++ b/libraries/MySensors/drivers/RF24/RF24.cpp @@ -19,7 +19,7 @@ void RF24::csn(bool mode) // divider of 4 is the minimum we want. // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz #ifdef ARDUINO - #if ( !defined(RF24_TINY) && !defined (__arm__) && !defined (SOFTSPI)) || defined (CORE_TEENSY) + #if ( !defined(RF24_TINY) && !defined (__arm__) && !defined (MY_SOFTSPI)) || defined (CORE_TEENSY) _SPI.setBitOrder(MSBFIRST); _SPI.setDataMode(SPI_MODE0); _SPI.setClockDivider(SPI_CLOCK_DIV2); diff --git a/libraries/MySensors/drivers/RF24/RF24_config.h b/libraries/MySensors/drivers/RF24/RF24_config.h index d8c8016..08a23cc 100644 --- a/libraries/MySensors/drivers/RF24/RF24_config.h +++ b/libraries/MySensors/drivers/RF24/RF24_config.h @@ -26,7 +26,7 @@ //#define SERIAL_DEBUG #define MINIMAL //#define SPI_UART // Requires library from https://github.com/TMRh20/Sketches/tree/master/SPI_UART - //#define SOFTSPI // Requires library from https://github.com/greiman/DigitalIO + //#define MY_SOFTSPI // Requires library from https://github.com/greiman/DigitalIO /**********************/ // Define _BV for non-Arduino platforms and for Arduino DUE diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index c5e10a4..34ee906 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -56,15 +56,61 @@ * */ +// Enable debug prints to console +#define MY_DEBUG +// This node has a NR24L01+ radio attached +#define MY_RADIO_NRF24 + + +// W5100 Ethernet in client mode (node opens conmection to controller) +#define MY_GATEWAY_W5100_CLIENT +// W5100 Ethernet in client mode (controller opens conmection to node) +//#define MY_GATEWAY_W5100_SERVER + +// Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) +#define MY_GATEWAY_PROTOCOL_DEFAULT + +// Enable Soft SPI for radio (note different radio wiring required) +// Useful for W5100 which sometimes have hard time co-operate with radio on the same spi bus. +//#define MY_SOFTSPI +//#define MY_SOFT_SPI_SCK_PIN 14 +//#define MY_SOFT_SPI_MISO_PIN 16 +//#define MY_SOFT_SPI_MOSI_PIN 15 + + +// Enable to use UDP +#define MY_USE_UDP + +#define MY_IP_ADDRESS 192,168,178,66 // If this is disabled, DHCP is used to retrieve address +// Renewal period if using DHCP +//#define MY_IP_RENEWAL_INTERVAL 60000 +// The port to keep open on node server mode / or port to contact in client mode +#define MY_PORT 5003 + +// Controller ip address (client mode) +#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 +// The port you want to contact on controller (client mode) +#define MY_CONTROLLER_PORT 5003 + +// The MAC address can be anything you want but should be unique on your network. +// Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. +// Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address. +#define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED + +// Flash leds on rx/tx/err #define MY_WITH_LEDS_BLINKING -#define MY_INCLUSION_MODE_FEATURE -#define MY_INCLUSION_BUTTON_FEATURE - +// Set blinking period #define MY_DEFAULT_LED_BLINK_PERIOD 300 -#define MY_INCLUSION_MODE_DURATION 60 // Number of minutes inclusion mode is enabled -#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Digital pin used for inclusion mode button +// Enable inclusion mode +#define MY_INCLUSION_MODE_FEATURE +// Enable Inclusion mode button on gateway +#define MY_INCLUSION_BUTTON_FEATURE +// Set inclusion mode duration (in seconds) +#define MY_INCLUSION_MODE_DURATION 60 +// Digital pin used for inclusion mode button +#define MY_INCLUSION_MODE_BUTTON_PIN 3 #define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin #define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin @@ -76,53 +122,11 @@ #include -#define MY_IP_PORT 5003 // The port you want to open -#ifndef MY_IP_ADDRESS_DHCP -// Gateway IP address if not using DHCP -IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later! -#endif /* IP_ADDRESS_DHCP */ - -// NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRFM69 transport; - -// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -//MySigningNone signer; -//MySigningAtsha204Soft signer; -//MySigningAtsha204 signer; - -// Hardware profile -MyHwATMega328 hw; - -// Use default controller protocol -MyProtocolDefault protocol; - -// The MAC address can be anything you want but should be unique on your network. -// Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. -// Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address. -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // DEAD BEEF FEED - -// Controller IP -IPAddress controllerIP = IPAddress(192, 168, 178, 254); - -// Gateway transport driver -#ifdef IP_ADDRESS_DHCP -MyGatewayTransportEthernet ctrlTransport(protocol, mac, /* gw port */ CONTROLLER_PORT, IP_RENEWAL_INTERVAL, controllerIP, CONTROLLER_PORT); -#else -MyGatewayTransportEthernet ctrlTransport(protocol, mac, myIp, /* gw port */ CONTROLLER_PORT, controllerIP, CONTROLLER_PORT); -#endif - - -// Construct MyGateway library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h -MyGateway gw(ctrlTransport, transport, hw /*, signer*/); - void setup() { - gw.begin(NULL); + dataCallback(); } void loop() { - gw.process(); } diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index a0d734b..099226f 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -28,8 +28,14 @@ */ //#define MY_DEBUG +//#define MY_SOFTSPI +//#define MY_OTA_FIRMWARE_FEATURE + +#define MY_RADIO_NRF24 // MY_RADIO_RFM69 + +#include + -#include "MySensor.h" unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) @@ -43,14 +49,14 @@ MyMessage msg(CHILD_ID, V_TRIPPED); void setup() { - gw.begin(); + dataDallback(); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Motion Sensor", "1.0"); + sendSketchInfo("Motion Sensor", "1.0"); pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input // Register all sensors to gw (they will be created as child devices) - gw.present(CHILD_ID, S_MOTION); + present(CHILD_ID, S_MOTION); } @@ -60,10 +66,10 @@ void loop() boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; Serial.println(tripped); - gw.send(msg.set(tripped?"1":"0")); // Send tripped value to gw + send(msg.set(tripped?"1":"0")); // Send tripped value to gw // Sleep until interrupt comes in on motion sensor. Send update every two minute. - gw.sleep(INTERRUPT,CHANGE, SLEEP_TIME); + sleep(INTERRUPT,CHANGE, SLEEP_TIME); } From 050782e1e6aa1a09b4e2346237f210154b8f17f9 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 13 Sep 2015 18:11:49 +0200 Subject: [PATCH 250/660] ESP libraries --- libraries/MySensors/MySensor.h | 36 +- .../{MyTransport.cpp => MyGatewayTransport.h} | 28 +- .../core/MyGatewayTransportEthernet.cpp | 4 +- .../core/MyGatewayTransportEthernet.h | 19 +- .../core/MyGatewayTransportSerial.cpp | 33 +- .../MySensors/core/MyGatewayTransportSerial.h | 24 +- libraries/MySensors/core/MyHw.h | 53 + libraries/MySensors/core/MyHwATMega328.h | 11 +- libraries/MySensors/core/MyHwESP8266.cpp | 18 +- libraries/MySensors/core/MyHwESP8266.h | 31 +- libraries/MySensors/core/MyProtocol.h | 18 +- .../MySensors/core/MyProtocolDefault.cpp | 16 +- libraries/MySensors/core/MyProtocolDefault.h | 14 +- libraries/MySensors/core/MySensorCore.cpp | 32 +- libraries/MySensors/core/MySensorCore.h | 1 - libraries/MySensors/core/MyTransport.h | 32 - libraries/MySensors/core/MyTransportNRF24.cpp | 74 +- libraries/MySensors/core/MyTransportNRF24.h | 23 +- libraries/MySensors/core/MyTransportRFM69.cpp | 47 +- libraries/MySensors/core/MyTransportRFM69.h | 22 +- .../drivers/{ => AVR}/DigitalIO/DigitalIO.h | 0 .../drivers/{ => AVR}/DigitalIO/DigitalPin.h | 0 .../{ => AVR}/DigitalIO/I2cConstants.h | 0 .../drivers/{ => AVR}/DigitalIO/PinIO.cpp | 0 .../drivers/{ => AVR}/DigitalIO/PinIO.h | 0 .../{ => AVR}/DigitalIO/SoftI2cMaster.cpp | 0 .../{ => AVR}/DigitalIO/SoftI2cMaster.h | 0 .../drivers/{ => AVR}/DigitalIO/SoftSPI.h | 0 .../{ => AVR}/DigitalIO/attic/ADS7818.h | 0 .../{ => AVR}/DigitalIO/attic/MCP320X.h | 0 .../{ => AVR}/DigitalIO/attic/MCP355X.h | 0 .../DigitalPinBlink/DigitalPinBlink.ino | 0 .../DigitalPinConfigToggle.ino | 0 .../DigitalPinReadWrite.ino | 0 .../DigitalPinShiftOut/DigitalPinShiftOut.ino | 0 .../examples/PinIOBegin/PinIOBegin.ino | 0 .../PinIOConfigToggle/PinIOConfigToggle.ino | 0 .../PinIOReadWrite/PinIOReadWrite.ino | 0 .../examples/ScanI2cBus/ScanI2cBus.ino | 0 .../SoftDS1307Utility/SoftDS1307Utility.ino | 0 .../examples/testArduino/testArduino.ino | 0 .../testDigitalPin/testDigitalPin.ino | 0 .../testFastDigital/testFastDigital.ino | 0 .../examples/testPinIO/testPinIO.ino | 0 .../examples/testSoftSPI/testSoftSPI.ino | 0 .../drivers/{ => AVR}/Ethernet_UIP/Dhcp.cpp | 0 .../drivers/{ => AVR}/Ethernet_UIP/Dhcp.h | 0 .../drivers/{ => AVR}/Ethernet_UIP/Dns.cpp | 0 .../drivers/{ => AVR}/Ethernet_UIP/Dns.h | 0 .../drivers/{ => AVR}/Ethernet_UIP/README | 0 .../{ => AVR}/Ethernet_UIP/UIPClient.cpp | 0 .../{ => AVR}/Ethernet_UIP/UIPClient.h | 0 .../{ => AVR}/Ethernet_UIP/UIPEthernet.cpp | 0 .../{ => AVR}/Ethernet_UIP/UIPEthernet.h | 0 .../{ => AVR}/Ethernet_UIP/UIPServer.cpp | 0 .../{ => AVR}/Ethernet_UIP/UIPServer.h | 0 .../drivers/{ => AVR}/Ethernet_UIP/UIPUdp.cpp | 0 .../drivers/{ => AVR}/Ethernet_UIP/UIPUdp.h | 0 .../{ => AVR}/Ethernet_UIP/ethernet_comp.h | 0 .../AdvancedChatServer/AdvancedChatServer.ino | 0 .../examples/EchoServer/EchoServer.ino | 0 .../examples/TcpClient/TcpClient.ino | 0 .../examples/TcpServer/TcpServer.ino | 0 .../examples/UdpClient/UdpClient.ino | 0 .../examples/UdpServer/UdpServer.ino | 0 .../{ => AVR}/Ethernet_UIP/keywords.txt | 0 .../{ => AVR}/Ethernet_UIP/library.properties | 0 .../Ethernet_UIP/tests/perl/tcpclient.pl | 0 .../Ethernet_UIP/tests/perl/tcpserver.pl | 0 .../Ethernet_UIP/tests/perl/udpclient.pl | 0 .../Ethernet_UIP/tests/perl/udpserver.pl | 0 .../Ethernet_UIP/utility/Enc28J60Network.cpp | 0 .../Ethernet_UIP/utility/Enc28J60Network.h | 0 .../Ethernet_UIP/utility/clock-arch.c | 0 .../Ethernet_UIP/utility/clock-arch.h | 0 .../{ => AVR}/Ethernet_UIP/utility/enc28j60.h | 0 .../Ethernet_UIP/utility/mempool.cpp | 0 .../{ => AVR}/Ethernet_UIP/utility/mempool.h | 0 .../Ethernet_UIP/utility/mempool_conf.h | 0 .../{ => AVR}/Ethernet_UIP/utility/uip-conf.h | 0 .../{ => AVR}/Ethernet_UIP/utility/uip.c | 0 .../{ => AVR}/Ethernet_UIP/utility/uip.h | 0 .../{ => AVR}/Ethernet_UIP/utility/uip_arch.h | 0 .../{ => AVR}/Ethernet_UIP/utility/uip_arp.c | 0 .../{ => AVR}/Ethernet_UIP/utility/uip_arp.h | 0 .../Ethernet_UIP/utility/uip_clock.h | 0 .../Ethernet_UIP/utility/uip_debug.cpp | 0 .../Ethernet_UIP/utility/uip_debug.h | 0 .../Ethernet_UIP/utility/uip_timer.c | 0 .../Ethernet_UIP/utility/uip_timer.h | 0 .../Ethernet_UIP/utility/uipethernet-conf.h | 0 .../{ => AVR}/Ethernet_UIP/utility/uipopt.h | 0 .../{ => AVR}/Ethernet_UIP/utility/util.h | 0 .../drivers/{ => AVR}/Ethernet_W5100/Client.h | 0 .../drivers/{ => AVR}/Ethernet_W5100/Dhcp.cpp | 0 .../drivers/{ => AVR}/Ethernet_W5100/Dhcp.h | 0 .../drivers/{ => AVR}/Ethernet_W5100/Dns.cpp | 0 .../drivers/{ => AVR}/Ethernet_W5100/Dns.h | 0 .../{ => AVR}/Ethernet_W5100/Ethernet.cpp | 0 .../{ => AVR}/Ethernet_W5100/Ethernet.h | 0 .../Ethernet_W5100/EthernetClient.cpp | 0 .../{ => AVR}/Ethernet_W5100/EthernetClient.h | 0 .../Ethernet_W5100/EthernetServer.cpp | 0 .../{ => AVR}/Ethernet_W5100/EthernetServer.h | 0 .../{ => AVR}/Ethernet_W5100/EthernetUdp.cpp | 0 .../{ => AVR}/Ethernet_W5100/EthernetUdp.h | 0 .../{ => AVR}/Ethernet_W5100/IPAddress.cpp | 0 .../{ => AVR}/Ethernet_W5100/IPAddress.h | 0 .../drivers/{ => AVR}/Ethernet_W5100/Server.h | 0 .../Ethernet_W5100/utility/socket.cpp | 0 .../{ => AVR}/Ethernet_W5100/utility/socket.h | 0 .../{ => AVR}/Ethernet_W5100/utility/util.h | 0 .../Ethernet_W5100/utility/w5100.cpp | 0 .../{ => AVR}/Ethernet_W5100/utility/w5100.h | 2 +- .../MySensors/drivers/{ => AVR}/SPI/SPI.cpp | 0 .../MySensors/drivers/{ => AVR}/SPI/SPI.h | 0 .../BarometricPressureSensor.ino | 0 .../DigitalPotControl/DigitalPotControl.ino | 0 .../drivers/{ => AVR}/SPI/keywords.txt | 0 .../drivers/{ => AVR}/SPI/library.properties | 0 .../drivers/ESP8266/EEPROM/EEPROM.cpp | 118 + .../MySensors/drivers/ESP8266/EEPROM/EEPROM.h | 70 + .../examples/eeprom_clear/eeprom_clear.ino | 26 + .../examples/eeprom_read/eeprom_read.ino | 44 + .../examples/eeprom_write/eeprom_write.ino | 43 + .../drivers/ESP8266/EEPROM/keywords.txt | 18 + .../drivers/ESP8266/EEPROM/library.properties | 8 + .../examples/NTPClient/NTPClient.ino | 153 ++ .../WiFiAccessPoint/WiFiAccessPoint.ino | 68 + .../examples/WiFiClient/WiFiClient.ino | 85 + .../examples/WiFiMulti/WiFiMulti.ino | 33 + .../examples/WiFiScan/WiFiScan.ino | 48 + .../WiFiTelnetToSerial/WiFiTelnetToSerial.ino | 90 + .../examples/WiFiWebServer/WiFiWebServer.ino | 98 + .../drivers/ESP8266/ESP8266WiFi/keywords.txt | 67 + .../ESP8266/ESP8266WiFi/library.properties | 9 + .../ESP8266/ESP8266WiFi/src/ESP8266WiFi.cpp | 700 ++++++ .../ESP8266/ESP8266WiFi/src/ESP8266WiFi.h | 353 +++ .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 207 ++ .../ESP8266WiFi/src/ESP8266WiFiMulti.h | 62 + .../ESP8266/ESP8266WiFi/src/WiFiClient.cpp | 290 +++ .../ESP8266/ESP8266WiFi/src/WiFiClient.h | 127 + .../ESP8266/ESP8266WiFi/src/WiFiServer.cpp | 170 ++ .../ESP8266/ESP8266WiFi/src/WiFiServer.h | 65 + .../ESP8266/ESP8266WiFi/src/WiFiUdp.cpp | 279 +++ .../drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.h | 112 + .../drivers/ESP8266/ESP8266WiFi/src/arch/cc.h | 117 + .../ESP8266/ESP8266WiFi/src/arch/perf.h | 40 + .../ESP8266/ESP8266WiFi/src/arch/sys_arch.h | 0 .../ESP8266WiFi/src/include/ClientContext.h | 319 +++ .../ESP8266WiFi/src/include/UdpContext.h | 389 ++++ .../ESP8266WiFi/src/include/lwipopts.h | 2037 ++++++++++++++++ .../ESP8266/ESP8266WiFi/src/include/slist.h | 38 + .../ESP8266WiFi/src/include/wl_definitions.h | 87 + .../ESP8266/ESP8266WiFi/src/lwip/api.h | 284 +++ .../ESP8266/ESP8266WiFi/src/lwip/api_msg.h | 174 ++ .../ESP8266/ESP8266WiFi/src/lwip/arch.h | 238 ++ .../ESP8266/ESP8266WiFi/src/lwip/autoip.h | 119 + .../ESP8266/ESP8266WiFi/src/lwip/debug.h | 98 + .../ESP8266/ESP8266WiFi/src/lwip/def.h | 127 + .../ESP8266/ESP8266WiFi/src/lwip/dhcp.h | 243 ++ .../ESP8266/ESP8266WiFi/src/lwip/dns.h | 124 + .../ESP8266/ESP8266WiFi/src/lwip/err.h | 86 + .../ESP8266/ESP8266WiFi/src/lwip/icmp.h | 115 + .../ESP8266/ESP8266WiFi/src/lwip/igmp.h | 106 + .../ESP8266/ESP8266WiFi/src/lwip/inet.h | 107 + .../ESP8266WiFi/src/lwip/inet_chksum.h | 90 + .../ESP8266/ESP8266WiFi/src/lwip/init.h | 73 + .../drivers/ESP8266/ESP8266WiFi/src/lwip/ip.h | 215 ++ .../ESP8266/ESP8266WiFi/src/lwip/ip_addr.h | 272 +++ .../ESP8266/ESP8266WiFi/src/lwip/ip_frag.h | 88 + .../ESP8266/ESP8266WiFi/src/lwip/mem.h | 143 ++ .../ESP8266WiFi/src/lwip/mem_manager.h | 81 + .../ESP8266/ESP8266WiFi/src/lwip/memp.h | 116 + .../ESP8266/ESP8266WiFi/src/lwip/memp_std.h | 126 + .../ESP8266/ESP8266WiFi/src/lwip/netbuf.h | 101 + .../ESP8266/ESP8266WiFi/src/lwip/netdb.h | 124 + .../ESP8266/ESP8266WiFi/src/lwip/netif.h | 315 +++ .../ESP8266/ESP8266WiFi/src/lwip/netifapi.h | 108 + .../ESP8266/ESP8266WiFi/src/lwip/opt.h | 2043 +++++++++++++++++ .../ESP8266/ESP8266WiFi/src/lwip/pbuf.h | 160 ++ .../ESP8266/ESP8266WiFi/src/lwip/raw.h | 98 + .../ESP8266/ESP8266WiFi/src/lwip/sio.h | 141 ++ .../ESP8266/ESP8266WiFi/src/lwip/snmp.h | 367 +++ .../ESP8266/ESP8266WiFi/src/lwip/snmp_asn1.h | 101 + .../ESP8266/ESP8266WiFi/src/lwip/snmp_msg.h | 315 +++ .../ESP8266WiFi/src/lwip/snmp_structs.h | 268 +++ .../ESP8266/ESP8266WiFi/src/lwip/sockets.h | 376 +++ .../ESP8266/ESP8266WiFi/src/lwip/stats.h | 292 +++ .../ESP8266/ESP8266WiFi/src/lwip/sys.h | 337 +++ .../ESP8266/ESP8266WiFi/src/lwip/tcp.h | 377 +++ .../ESP8266/ESP8266WiFi/src/lwip/tcp_impl.h | 472 ++++ .../ESP8266/ESP8266WiFi/src/lwip/tcpip.h | 159 ++ .../ESP8266/ESP8266WiFi/src/lwip/timers.h | 98 + .../ESP8266/ESP8266WiFi/src/lwip/udp.h | 171 ++ .../drivers/ESP8266/Ethernet/README.adoc | 24 + .../AdvancedChatServer/AdvancedChatServer.ino | 108 + .../BarometricPressureWebServer.ino | 223 ++ .../examples/ChatServer/ChatServer.ino | 80 + .../DhcpAddressPrinter/DhcpAddressPrinter.ino | 60 + .../DhcpChatServer/DhcpChatServer.ino | 88 + .../examples/TelnetClient/TelnetClient.ino | 94 + .../UDPSendReceiveString.ino | 119 + .../examples/UdpNtpClient/UdpNtpClient.ino | 142 ++ .../Ethernet/examples/WebClient/WebClient.ino | 88 + .../WebClientRepeating/WebClientRepeating.ino | 108 + .../Ethernet/examples/WebServer/WebServer.ino | 101 + .../drivers/ESP8266/Ethernet/keywords.txt | 37 + .../ESP8266/Ethernet/library.properties | 9 + .../drivers/ESP8266/Ethernet/src/Dhcp.cpp | 481 ++++ .../drivers/ESP8266/Ethernet/src/Dhcp.h | 178 ++ .../drivers/ESP8266/Ethernet/src/Dns.cpp | 423 ++++ .../drivers/ESP8266/Ethernet/src/Dns.h | 41 + .../drivers/ESP8266/Ethernet/src/Ethernet.cpp | 136 ++ .../drivers/ESP8266/Ethernet/src/Ethernet.h | 41 + .../ESP8266/Ethernet/src/EthernetClient.cpp | 173 ++ .../ESP8266/Ethernet/src/EthernetClient.h | 41 + .../ESP8266/Ethernet/src/EthernetServer.cpp | 92 + .../ESP8266/Ethernet/src/EthernetServer.h | 22 + .../ESP8266/Ethernet/src/EthernetUdp.cpp | 218 ++ .../ESP8266/Ethernet/src/EthernetUdp.h | 99 + .../ESP8266/Ethernet/src/utility/socket.cpp | 469 ++++ .../ESP8266/Ethernet/src/utility/socket.h | 44 + .../ESP8266/Ethernet/src/utility/util.h | 14 + .../ESP8266/Ethernet/src/utility/w5100.cpp | 225 ++ .../ESP8266/Ethernet/src/utility/w5100.h | 412 ++++ .../MySensors/drivers/ESP8266/SPI/SPI.cpp | 454 ++++ libraries/MySensors/drivers/ESP8266/SPI/SPI.h | 85 + .../drivers/ESP8266/SPI/keywords.txt | 36 + .../drivers/ESP8266/SPI/library.properties | 8 + .../MySensors/drivers/RF24/RF24_config.h | 4 +- .../MySensors/drivers/SPIFlash/SPIFlash.h | 2 +- .../EthernetGateway/EthernetGateway.ino | 2 +- .../examples/MotionSensor/MotionSensor.ino | 6 +- 234 files changed, 21028 insertions(+), 315 deletions(-) rename libraries/MySensors/core/{MyTransport.cpp => MyGatewayTransport.h} (57%) create mode 100644 libraries/MySensors/core/MyHw.h rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/DigitalIO.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/DigitalPin.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/I2cConstants.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/PinIO.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/PinIO.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/SoftI2cMaster.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/SoftI2cMaster.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/SoftSPI.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/attic/ADS7818.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/attic/MCP320X.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/attic/MCP355X.h (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/PinIOBegin/PinIOBegin.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/testArduino/testArduino.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/testDigitalPin/testDigitalPin.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/testFastDigital/testFastDigital.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/testPinIO/testPinIO.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/DigitalIO/examples/testSoftSPI/testSoftSPI.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/Dhcp.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/Dhcp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/Dns.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/Dns.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/README (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPClient.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPClient.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPEthernet.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPEthernet.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPServer.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPServer.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPUdp.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/UIPUdp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/ethernet_comp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/EchoServer/EchoServer.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/TcpClient/TcpClient.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/TcpServer/TcpServer.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/UdpClient/UdpClient.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/examples/UdpServer/UdpServer.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/keywords.txt (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/library.properties (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/tests/perl/tcpclient.pl (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/tests/perl/tcpserver.pl (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/tests/perl/udpclient.pl (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/tests/perl/udpserver.pl (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/Enc28J60Network.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/Enc28J60Network.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/clock-arch.c (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/clock-arch.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/enc28j60.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/mempool.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/mempool.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/mempool_conf.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip-conf.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip.c (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_arch.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_arp.c (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_arp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_clock.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_debug.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_debug.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_timer.c (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uip_timer.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uipethernet-conf.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/uipopt.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_UIP/utility/util.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Client.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Dhcp.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Dhcp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Dns.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Dns.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Ethernet.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Ethernet.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetClient.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetClient.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetServer.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetServer.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetUdp.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/EthernetUdp.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/IPAddress.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/IPAddress.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/Server.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/utility/socket.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/utility/socket.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/utility/util.h (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/utility/w5100.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/Ethernet_W5100/utility/w5100.h (99%) rename libraries/MySensors/drivers/{ => AVR}/SPI/SPI.cpp (100%) rename libraries/MySensors/drivers/{ => AVR}/SPI/SPI.h (100%) rename libraries/MySensors/drivers/{ => AVR}/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/SPI/examples/DigitalPotControl/DigitalPotControl.ino (100%) rename libraries/MySensors/drivers/{ => AVR}/SPI/keywords.txt (100%) rename libraries/MySensors/drivers/{ => AVR}/SPI/library.properties (100%) create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.h create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_clear/eeprom_clear.ino create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_read/eeprom_read.ino create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_write/eeprom_write.ino create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/keywords.txt create mode 100644 libraries/MySensors/drivers/ESP8266/EEPROM/library.properties create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/NTPClient/NTPClient.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/keywords.txt create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/library.properties create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/cc.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/perf.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/sys_arch.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/ClientContext.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/UdpContext.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/lwipopts.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/slist.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/wl_definitions.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api_msg.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/arch.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/autoip.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/debug.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/def.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dhcp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dns.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/err.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/icmp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/igmp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet_chksum.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/init.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_addr.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_frag.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem_manager.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp_std.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netbuf.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netdb.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netif.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netifapi.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/opt.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/pbuf.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/raw.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sio.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_asn1.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_msg.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_structs.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sockets.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/stats.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sys.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp_impl.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcpip.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/timers.h create mode 100644 libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/udp.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/README.adoc create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/ChatServer/ChatServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/TelnetClient/TelnetClient.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClient/WebClient.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebServer/WebServer.ino create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/keywords.txt create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/library.properties create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/util.h create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.h create mode 100644 libraries/MySensors/drivers/ESP8266/SPI/SPI.cpp create mode 100644 libraries/MySensors/drivers/ESP8266/SPI/SPI.h create mode 100644 libraries/MySensors/drivers/ESP8266/SPI/keywords.txt create mode 100644 libraries/MySensors/drivers/ESP8266/SPI/library.properties diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index e9d4e75..3327516 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -36,13 +36,14 @@ #endif // CORE -#include "drivers/SPI/SPI.cpp" // HARDWARE #if defined(ARDUINO_ARCH_ESP8266) + #include "drivers/ESP8266/SPI/SPI.cpp" #include "core/MyHwESP8266.cpp" #elif defined(ARDUINO_ARCH_AVR) + #include "drivers/AVR/SPI/SPI.cpp" #include "core/MyHwATMega328.cpp" #endif @@ -66,26 +67,25 @@ #define MY_RADIO_FEATURE // SOFTSPI #ifdef MY_SOFTSPI - #include "drivers/DigitalIO/SoftI2cMaster.cpp" - #include "drivers/DigitalIO/PinIO.cpp" + #if defined(ARDUINO_ARCH_ESP8266) + #error Soft SPI is not available on ESP8266 + #endif + #include "drivers/AVR/DigitalIO/SoftI2cMaster.cpp" + #include "drivers/AVR/DigitalIO/PinIO.cpp" #endif // FLASH #ifdef MY_OTA_FIRMWARE_FEATURE - SPIFlash flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); #include "drivers/SPIFlash/SPIFlash.cpp" + SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); #endif - #include "core/MyTransport.cpp" #if defined(MY_RADIO_NRF24) #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" - MyTransportNRF24 transport; - #elif defined(MY_RADIO_RFM69) #include "drivers/RFM69/RFM69.cpp" #include "core/MyTransportRFM69.cpp" - MyTransportRFM69 transport; #endif #endif @@ -93,10 +93,8 @@ // GATEWAY - TRANSPORT #if defined(MY_GATEWAY_FEATURE) // GATEWAY - PROTOCOL - #include "core/MyProtocol.cpp" #if defined(MY_GATEWAY_PROTOCOL_DEFAULT) #include "core/MyProtocolDefault.cpp" - MyProtocolDefault _protocol; #else #error No gateway protocol specified! #endif @@ -105,29 +103,29 @@ #define MY_REPEATER_FEATURE #endif #if defined(MY_GATEWAY_W5100_CLIENT) || defined(MY_GATEWAY_W5100_SERVER) - #include "drivers/Ethernet_W5100/utility/socket.cpp" - #include "drivers/Ethernet_W5100/utility/w5100.cpp" - #include "drivers/Ethernet_W5100/DNS.cpp" - #include "drivers/Ethernet_W5100/Ethernet.cpp" - #include "drivers/Ethernet_W5100/EthernetUdp.cpp" - #include "drivers/Ethernet_W5100/IPAddress.cpp" + #include "drivers/AVR/Ethernet_W5100/utility/socket.cpp" + #include "drivers/AVR/Ethernet_W5100/utility/w5100.cpp" + #include "drivers/AVR/Ethernet_W5100/DNS.cpp" + #include "drivers/AVR/Ethernet_W5100/Ethernet.cpp" + #include "drivers/AVR/Ethernet_W5100/EthernetUdp.cpp" + #include "drivers/AVR/Ethernet_W5100/IPAddress.cpp" + #if !defined(MY_PORT) #error You must define MY_PORT #endif #if !defined(USE_UDP) - #include "drivers/Ethernet_W5100/EthernetServer.cpp" + #include "drivers/AVR/Ethernet_W5100/EthernetServer.cpp" #endif #if defined(MY_GATEWAY_W5100_CLIENT) && !defined(MY_CONTROLLER_IP_ADDRESS) #error You must define MY_CONTROLLER_IP_ADDRESS when acting as client #endif #if defined(MY_GATEWAY_W5100_CLIENT) - #include "drivers/Ethernet_W5100/EthernetClient.cpp" + #include "drivers/AVR/Ethernet_W5100/EthernetClient.cpp" #include "core/MyGatewayTransportEthernet.cpp" #endif #elif defined(MY_GATEWAY_SERIAL) #include "core/MyGatewayTransportSerial.cpp" - MyGatewayTransportSerial gwTransport(protocol); #endif #else #undef MY_GATEWAY_FEATURE diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.h similarity index 57% rename from libraries/MySensors/core/MyTransport.cpp rename to libraries/MySensors/core/MyGatewayTransport.h index 05627de..4df3244 100644 --- a/libraries/MySensors/core/MyTransport.cpp +++ b/libraries/MySensors/core/MyGatewayTransport.h @@ -5,8 +5,8 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB + * Created by Tomas Hozza + * Copyright (C) 2015 Tomas Hozza * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -17,7 +17,25 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyTransport.h" +#ifndef MyGatewayTransport_h +#define MyGatewayTransport_h -MyTransport::MyTransport() { -} +#include "MyConfig.h" +#include "MyMessage.h" +#include "MyProtocol.h" + + + +// initialize the driver +bool gatewayTransportBegin(); + +// Send message to controller +bool gatewayTransportSend(MyMessage &message); + +// Check if a new message is available from controller +bool gatewayTransportAvailable(); + +// Pick up last message received from controller +MyMessage& gatewayTransportReceive(); + +#endif /* MyGatewayTransportEthernet_h */ diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp index b2b21ee..83fa9b1 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp @@ -64,7 +64,7 @@ bool gatewayTransportSend(MyMessage &message) return false; } else { - _ethernetMsg = _protocol.format(message); + _ethernetMsg = protocolFormat(message); #ifdef MY_USE_UDP _ethernetServer.beginPacket(_ethernetControllerIP, MY_CONTROLLER_PORT); _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); @@ -128,7 +128,7 @@ bool gatewayTransportAvailable() if (available) { // Parse message and return parse result - available = _protocol.parse(_ethernetMsg, _ethernetInputBuffer); + available = protocolParse(_ethernetMsg, _ethernetInputBuffer); } return available; diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.h b/libraries/MySensors/core/MyGatewayTransportEthernet.h index da1abc1..c7cd7f9 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.h +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.h @@ -24,36 +24,19 @@ #include "MyMessage.h" #include "MyProtocol.h" #include "MyProtocolDefault.h" +#include "MyGatewayTransport.h" -#include "drivers/Ethernet_W5100/IPAddress.h" // Use this if you have attached a Ethernet ENC28J60 shields //#include -// Use this fo WizNET W5100 module and Arduino Ethernet Shield -#include "drivers/Ethernet_W5100/Ethernet.h" -#ifdef MY_USE_UDP -#include "drivers/Ethernet_W5100/EthernetUdp.h" -#endif /* MY_USE_UDP */ #define CONTROLLER_PORT 5003 #define IP_RENEWAL_INTERVAL 60000 // in milliseconds #define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller -// initialize the driver -bool gatewayTransportBegin(); - -// Send message to controller -bool gatewayTransportSend(MyMessage &message); - -// Check if a new message is available from controller -bool gatewayTransportAvailable(); - -// Pick up last message received from controller -MyMessage& gatewayTransportReceive(); - #ifndef MY_IP_ADDRESS void gatewayTransportRenewIP(); #endif diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.cpp b/libraries/MySensors/core/MyGatewayTransportSerial.cpp index f5acbed..313efac 100644 --- a/libraries/MySensors/core/MyGatewayTransportSerial.cpp +++ b/libraries/MySensors/core/MyGatewayTransportSerial.cpp @@ -17,54 +17,55 @@ * version 2 as published by the Free Software Foundation. */ + #include "MyGatewayTransportSerial.h" +char _serialInputString[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface +int _serialInputPos; +MyMessage _serialMsg; -MyGatewayTransportSerial::MyGatewayTransportSerial(MyProtocol &_protocol) : MyGatewayTransport(_protocol),inputPos(0) -{ -} -bool MyGatewayTransportSerial::begin() { +bool gatewayTransportBegin() { return true; } -bool MyGatewayTransportSerial::send(MyMessage &message) { - Serial.print(protocol.format(message)); +bool gatewayTransportSend(MyMessage &message) { + Serial.print(protocolFormat(message)); // Serial print is always successful return true; } -bool MyGatewayTransportSerial::available() { +bool gatewayTransportAvailable() { bool available = false; while (Serial.available()) { // get the new byte: char inChar = (char) Serial.read(); // if the incoming character is a newline, set a flag // so the main loop can do something about it: - if (inputPos < MAX_RECEIVE_LENGTH - 1 && !available) { + if (_serialInputPos < MAX_RECEIVE_LENGTH - 1 && !available) { if (inChar == '\n') { - inputString[inputPos] = 0; + _serialInputString[_serialInputPos] = 0; available = true; } else { // add it to the inputString: - inputString[inputPos] = inChar; - inputPos++; + _serialInputString[_serialInputPos] = inChar; + _serialInputPos++; } } else { // Incoming message too long. Throw away - inputPos = 0; + _serialInputPos = 0; } } if (available) { // Parse message and return parse result - available = protocol.parse(msg, inputString); - inputPos = 0; + available = protocolParse(_serialMsg, _serialInputString); + _serialInputPos = 0; } return available; } -MyMessage & MyGatewayTransportSerial::receive() { +MyMessage & gatewayTransportReceive() { // Return the last parsed message - return msg; + return _serialMsg; } diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.h b/libraries/MySensors/core/MyGatewayTransportSerial.h index 302a06c..7dabf02 100644 --- a/libraries/MySensors/core/MyGatewayTransportSerial.h +++ b/libraries/MySensors/core/MyGatewayTransportSerial.h @@ -21,32 +21,10 @@ #define MyGatewayTransportSerial_h #include "MyMessage.h" +#include "MyGatewayTransport.h" #include "MyProtocol.h" #include "MyProtocolDefault.h" #define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller -class MyGatewayTransportSerial : public MyGatewayTransport -{ -public: - // MyGateway constructor - MyGatewayTransportSerial(MyProtocol &protocol = *new MyProtocolDefault()); - - // initialize the transport driver - bool begin(); - - // Send message to controller - bool send(MyMessage &message); - - // Check if a new message is available from controller - bool available(); - - // Pick up last message received from controller - MyMessage& receive(); -private: - char inputString[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface - int inputPos; - MyMessage msg; -}; - #endif diff --git a/libraries/MySensors/core/MyHw.h b/libraries/MySensors/core/MyHw.h new file mode 100644 index 0000000..c4387de --- /dev/null +++ b/libraries/MySensors/core/MyHw.h @@ -0,0 +1,53 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyHw_h +#define MyHw_h + +#include "MyConfig.h" +#include "MyMessage.h" +#include "MyHw.h" + + +#ifdef __cplusplus +#include +#endif + +// Implement these as functions or macros +/* +#define hwDigitalWrite(__pin, __value) +#define hwInit() Serial.begin(BAUD_RATE) +#define hwWatchdogReset() wdt_reset() +#define hwReboot() wdt_enable(WDTO_15MS); while (1) +#define hwMillis() millis() + +void hwReadConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfig(int adr, uint8_t value); +uint8_t hwReadConfig(int adr); +*/ + +void hwSleep(unsigned long ms); +bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); +uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +#ifdef MY_DEBUG + void hwDebugPrint(const char *fmt, ... ); +#endif + +#endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/core/MyHwATMega328.h b/libraries/MySensors/core/MyHwATMega328.h index 90ea09b..65d0190 100644 --- a/libraries/MySensors/core/MyHwATMega328.h +++ b/libraries/MySensors/core/MyHwATMega328.h @@ -20,8 +20,7 @@ #ifndef MyHwATMega328_h #define MyHwATMega328_h -#ifdef ARDUINO_ARCH_AVR - +#include "MyHw.h" #include "MyConfig.h" #include "MyMessage.h" #include @@ -92,14 +91,6 @@ enum period_t SLEEP_FOREVER }; - -void hwSleep(unsigned long ms); -bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); -uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); -#ifdef MY_DEBUG - void hwDebugPrint(const char *fmt, ... ); -#endif void hwInternalSleep(unsigned long ms); -#endif // #ifdef ARDUINO_ARCH_AVR #endif diff --git a/libraries/MySensors/core/MyHwESP8266.cpp b/libraries/MySensors/core/MyHwESP8266.cpp index 5a0eb64..d638bf2 100644 --- a/libraries/MySensors/core/MyHwESP8266.cpp +++ b/libraries/MySensors/core/MyHwESP8266.cpp @@ -17,10 +17,8 @@ * version 2 as published by the Free Software Foundation. */ -#ifdef ARDUINO_ARCH_ESP8266 - #include "MyHwESP8266.h" -#include +#include "drivers/ESP8266/EEPROM/EEPROM.cpp" /* int8_t pinIntTrigger = 0; @@ -54,7 +52,7 @@ static void hwInitConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ void hwReadConfigBlock(void* buf, void* adr, size_t length) { - hw_initConfigBlock(); + hwInitConfigBlock(); uint8_t* dst = static_cast(buf); int offs = reinterpret_cast(adr); while (length-- > 0) @@ -65,7 +63,7 @@ void hwReadConfigBlock(void* buf, void* adr, size_t length) void hwWriteConfigBlock(void* buf, void* adr, size_t length) { - hw_initConfigBlock(); + hwInitConfigBlock(); uint8_t* src = static_cast(buf); int offs = reinterpret_cast(adr); while (length-- > 0) @@ -78,16 +76,16 @@ void hwWriteConfigBlock(void* buf, void* adr, size_t length) uint8_t hwReadConfig(int adr) { uint8_t value; - hw_readConfigBlock(&value, reinterpret_cast(adr), 1); + hwReadConfigBlock(&value, reinterpret_cast(adr), 1); return value; } void hwWriteConfig(int adr, uint8_t value) { - uint8_t curr = hw_readConfig(adr); + uint8_t curr = hwReadConfig(adr); if (curr != value) { - hw_writeConfigBlock(&value, reinterpret_cast(adr), 1); + hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); } } @@ -109,7 +107,7 @@ uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t m } #ifdef MY_DEBUG -void hwDebugPrint(bool isGW, const char *fmt, ... ) { +void hwDebugPrint(const char *fmt, ... ) { char fmtBuffer[300]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) @@ -134,5 +132,3 @@ void hwDebugPrint(bool isGW, const char *fmt, ... ) { //Serial.write(freeRam()); } #endif - -#endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/core/MyHwESP8266.h b/libraries/MySensors/core/MyHwESP8266.h index 6f99201..461ddbb 100644 --- a/libraries/MySensors/core/MyHwESP8266.h +++ b/libraries/MySensors/core/MyHwESP8266.h @@ -16,25 +16,23 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - -#ifdef ARDUINO_ARCH_ESP8266 - #ifndef MyHwESP8266_h #define MyHwESP8266_h +#include "MyHw.h" #include "MyConfig.h" #include "MyMessage.h" #ifdef __cplusplus #include -#include +//#include #endif // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hwInit() Serial.begin(BAUD_RATE) +#define hwInit() Serial.begin(MY_BAUD_RATE) #define hwWatchdogReset() wdt_reset() #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() @@ -44,28 +42,5 @@ void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); -enum period_t -{ - SLEEP_15Ms, - SLEEP_30MS, - SLEEP_60MS, - SLEEP_120MS, - SLEEP_250MS, - SLEEP_500MS, - SLEEP_1S, - SLEEP_2S, - SLEEP_4S, - SLEEP_8S, - SLEEP_FOREVER -}; - - - -void hwSleep(unsigned long ms); -bool hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); -uint8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); -#ifdef MY_DEBUG - void hwDebugPrint(const char *fmt, ... ); -#endif #endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/libraries/MySensors/core/MyProtocol.h b/libraries/MySensors/core/MyProtocol.h index 5b0298f..c425809 100644 --- a/libraries/MySensors/core/MyProtocol.h +++ b/libraries/MySensors/core/MyProtocol.h @@ -22,18 +22,12 @@ #include "MyMessage.h" -class MyProtocol -{ -public: - // MyProtocol constructor - MyProtocol(); - // parse(message, inputString) - // parse a string into a message element - // returns true if successfully parsed the input string - virtual bool parse(MyMessage &message, char *inputString) = 0; +// parse(message, inputString) +// parse a string into a message element +// returns true if successfully parsed the input string +bool protocolParse(MyMessage &message, char *inputString); - // Format MyMessage to the protocol represenataion - virtual char *format(MyMessage &message) = 0; +// Format MyMessage to the protocol represenataion +char *protocolFormat(MyMessage &message); -}; #endif diff --git a/libraries/MySensors/core/MyProtocolDefault.cpp b/libraries/MySensors/core/MyProtocolDefault.cpp index f410abe..727b337 100644 --- a/libraries/MySensors/core/MyProtocolDefault.cpp +++ b/libraries/MySensors/core/MyProtocolDefault.cpp @@ -21,9 +21,10 @@ #include "MyProtocolDefault.h" #include "MyTransport.h" -MyProtocolDefault::MyProtocolDefault() : MyProtocol() {} +char fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; +char convBuffer[MAX_PAYLOAD*2+1]; -bool MyProtocolDefault::parse(MyMessage &message, char *inputString) { +bool protocolParse(MyMessage &message, char *inputString) { char *str, *p, *value=NULL; uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; @@ -58,8 +59,8 @@ bool MyProtocolDefault::parse(MyMessage &message, char *inputString) { blen = 0; uint8_t val; while (*str) { - val = h2i(*str++) << 4; - val += h2i(*str++); + val = protocolH2i(*str++) << 4; + val += protocolH2i(*str++); bvalue[blen] = val; blen++; } @@ -89,13 +90,12 @@ bool MyProtocolDefault::parse(MyMessage &message, char *inputString) { return true; } -char * MyProtocolDefault::format(MyMessage &message) { +char * protocolFormat(MyMessage &message) { snprintf_P(fmtBuffer, MAX_FORMAT_BUFFER_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuffer)); return fmtBuffer; } - -uint8_t MyProtocolDefault::h2i(char c) { +uint8_t protocolH2i(char c) { uint8_t i = 0; if (c <= '9') i += c - '0'; @@ -105,3 +105,5 @@ uint8_t MyProtocolDefault::h2i(char c) { i += c - 'A' + 10; return i; } + + diff --git a/libraries/MySensors/core/MyProtocolDefault.h b/libraries/MySensors/core/MyProtocolDefault.h index 8d35609..4583abd 100644 --- a/libraries/MySensors/core/MyProtocolDefault.h +++ b/libraries/MySensors/core/MyProtocolDefault.h @@ -21,22 +21,10 @@ #define MyProtocolDefault_h #include "MyConfig.h" -#include "MyProtocol.h" #include "MyTransport.h" #define MAX_FORMAT_BUFFER_LENGTH 120 // Max buffersize when formatting messages +uint8_t protocolH2i(char c); -class MyProtocolDefault : public MyProtocol -{ -public: - MyProtocolDefault(); - bool parse(MyMessage &message, char *inputString); - char *format(MyMessage &message); -private: - char fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; - char convBuffer[MAX_PAYLOAD*2+1]; - - uint8_t h2i(char c); -}; #endif diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index 05121cf..0d8b496 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -109,7 +109,7 @@ bool isValidFirmware() { // init crc uint16_t crc = ~0; for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - crc ^= flash.readByte(i + FIRMWARE_START_OFFSET); + crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); for (int8_t j = 0; j < 8; ++j) { if (crc & 1) crc = (crc >> 1) ^ 0xA001; @@ -217,7 +217,7 @@ void begin() { _failedTransmissions = 0; // Setup radio - if (!transport.init()) { + if (!transportInit()) { debug(PSTR("radio init fail\n")); while(1); // Nothing more we can do } @@ -311,7 +311,7 @@ ControllerConfig getConfig() { #if defined(MY_RADIO_FEATURE) void requestNodeId() { debug(PSTR("req id\n")); - transport.setAddress(_nc.nodeId); + transportSetAddress(_nc.nodeId); build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); sendWrite(_nc.parentNodeId, _msg); wait(2000); @@ -323,7 +323,7 @@ void requestNodeId() { void setupNode() { // Open reading pipe for messages directed to this node (set write pipe to same) - transport.setAddress(_nc.nodeId); + transportSetAddress(_nc.nodeId); // Present node and request config #ifndef MY_GATEWAY_FEATURE if (_nc.nodeId != AUTO) { @@ -563,7 +563,7 @@ boolean sendWrite(uint8_t to, MyMessage &message) { #ifdef MY_LEDS_BLINKING_FEATURE txBlink(1); #endif - bool ok = transport.send(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); + bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, @@ -660,7 +660,7 @@ void process() { #if defined(MY_RADIO_FEATURE) uint8_t to = 0; - if (!transport.available(&to)) + if (!transportAvailable(&to)) { #ifdef MY_OTA_FIRMWARE_FEATURE unsigned long enter = hwMillis(); @@ -692,7 +692,7 @@ void process() { (void)signer.checkTimer(); // Manage signing timeout #endif - uint8_t len = transport.receive((uint8_t *)&_msg); + uint8_t len = transportReceive((uint8_t *)&_msg); (void)len; //until somebody makes use of 'len' #ifdef MY_LEDS_BLINKING_FEATURE rxBlink(1); @@ -842,14 +842,14 @@ void process() { // copy new FW config memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); // Init flash - if (!flash.initialize()) { + if (!_flash.initialize()) { debug(PSTR("flash init fail\n")); _fwUpdateOngoing = false; } else { // erase lower 32K -> max flash size for ATMEGA328 - flash.blockErase32K(0); + _flash.blockErase32K(0); // wait until flash erased - while ( flash.busy() ); + while ( _flash.busy() ); _fwBlock = _fc.blocks; _fwUpdateOngoing = true; // reset flags @@ -865,9 +865,9 @@ void process() { // extract FW block ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; // write to flash - flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written - while ( flash.busy() ); + while ( _flash.busy() ); _fwBlock--; if (!_fwBlock) { // We're finished! Do a checksum and reboot. @@ -877,7 +877,7 @@ void process() { // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; - flash.writeBytes(0, OTAbuffer, 10); + _flash.writeBytes(0, OTAbuffer, 10); // Write the new firmware config to eeprom hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); hwReboot(); @@ -986,7 +986,7 @@ void sleep(unsigned long ms) { } else { #endif #if defined(MY_RADIO_FEATURE) - transport.powerDown(); + transportPowerDown(); #endif hwSleep(ms); #if defined(MY_OTA_FIRMWARE_FEATURE) @@ -1003,7 +1003,7 @@ bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { } else { #endif #if defined(MY_RADIO_FEATURE) - transport.powerDown(); + transportPowerDown(); #endif return hwSleep(interrupt, mode, ms) ; #if defined(MY_OTA_FIRMWARE_FEATURE) @@ -1020,7 +1020,7 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode } else { #endif #if defined(MY_RADIO_FEATURE) - transport.powerDown(); + transportPowerDown(); #endif return hwSleep(interrupt1, mode1, interrupt2, mode2, ms) ; #if defined(MY_OTA_FIRMWARE_FEATURE) diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index 6deb634..24a7874 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -23,7 +23,6 @@ #include "Version.h" // Auto generated by bot #include "MyConfig.h" -#include "MyTransport.h" #ifdef MY_SIGNING_FEATURE #include "MySigning.h" #include "MySigningNone.h" diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index aab12f3..503f8c1 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -29,37 +29,5 @@ #define GATEWAY_ADDRESS ((uint8_t)0) #define BROADCAST_ADDRESS ((uint8_t)0xFF) -class MyTransport -{ -public: - // MyTransport constructor - // different parameters would be needed depending on radio module (e.g. pins connected etc.) - // keeping these parameters as #define's in MyConfig to streamline the driver interface - MyTransport(); - // init() - // different parameters would be needed depending on radio module (e.g. channel, power, crc, etc.) - // keeping these parameters as #define's in MyConfig to streamline the driver interface - virtual bool init() = 0; - // setAddress(address) - // set the node address and start listening to that address (and the broadcast address) - virtual void setAddress(uint8_t address) = 0; - // getAddress() - // returns the current address from the radio driver - virtual uint8_t getAddress() = 0; - // send(to, data, len) - // reliable transmission of the data with given length (in bytes) to the destination address - // returns true if successfully submitted - virtual bool send(uint8_t to, const void* data, uint8_t len) = 0; - // available(to) - // returns true if a new packet arrived in the rx buffer - // populates "to" parameter with the address the packet was sent to (either own address or broadcast) - virtual bool available(uint8_t *to) = 0; - // receive(data) - // returns length of received packet - // populates "data" parameter with received data - virtual uint8_t receive(void* data) = 0; - // powers down the radio - virtual void powerDown() = 0; -}; #endif diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index 5affb12..91e9fc2 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -17,76 +17,72 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyTransport.h" #include "MyTransportNRF24.h" -MyTransportNRF24::MyTransportNRF24() - : - MyTransport(), - rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN) -{ -} +RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN); +uint8_t _address; +uint8_t _paLevel; -bool MyTransportNRF24::init() { +bool transportInit() { // Start up the radio library - rf24.begin(); + _rf24.begin(); - if (!rf24.isPVariant()) { + if (!_rf24.isPVariant()) { return false; } - rf24.setAutoAck(1); - rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast - rf24.enableAckPayload(); - rf24.setChannel(MY_RF24_CHANNEL); - rf24.setPALevel(_paLevel); - rf24.setDataRate(MY_RF24_DATARATE); - rf24.setRetries(5,15); - rf24.setCRCLength(RF24_CRC_16); - rf24.enableDynamicPayloads(); + _rf24.setAutoAck(1); + _rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast + _rf24.enableAckPayload(); + _rf24.setChannel(MY_RF24_CHANNEL); + _rf24.setPALevel(_paLevel); + _rf24.setDataRate(MY_RF24_DATARATE); + _rf24.setRetries(5,15); + _rf24.setCRCLength(RF24_CRC_16); + _rf24.enableDynamicPayloads(); // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) - rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); + _rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); return true; } -void MyTransportNRF24::setAddress(uint8_t address) { +void transportSetAddress(uint8_t address) { _address = address; - rf24.openReadingPipe(WRITE_PIPE, TO_ADDR(address)); - rf24.openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); - rf24.startListening(); + _rf24.openReadingPipe(WRITE_PIPE, TO_ADDR(address)); + _rf24.openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(address)); + _rf24.startListening(); } -uint8_t MyTransportNRF24::getAddress() { +uint8_t transportGetAddress() { return _address; } -bool MyTransportNRF24::send(uint8_t to, const void* data, uint8_t len) { +bool transportSend(uint8_t to, const void* data, uint8_t len) { // Make sure radio has powered up - rf24.powerUp(); - rf24.stopListening(); - rf24.openWritingPipe(TO_ADDR(to)); - bool ok = rf24.write(data, len, to == BROADCAST_ADDRESS); - rf24.startListening(); + _rf24.powerUp(); + _rf24.stopListening(); + _rf24.openWritingPipe(TO_ADDR(to)); + bool ok = _rf24.write(data, len, to == BROADCAST_ADDRESS); + _rf24.startListening(); return ok; } -bool MyTransportNRF24::available(uint8_t *to) { +bool transportAvailable(uint8_t *to) { uint8_t pipe = 255; - boolean avail = rf24.available(&pipe); + boolean avail = _rf24.available(&pipe); (void)avail; //until somebody makes use of 'avail' if (pipe == CURRENT_NODE_PIPE) *to = _address; else if (pipe == BROADCAST_PIPE) *to = BROADCAST_ADDRESS; - return (rf24.available() && pipe < 6); + return (_rf24.available() && pipe < 6); } -uint8_t MyTransportNRF24::receive(void* data) { - uint8_t len = rf24.getDynamicPayloadSize(); - rf24.read(data, len); +uint8_t transportReceive(void* data) { + uint8_t len = _rf24.getDynamicPayloadSize(); + _rf24.read(data, len); return len; } -void MyTransportNRF24::powerDown() { - rf24.powerDown(); +void transportPowerDown() { + _rf24.powerDown(); } diff --git a/libraries/MySensors/core/MyTransportNRF24.h b/libraries/MySensors/core/MyTransportNRF24.h index d8a7b81..0d0bcf8 100644 --- a/libraries/MySensors/core/MyTransportNRF24.h +++ b/libraries/MySensors/core/MyTransportNRF24.h @@ -32,21 +32,12 @@ #define CURRENT_NODE_PIPE ((uint8_t)1) #define BROADCAST_PIPE ((uint8_t)2) -class MyTransportNRF24 : public MyTransport -{ -public: - MyTransportNRF24(); - bool init(); - void setAddress(uint8_t address); - uint8_t getAddress(); - bool send(uint8_t to, const void* data, uint8_t len); - bool available(uint8_t *to); - uint8_t receive(void* data); - void powerDown(); -private: - RF24 rf24; - uint8_t _address; - uint8_t _paLevel; -}; +bool transportInit(); +void transportSetAddress(uint8_t address); +uint8_t transportGetAddress(); +bool transportSend(uint8_t to, const void* data, uint8_t len); +bool transportAvailable(uint8_t *to); +uint8_t transportReceive(void* data); +void transportPowerDown(); #endif diff --git a/libraries/MySensors/core/MyTransportRFM69.cpp b/libraries/MySensors/core/MyTransportRFM69.cpp index 30e923e..fc3deb1 100644 --- a/libraries/MySensors/core/MyTransportRFM69.cpp +++ b/libraries/MySensors/core/MyTransportRFM69.cpp @@ -20,52 +20,49 @@ #include "MyTransport.h" #include "MyTransportRFM69.h" -MyTransportRFM69::MyTransportRFM69() - : - MyTransport(), - radio(MY_RF69_SPI_CS, MY_RF69_IRQ_PIN, MY_IS_RFM69HW, MY_RF69_IRQ_NUM) -{ -} +RFM69 _radio(MY_RF69_SPI_CS, MY_RF69_IRQ_PIN, MY_IS_RFM69HW, MY_RF69_IRQ_NUM); +uint8_t _address; -bool MyTransportRFM69::init() { + +bool transportInit() { // Start up the radio library (_address will be set later by the MySensors library) - radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID); + _radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID); #ifdef MY_RFM69_ENABLE_ENCRYPTION - radio.encrypt(RFM69_ENCRYPTKEY); + _radio.encrypt(RFM69_ENCRYPTKEY); #endif return true; } -void MyTransportRFM69::setAddress(uint8_t address) { +void transportSetAddress(uint8_t address) { _address = address; - radio.setAddress(address); + _radio.setAddress(address); } -uint8_t MyTransportRFM69::getAddress() { +uint8_t transportGetAddress() { return _address; } -bool MyTransportRFM69::send(uint8_t to, const void* data, uint8_t len) { - return radio.sendWithRetry(to,data,len); +bool transportSend(uint8_t to, const void* data, uint8_t len) { + return _radio.sendWithRetry(to,data,len); } -bool MyTransportRFM69::available(uint8_t *to) { - if (radio.TARGETID == BROADCAST_ADDRESS) +bool transportAvailable(uint8_t *to) { + if (_radio.TARGETID == BROADCAST_ADDRESS) *to = BROADCAST_ADDRESS; else *to = _address; - return radio.receiveDone(); + return _radio.receiveDone(); } -uint8_t MyTransportRFM69::receive(void* data) { - memcpy(data,(const void *)radio.DATA, radio.DATALEN); +uint8_t transportReceive(void* data) { + memcpy(data,(const void *)_radio.DATA, _radio.DATALEN); // Send ack back if this message wasn't a broadcast - if (radio.TARGETID != RF69_BROADCAST_ADDR) - radio.ACKRequested(); - radio.sendACK(); - return radio.DATALEN; + if (_radio.TARGETID != RF69_BROADCAST_ADDR) + _radio.ACKRequested(); + _radio.sendACK(); + return _radio.DATALEN; } -void MyTransportRFM69::powerDown() { - radio.sleep(); +void transportPowerDown() { + _radio.sleep(); } diff --git a/libraries/MySensors/core/MyTransportRFM69.h b/libraries/MySensors/core/MyTransportRFM69.h index 1336d1e..36ef1a9 100644 --- a/libraries/MySensors/core/MyTransportRFM69.h +++ b/libraries/MySensors/core/MyTransportRFM69.h @@ -27,20 +27,12 @@ #include "drivers/SPI/SPI.h" -class MyTransportRFM69 : public MyTransport -{ -public: - MyTransportRFM69(); - bool init(); - void setAddress(uint8_t address); - uint8_t getAddress(); - bool send(uint8_t to, const void* data, uint8_t len); - bool available(uint8_t *to); - uint8_t receive(void* data); - void powerDown(); -private: - RFM69 radio; - uint8_t _address; -}; +bool transportInit(); +void transportSetAddress(uint8_t address); +uint8_t transportGetAddress(); +bool transportSend(uint8_t to, const void* data, uint8_t len); +bool transportAvailable(uint8_t *to); +uint8_t transportReceive(void* data); +void transportPowerDown(); #endif diff --git a/libraries/MySensors/drivers/DigitalIO/DigitalIO.h b/libraries/MySensors/drivers/AVR/DigitalIO/DigitalIO.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/DigitalIO.h rename to libraries/MySensors/drivers/AVR/DigitalIO/DigitalIO.h diff --git a/libraries/MySensors/drivers/DigitalIO/DigitalPin.h b/libraries/MySensors/drivers/AVR/DigitalIO/DigitalPin.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/DigitalPin.h rename to libraries/MySensors/drivers/AVR/DigitalIO/DigitalPin.h diff --git a/libraries/MySensors/drivers/DigitalIO/I2cConstants.h b/libraries/MySensors/drivers/AVR/DigitalIO/I2cConstants.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/I2cConstants.h rename to libraries/MySensors/drivers/AVR/DigitalIO/I2cConstants.h diff --git a/libraries/MySensors/drivers/DigitalIO/PinIO.cpp b/libraries/MySensors/drivers/AVR/DigitalIO/PinIO.cpp similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/PinIO.cpp rename to libraries/MySensors/drivers/AVR/DigitalIO/PinIO.cpp diff --git a/libraries/MySensors/drivers/DigitalIO/PinIO.h b/libraries/MySensors/drivers/AVR/DigitalIO/PinIO.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/PinIO.h rename to libraries/MySensors/drivers/AVR/DigitalIO/PinIO.h diff --git a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp b/libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.cpp similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.cpp rename to libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.cpp diff --git a/libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h b/libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/SoftI2cMaster.h rename to libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.h diff --git a/libraries/MySensors/drivers/DigitalIO/SoftSPI.h b/libraries/MySensors/drivers/AVR/DigitalIO/SoftSPI.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/SoftSPI.h rename to libraries/MySensors/drivers/AVR/DigitalIO/SoftSPI.h diff --git a/libraries/MySensors/drivers/DigitalIO/attic/ADS7818.h b/libraries/MySensors/drivers/AVR/DigitalIO/attic/ADS7818.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/attic/ADS7818.h rename to libraries/MySensors/drivers/AVR/DigitalIO/attic/ADS7818.h diff --git a/libraries/MySensors/drivers/DigitalIO/attic/MCP320X.h b/libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP320X.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/attic/MCP320X.h rename to libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP320X.h diff --git a/libraries/MySensors/drivers/DigitalIO/attic/MCP355X.h b/libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP355X.h similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/attic/MCP355X.h rename to libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP355X.h diff --git a/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/PinIOBegin/PinIOBegin.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/PinIOBegin/PinIOBegin.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/testArduino/testArduino.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/testArduino/testArduino.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/testDigitalPin/testDigitalPin.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/testDigitalPin/testDigitalPin.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/testFastDigital/testFastDigital.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/testFastDigital/testFastDigital.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/testPinIO/testPinIO.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/testPinIO/testPinIO.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino diff --git a/libraries/MySensors/drivers/DigitalIO/examples/testSoftSPI/testSoftSPI.ino b/libraries/MySensors/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino similarity index 100% rename from libraries/MySensors/drivers/DigitalIO/examples/testSoftSPI/testSoftSPI.ino rename to libraries/MySensors/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/Dhcp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/Dhcp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/Dns.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/Dns.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/Dns.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/README b/libraries/MySensors/drivers/AVR/Ethernet_UIP/README similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/README rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/README diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPClient.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPClient.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPEthernet.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPServer.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPServer.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/UIPUdp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/ethernet_comp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/ethernet_comp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/ethernet_comp.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/EchoServer/EchoServer.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/TcpClient/TcpClient.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/TcpServer/TcpServer.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/UdpClient/UdpClient.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/examples/UdpServer/UdpServer.ino rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino diff --git a/libraries/MySensors/drivers/Ethernet_UIP/keywords.txt b/libraries/MySensors/drivers/AVR/Ethernet_UIP/keywords.txt similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/keywords.txt rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/keywords.txt diff --git a/libraries/MySensors/drivers/Ethernet_UIP/library.properties b/libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/library.properties rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpclient.pl rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/tests/perl/tcpserver.pl rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpclient.pl rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl diff --git a/libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/tests/perl/udpserver.pl rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/Enc28J60Network.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/clock-arch.c similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/clock-arch.c diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/clock-arch.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/clock-arch.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/clock-arch.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/enc28j60.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/enc28j60.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/enc28j60.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/mempool.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool_conf.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/mempool_conf.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/mempool_conf.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip-conf.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip-conf.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip-conf.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.c similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.c diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arch.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arch.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arch.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.c similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.c diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_arp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_clock.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_clock.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_clock.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.cpp diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_debug.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.c similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.c diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uip_timer.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipethernet-conf.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uipethernet-conf.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipethernet-conf.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipopt.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/uipopt.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipopt.h diff --git a/libraries/MySensors/drivers/Ethernet_UIP/utility/util.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/util.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_UIP/utility/util.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/util.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Client.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Client.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Client.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Client.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Dhcp.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Dhcp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Dhcp.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Dhcp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Dhcp.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Dhcp.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Dns.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Dns.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Dns.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Dns.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Dns.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Dns.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Dns.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Ethernet.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Ethernet.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Ethernet.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Ethernet.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Ethernet.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Ethernet.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetClient.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetClient.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetClient.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetClient.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetClient.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetServer.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetServer.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetServer.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetServer.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetServer.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetUdp.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetUdp.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetUdp.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/EthernetUdp.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/EthernetUdp.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/IPAddress.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/IPAddress.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/IPAddress.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/IPAddress.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/IPAddress.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/IPAddress.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/Server.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/Server.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/Server.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/Server.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/socket.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/utility/socket.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/socket.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/socket.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/utility/socket.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/socket.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/util.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/util.h similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/utility/util.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/util.h diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/w5100.cpp similarity index 100% rename from libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/w5100.cpp diff --git a/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/w5100.h similarity index 99% rename from libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h rename to libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/w5100.h index 358e25c..0397866 100644 --- a/libraries/MySensors/drivers/Ethernet_W5100/utility/w5100.h +++ b/libraries/MySensors/drivers/AVR/Ethernet_W5100/utility/w5100.h @@ -10,7 +10,7 @@ #ifndef W5100_H_INCLUDED #define W5100_H_INCLUDED -#include "drivers/SPI/SPI.h" +#include "drivers/AVR/SPI/SPI.h" #define ETHERNET_SHIELD_SPI_CS 10 diff --git a/libraries/MySensors/drivers/SPI/SPI.cpp b/libraries/MySensors/drivers/AVR/SPI/SPI.cpp similarity index 100% rename from libraries/MySensors/drivers/SPI/SPI.cpp rename to libraries/MySensors/drivers/AVR/SPI/SPI.cpp diff --git a/libraries/MySensors/drivers/SPI/SPI.h b/libraries/MySensors/drivers/AVR/SPI/SPI.h similarity index 100% rename from libraries/MySensors/drivers/SPI/SPI.h rename to libraries/MySensors/drivers/AVR/SPI/SPI.h diff --git a/libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/libraries/MySensors/drivers/AVR/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino similarity index 100% rename from libraries/MySensors/drivers/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino rename to libraries/MySensors/drivers/AVR/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino diff --git a/libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/libraries/MySensors/drivers/AVR/SPI/examples/DigitalPotControl/DigitalPotControl.ino similarity index 100% rename from libraries/MySensors/drivers/SPI/examples/DigitalPotControl/DigitalPotControl.ino rename to libraries/MySensors/drivers/AVR/SPI/examples/DigitalPotControl/DigitalPotControl.ino diff --git a/libraries/MySensors/drivers/SPI/keywords.txt b/libraries/MySensors/drivers/AVR/SPI/keywords.txt similarity index 100% rename from libraries/MySensors/drivers/SPI/keywords.txt rename to libraries/MySensors/drivers/AVR/SPI/keywords.txt diff --git a/libraries/MySensors/drivers/SPI/library.properties b/libraries/MySensors/drivers/AVR/SPI/library.properties similarity index 100% rename from libraries/MySensors/drivers/SPI/library.properties rename to libraries/MySensors/drivers/AVR/SPI/library.properties diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.cpp b/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.cpp new file mode 100644 index 0000000..dfd968a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.cpp @@ -0,0 +1,118 @@ +/* + EEPROM.cpp - esp8266 EEPROM emulation + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Arduino.h" +#include "EEPROM.h" + + extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "spi_flash.h" +} + +EEPROMClass::EEPROMClass(uint32_t sector) +: _sector(sector) +, _data(0) +, _size(0) +, _dirty(false) +{ +} + +void EEPROMClass::begin(size_t size) { + if (size <= 0) + return; + if (size > SPI_FLASH_SEC_SIZE) + size = SPI_FLASH_SEC_SIZE; + + if (_data) { + delete[] _data; + } + + _data = new uint8_t[size]; + _size = size; + + noInterrupts(); + spi_flash_read(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size); + interrupts(); +} + +void EEPROMClass::end() { + if (!_size) + return; + + commit(); + if(_data) { + delete[] _data; + } + _data = 0; + _size = 0; +} + + +uint8_t EEPROMClass::read(int address) { + if (address < 0 || (size_t)address >= _size) + return 0; + if(!_data) + return 0; + + return _data[address]; +} + +void EEPROMClass::write(int address, uint8_t value) { + if (address < 0 || (size_t)address >= _size) + return; + if(!_data) + return; + + _data[address] = value; + _dirty = true; +} + +bool EEPROMClass::commit() { + bool ret = false; + if (!_size) + return false; + if(!_dirty) + return true; + if(!_data) + return false; + + noInterrupts(); + if(spi_flash_erase_sector(_sector) == SPI_FLASH_RESULT_OK) { + if(spi_flash_write(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size) == SPI_FLASH_RESULT_OK) { + _dirty = false; + ret = true; + } + } + interrupts(); + + return ret; +} + +uint8_t * EEPROMClass::getDataPtr() { + _dirty = true; + return &_data[0]; +} + +extern "C" uint32_t _SPIFFS_end; +EEPROMClass EEPROM((((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE)); diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.h b/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.h new file mode 100644 index 0000000..ef7ac45 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/EEPROM.h @@ -0,0 +1,70 @@ +/* + EEPROM.cpp - esp8266 EEPROM emulation + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#include +#include +#include + +class EEPROMClass { +public: + EEPROMClass(uint32_t sector); + + void begin(size_t size); + uint8_t read(int address); + void write(int address, uint8_t val); + bool commit(); + void end(); + + uint8_t * getDataPtr(); + + template + T &get(int address, T &t) { + if (address < 0 || address + sizeof(T) > _size) + return t; + + memcpy((uint8_t*) &t, _data + address, sizeof(T)); + return t; + } + + template + const T &put(int address, const T &t) { + if (address < 0 || address + sizeof(T) > _size) + return t; + + memcpy(_data + address, (const uint8_t*) &t, sizeof(T)); + _dirty = true; + return t; + } + +protected: + uint32_t _sector; + uint8_t* _data; + size_t _size; + bool _dirty; +}; + +extern EEPROMClass EEPROM; + +#endif + diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_clear/eeprom_clear.ino b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 0000000..98b7ad7 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,26 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0. + * This example code is in the public domain. + + */ + +#include + +void setup() +{ + EEPROM.begin(512); + // write a 0 to all 512 bytes of the EEPROM + for (int i = 0; i < 512; i++) + EEPROM.write(i, 0); + + // turn the LED on when we're done + pinMode(13, OUTPUT); + digitalWrite(13, HIGH); + EEPROM.end(); +} + +void loop() +{ +} diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_read/eeprom_read.ino b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 0000000..d1395b3 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,44 @@ +/* + * EEPROM Read + * + * Reads the value of each byte of the EEPROM and prints it + * to the computer. + * This example code is in the public domain. + */ + +#include + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +byte value; + +void setup() +{ + // initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + EEPROM.begin(512); +} + +void loop() +{ + // read a byte from the current address of the EEPROM + value = EEPROM.read(address); + + Serial.print(address); + Serial.print("\t"); + Serial.print(value, DEC); + Serial.println(); + + // advance to the next address of the EEPROM + address = address + 1; + + // there are only 512 bytes of EEPROM, from 0 to 511, so if we're + // on address 512, wrap around to address 0 + if (address == 512) + address = 0; + + delay(500); +} diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_write/eeprom_write.ino b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 0000000..b41a5ca --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,43 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + */ + +#include + +// the current address in the EEPROM (i.e. which byte +// we're going to write to next) +int addr = 0; + +void setup() +{ + EEPROM.begin(512); +} + +void loop() +{ + // need to divide by 4 because analog inputs range from + // 0 to 1023 and each byte of the EEPROM can only hold a + // value from 0 to 255. + int val = analogRead(A0) / 4; + + // write the value to the appropriate byte of the EEPROM. + // these values will remain there when the board is + // turned off. + EEPROM.write(addr, val); + + // advance to the next address. there are 512 bytes in + // the EEPROM, so go back to 0 when we hit 512. + // save all changes to the flash. + addr = addr + 1; + if (addr == 512) + { + addr = 0; + EEPROM.commit(); + } + + delay(100); +} diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/keywords.txt b/libraries/MySensors/drivers/ESP8266/EEPROM/keywords.txt new file mode 100644 index 0000000..d3218fe --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/keywords.txt @@ -0,0 +1,18 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EEPROM KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/MySensors/drivers/ESP8266/EEPROM/library.properties b/libraries/MySensors/drivers/ESP8266/EEPROM/library.properties new file mode 100644 index 0000000..fbd9908 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/EEPROM/library.properties @@ -0,0 +1,8 @@ +name=EEPROM +version=1.0 +author=Ivan Grokhotkov +maintainer=Ivan Grokhotkov +sentence=Enables reading and writing data to the permanent FLASH storage, up to 4kb. +paragraph= +url=http://arduino.cc/en/Reference/EEPROM +architectures=esp8266 diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/NTPClient/NTPClient.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/NTPClient/NTPClient.ino new file mode 100644 index 0000000..4176c51 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/NTPClient/NTPClient.ino @@ -0,0 +1,153 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + updated for the ESP8266 12 Apr 2015 + by Ivan Grokhotkov + + This code is in the public domain. + + */ + +#include +#include + +char ssid[] = "*************"; // your network SSID (name) +char pass[] = "********"; // your network password + + +unsigned int localPort = 2390; // local port to listen for UDP packets + +/* Don't hardwire the IP address or we won't get the benefits of the pool. + * Lookup the IP address for the host name instead */ +//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server +IPAddress timeServerIP; // time.nist.gov NTP server address +const char* ntpServerName = "time.nist.gov"; + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP udp; + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println(); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, pass); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + Serial.println("Starting UDP"); + udp.begin(localPort); + Serial.print("Local port: "); + Serial.println(udp.localPort()); +} + +void loop() +{ + //get a random server from the pool + WiFi.hostByName(ntpServerName, timeServerIP); + + sendNTPpacket(timeServerIP); // send an NTP packet to a time server + // wait to see if a reply is available + delay(1000); + + int cb = udp.parsePacket(); + if (!cb) { + Serial.println("no packet yet"); + } + else { + Serial.print("packet received, length="); + Serial.println(cb); + // We've received a packet, read the data from it + udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = " ); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if ( ((epoch % 3600) / 60) < 10 ) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ( (epoch % 60) < 10 ) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) +{ + Serial.println("sending NTP packet..."); + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + udp.beginPacket(address, 123); //NTP requests are to port 123 + udp.write(packetBuffer, NTP_PACKET_SIZE); + udp.endPacket(); +} diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino new file mode 100644 index 0000000..1a11307 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Majenko Technologies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * * Neither the name of Majenko Technologies nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Create a WiFi access point and provide a web server on it. */ + +#include +#include +#include + +/* Set these to your desired credentials. */ +const char *ssid = "ESPap"; +const char *password = "thereisnospoon"; + +ESP8266WebServer server(80); + +/* Just a little test message. Go to http://192.168.4.1 in a web browser + * connected to this access point to see it. + */ +void handleRoot() { + server.send(200, "text/html", "

    You are connected

    "); +} + +void setup() { + delay(1000); + Serial.begin(115200); + Serial.println(); + Serial.print("Configuring access point..."); + /* You can remove the password parameter if you want the AP to be open. */ + WiFi.softAP(ssid, password); + + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); + server.on("/", handleRoot); + server.begin(); + Serial.println("HTTP server started"); +} + +void loop() { + server.handleClient(); +} diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino new file mode 100644 index 0000000..7ffc78a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino @@ -0,0 +1,85 @@ +/* + * This sketch sends data via HTTP GET requests to data.sparkfun.com service. + * + * You need to get streamId and privateKey at data.sparkfun.com and paste them + * below. Or just customize this script to talk to other HTTP servers. + * + */ + +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +const char* host = "data.sparkfun.com"; +const char* streamId = "...................."; +const char* privateKey = "...................."; + +void setup() { + Serial.begin(115200); + delay(10); + + // We start by connecting to a WiFi network + + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +int value = 0; + +void loop() { + delay(5000); + ++value; + + Serial.print("connecting to "); + Serial.println(host); + + // Use WiFiClient class to create TCP connections + WiFiClient client; + const int httpPort = 80; + if (!client.connect(host, httpPort)) { + Serial.println("connection failed"); + return; + } + + // We now create a URI for the request + String url = "/input/"; + url += streamId; + url += "?private_key="; + url += privateKey; + url += "&value="; + url += value; + + Serial.print("Requesting URL: "); + Serial.println(url); + + // This will send the request to the server + client.print(String("GET ") + url + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Connection: close\r\n\r\n"); + delay(10); + + // Read all the lines of the reply from server and print them to Serial + while(client.available()){ + String line = client.readStringUntil('\r'); + Serial.print(line); + } + + Serial.println(); + Serial.println("closing connection"); +} + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino new file mode 100644 index 0000000..7080325 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino @@ -0,0 +1,33 @@ +/* + * This sketch trys to Connect to the best AP based on a given list + * + */ + +#include +#include + +ESP8266WiFiMulti wifiMulti; + +void setup() { + Serial.begin(115200); + delay(10); + + wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); + wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); + wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); + + Serial.println("Connecting Wifi..."); + if(wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + } +} + +void loop() { + if(wifiMulti.run() != WL_CONNECTED) { + Serial.println("WiFi not connected!"); + delay(1000); + } +} \ No newline at end of file diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino new file mode 100644 index 0000000..3e6ff73 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino @@ -0,0 +1,48 @@ +/* + * This sketch demonstrates how to scan WiFi networks. + * The API is almost the same as with the WiFi Shield library, + * the most obvious difference being the different file you need to include: + */ +#include "ESP8266WiFi.h" + +void setup() { + Serial.begin(115200); + + // Set WiFi to station mode and disconnect from an AP if it was previously connected + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + + Serial.println("Setup done"); +} + +void loop() { + Serial.println("scan start"); + + // WiFi.scanNetworks will return the number of networks found + int n = WiFi.scanNetworks(); + Serial.println("scan done"); + if (n == 0) + Serial.println("no networks found"); + else + { + Serial.print(n); + Serial.println(" networks found"); + for (int i = 0; i < n; ++i) + { + // Print SSID and RSSI for each network found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*"); + delay(10); + } + } + Serial.println(""); + + // Wait a bit before scanning again + delay(5000); +} diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino new file mode 100644 index 0000000..43a9d82 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino @@ -0,0 +1,90 @@ +/* + WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the ESP8266WiFi library for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include + +//how many clients should be able to telnet to this ESP8266 +#define MAX_SRV_CLIENTS 1 +const char* ssid = "**********"; +const char* password = "**********"; + +WiFiServer server(21); +WiFiClient serverClients[MAX_SRV_CLIENTS]; + +void setup() { + Serial1.begin(115200); + WiFi.begin(ssid, password); + Serial1.print("\nConnecting to "); Serial1.println(ssid); + uint8_t i = 0; + while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500); + if(i == 21){ + Serial1.print("Could not connect to"); Serial1.println(ssid); + while(1) delay(500); + } + //start UART and the server + Serial.begin(115200); + server.begin(); + server.setNoDelay(true); + + Serial1.print("Ready! Use 'telnet "); + Serial1.print(WiFi.localIP()); + Serial1.println(" 21' to connect"); +} + +void loop() { + uint8_t i; + //check if there are any new clients + if (server.hasClient()){ + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + //find free/disconnected spot + if (!serverClients[i] || !serverClients[i].connected()){ + if(serverClients[i]) serverClients[i].stop(); + serverClients[i] = server.available(); + Serial1.print("New client: "); Serial1.print(i); + continue; + } + } + //no free/disconnected spot so reject + WiFiClient serverClient = server.available(); + serverClient.stop(); + } + //check clients for data + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + if(serverClients[i].available()){ + //get data from the telnet client and push it to the UART + while(serverClients[i].available()) Serial.write(serverClients[i].read()); + } + } + } + //check UART for data + if(Serial.available()){ + size_t len = Serial.available(); + uint8_t sbuf[len]; + Serial.readBytes(sbuf, len); + //push UART data to all connected telnet clients + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + serverClients[i].write(sbuf, len); + delay(1); + } + } + } +} diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino new file mode 100644 index 0000000..fa40678 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino @@ -0,0 +1,98 @@ +/* + * This sketch demonstrates how to set up a simple HTTP-like server. + * The server will set a GPIO pin depending on the request + * http://server_ip/gpio/0 will set the GPIO2 low, + * http://server_ip/gpio/1 will set the GPIO2 high + * server_ip is the IP address of the ESP8266 module, will be + * printed to Serial when the module is connected. + */ + +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +// Create an instance of the server +// specify the port to listen on as an argument +WiFiServer server(80); + +void setup() { + Serial.begin(115200); + delay(10); + + // prepare GPIO2 + pinMode(2, OUTPUT); + digitalWrite(2, 0); + + // Connect to WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + + // Start the server + server.begin(); + Serial.println("Server started"); + + // Print the IP address + Serial.println(WiFi.localIP()); +} + +void loop() { + // Check if a client has connected + WiFiClient client = server.available(); + if (!client) { + return; + } + + // Wait until the client sends some data + Serial.println("new client"); + while(!client.available()){ + delay(1); + } + + // Read the first line of the request + String req = client.readStringUntil('\r'); + Serial.println(req); + client.flush(); + + // Match the request + int val; + if (req.indexOf("/gpio/0") != -1) + val = 0; + else if (req.indexOf("/gpio/1") != -1) + val = 1; + else { + Serial.println("invalid request"); + client.stop(); + return; + } + + // Set GPIO2 according to the request + digitalWrite(2, val); + + client.flush(); + + // Prepare the response + String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\nGPIO is now "; + s += (val)?"high":"low"; + s += "\n"; + + // Send the response to the client + client.print(s); + delay(1); + Serial.println("Client disonnected"); + + // The client will actually be disconnected + // when the function returns and 'client' object is detroyed +} + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/keywords.txt b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/keywords.txt new file mode 100644 index 0000000..e693ea4 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/keywords.txt @@ -0,0 +1,67 @@ +####################################### +# Syntax Coloring Map For ESP8266WiFi +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +ESP8266WiFi KEYWORD3 + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WiFi KEYWORD1 +WiFiClient KEYWORD1 +WiFiServer KEYWORD1 +WiFiUDP KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +status KEYWORD2 +mode KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +config KEYWORD2 +setDNS KEYWORD2 +read KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +beginMulticast KEYWORD2 +disconnect KEYWORD2 +macAddress KEYWORD2 +localIP KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +SSID KEYWORD2 +BSSID KEYWORD2 +RSSI KEYWORD2 +encryptionType KEYWORD2 +beginPacket KEYWORD2 +beginPacketMulticast KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +destinationIP KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 +softAP KEYWORD2 +softAPIP KEYWORD2 +softAPmacAddress KEYWORD2 +softAPConfig KEYWORD2 +printDiag KEYWORD2 +hostByName KEYWORD2 +scanNetworks KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +WIFI_AP LITERAL1 +WIFI_STA LITERAL1 +WIFI_AP_STA LITERAL1 + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/library.properties b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/library.properties new file mode 100644 index 0000000..3db731e --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/library.properties @@ -0,0 +1,9 @@ +name=ESP8266WiFi +version=1.0 +author=Ivan Grokhotkov +maintainer=Ivan Grokhtkov +sentence=Enables network connection (local and Internet) using the ESP8266 built-in WiFi. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url= +architectures=esp8266 diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.cpp b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.cpp new file mode 100644 index 0000000..f65907f --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -0,0 +1,700 @@ +/* + ESP8266WiFi.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "ESP8266WiFi.h" +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" +#include "smartconfig.h" +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/dns.h" +} + +#include "WiFiClient.h" +#include "WiFiUdp.h" + +extern "C" void esp_schedule(); +extern "C" void esp_yield(); + +ESP8266WiFiClass::ESP8266WiFiClass() +: _smartConfigStarted(false) +, _smartConfigDone(false) +, _useApMode(false) +, _useClientMode(false) +, _useStaticIp(false) +{ + wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback); +} + +void ESP8266WiFiClass::mode(WiFiMode m) +{ + if(wifi_get_opmode() == (uint8)m) { + return; + } + ETS_UART_INTR_DISABLE(); + wifi_set_opmode(m); + ETS_UART_INTR_ENABLE(); +} + +int ESP8266WiFiClass::begin(char* ssid, char *passphrase, int32_t channel, uint8_t bssid[6]){ + return begin((const char*) ssid, (const char*) passphrase, channel, bssid); +} + +int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t channel, uint8_t bssid[6]){ + _useClientMode = true; + + if(_useApMode) { + // turn on AP+STA mode + mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_STA); + } + + if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { + // fail SSID to long or missing! + return WL_CONNECT_FAILED; + } + + if(passphrase && strlen(passphrase) > 63) { + // fail passphrase to long! + return WL_CONNECT_FAILED; + } + + struct station_config conf; + strcpy(reinterpret_cast(conf.ssid), ssid); + + if (passphrase) { + strcpy(reinterpret_cast(conf.password), passphrase); + } else { + *conf.password = 0; + } + + if (bssid) { + conf.bssid_set = 1; + memcpy((void *) &conf.bssid[0], (void *) bssid, 6); + } else { + conf.bssid_set = 0; + } + + ETS_UART_INTR_DISABLE(); + wifi_station_set_config(&conf); + wifi_station_connect(); + ETS_UART_INTR_ENABLE(); + + if(channel > 0 && channel <= 13) { + wifi_set_channel(channel); + } + + if(!_useStaticIp) + wifi_station_dhcpc_start(); + return status(); +} + +uint8_t ESP8266WiFiClass::waitForConnectResult(){ + if ((wifi_get_opmode() & 1) == 0)//1 and 3 have STA enabled + return WL_DISCONNECTED; + while (status() == WL_DISCONNECTED) + delay(100); + return status(); +} + + +// You will have to set the DNS-Server manually later since this will not enable DHCP2 +void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) +{ + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + + wifi_station_dhcpc_stop(); + wifi_set_ip_info(STATION_IF, &info); + + _useStaticIp = true; +} + +void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns) +{ + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + + wifi_station_dhcpc_stop(); + wifi_set_ip_info(STATION_IF, &info); + + // Set DNS-Server + ip_addr_t d; + d.addr = static_cast(dns); + dns_setserver(0,&d); + + _useStaticIp = true; +} + +int ESP8266WiFiClass::disconnect() +{ + struct station_config conf; + *conf.ssid = 0; + *conf.password = 0; + ETS_UART_INTR_DISABLE(); + wifi_station_set_config(&conf); + wifi_station_disconnect(); + ETS_UART_INTR_ENABLE(); + return 0; +} + +void ESP8266WiFiClass::softAP(const char* ssid) +{ + softAP(ssid, 0); +} + + +void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden) +{ + _useApMode = true; + if(_useClientMode) { + // turn on AP+STA mode + mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_AP); + } + + if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { + // fail SSID to long or missing! + return; + } + + if(passphrase && strlen(passphrase) > 63) { + // fail passphrase to long! + return; + } + + struct softap_config conf; + wifi_softap_get_config(&conf); + strcpy(reinterpret_cast(conf.ssid), ssid); + conf.channel = channel; + conf.ssid_len = strlen(ssid); + conf.ssid_hidden = ssid_hidden; + conf.max_connection = 4; + conf.beacon_interval = 100; + + if (!passphrase || strlen(passphrase) == 0) + { + conf.authmode = AUTH_OPEN; + *conf.password = 0; + } + else + { + conf.authmode = AUTH_WPA2_PSK; + strcpy(reinterpret_cast(conf.password), passphrase); + } + + ETS_UART_INTR_DISABLE(); + wifi_softap_set_config(&conf); + ETS_UART_INTR_ENABLE(); +} + +void ESP8266WiFiClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) +{ + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + wifi_softap_dhcps_stop(); + wifi_set_ip_info(SOFTAP_IF, &info); + wifi_softap_dhcps_start(); +} + +uint8_t* ESP8266WiFiClass::macAddress(uint8_t* mac) +{ + wifi_get_macaddr(STATION_IF, mac); + return mac; +} + +String ESP8266WiFiClass::macAddress(void) +{ + uint8_t mac[6]; + char macStr[18] = {0}; + wifi_get_macaddr(STATION_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + +uint8_t* ESP8266WiFiClass::softAPmacAddress(uint8_t* mac) +{ + wifi_get_macaddr(SOFTAP_IF, mac); + return mac; +} + +String ESP8266WiFiClass::softAPmacAddress(void) +{ + uint8_t mac[6]; + char macStr[18] = {0}; + wifi_get_macaddr(SOFTAP_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + +IPAddress ESP8266WiFiClass::localIP() +{ + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.ip.addr); +} + +IPAddress ESP8266WiFiClass::softAPIP() +{ + struct ip_info ip; + wifi_get_ip_info(SOFTAP_IF, &ip); + return IPAddress(ip.ip.addr); +} + +IPAddress ESP8266WiFiClass::subnetMask() +{ + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.netmask.addr); +} + +IPAddress ESP8266WiFiClass::gatewayIP() +{ + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.gw.addr); +} + +char* ESP8266WiFiClass::SSID() +{ + static struct station_config conf; + wifi_station_get_config(&conf); + return reinterpret_cast(conf.ssid); +} + +uint8_t* ESP8266WiFiClass::BSSID(void) +{ + static struct station_config conf; + wifi_station_get_config(&conf); + return reinterpret_cast(conf.bssid); +} + +String ESP8266WiFiClass::BSSIDstr(void) +{ + static struct station_config conf; + char mac[18] = {0}; + wifi_station_get_config(&conf); + sprintf(mac,"%02X:%02X:%02X:%02X:%02X:%02X", conf.bssid[0], conf.bssid[1], conf.bssid[2], conf.bssid[3], conf.bssid[4], conf.bssid[5]); + return String(mac); +} + + +int32_t ESP8266WiFiClass::channel(void) { + return wifi_get_channel(); +} + + +int32_t ESP8266WiFiClass::RSSI(void) { + return wifi_station_get_rssi(); +} + +extern "C" +{ + typedef STAILQ_HEAD(, bss_info) bss_info_head_t; +} + +void ESP8266WiFiClass::_scanDone(void* result, int status) +{ + if (status != OK) + { + ESP8266WiFiClass::_scanCount = 0; + ESP8266WiFiClass::_scanResult = 0; + } + else + { + + int i = 0; + bss_info_head_t* head = reinterpret_cast(result); + + for (bss_info* it = STAILQ_FIRST(head); it; it = STAILQ_NEXT(it, next), ++i); + ESP8266WiFiClass::_scanCount = i; + if (i == 0) + { + ESP8266WiFiClass::_scanResult = 0; + } + else + { + bss_info* copied_info = new bss_info[i]; + i = 0; + for (bss_info* it = STAILQ_FIRST(head); it; it = STAILQ_NEXT(it, next), ++i) + { + memcpy(copied_info + i, it, sizeof(bss_info)); + } + + ESP8266WiFiClass::_scanResult = copied_info; + } + + } + + ESP8266WiFiClass::_scanStarted = false; + ESP8266WiFiClass::_scanComplete = true; + + if(!ESP8266WiFiClass::_scanAsync) { + esp_schedule(); + } +} + +int8_t ESP8266WiFiClass::scanComplete() { + + if(_scanStarted) { + return WIFI_SCAN_RUNNING; + } + + if(_scanComplete) { + return ESP8266WiFiClass::_scanCount; + } + + return WIFI_SCAN_FAILD; +} + +void ESP8266WiFiClass::scanDelete() +{ + if (ESP8266WiFiClass::_scanResult) + { + delete[] reinterpret_cast(ESP8266WiFiClass::_scanResult); + ESP8266WiFiClass::_scanResult = 0; + ESP8266WiFiClass::_scanCount = 0; + } + _scanComplete = false; +} + +int8_t ESP8266WiFiClass::scanNetworks(bool async) +{ + if(ESP8266WiFiClass::_scanStarted) { + return WIFI_SCAN_RUNNING; + } + + ESP8266WiFiClass::_scanAsync = async; + + if(_useApMode) { + // turn on AP+STA mode + mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_STA); + } + + int status = wifi_station_get_connect_status(); + if (status != STATION_GOT_IP && status != STATION_IDLE) + { + disconnect(); + } + + scanDelete(); + + struct scan_config config; + config.ssid = 0; + config.bssid = 0; + config.channel = 0; + config.show_hidden = 0; + if(wifi_station_scan(&config, reinterpret_cast(&ESP8266WiFiClass::_scanDone))) { + ESP8266WiFiClass::_scanComplete = false; + ESP8266WiFiClass::_scanStarted = true; + + if(ESP8266WiFiClass::_scanAsync) { + delay(0); // time for the OS to trigger the scan + return WIFI_SCAN_RUNNING; + } + + esp_yield(); + return ESP8266WiFiClass::_scanCount; + } else { + return WIFI_SCAN_FAILD; + } + +} + +void * ESP8266WiFiClass::_getScanInfoByIndex(int i) +{ + if (!ESP8266WiFiClass::_scanResult || (size_t)i > ESP8266WiFiClass::_scanCount) + { + return 0; + } + + return reinterpret_cast(ESP8266WiFiClass::_scanResult) + i; +} + +const char* ESP8266WiFiClass::SSID(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return 0; + + return reinterpret_cast(it->ssid); +} + +uint8_t * ESP8266WiFiClass::BSSID(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return 0; + + return it->bssid; +} + +String ESP8266WiFiClass::BSSIDstr(uint8_t i) +{ + char mac[18] = {0}; + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return String(""); + + sprintf(mac,"%02X:%02X:%02X:%02X:%02X:%02X", it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]); + return String(mac); +} + +int32_t ESP8266WiFiClass::channel(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return 0; + + return it->channel; +} + +bool ESP8266WiFiClass::isHidden(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return false; + + return (it->is_hidden != 0); +} + +bool ESP8266WiFiClass::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &isHidden) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return false; + + ssid = (const char*)it->ssid; + encType = encryptionType(i); + rssi = it->rssi; + bssid = it->bssid; // move ptr + channel = it->channel; + isHidden = (it->is_hidden != 0); + + return true; +} + +int32_t ESP8266WiFiClass::RSSI(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return 0; + + return it->rssi; +} + +uint8_t ESP8266WiFiClass::encryptionType(uint8_t i) +{ + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if (!it) + return -1; + + int authmode = it->authmode; + if (authmode == AUTH_OPEN) + return ENC_TYPE_NONE; + if (authmode == AUTH_WEP) + return ENC_TYPE_WEP; + if (authmode == AUTH_WPA_PSK) + return ENC_TYPE_TKIP; + if (authmode == AUTH_WPA2_PSK) + return ENC_TYPE_CCMP; + if (authmode == AUTH_WPA_WPA2_PSK) + return ENC_TYPE_AUTO; + return -1; +} + +wl_status_t ESP8266WiFiClass::status() +{ + int status = wifi_station_get_connect_status(); + + if (status == STATION_GOT_IP) + return WL_CONNECTED; + else if (status == STATION_NO_AP_FOUND) + return WL_NO_SSID_AVAIL; + else if (status == STATION_CONNECT_FAIL || status == STATION_WRONG_PASSWORD) + return WL_CONNECT_FAILED; + else if (status == STATION_IDLE) + return WL_IDLE_STATUS; + else + return WL_DISCONNECTED; +} + +void wifi_dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg) +{ + if (ipaddr) + (*reinterpret_cast(callback_arg)) = ipaddr->addr; + esp_schedule(); // resume the hostByName function +} + +int ESP8266WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + ip_addr_t addr; + aResult = static_cast(0); + err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult); + if (err == ERR_OK) + { + aResult = addr.addr; + } + else if (err == ERR_INPROGRESS) + { + esp_yield(); + // will return here when dns_found_callback fires + } + + return (aResult != 0) ? 1 : 0; +} + +void ESP8266WiFiClass::beginSmartConfig() +{ + if (_smartConfigStarted) + return; + + if(_useApMode) { + // turn on AP+STA mode + mode(WIFI_AP_STA); + } else { + // turn on STA mode + mode(WIFI_STA); + } + + _smartConfigStarted = true; + _smartConfigDone = false; + + //SC_TYPE_ESPTOUCH use ESPTOUCH for smartconfig, or use SC_TYPE_AIRKISS for AIRKISS + smartconfig_start(SC_TYPE_ESPTOUCH, reinterpret_cast(&ESP8266WiFiClass::_smartConfigCallback), 1); +} + +void ESP8266WiFiClass::stopSmartConfig() +{ + if (!_smartConfigStarted) + return; + + smartconfig_stop(); + _smartConfigStarted = false; +} + +bool ESP8266WiFiClass::smartConfigDone() +{ + if (!_smartConfigStarted) + return false; + + return _smartConfigDone; +} + +void ESP8266WiFiClass::_smartConfigCallback(uint32_t st, void* result) +{ + sc_status status = (sc_status) st; + if (status == SC_STATUS_LINK) { + station_config* sta_conf = reinterpret_cast(result); + + wifi_station_set_config(sta_conf); + wifi_station_disconnect(); + wifi_station_connect(); + + WiFi._smartConfigDone = true; + } + else if (status == SC_STATUS_LINK_OVER) { + WiFi.stopSmartConfig(); + } +} + +void ESP8266WiFiClass::_eventCallback(void* arg) +{ + System_Event_t* event = reinterpret_cast(arg); + DEBUGV("wifi evt: %d\r\n", event->event); + + if (event->event == EVENT_STAMODE_DISCONNECTED) { + WiFiClient::stopAll(); + WiFiUDP::stopAll(); + } +} + +void ESP8266WiFiClass::printDiag(Print& p) +{ + const char* modes[] = {"NULL", "STA", "AP", "STA+AP"}; + p.print("Mode: "); + p.println(modes[wifi_get_opmode()]); + + const char* phymodes[] = {"", "B", "G", "N"}; + p.print("PHY mode: "); + p.println(phymodes[(int) wifi_get_phy_mode()]); + + p.print("Channel: "); + p.println(wifi_get_channel()); + + p.print("AP id: "); + p.println(wifi_station_get_current_ap_id()); + + p.print("Status: "); + p.println(wifi_station_get_connect_status()); + + p.print("Auto connect: "); + p.println(wifi_station_get_auto_connect()); + + static struct station_config conf; + wifi_station_get_config(&conf); + + const char* ssid = reinterpret_cast(conf.ssid); + p.print("SSID ("); + p.print(strlen(ssid)); + p.print("): "); + p.println(ssid); + + const char* passphrase = reinterpret_cast(conf.password); + p.print("Passphrase ("); + p.print(strlen(passphrase)); + p.print("): "); + p.println(passphrase); + + p.print("BSSID set: "); + p.println(conf.bssid_set); + +} + +bool ESP8266WiFiClass::_scanAsync = false; +bool ESP8266WiFiClass::_scanStarted = false; +bool ESP8266WiFiClass::_scanComplete = false; + +size_t ESP8266WiFiClass::_scanCount = 0; +void* ESP8266WiFiClass::_scanResult = 0; + + +ESP8266WiFiClass WiFi; diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.h new file mode 100644 index 0000000..bd4502b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFi.h @@ -0,0 +1,353 @@ +/* + ESP8266WiFi.h - esp8266 Wifi support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_h +#define WiFi_h + +#include + +extern "C" { + #include "include/wl_definitions.h" +} + +#include "IPAddress.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +#define WIFI_SCAN_RUNNING (-1) +#define WIFI_SCAN_FAILD (-2) + +enum WiFiMode { WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3 }; + +class ESP8266WiFiClass +{ +public: + + ESP8266WiFiClass(); + + void mode(WiFiMode); + + /** + * Start Wifi connection + * if passphrase is set the most secure supported mode will be automatically selected + * @param ssid const char* Pointer to the SSID string. + * @param passphrase const char * Optional. Passphrase. Valid characters in a passphrase must be between ASCII 32-126 (decimal). + * @param bssid uint8_t[6] Optional. BSSID / MAC of AP + * @param channel Optional. Channel of AP + * @return + */ + int begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, uint8_t bssid[6] = NULL); + int begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, uint8_t bssid[6] = NULL); + + + /* Wait for Wifi connection to reach a result + * returns the status reached or disconnect if STA is off + */ + uint8_t waitForConnectResult(); + + /* Set up an open access point + * + * param ssid: Pointer to the SSID string. + */ + void softAP(const char* ssid); + + + /* Set up a WPA2-secured access point + * + * param ssid: Pointer to the SSID string. + * param passphrase: Pointer to passphrase, 8 characters min. + * param channel: WiFi channel number, 1 - 13. + * param ssid_hidden: Network cloaking? 0 = broadcast SSID, 1 = hide SSID + */ + void softAP(const char* ssid, const char* passphrase, int channel = 1, int ssid_hidden = 0); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param gateway: Static gateway configuration + * param subnet: Static Subnet mask + */ + void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param gateway: Static gateway configuration + * param subnet: Static Subnet mask + * param dns: Defined DNS + */ + void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns); + + /* Configure access point + * + * param local_ip: access point IP + * param gateway: gateway IP + * param subnet: subnet mask + */ + void softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet); + + /* + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + int disconnect(void); + + /* + * Get the station interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * return: String + */ + uint8_t* macAddress(uint8_t* mac); + String macAddress(void); + + /* + * Get the softAP interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * return: String + */ + uint8_t* softAPmacAddress(uint8_t* mac); + String softAPmacAddress(void); + + /* + * Get the station interface IP address. + * + * return: Ip address value + */ + IPAddress localIP(); + + /* + * Get the softAP interface IP address. + * + * return: Ip address value + */ + IPAddress softAPIP(); + + /* + * Get the interface subnet mask address. + * + * return: subnet mask address value + */ + IPAddress subnetMask(); + + /* + * Get the gateway ip address. + * + * return: gateway ip address value + */ + IPAddress gatewayIP(); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + char* SSID(); + + /* + * Return the current bssid / mac associated with the network if configured + * + * return: bssid uint8_t * + */ + uint8_t * BSSID(void); + + /* + * Return the current bssid / mac associated with the network if configured + * + * return: bssid string + */ + String BSSIDstr(void); + + /* + * Return the current channel associated with the network + * + * return: channel + */ + int32_t channel(void); + + /* + * Return the current network RSSI. + * + * return: RSSI value + */ + + int32_t RSSI(); + + + /* + * called to get the scan state in Async mode + * + * return -1 if scan not fin + * return -2 if scan not triggered + */ + int8_t scanComplete(); + + /* + * delete last scan result from RAM + */ + void scanDelete(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + int8_t scanNetworks(bool async = false); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + const char* SSID(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + uint8_t encryptionType(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + int32_t RSSI(uint8_t networkItem); + + + /** + * return MAC / BSSID of scanned wifi + * @param networkItem specify from which network item want to get the information + * @return uint8_t * MAC / BSSID of scanned wifi + */ + uint8_t * BSSID(uint8_t networkItem); + + /** + * return MAC / BSSID of scanned wifi + * @param networkItem specify from which network item want to get the information + * @return String MAC / BSSID of scanned wifi + */ + String BSSIDstr(uint8_t networkItem); + + /** + * return channel of scanned wifi + * @param networkItem specify from which network item want to get the information + * @return uint32_t channel of scanned wifi + */ + int32_t channel(uint8_t networkItem); + + /** + * return if the scanned wifi is Hidden (no SSID) + * @param networkItem specify from which network item want to get the information + * @return bool (true == hidden) + */ + bool isHidden(uint8_t networkItem); + + /** + * loads all infos from a scanned wifi in to the ptr parameters + * @param networkItem uint8_t + * @param ssid const char** + * @param encryptionType uint8_t * + * @param RSSI int32_t * + * @param BSSID uint8_t ** + * @param channel int32_t * + * @param isHidden bool * + * @return (true if ok) + */ + bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden); + + + /* + * Return Connection status. + * + * return: one of the value defined in wl_status_t + */ + wl_status_t status(); + + /* + * Resolve the given hostname to an IP address. + * param aHostname: Name to be resolved + * param aResult: IPAddress structure to store the returned IP address + * result: 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ + int hostByName(const char* aHostname, IPAddress& aResult); + + /* + * Output WiFi settings to an object derived from Print interface (like Serial). + * + */ + void printDiag(Print& dest); + + /* + * Start SmartConfig + * + */ + void beginSmartConfig(); + + /* + * Query SmartConfig status, to decide when stop config + * + */ + bool smartConfigDone(); + + /* + * Stop SmartConfig + * + */ + void stopSmartConfig(); + + friend class WiFiClient; + friend class WiFiServer; + +protected: + static void _scanDone(void* result, int status); + void * _getScanInfoByIndex(int i); + static void _smartConfigCallback(uint32_t status, void* result); + static void _eventCallback(void *event); + bool _smartConfigStarted; + bool _smartConfigDone; + + bool _useApMode; + bool _useClientMode; + bool _useStaticIp; + + static bool _scanAsync; + static bool _scanStarted; + static bool _scanComplete; + + static size_t _scanCount; + static void* _scanResult; + +}; + +extern ESP8266WiFiClass WiFi; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.cpp new file mode 100644 index 0000000..edf2c21 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -0,0 +1,207 @@ +/** + * + * @file ESP8266WiFiMulti.cpp + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "ESP8266WiFiMulti.h" +#include +#include + +ESP8266WiFiMulti::ESP8266WiFiMulti() { +} + +ESP8266WiFiMulti::~ESP8266WiFiMulti() { + APlistClean(); +} + +bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) { + return APlistAdd(ssid, passphrase); +} + +wl_status_t ESP8266WiFiMulti::run(void) { + + int8_t scanResult; + wl_status_t status = WiFi.status(); + if(status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) { + + scanResult = WiFi.scanComplete(); + if(scanResult == WIFI_SCAN_RUNNING) { + // scan is running + return WL_NO_SSID_AVAIL; + } else if(scanResult > 0) { + // scan done analyze + WifiAPlist_t bestNetwork { NULL, NULL }; + int bestNetworkDb = INT_MIN; + uint8 bestBSSID[6]; + int32_t bestChannel; + + DEBUG_WIFI_MULTI("[WIFI] scan done\n"); + delay(0); + + if(scanResult <= 0) { + DEBUG_WIFI_MULTI("[WIFI] no networks found\n"); + } else { + DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", scanResult); + for(int8_t i = 0; i < scanResult; ++i) { + + String ssid_scan; + int32_t rssi_scan; + uint8_t sec_scan; + uint8_t* BSSID_scan; + int32_t chan_scan; + bool hidden_scan; + + WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan); + + bool known = false; + for(uint32_t x = 0; x < APlist.size(); x++) { + WifiAPlist_t entry = APlist[x]; + + if(ssid_scan == entry.ssid) { // SSID match + known = true; + if(rssi_scan > bestNetworkDb) { // best network + if(sec_scan == ENC_TYPE_NONE || entry.passphrase) { // check for passphrase if not open wlan + bestNetworkDb = rssi_scan; + bestChannel = chan_scan; + memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork)); + memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID)); + } + } + break; + } + } + + if(known) { + DEBUG_WIFI_MULTI(" ---> "); + } else { + DEBUG_WIFI_MULTI(" "); + } + + DEBUG_WIFI_MULTI(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c\n", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*'); + delay(0); + } + } + + // clean up ram + WiFi.scanDelete(); + + DEBUG_WIFI_MULTI("\n\n"); + delay(0); + + if(bestNetwork.ssid) { + DEBUG_WIFI_MULTI("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channal: %d (%d)\n", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb); + + WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID); + status = WiFi.status(); + + // wait for connection or fail + while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED) { + delay(10); + status = WiFi.status(); + } + + IPAddress ip; + uint8_t * mac; + switch(status) { + case WL_CONNECTED: + ip = WiFi.localIP(); + mac = WiFi.BSSID(); + DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n"); + DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID()); + DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + DEBUG_WIFI_MULTI("[WIFI] MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DEBUG_WIFI_MULTI("[WIFI] Channel: %d\n", WiFi.channel()); + break; + case WL_NO_SSID_AVAIL: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild AP not found.\n"); + break; + case WL_CONNECT_FAILED: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild.\n"); + break; + default: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild (%d).\n", status); + break; + } + } else { + DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n"); + } + } else { + // start scan + DEBUG_WIFI_MULTI("[WIFI] delete old wifi config...\n"); + WiFi.disconnect(); + + DEBUG_WIFI_MULTI("[WIFI] start scan\n"); + // scan wifi async mode + WiFi.scanNetworks(true); + } + } + return status; +} + +// ################################################################################## + +bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { + + WifiAPlist_t newAP; + + if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { + // fail SSID to long or missing! + return false; + } + + if(passphrase && strlen(passphrase) > 63) { + // fail passphrase to long! + return false; + } + + newAP.ssid = strdup(ssid); + + if(!newAP.ssid) { + return false; + } + + if(passphrase && *passphrase != 0x00) { + newAP.passphrase = strdup(passphrase); + if(!newAP.passphrase) { + free(newAP.ssid); + return false; + } + } + + APlist.push_back(newAP); + return true; +} + +void ESP8266WiFiMulti::APlistClean(void) { + for(uint32_t i = 0; i < APlist.size(); i++) { + WifiAPlist_t entry = APlist[i]; + if(entry.ssid) { + free(entry.ssid); + } + if(entry.passphrase) { + free(entry.passphrase); + } + } + APlist.clear(); +} + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.h new file mode 100644 index 0000000..dbfbbb7 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -0,0 +1,62 @@ +/** + * + * @file ESP8266WiFiMulti.h + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef WIFICLIENTMULTI_H_ +#define WIFICLIENTMULTI_H_ + +#include "ESP8266WiFi.h" +#undef min +#undef max +#include + +//#define DEBUG_WIFI_MULTI(...) Serial1.printf( __VA_ARGS__ ) + +#ifndef DEBUG_WIFI_MULTI +#define DEBUG_WIFI_MULTI(...) +#endif + +typedef struct { + char * ssid; + char * passphrase; +} WifiAPlist_t; + +class ESP8266WiFiMulti { + public: + ESP8266WiFiMulti(); + ~ESP8266WiFiMulti(); + + bool addAP(const char* ssid, const char *passphrase = NULL); + + wl_status_t run(void); + + private: + std::vector APlist; + bool APlistAdd(const char* ssid, const char *passphrase = NULL); + void APlistClean(void); + +}; + +#endif /* WIFICLIENTMULTI_H_ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.cpp b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.cpp new file mode 100644 index 0000000..9117a41 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.cpp @@ -0,0 +1,290 @@ +/* + WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define LWIP_INTERNAL + +extern "C" +{ + #include "include/wl_definitions.h" + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "cbuf.h" +#include "include/ClientContext.h" +#include "c_types.h" + +uint16_t WiFiClient::_localPort = 0; + +template<> +WiFiClient* SList::_s_first = 0; + + +WiFiClient::WiFiClient() +: _client(0) +{ + WiFiClient::_add(this); +} + +WiFiClient::WiFiClient(ClientContext* client) : _client(client) +{ + _client->ref(); + WiFiClient::_add(this); +} + +WiFiClient::~WiFiClient() +{ + WiFiClient::_remove(this); + if (_client) + _client->unref(); +} + +WiFiClient::WiFiClient(const WiFiClient& other) +{ + _client = other._client; + if (_client) + _client->ref(); + WiFiClient::_add(this); +} + +WiFiClient& WiFiClient::operator=(const WiFiClient& other) +{ + if (_client) + _client->unref(); + _client = other._client; + if (_client) + _client->ref(); + return *this; +} + + +int WiFiClient::connect(const char* host, uint16_t port) +{ + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) +{ + ip_addr_t addr; + addr.addr = ip; + + if (_client) + stop(); + + // if the default interface is down, tcp_connect exits early without + // ever calling tcp_err + // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html + netif* interface = ip_route(&addr); + if (!interface) { + DEBUGV("no route to host\r\n"); + return 1; + } + + tcp_pcb* pcb = tcp_new(); + if (!pcb) + return 0; + + if (_localPort > 0) { + pcb->local_port = _localPort++; + } + + tcp_arg(pcb, this); + tcp_err(pcb, &WiFiClient::_s_err); + tcp_connect(pcb, &addr, port, reinterpret_cast(&WiFiClient::_s_connected)); + + esp_yield(); + if (_client) + return 1; + + // if tcp_error was called, pcb has already been destroyed. + // tcp_abort(pcb); + return 0; +} + +int8_t WiFiClient::_connected(void* pcb, int8_t err) +{ + tcp_pcb* tpcb = reinterpret_cast(pcb); + _client = new ClientContext(tpcb, 0, 0); + _client->ref(); + esp_schedule(); + return ERR_OK; +} + +void WiFiClient::_err(int8_t err) +{ + DEBUGV(":err %d\r\n", err); + esp_schedule(); +} + + +void WiFiClient::setNoDelay(bool nodelay) { + if (!_client) + return; + _client->setNoDelay(nodelay); +} + +bool WiFiClient::getNoDelay() { + if (!_client) + return false; + return _client->getNoDelay(); +} + +size_t WiFiClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) +{ + if (!_client || !size) + { + return 0; + } + + return _client->write(reinterpret_cast(buf), size); +} + +extern "C" uint32_t esp_micros_at_task_start(); + +int WiFiClient::available() +{ + static uint32_t lastPollTime = 0; + if (!_client) + return 0; + + if (lastPollTime > esp_micros_at_task_start()) + yield(); + + lastPollTime = micros(); + + int result = _client->getSize(); + return result; +} + +int WiFiClient::read() +{ + if (!available()) + return -1; + + return _client->read(); +} + + +int WiFiClient::read(uint8_t* buf, size_t size) +{ + return (int) _client->read(reinterpret_cast(buf), size); +} + +int WiFiClient::peek() +{ + if (!available()) + return -1; + + return _client->peek(); +} + +void WiFiClient::flush() +{ + if (_client) + _client->flush(); +} + +void WiFiClient::stop() +{ + if (!_client) + return; + + _client->unref(); + _client = 0; +} + +uint8_t WiFiClient::connected() +{ + if (!_client) + return 0; + + return _client->state() == ESTABLISHED || available(); +} + +uint8_t WiFiClient::status() +{ + if (!_client) + return CLOSED; + return _client->state(); +} + + WiFiClient::operator bool() +{ + return _client != 0; +} + +IPAddress WiFiClient::remoteIP() +{ + if (!_client) + return IPAddress(0U); + + return IPAddress(_client->getRemoteAddress()); +} + +uint16_t WiFiClient::remotePort() +{ + if (!_client) + return 0; + + return _client->getRemotePort(); +} + +int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err) +{ + return reinterpret_cast(arg)->_connected(tpcb, err); +} + +void WiFiClient::_s_err(void* arg, int8_t err) +{ + reinterpret_cast(arg)->_err(err); +} + +void WiFiClient::stopAll() +{ + for (WiFiClient* it = _s_first; it; it = it->_next) { + ClientContext* c = it->_client; + if (c) { + c->abort(); + c->unref(); + it->_client = 0; + } + } +} diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.h new file mode 100644 index 0000000..161ca0b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiClient.h @@ -0,0 +1,127 @@ +/* + WiFiClient.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, December 2014 - esp8266 support +*/ + +#ifndef wificlient_h +#define wificlient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" +#include +#include "include/slist.h" + +class ClientContext; +class WiFiServer; + +class WiFiClient : public Client, public SList { +protected: + WiFiClient(ClientContext* client); + +public: + WiFiClient(); + virtual ~WiFiClient(); + WiFiClient(const WiFiClient&); + WiFiClient& operator=(const WiFiClient&); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + template + size_t write(T& source, size_t unitSize); + + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + IPAddress remoteIP(); + uint16_t remotePort(); + bool getNoDelay(); + void setNoDelay(bool nodelay); + static void setLocalPortStart(uint16_t port) { _localPort = port; } + + template size_t write(T &src){ + uint8_t obuf[1460]; + size_t doneLen = 0; + size_t sentLen; + int i; + + while (src.available() > 1460){ + src.read(obuf, 1460); + sentLen = write(obuf, 1460); + doneLen = doneLen + sentLen; + if(sentLen != 1460){ + return doneLen; + } + } + + uint16_t leftLen = src.available(); + src.read(obuf, leftLen); + sentLen = write(obuf, leftLen); + doneLen = doneLen + sentLen; + return doneLen; + } + + friend class WiFiServer; + + using Print::write; + + static void stopAll(); + +private: + + static int8_t _s_connected(void* arg, void* tpcb, int8_t err); + static void _s_err(void* arg, int8_t err); + + int8_t _connected(void* tpcb, int8_t err); + void _err(int8_t err); + + ClientContext* _client; + static uint16_t _localPort; +}; + + +template +inline size_t WiFiClient::write(T& source, size_t unitSize) { + std::unique_ptr buffer(new uint8_t[unitSize]); + size_t size_sent = 0; + while(true) { + size_t left = source.available(); + if (!left) + break; + size_t will_send = (left < unitSize) ? left : unitSize; + source.read(buffer.get(), will_send); + size_t cb = write(buffer.get(), will_send); + size_sent += cb; + if (cb != will_send) { + break; + } + } + return size_sent; +} + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.cpp b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.cpp new file mode 100644 index 0000000..69ad4ff --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.cpp @@ -0,0 +1,170 @@ +/* + WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#define LWIP_INTERNAL + +extern "C" { + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "lwip/opt.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "cbuf.h" +#include "include/ClientContext.h" + +WiFiServer::WiFiServer(uint16_t port) +{ + _port = port; + _pcb = 0; + _unclaimed = 0; + _discarded = 0; +} + +void WiFiServer::begin() +{ + err_t err; + + tcp_pcb* pcb = tcp_new(); + if (!pcb) + return; + + err = tcp_bind(pcb, INADDR_ANY, _port); + + if (err != ERR_OK) + { + tcp_close(pcb); + return; + } + + tcp_pcb* listen_pcb = tcp_listen(pcb); + if (!listen_pcb) + { + tcp_close(pcb); + return; + } + _pcb = listen_pcb; + tcp_accept(listen_pcb, &WiFiServer::_s_accept); + tcp_arg(listen_pcb, (void*) this); +} + +void WiFiServer::setNoDelay(bool nodelay){ + if(!_pcb) return; + if(nodelay) tcp_nagle_disable(_pcb); + else tcp_nagle_enable(_pcb); +} + +bool WiFiServer::getNoDelay(){ + if(!_pcb) return false; + return tcp_nagle_disabled(_pcb); +} + +extern "C" uint32_t esp_micros_at_task_start(); + +bool WiFiServer::hasClient(){ + if (_unclaimed) return true; + return false; +} + +WiFiClient WiFiServer::available(byte* status) +{ + static uint32_t lastPollTime = 0; + + if (_unclaimed) + { + WiFiClient result(_unclaimed); + _unclaimed = _unclaimed->next(); + DEBUGV("WS:av\r\n"); + return result; + } + + if (lastPollTime > esp_micros_at_task_start()) + yield(); + lastPollTime = micros(); + + return WiFiClient(); +} + +uint8_t WiFiServer::status() { + if (!_pcb) + return CLOSED; + return _pcb->state; +} + + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + // write to all clients + // not implemented + return 0; +} + +template +T* slist_append_tail(T* head, T* item) +{ + if (!head) + return item; + T* last = head; + while(last->next()) + last = last->next(); + last->next(item); + return head; +} + +int8_t WiFiServer::_accept(tcp_pcb* apcb, int8_t err) +{ + DEBUGV("WS:ac\r\n"); + ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this); + _unclaimed = slist_append_tail(_unclaimed, client); + tcp_accepted(_pcb); + // printf("WiFiServer::_accept\r\n"); + return ERR_OK; +} + +void WiFiServer::_discard(ClientContext* client) +{ + // _discarded = slist_append_tail(_discarded, client); + DEBUGV("WS:dis\r\n"); + // printf("WiFiServer::_discard\r\n"); +} + +int8_t WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, int8_t err) +{ + return reinterpret_cast(arg)->_accept(newpcb, err); +} + +void WiFiServer::_s_discard(void* server, ClientContext* ctx) +{ + reinterpret_cast(server)->_discard(ctx); +} + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.h new file mode 100644 index 0000000..ef64276 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiServer.h @@ -0,0 +1,65 @@ +/* + WiFiServer.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, December 2014 - esp8266 support +*/ + +#ifndef wifiserver_h +#define wifiserver_h + +extern "C" { + #include "include/wl_definitions.h" + + struct tcp_pcb; +} + +#include "Server.h" + +class ClientContext; +class WiFiClient; + +class WiFiServer : public Server { +private: + uint16_t _port; + tcp_pcb* _pcb; + + ClientContext* _unclaimed; + ClientContext* _discarded; + +public: + WiFiServer(uint16_t port); + WiFiClient available(uint8_t* status = NULL); + bool hasClient(); + void begin(); + void setNoDelay(bool nodelay); + bool getNoDelay(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + + using Print::write; + +protected: + int8_t _accept(tcp_pcb* newpcb, int8_t err); + void _discard(ClientContext* client); + + static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); + static void _s_discard(void* server, ClientContext* ctx); +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.cpp new file mode 100644 index 0000000..80b0055 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.cpp @@ -0,0 +1,279 @@ +/* + WiFiUdp.cpp - UDP client/server for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define LWIP_INTERNAL +#include + +extern "C" +{ + #include "include/wl_definitions.h" + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiUdp.h" +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + + +template<> +WiFiUDP* SList::_s_first = 0; + +/* Constructor */ +WiFiUDP::WiFiUDP() : _ctx(0) +{ + WiFiUDP::_add(this); +} + +WiFiUDP::WiFiUDP(const WiFiUDP& other) +{ + _ctx = other._ctx; + if (_ctx) + _ctx->ref(); + WiFiUDP::_add(this); +} + +WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) +{ + _ctx = rhs._ctx; + if (_ctx) + _ctx->ref(); + return *this; +} + +WiFiUDP::~WiFiUDP() +{ + WiFiUDP::_remove(this); + if (_ctx) + _ctx->unref(); +} + +/* Start WiFiUDP socket, listening at local port */ +uint8_t WiFiUDP::begin(uint16_t port) +{ + if (_ctx) { + _ctx->unref(); + _ctx = 0; + } + + _ctx = new UdpContext; + _ctx->ref(); + ip_addr_t addr; + addr.addr = INADDR_ANY; + return (_ctx->listen(addr, port)) ? 1 : 0; +} + +uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) +{ + if (_ctx) { + _ctx->unref(); + _ctx = 0; + } + + ip_addr_t ifaddr; + ifaddr.addr = (uint32_t) interfaceAddr; + ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t) multicast; + + if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { + return 0; + } + + _ctx = new UdpContext; + _ctx->ref(); + if (!_ctx->listen(*IP_ADDR_ANY, port)) { + return 0; + } + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() { + if (!_ctx) + return 0; + return static_cast(_ctx->getSize()); +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_ctx) { + _ctx->disconnect(); + _ctx->unref(); + } + _ctx = 0; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return beginPacket(remote_addr, port); + } + return 0; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + ip_addr_t addr; + addr.addr = ip; + + if (!_ctx) { + _ctx = new UdpContext; + _ctx->ref(); + } + return (_ctx->connect(addr, port)) ? 1 : 0; +} + +int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port, + IPAddress interfaceAddress, int ttl) +{ + ip_addr_t mcastAddr; + mcastAddr.addr = multicastAddress; + ip_addr_t ifaceAddr; + ifaceAddr.addr = interfaceAddress; + + if (!_ctx) { + _ctx = new UdpContext; + _ctx->ref(); + } + if (!_ctx->connect(mcastAddr, port)) { + return 0; + } + _ctx->setMulticastInterface(ifaceAddr); + _ctx->setMulticastTTL(ttl); + return 1; +} + +int WiFiUDP::endPacket() +{ + if (!_ctx) + return 0; + + _ctx->send(); + return 1; +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + if (!_ctx) + return 0; + + return _ctx->append(reinterpret_cast(buffer), size); +} + +int WiFiUDP::parsePacket() +{ + if (!_ctx) + return 0; + if (!_ctx->next()) + return 0; + return _ctx->getSize(); +} + +int WiFiUDP::read() +{ + if (!_ctx) + return -1; + + return _ctx->read(); +} + +int WiFiUDP::read(unsigned char* buffer, size_t len) +{ + if (!_ctx) + return 0; + + return _ctx->read(reinterpret_cast(buffer), len); +} + +int WiFiUDP::peek() +{ + if (!_ctx) + return 0; + + return _ctx->peek(); +} + +void WiFiUDP::flush() +{ + if (_ctx) + _ctx->flush(); +} + +IPAddress WiFiUDP::remoteIP() +{ + if (!_ctx) + return IPAddress(0U); + + return IPAddress(_ctx->getRemoteAddress()); +} + +uint16_t WiFiUDP::remotePort() +{ + if (!_ctx) + return 0; + + return _ctx->getRemotePort(); +} + +IPAddress WiFiUDP::destinationIP() +{ + IPAddress addr; + + if (!_ctx) + return addr; + + addr = _ctx->getDestAddress(); + return addr; +} + +uint16_t WiFiUDP::localPort() +{ + if (!_ctx) + return 0; + + return _ctx->getLocalPort(); +} + +void WiFiUDP::stopAll() +{ + for (WiFiUDP* it = _s_first; it; it = it->_next) { + DEBUGV("%s %08x %08x\n", __func__, (uint32_t) it, (uint32_t) _s_first); + it->stop(); + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.h new file mode 100644 index 0000000..16aa0a3 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/WiFiUdp.h @@ -0,0 +1,112 @@ +/* + WiFiUdp.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, January 2015 - esp8266 support +*/ + +#ifndef WIFIUDP_H +#define WIFIUDP_H + +#include +#include + +#define UDP_TX_PACKET_MAX_SIZE 8192 + +class UdpContext; + +class WiFiUDP : public UDP, public SList { +private: + UdpContext* _ctx; + +public: + WiFiUDP(); // Constructor + WiFiUDP(const WiFiUDP& other); + WiFiUDP& operator=(const WiFiUDP& rhs); + ~WiFiUDP(); + + operator bool() const { return _ctx != 0; } + + // initialize, start listening on specified port. + // Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t begin(uint16_t port); + // Finish with the UDP connetion + virtual void stop(); + // join a multicast group and listen on the given port + uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port); + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Start building up a packet to send to the multicast address + // multicastAddress - muticast address to send to + // interfaceAddress - the local IP address of the interface that should be used + // use WiFi.localIP() or WiFi.softAPIP() depending on the interface you need + // ttl - multicast packet TTL (default is 1) + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacketMulticast(IPAddress multicastAddress, + uint16_t port, + IPAddress interfaceAddress, + int ttl = 1); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + // Return the destination address for incoming packets, + // useful to distinguish multicast and ordinary packets + IPAddress destinationIP(); + // Return the local port for outgoing packets + uint16_t localPort(); + + static void stopAll(); + +}; + +#endif //WIFIUDP_H + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/cc.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/cc.h new file mode 100644 index 0000000..ff03b30 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/cc.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __ARCH_CC_H__ +#define __ARCH_CC_H__ + +//#include +#include "c_types.h" +#include "ets_sys.h" +#include "osapi.h" +#define EFAULT 14 + +//#define LWIP_PROVIDE_ERRNO + +#if (1) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif + + +typedef unsigned char u8_t; +typedef signed char s8_t; +typedef unsigned short u16_t; +typedef signed short s16_t; +typedef unsigned long u32_t; +typedef signed long s32_t; +typedef unsigned long mem_ptr_t; + +#define S16_F "d" +#define U16_F "d" +#define X16_F "x" + +#define S32_F "d" +#define U32_F "d" +#define X32_F "x" + + + +//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +//#define LWIP_DEBUG + +#ifdef LWIP_DEBUG +#define LWIP_PLATFORM_DIAG(x) os_printf x +#define LWIP_PLATFORM_ASSERT(x) ETS_ASSERT(x) +#else +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) +#endif + +#define SYS_ARCH_DECL_PROTECT(x) +#define SYS_ARCH_PROTECT(x) +#define SYS_ARCH_UNPROTECT(x) + +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff))) +#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) + +#if LWIP_RAW +extern u8_t memp_memory_RAW_PCB_base[]; +#endif /* LWIP_RAW */ + +#if LWIP_UDP +extern u8_t memp_memory_UDP_PCB_base[]; +#endif /* LWIP_UDP */ + +#if LWIP_TCP +extern u8_t memp_memory_TCP_PCB_base[]; +extern u8_t memp_memory_TCP_PCB_LISTEN_base[]; +extern u8_t memp_memory_TCP_SEG_base[] SHMEM_ATTR; +#endif /* LWIP_TCP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +extern u8_t memp_memory_SYS_TIMEOUT_base[]; +#endif /* LWIP_TIMERS */ + +extern u8_t memp_memory_PBUF_base[]; +extern u8_t memp_memory_PBUF_POOL_base[]; + + + +#endif /* __ARCH_CC_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/perf.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/perf.h new file mode 100644 index 0000000..089faca --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/sys_arch.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/arch/sys_arch.h new file mode 100644 index 0000000..e69de29 diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/ClientContext.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/ClientContext.h new file mode 100644 index 0000000..6193568 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/ClientContext.h @@ -0,0 +1,319 @@ +/* + ClientContext.h - TCP connection handling on top of lwIP + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef CLIENTCONTEXT_H +#define CLIENTCONTEXT_H + +class ClientContext; +class WiFiClient; + +typedef void (*discard_cb_t)(void*, ClientContext*); + +extern "C" void esp_yield(); +extern "C" void esp_schedule(); + +class ClientContext { + public: + ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) : + _pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0), _send_waiting(false) { + tcp_setprio(pcb, TCP_PRIO_MIN); + tcp_arg(pcb, this); + tcp_recv(pcb, &_s_recv); + tcp_sent(pcb, &_s_sent); + tcp_err(pcb, &_s_error); + } + + err_t abort(){ + if(_pcb) { + DEBUGV(":abort\r\n"); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_abort(_pcb); + _pcb = 0; + } + return ERR_ABRT; + } + + err_t close(){ + err_t err = ERR_OK; + if(_pcb) { + DEBUGV(":close\r\n"); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + err = tcp_close(_pcb); + if(err != ERR_OK) { + DEBUGV(":tc err %d\r\n", err); + tcp_abort(_pcb); + err = ERR_ABRT; + } + _pcb = 0; + } + return err; + } + + ~ClientContext() { + } + + ClientContext* next() const { + return _next; + } + + ClientContext* next(ClientContext* new_next) { + _next = new_next; + return _next; + } + + void ref() { + ++_refcnt; + DEBUGV(":ref %d\r\n", _refcnt); + } + + void unref() { + if(this != 0) { + DEBUGV(":ur %d\r\n", _refcnt); + if(--_refcnt == 0) { + flush(); + close(); + if(_discard_cb) + _discard_cb(_discard_cb_arg, this); + delete this; + } + } + } + + void setNoDelay(bool nodelay){ + if(!_pcb) return; + if(nodelay) tcp_nagle_disable(_pcb); + else tcp_nagle_enable(_pcb); + } + + bool getNoDelay(){ + if(!_pcb) return false; + return tcp_nagle_disabled(_pcb); + } + + uint32_t getRemoteAddress() { + if(!_pcb) return 0; + + return _pcb->remote_ip.addr; + } + + uint16_t getRemotePort() { + if(!_pcb) return 0; + + return _pcb->remote_port; + } + + size_t getSize() const { + if(!_rx_buf) return 0; + + return _rx_buf->tot_len - _rx_buf_offset; + } + + char read() { + if(!_rx_buf) return 0; + + char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + _consume(1); + return c; + } + + size_t read(char* dst, size_t size) { + if(!_rx_buf) return 0; + + size_t max_size = _rx_buf->tot_len - _rx_buf_offset; + size = (size < max_size) ? size : max_size; + + DEBUGV(":rd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset); + size_t size_read = 0; + while(size) { + size_t buf_size = _rx_buf->len - _rx_buf_offset; + size_t copy_size = (size < buf_size) ? size : buf_size; + DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size); + os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, copy_size); + dst += copy_size; + _consume(copy_size); + size -= copy_size; + size_read += copy_size; + } + return size_read; + } + + char peek() { + if(!_rx_buf) return 0; + + return reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + } + + void flush() { + if(!_rx_buf) { + return; + } + if(_pcb) { + tcp_recved(_pcb, (size_t) _rx_buf->tot_len); + } + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } + + uint8_t state() const { + if(!_pcb) return CLOSED; + + return _pcb->state; + } + + size_t write(const char* data, size_t size) { + if(!_pcb) { + DEBUGV(":wr !_pcb\r\n"); + return 0; + } + + if(size == 0) { + return 0; + } + + size_t room = tcp_sndbuf(_pcb); + size_t will_send = (room < size) ? room : size; + err_t err = tcp_write(_pcb, data, will_send, 0); + if(err != ERR_OK) { + DEBUGV(":wr !ERR_OK\r\n"); + return 0; + } + + _size_sent = will_send; + DEBUGV(":wr\r\n"); + tcp_output( _pcb ); + _send_waiting = true; + delay(5000); // max send timeout + _send_waiting = false; + DEBUGV(":ww\r\n"); + return will_send - _size_sent; + } + + private: + + err_t _sent(tcp_pcb* pcb, uint16_t len) { + DEBUGV(":sent %d\r\n", len); + _size_sent -= len; + if(_size_sent == 0 && _send_waiting) esp_schedule(); + return ERR_OK; + } + + void _consume(size_t size) { + ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size; + if(left > 0) { + _rx_buf_offset += size; + } else if(!_rx_buf->next) { + DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len); + if(_pcb) tcp_recved(_pcb, _rx_buf->len); + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } else { + DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len); + auto head = _rx_buf; + _rx_buf = _rx_buf->next; + _rx_buf_offset = 0; + pbuf_ref(_rx_buf); + if(_pcb) tcp_recved(_pcb, head->len); + pbuf_free(head); + } + } + + err_t _recv(tcp_pcb* pcb, pbuf* pb, err_t err) { + + if(pb == 0) // connection closed + { + DEBUGV(":rcla\r\n"); + return abort(); + } + + if(_rx_buf) { + // there is some unread data + // chain the new pbuf to the existing one + DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); + pbuf_cat(_rx_buf, pb); + } else { + DEBUGV(":rn %d\r\n", pb->tot_len); + _rx_buf = pb; + _rx_buf_offset = 0; + } + return ERR_OK; + } + + void _error(err_t err) { + DEBUGV(":er %d %d %d\r\n", err, _size_sent, _send_waiting); + if (err != ERR_ABRT) { + abort(); + } + else { + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + _pcb = NULL; + } + if(_size_sent && _send_waiting) { + esp_schedule(); + } + } + + err_t _poll(tcp_pcb* pcb) { + return ERR_OK; + } + + static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) { + return reinterpret_cast(arg)->_recv(tpcb, pb, err); + } + + static void _s_error(void *arg, err_t err) { + reinterpret_cast(arg)->_error(err); + } + + static err_t _s_poll(void *arg, struct tcp_pcb *tpcb) { + return reinterpret_cast(arg)->_poll(tpcb); + } + + static err_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len) { + return reinterpret_cast(arg)->_sent(tpcb, len); + } + + private: + ClientContext* _next; + int _refcnt; + + tcp_pcb* _pcb; + + pbuf* _rx_buf; + size_t _rx_buf_offset; + + discard_cb_t _discard_cb; + void* _discard_cb_arg; + + size_t _size_sent; + bool _send_waiting; +}; + +#endif//CLIENTCONTEXT_H diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/UdpContext.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/UdpContext.h new file mode 100644 index 0000000..f7cebc8 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/UdpContext.h @@ -0,0 +1,389 @@ +/* + UdpContext.h - UDP connection handling on top of lwIP + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef UDPCONTEXT_H +#define UDPCONTEXT_H + +class UdpContext; + +extern "C" void esp_yield(); +extern "C" void esp_schedule(); + +#define GET_IP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN); +#define GET_UDP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN); + +class UdpContext +{ +public: + + typedef std::function rxhandler_t; + + UdpContext() + : _pcb(0) + , _rx_buf(0) + , _first_buf_taken(false) + , _rx_buf_offset(0) + , _refcnt(0) + , _tx_buf_head(0) + , _tx_buf_cur(0) + , _tx_buf_offset(0) + , _multicast_ttl(1) + , _dest_port(0) + { + _pcb = udp_new(); + _dest_addr.addr = 0; + } + + ~UdpContext() + { + udp_remove(_pcb); + _pcb = 0; + if (_tx_buf_head) + { + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + } + if (_rx_buf) + { + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } + } + + void ref() + { + ++_refcnt; + } + + void unref() + { + if(this != 0) { + DEBUGV(":ur %d\r\n", _refcnt); + if(--_refcnt == 0) { + delete this; + } + } + } + + bool connect(ip_addr_t addr, uint16_t port) + { + _dest_addr = addr; + _dest_port = port; + return true; + } + + bool listen(ip_addr_t addr, uint16_t port) + { + udp_recv(_pcb, &_s_recv, (void *) this); + err_t err = udp_bind(_pcb, &addr, port); + return err == ERR_OK; + } + + void disconnect() + { + udp_disconnect(_pcb); + } + + void setMulticastInterface(ip_addr_t addr) + { + // newer versions of lwip have a macro to set the multicast ip + // udp_set_multicast_netif_addr(_pcb, addr); + _pcb->multicast_ip = addr; + } + + void setMulticastTTL(int ttl) + { + // newer versions of lwip have an additional field (mcast_ttl) for this purpose + // and a macro to set it instead of direct field access + // udp_set_multicast_ttl(_pcb, ttl); + _multicast_ttl = ttl; + } + + // warning: handler is called from tcp stack context + // esp_yield and non-reentrant functions which depend on it will fail + void onRx(rxhandler_t handler) { + _on_rx = handler; + } + + size_t getSize() const + { + if (!_rx_buf) + return 0; + + return _rx_buf->len - _rx_buf_offset; + } + + uint32_t getRemoteAddress() + { + if (!_rx_buf) + return 0; + + ip_hdr* iphdr = GET_IP_HDR(_rx_buf); + return iphdr->src.addr; + } + + uint16_t getRemotePort() + { + if (!_rx_buf) + return 0; + + udp_hdr* udphdr = GET_UDP_HDR(_rx_buf); + return ntohs(udphdr->src); + } + + uint32_t getDestAddress() + { + ip_hdr* iphdr = GET_IP_HDR(_rx_buf); + return iphdr->dest.addr; + } + + uint16_t getLocalPort() + { + if (!_pcb) + return 0; + + return _pcb->local_port; + } + + bool next() + { + if (!_rx_buf) + return false; + + if (!_first_buf_taken) + { + _first_buf_taken = true; + return true; + } + + auto head = _rx_buf; + _rx_buf = _rx_buf->next; + _rx_buf_offset = 0; + + if (_rx_buf) + { + pbuf_ref(_rx_buf); + } + pbuf_free(head); + return _rx_buf != 0; + } + + int read() + { + if (!_rx_buf || _rx_buf->len == _rx_buf_offset) + return -1; + + char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + _consume(1); + return c; + } + + size_t read(char* dst, size_t size) + { + if (!_rx_buf) + return 0; + + size_t max_size = _rx_buf->len - _rx_buf_offset; + size = (size < max_size) ? size : max_size; + DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); + + os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); + _consume(size); + + return size; + } + + char peek() + { + if (!_rx_buf) + return 0; + + return reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + } + + void flush() + { + if (!_rx_buf) + return; + + _consume(_rx_buf->len - _rx_buf_offset); + } + + + size_t append(const char* data, size_t size) + { + if (!_tx_buf_head || _tx_buf_head->tot_len < _tx_buf_offset + size) + { + _reserve(_tx_buf_offset + size); + } + + size_t left_to_copy = size; + while(left_to_copy) + { + // size already used in current pbuf + size_t used_cur = _tx_buf_offset - (_tx_buf_head->tot_len - _tx_buf_cur->tot_len); + size_t free_cur = _tx_buf_cur->len - used_cur; + if (free_cur == 0) + { + _tx_buf_cur = _tx_buf_cur->next; + continue; + } + size_t will_copy = (left_to_copy < free_cur) ? left_to_copy : free_cur; + os_memcpy(reinterpret_cast(_tx_buf_cur->payload) + used_cur, data, will_copy); + _tx_buf_offset += will_copy; + left_to_copy -= will_copy; + data += will_copy; + } + return size; + } + + void send(ip_addr_t* addr = 0, uint16_t port = 0) + { + size_t orig_size = _tx_buf_head->tot_len; + + size_t data_size = _tx_buf_offset; + size_t size_adjustment = orig_size - data_size; + for (pbuf* p = _tx_buf_head; p; p = p->next) + { + p->tot_len -= size_adjustment; + if (!p->next) + { + p->len = p->tot_len; + } + } + + if (!addr) { + addr = &_dest_addr; + port = _dest_port; + } + + uint16_t old_ttl = _pcb->ttl; + if (ip_addr_ismulticast(addr)) { + _pcb->ttl = _multicast_ttl; + } + + udp_sendto(_pcb, _tx_buf_head, addr, port); + + _pcb->ttl = old_ttl; + + for (pbuf* p = _tx_buf_head; p; p = p->next) + { + p->tot_len += size_adjustment; + if (!p->next) + { + p->len = p->tot_len; + } + } + + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + } + +private: + + void _reserve(size_t size) + { + const size_t pbuf_unit_size = 512; + if (!_tx_buf_head) + { + _tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); + _tx_buf_cur = _tx_buf_head; + _tx_buf_offset = 0; + } + + size_t cur_size = _tx_buf_head->tot_len; + if (size < cur_size) + return; + + size_t grow_size = size - cur_size; + + while(grow_size) + { + pbuf* pb = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); + pbuf_cat(_tx_buf_head, pb); + if (grow_size < pbuf_unit_size) + return; + grow_size -= pbuf_unit_size; + } + } + + void _consume(size_t size) + { + _rx_buf_offset += size; + } + + void _recv(udp_pcb *upcb, pbuf *pb, + ip_addr_t *addr, u16_t port) + { + if (_rx_buf) + { + // there is some unread data + // chain the new pbuf to the existing one + DEBUGV(":urch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); + pbuf_cat(_rx_buf, pb); + } + else + { + DEBUGV(":urn %d\r\n", pb->tot_len); + _first_buf_taken = false; + _rx_buf = pb; + _rx_buf_offset = 0; + } + if (_on_rx) { + _on_rx(); + } + } + + + static void _s_recv(void *arg, + udp_pcb *upcb, pbuf *p, + ip_addr_t *addr, u16_t port) + { + reinterpret_cast(arg)->_recv(upcb, p, addr, port); + } + +private: + int _refcnt; + udp_pcb* _pcb; + + ip_addr_t _dest_addr; + uint16_t _dest_port; + + uint16_t _multicast_ttl; + + bool _first_buf_taken; + pbuf* _rx_buf; + size_t _rx_buf_offset; + + pbuf* _tx_buf_head; + pbuf* _tx_buf_cur; + size_t _tx_buf_offset; + + rxhandler_t _on_rx; +}; + + + +#endif//CLIENTCONTEXT_H diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/lwipopts.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/lwipopts.h new file mode 100644 index 0000000..1678a40 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/lwipopts.h @@ -0,0 +1,2037 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + + +#define EBUF_LWIP 1 +#define LWIP_ESP 1 +#define EP_OFFSET 36 +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 0 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 1 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 1 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 16000 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 1 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 1 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 10 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB (*((volatile uint32*)0x600011FC)) +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 2 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 0 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 0 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 10 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 6 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 0 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 0 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 4 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 0 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 0 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 0 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 0 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 0 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 0 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 0 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 10 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 1 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 1 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 0 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 0 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 0 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 1 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 0 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 1 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 0 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 0 +#endif + +/** + * SNMP_PRIVATE_MIB: + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 0 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 1 +#endif + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 1 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX 5 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX 5 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 0 +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 1460 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 2 * TCP_MSS +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#define LWIP_EVENT_API 1 +#define LWIP_CALLBACK_API 0 +#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 0 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 0 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 1 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 0 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else +#define ETHARP_STATS 0 +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/slist.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/slist.h new file mode 100644 index 0000000..0606f72 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/slist.h @@ -0,0 +1,38 @@ +#ifndef SLIST_H +#define SLIST_H + +template +class SList { +public: + SList() : _next(0) { } + +protected: + + static void _add(T* self) { + T* tmp = _s_first; + _s_first = self; + self->_next = tmp; + } + + static void _remove(T* self) { + if (_s_first == self) { + _s_first = self->_next; + self->_next = 0; + return; + } + + for (T* prev = _s_first; prev->_next; prev = prev->_next) { + if (prev->_next == self) { + prev->_next = self->_next; + self->_next = 0; + return; + } + } + } + + static T* _s_first; + T* _next; +}; + + +#endif //SLIST_H diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/wl_definitions.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/wl_definitions.h new file mode 100644 index 0000000..45bee67 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/include/wl_definitions.h @@ -0,0 +1,87 @@ +/* + wl_definitions.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_definitions.h + * + * Created on: Mar 6, 2011 + * Author: dlafauci + */ + +#ifndef WL_DEFINITIONS_H_ +#define WL_DEFINITIONS_H_ + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 +// Maxmium number of socket +#define MAX_SOCK_NUM 4 +// Socket not available constant +#define SOCK_NOT_AVAIL 255 +// Default state value for Wifi state field +#define NA_STATE -1 +//Maximum number of attempts to establish wifi connection +#define WL_MAX_ATTEMPT_CONNECTION 10 + +typedef enum { + WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL = 1, + WL_SCAN_COMPLETED = 2, + WL_CONNECTED = 3, + WL_CONNECT_FAILED = 4, + WL_CONNECTION_LOST = 5, + WL_DISCONNECTED = 6 +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = 5, + ENC_TYPE_TKIP = 2, + ENC_TYPE_CCMP = 4, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = 7, + ENC_TYPE_AUTO = 8 +}; + +#if !defined(LWIP_INTERNAL) +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; +#endif + +#endif /* WL_DEFINITIONS_H_ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api.h new file mode 100644 index 0000000..91b9e5d --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores whether to wake up the original application task + if data couldn't be sent in the first try. */ +#define NETCONN_FLAG_WRITE_DELAYED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If this is set, a TCP netconn must call netconn_recved() to update + the TCP receive window (done automatically if not set). */ +#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 + + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t) (t&0xF0) +#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) + +/** Protocol family and type of the netconn */ +enum netconn_type { + NETCONN_INVALID = 0, + /* NETCONN_TCP Group */ + NETCONN_TCP = 0x10, + /* NETCONN_UDP Group */ + NETCONN_UDP = 0x20, + NETCONN_UDPLITE = 0x21, + NETCONN_UDPNOCHKSUM= 0x22, + /* NETCONN_RAW Group */ + NETCONN_RAW = 0x40 +}; + +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ +enum netconn_state { + NETCONN_NONE, + NETCONN_WRITE, + NETCONN_LISTEN, + NETCONN_CONNECT, + NETCONN_CLOSE +}; + +/** Use to inform the callback function about changes */ +enum netconn_evt { + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR +}; + +#if LWIP_IGMP +/** Used for netconn_join_leave_group() */ +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; +struct api_msg_msg; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { + /** type of the netconn (TCP, UDP or RAW) */ + enum netconn_type type; + /** current state of the netconn */ + enum netconn_state state; + /** the lwIP internal protocol control block */ + union { + struct ip_pcb *ip; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct raw_pcb *raw; + } pcb; + /** the last error this netconn had */ + err_t last_err; + /** sem that is used to synchroneously execute functions in the core context */ + sys_sem_t op_completed; + /** mbox where received packets are stored until they are fetched + by the netconn application thread (can grow quite big) */ + sys_mbox_t recvmbox; +#if LWIP_TCP + /** mbox where new connections are stored until processed + by the application thread */ + sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ + /** only used for socket layer */ +#if LWIP_SOCKET + int socket; +#endif /* LWIP_SOCKET */ +#if LWIP_SO_RCVTIMEO + /** timeout to wait for new data to be received + (or connections to arrive for listening netconns) */ + int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ + int recv_bufsize; + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ + s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; +#if LWIP_TCP + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores how much is already sent. */ + size_t write_offset; + /** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg_msg *current_msg; +#endif /* LWIP_TCP */ + /** A callback function that is informed about events for this netconn */ + netconn_callback callback; +}; + +/** Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) { \ + (*c->callback)(c, e, l); \ + } + +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(lev); \ +} while(0); + +/* Network connection functions: */ +#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +void netconn_recved(struct netconn *conn, u32_t length); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags); +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); + +#if LWIP_IGMP +err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#endif /* LWIP_DNS */ + +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_set_noautorecved(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) +/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) + +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api_msg.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api_msg.h new file mode 100644 index 0000000..f99d8c3 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/api_msg.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function + for a netconn in another thread context (mainly used to process netconns + in the tcpip_thread context to be thread safe). */ +struct api_msg_msg { + /** The netconn which to process - always needed: it includes the semaphore + which is used to block the application thread until the function finished. */ + struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; + /** Depending on the executed function, one of these union members is used */ + union { + /** used for do_send */ + struct netbuf *b; + /** used for do_newconn */ + struct { + u8_t proto; + } n; + /** used for do_bind and do_connect */ + struct { + ip_addr_t *ipaddr; + u16_t port; + } bc; + /** used for do_getaddr */ + struct { + ip_addr_t *ipaddr; + u16_t *port; + u8_t local; + } ad; + /** used for do_write */ + struct { + const void *dataptr; + size_t len; + u8_t apiflags; + } w; + /** used for do_recv */ + struct { + u32_t len; + } r; + /** used for do_close (/shutdown) */ + struct { + u8_t shut; + } sd; +#if LWIP_IGMP + /** used for do_join_leave_group */ + struct { + ip_addr_t *multiaddr; + ip_addr_t *netif_addr; + enum netconn_igmp join_or_leave; + } jl; +#endif /* LWIP_IGMP */ +#if TCP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* TCP_LISTEN_BACKLOG */ + } msg; +}; + +/** This struct contains a function to execute in another thread context and + a struct api_msg_msg that serves as an argument for this function. + This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ +struct api_msg { + /** function to execute in tcpip_thread context */ + void (* function)(struct api_msg_msg *msg); + /** arguments for this function */ + struct api_msg_msg msg; +}; + +#if LWIP_DNS +/** As do_gethostbyname requires more arguments but doesn't require a netconn, + it has its own struct (to avoid struct api_msg getting bigger than necessary). + do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg + (see netconn_gethostbyname). */ +struct dns_api_msg { + /** Hostname to query or dotted IP address string */ + const char *name; + /** Rhe resolved address is stored here */ + ip_addr_t *addr; + /** This semaphore is posted when the name is resolved, the application thread + should wait on it. */ + sys_sem_t *sem; + /** Errors are given back here */ + err_t *err; +}; +#endif /* LWIP_DNS */ + +void do_newconn ( struct api_msg_msg *msg); +void do_delconn ( struct api_msg_msg *msg); +void do_bind ( struct api_msg_msg *msg); +void do_connect ( struct api_msg_msg *msg); +void do_disconnect ( struct api_msg_msg *msg); +void do_listen ( struct api_msg_msg *msg); +void do_send ( struct api_msg_msg *msg); +void do_recv ( struct api_msg_msg *msg); +void do_write ( struct api_msg_msg *msg); +void do_getaddr ( struct api_msg_msg *msg); +void do_close ( struct api_msg_msg *msg); +void do_shutdown ( struct api_msg_msg *msg); +#if LWIP_IGMP +void do_join_leave_group( struct api_msg_msg *msg); +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +void do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/arch.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/arch.h new file mode 100644 index 0000000..524af6b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/arch.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ +/** Temporary upgrade helper: define format string for u8_t as hex if not + defined in cc.h */ +#ifndef X8_F +#define X8_F "02x" +#endif /* X8_F */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */ + + +#ifdef LWIP_PROVIDE_ERRNO + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + + +#define ENSROK 0 /* DNS server returned answer with no data */ +#define ENSRNODATA 160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162 /* DNS server returned general failure */ +#define ENSRNOTFOUND 163 /* Domain name not found */ +#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166 /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF 172 /* End of file */ +#define ENSRFILE 173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/autoip.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/autoip.h new file mode 100644 index 0000000..23c264a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/autoip.h @@ -0,0 +1,119 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * + */ + +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL 100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/* RFC 3927 Constants */ +#define PROBE_WAIT 1 /* second (initial random delay) */ +#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ +#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ +#define PROBE_NUM 3 /* (number of probe packets) */ +#define ANNOUNCE_NUM 2 /* (number of announcement packets) */ +#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ +#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ +#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ +#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ +#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF 0 +#define AUTOIP_STATE_PROBING 1 +#define AUTOIP_STATE_ANNOUNCING 2 +#define AUTOIP_STATE_BOUND 3 + +struct autoip +{ + ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ + u8_t state; /* current AutoIP state machine state */ + u8_t sent_num; /* sent number of probes or announces, dependent on state */ + u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ + u8_t lastconflict; /* ticks until a conflict can be solved by defending */ + u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Set a struct autoip allocated by the application to work with */ +void autoip_set_struct(struct netif *netif, struct autoip *autoip); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ +void autoip_tmr(void); + +/** Handle a possible change in the network configuration */ +void autoip_network_changed(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_AUTOIP */ + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/debug.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/debug.h new file mode 100644 index 0000000..d8359ea --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/debug.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "lwip/arch.h" + +/** lower two bits indicate debug level + * - 0 all + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_ALL 0x00 +#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE 0x03 +#define LWIP_DBG_MASK_LEVEL 0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON 0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF 0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE 0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE 0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH 0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT 0x08U + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ + LWIP_PLATFORM_ASSERT(message); } while(0) +#else /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion) +#endif /* LWIP_NOASSERT */ + +/** if "expression" isn't true, then print "message" and execute "handler" expression */ +#ifndef LWIP_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + LWIP_PLATFORM_ASSERT(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + * AND is of correct type AND is at least LWIP_DBG_LEVEL + */ +#define LWIP_DEBUGF(debug, message) do { \ + if ( \ + ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ + LWIP_PLATFORM_DIAG(message); \ + if ((debug) & LWIP_DBG_HALT) { \ + while(1); \ + } \ + } \ + } while(0) + +#else /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message) +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/def.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/def.h new file mode 100644 index 0000000..9b6de6a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/def.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* arch.h might define NULL already */ +#include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/** Get the absolute difference between 2 u32_t values (correcting overflows) + * 'a' is expected to be 'higher' (without overflow) than 'b'. */ +#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) + +/* Endianess-optimized shifting of two u8_t to create one u16_t */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define LWIP_MAKE_U16(a, b) ((a << 8) | b) +#else +#define LWIP_MAKE_U16(a, b) ((b << 8) | a) +#endif + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#ifndef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#if LWIP_PLATFORM_BYTESWAP +#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) +#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) +#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) +#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t lwip_htons(u16_t x); +u16_t lwip_ntohs(u16_t x); +u32_t lwip_htonl(u32_t x); +u32_t lwip_ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_DEF_H__ */ + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dhcp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dhcp.h new file mode 100644 index 0000000..ba21068 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dhcp.h @@ -0,0 +1,243 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60 +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500 + +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_LEN 128U + +struct dhcp +{ + /** transaction identifier of last sent request */ + u32_t xid; + /** our connection to the DHCP server */ + struct udp_pcb *pcb; + /** incoming msg */ + struct dhcp_msg *msg_in; + /** current DHCP state machine state */ + u8_t state; + /** retries of current request */ + u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; + + struct pbuf *p_out; /* pbuf of outcoming msg */ + struct dhcp_msg *msg_out; /* outgoing msg */ + u16_t options_out_len; /* outgoing msg options length */ + u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ + u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ + u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ + ip_addr_t offered_ip_addr; + ip_addr_t offered_sn_mask; + ip_addr_t offered_gw_addr; + + u32_t offered_t0_lease; /* lease period (in seconds) */ + u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ + u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ + /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? + integrate with possible TFTP-client for booting? */ +#define LWIP_DHCP_BOOTP_FILE 0 +#if LWIP_DHCP_BOOTP_FILE + ip_addr_t offered_si_addr; + char boot_file_name[DHCP_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ + PACK_STRUCT_FIELD(u8_t op); + PACK_STRUCT_FIELD(u8_t htype); + PACK_STRUCT_FIELD(u8_t hlen); + PACK_STRUCT_FIELD(u8_t hops); + PACK_STRUCT_FIELD(u32_t xid); + PACK_STRUCT_FIELD(u16_t secs); + PACK_STRUCT_FIELD(u16_t flags); + PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); + PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); + PACK_STRUCT_FIELD(ip_addr_p_t siaddr); + PACK_STRUCT_FIELD(ip_addr_p_t giaddr); + PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); + PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); + PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); + PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +# undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif + PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); +/** Handle a possible change in the network configuration */ +void dhcp_network_changed(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); + +/** DHCP message item offsets and length */ +#define DHCP_OP_OFS 0 +#define DHCP_HTYPE_OFS 1 +#define DHCP_HLEN_OFS 2 +#define DHCP_HOPS_OFS 3 +#define DHCP_XID_OFS 4 +#define DHCP_SECS_OFS 8 +#define DHCP_FLAGS_OFS 10 +#define DHCP_CIADDR_OFS 12 +#define DHCP_YIADDR_OFS 16 +#define DHCP_SIADDR_OFS 20 +#define DHCP_GIADDR_OFS 24 +#define DHCP_CHADDR_OFS 28 +#define DHCP_SNAME_OFS 44 +#define DHCP_FILE_OFS 108 +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS DHCP_MSG_LEN +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_OFF 0 +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/** DHCP message types */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ +#define DHCP_HTYPE_ETH 1 + +#define DHCP_MAGIC_COOKIE 0x63825363UL + +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*__LWIP_DHCP_H__*/ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dns.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dns.h new file mode 100644 index 0000000..6c7d9b0 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/dns.h @@ -0,0 +1,124 @@ +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato + * April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_DNS_H__ +#define __LWIP_DNS_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** DNS timer period */ +#define DNS_TMR_INTERVAL 1000 + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + +/* The size used for the next line is rather a hack, but it prevents including socket.h in all files + that include memp.h, and that would possibly break portability (since socket.h defines some types + and constants possibly already define by the OS). + Calculation rule: + sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ +#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, + * or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); + +void dns_init(void); +void dns_tmr(void); +void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +ip_addr_t dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, + dns_found_callback found, void *callback_arg); + +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/err.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/err.h new file mode 100644 index 0000000..cb69a9f --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/err.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define LWIP_ERR_T in cc.h if you want to use + * a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ +typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/* Definitions for error constants. */ + +#define ERR_OK 0 /* No error, everything OK. */ +#define ERR_MEM -1 /* Out of memory error. */ +#define ERR_BUF -2 /* Buffer error. */ +#define ERR_TIMEOUT -3 /* Timeout. */ +#define ERR_RTE -4 /* Routing problem. */ +#define ERR_INPROGRESS -5 /* Operation in progress */ +#define ERR_VAL -6 /* Illegal value. */ +#define ERR_WOULDBLOCK -7 /* Operation would block. */ + +#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK) + +#define ERR_ABRT -8 /* Connection aborted. */ +#define ERR_RST -9 /* Connection reset. */ +#define ERR_CLSD -10 /* Connection closed. */ +#define ERR_CONN -11 /* Not connected. */ + +#define ERR_ARG -12 /* Illegal argument. */ + +#define ERR_USE -13 /* Address in use. */ + +#define ERR_IF -14 /* Low-level netif error */ +#define ERR_ISCONN -15 /* Already connected. */ + + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err)ICACHE_FLASH_ATTR; +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/icmp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/icmp.h new file mode 100644 index 0000000..9bcb7bc --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/icmp.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ +#define ICMP_ECHO 8 /* echo */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ +#define ICMP_TSR 14 /* timestamp reply */ +#define ICMP_IRQ 15 /* information request */ +#define ICMP_IR 16 /* information reply */ + +enum icmp_dur_type { + ICMP_DUR_NET = 0, /* net unreachable */ + ICMP_DUR_HOST = 1, /* host unreachable */ + ICMP_DUR_PROTO = 2, /* protocol unreachable */ + ICMP_DUR_PORT = 3, /* port unreachable */ + ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + ICMP_DUR_SR = 5 /* source route failed */ +}; + +enum icmp_te_type { + ICMP_TE_TTL = 0, /* time to live exceeded in transit */ + ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ +}; + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + * is splitted to two u16_t like ICMP echo needs it. + * This header is also used for other ICMP types that do not + * use the data part. + * ¶¨ÒåICMP»ØËÍÇëÇó±¨ÎÄÊײ¿½á¹¹£¬ + * ÓÉÓÚËùÓÐICMP±¨ÎÄÊײ¿ÓкܴóÏàËÆÐÔ£¬ + * ¸Ã½á¹¹Í¬ÑùÊÊÓÃÓÚÆäËüICMP±¨ÎÄ¡£ + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +//¶ÁÈ¡ICMPÊײ¿ÖÐ×Ö¶Î +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t ÏòICMP±¨ÎÄÊײ¿×Ö¶ÎÖÐдÈëÏàÓ¦Öµ*/ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +void icmp_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)ICACHE_FLASH_ATTR; +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)ICACHE_FLASH_ATTR; + +#endif /* LWIP_ICMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ICMP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/igmp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/igmp.h new file mode 100644 index 0000000..8cf9a48 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/igmp.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef __LWIP_IGMP_H__ +#define __LWIP_IGMP_H__ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL 100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* MAC Filter Actions, these are passed to a netif's + * igmp_mac_filter callback function. */ +#define IGMP_DEL_MAC_FILTER 0 +#define IGMP_ADD_MAC_FILTER 1 + + +/** + * igmp group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + * + * There will be a group for the all systems group address but this + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ +struct igmp_group { + /** next link */ + struct igmp_group *next; + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting, negative is OFF */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/* Prototypes */ +void igmp_init(void)ICACHE_FLASH_ATTR; +err_t igmp_start(struct netif *netif)ICACHE_FLASH_ATTR; +err_t igmp_stop(struct netif *netif)ICACHE_FLASH_ATTR; +void igmp_report_groups(struct netif *netif)ICACHE_FLASH_ATTR; +struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLASH_ATTR; +err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; +void igmp_tmr(void)ICACHE_FLASH_ATTR; +#define LWIP_RAND() rand() +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet.h new file mode 100644 index 0000000..7bff49b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** For compatibility with BSD code */ +struct in_addr { + u32_t s_addr; +}; + +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + +#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ +#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) + +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) +#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet_chksum.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet_chksum.h new file mode 100644 index 0000000..41be641 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/inet_chksum.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INET_CHKSUM_H__ +#define __LWIP_INET_CHKSUM_H__ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/** Swap the bytes in an u16_t: much like htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +#ifndef LWIP_CHKSUM_COPY +#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +#ifndef LWIP_CHKSUM_COPY_ALGORITHM +#define LWIP_CHKSUM_COPY_ALGORITHM 1 +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +#endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +#define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pbuf(struct pbuf *p)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len)ICACHE_FLASH_ATTR; +u16_t inet_chksum_pseudo_partial(struct pbuf *p, + ip_addr_t *src, ip_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len)ICACHE_FLASH_ATTR; +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/init.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/init.h new file mode 100644 index 0000000..7a58aec --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/init.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_INIT_H__ +#define __LWIP_INIT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR 1U +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR 4U +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION 0U +/** For release candidates, this is set to 1..254 + * For official releases, this is set to 255 (LWIP_RC_RELEASE) + * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC 2U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE 255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT 0U + +#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ + LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +/* Modules initialization */ +void lwip_init(void) ICACHE_FLASH_ATTR; +//void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip.h new file mode 100644 index 0000000..1f361fa --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND LWIP_IGMP + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_UDP 17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP 6 + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + /* ip addresses in network byte order */ \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ +#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { + /* version / header length / type of service */ + PACK_STRUCT_FIELD(u16_t _v_hl_tos); + /* total length */ + PACK_STRUCT_FIELD(u16_t _len); + /* identification */ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FIELD(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FIELD(u8_t _proto); + /* checksum */ + PACK_STRUCT_FIELD(u16_t _chksum); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(ip_addr_p_t src); + PACK_STRUCT_FIELD(ip_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +/** The interface that provided the packet for the current callback invocation. */ +extern struct netif *current_netif; +/** Header of the input packet currently being processed. */ +extern const struct ip_hdr *current_header; +/** Source IP address of current_header */ +extern ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +extern ip_addr_t current_iphdr_dest; + +#define ip_init() /* Compatibility define, not init needed. */ +struct netif *ip_route(ip_addr_t *dest)ICACHE_FLASH_ATTR; +struct netif *ip_router(ip_addr_t *dest, ip_addr_t *source); + +err_t ip_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto)ICACHE_FLASH_ATTR; +err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, + struct netif *netif)ICACHE_FLASH_ATTR; +#if LWIP_NETIF_HWADDRHINT +err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen)ICACHE_FLASH_ATTR; +#endif /* IP_OPTIONS_SEND */ +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (current_netif) +/** Get the IP header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_header() (current_header) +/** Source IP address of current_header */ +#define ip_current_src_addr() (¤t_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (¤t_iphdr_dest) + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p)ICACHE_FLASH_ATTR; +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_addr.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_addr.h new file mode 100644 index 0000000..2787d12 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_addr.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the aligned version of ip_addr_t, + used as local variable, on the stack, etc. */ +#if !defined(IP2STR) +struct ip_addr { + u32_t addr; +}; +#endif + +/* This is the packed version of ip_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr_packed { + PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** ip_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip_addr_t as well as on ip_addr_p_t. */ +#if !defined(IP2STR) +typedef struct ip_addr ip_addr_t; +#endif +typedef struct ip_addr_packed ip_addr_p_t; + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { + PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Forward declaration to not include netif.h */ +struct netif; + +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + * for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) + +/** 255.255.255.255 */ +#if !defined(IPADDR_NONE) +#define IPADDR_NONE ((u32_t)0xffffffffUL) +#endif +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#if !defined(IPADDR_ANY) +#define IPADDR_ANY ((u32_t)0x00000000UL) +#endif +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) + +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) + +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IP_LOOPBACKNET 127 /* official! */ + + +#if !defined(IP4_ADDR) +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IP address given by the four byte-parts. + Little-endian version that prevents the use of htonl. */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif +#endif + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) +#endif + +/** Copy IP address - faster than ip_addr_set: no NULL check */ +#define ip_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for htonl()) */ +#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) + +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ + (mask)->addr) == \ + ((addr2)->addr & \ + (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) + +#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) +u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)ICACHE_FLASH_ATTR; + +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask)ICACHE_FLASH_ATTR; + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) + +#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) + +#define ip_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, \ + ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) + +/* Get one byte from the 4-byte address */ +#if !defined(IP2STR) +#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) +#endif + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +#if !defined(IP2STR) +u32_t ipaddr_addr(const char *cp)ICACHE_FLASH_ATTR; +#endif +int ipaddr_aton(const char *cp, ip_addr_t *addr)ICACHE_FLASH_ATTR; +/** returns ptr to static buffer; not reentrant! */ +char *ipaddr_ntoa(const ip_addr_t *addr)ICACHE_FLASH_ATTR; +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)ICACHE_FLASH_ATTR; + +#if !defined(IP2STR) +#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ + ip4_addr2_16(ipaddr), \ + ip4_addr3_16(ipaddr), \ + ip4_addr4_16(ipaddr) + +#define IPSTR "%d.%d.%d.%d" + +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_frag.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_frag.h new file mode 100644 index 0000000..df6db5f --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/ip_frag.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Jani Monoses + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/* IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { + struct ip_reassdata *next; + struct pbuf *p; + struct ip_hdr iphdr; + u16_t datagram_len; + u8_t flags; + u8_t timer; +}; + +void ip_reass_init(void)ICACHE_FLASH_ATTR; +void ip_reass_tmr(void)ICACHE_FLASH_ATTR; +struct pbuf * ip_reass(struct pbuf *p)ICACHE_FLASH_ATTR; +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)ICACHE_FLASH_ATTR; +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem.h new file mode 100644 index 0000000..7a4febc --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" +#include "mem_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include /* for size_t */ + +typedef size_t mem_size_t; + +/* aliases for C library malloc() */ +#define mem_init() +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_free +#define mem_free vPortFree +#endif +#ifndef mem_malloc +#define mem_malloc pvPortMalloc +#endif +#ifndef mem_calloc +#define mem_calloc pvPortCalloc +#endif +#ifndef mem_realloc +#define mem_realloc pvPortRealloc +#endif +#ifndef mem_zalloc +#define mem_zalloc pvPortZalloc +#endif + +#ifndef os_malloc +#define os_malloc(s) mem_malloc((s)) +#endif +#ifndef os_realloc +#define os_realloc(p, s) mem_realloc((p), (s)) +#endif +#ifndef os_zalloc +#define os_zalloc(s) mem_zalloc((s)) +#endif +#ifndef os_free +#define os_free(p) mem_free((p)) +#endif + +/* Since there is no C library allocation function to shrink memory without + moving it, define this to nothing. */ +#ifndef mem_trim +#define mem_trim(mem, size) (mem) +#endif +#else /* MEM_LIBC_MALLOC */ + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F +#else +typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F +#endif /* MEM_SIZE > 64000 */ + +#if MEM_USE_POOLS +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_trim is not used when using pools instead of a heap: + we can't free part of a pool element and don't want to copy the rest */ +#define mem_trim(mem, size) (mem) +#else /* MEM_USE_POOLS */ +/* lwIP alternative malloc */ +void mem_init(void)ICACHE_FLASH_ATTR; +void *mem_trim(void *mem, mem_size_t size)ICACHE_FLASH_ATTR; +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size)ICACHE_FLASH_ATTR; +void *mem_calloc(mem_size_t count, mem_size_t size)ICACHE_FLASH_ATTR; +void mem_free(void *mem)ICACHE_FLASH_ATTR; +#endif /* MEM_LIBC_MALLOC */ + +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEM_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem_manager.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem_manager.h new file mode 100644 index 0000000..0355968 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/mem_manager.h @@ -0,0 +1,81 @@ +#ifndef __MEM_MANAGER_H__ +#define __MEM_MANAGER_H__ + +#include "c_types.h" + +/*------------------------±äÁ¿¶¨Òå------------------------*/ + +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE +#ifndef IOT_SIP_MODE +//#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 0x3fffc000 - (uint32)&_heap_start ) )//fix 16000 to 24000 on 14.2.26 +#else +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 8000 ) ) +#endif +#define portBYTE_ALIGNMENT 8 +#define pdFALSE 0 +#define pdTRUE 1 + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE +#if portBYTE_ALIGNMENT == 8 + #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) +#endif + +#if portBYTE_ALIGNMENT == 4 + #define portBYTE_ALIGNMENT_MASK ( 0x0003 ) +#endif + +#if portBYTE_ALIGNMENT == 2 + #define portBYTE_ALIGNMENT_MASK ( 0x0001 ) +#endif + +#if portBYTE_ALIGNMENT == 1 + #define portBYTE_ALIGNMENT_MASK ( 0x0000 ) +#endif + +#ifndef portBYTE_ALIGNMENT_MASK + #error "Invalid portBYTE_ALIGNMENT definition" +#endif + +#define configUSE_MALLOC_FAILED_HOOK 1 +#define portPOINTER_SIZE_TYPE unsigned int + +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) + +//#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +//static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]; +//static unsigned char *ucHeap; + +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; //The next free block in the list. + size_t xBlockSize; //The size of the free block. +} xBlockLink; + +static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) ); + +//static const size_t xTotalHeapSize = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); + +//static xBlockLink xStart, *pxEnd = NULL; + +//static size_t xFreeBytesRemaining = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); + + +/*------------------------º¯ÊýÉùÃ÷-----------------------------------*/ + +//static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert ) ;//ICACHE_FLASH_ATTR; + +//static void prvHeapInit( void ) ;//ICACHE_FLASH_ATTR; + +void vApplicationMallocFailedHook( void ) ;//ICACHE_FLASH_ATTR; + +void *pvPortMalloc( size_t xWantedSize ) ;//ICACHE_FLASH_ATTR; + +void vPortFree( void *pv ) ;//ICACHE_FLASH_ATTR; + +size_t xPortGetFreeHeapSize( void ) ;//ICACHE_FLASH_ATTR; + +void vPortInitialiseBlocks( void ) ;//ICACHE_FLASH_ATTR; +/*-----------------------------------------------------------*/ + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp.h new file mode 100644 index 0000000..764dedb --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc, attr) MEMP_##name, +#include "lwip/memp_std.h" + MEMP_MAX +} memp_t; + +#if MEM_USE_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { + /* Get the first (via: + MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ + MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/memp_std.h" + ) , + /* Get the last (via: + MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ + MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/memp_std.h" + ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) + We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC || MEM_USE_POOLS +extern const u16_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#include "mem.h" + +#define memp_init() +#define memp_malloc(type) mem_malloc(memp_sizes[type]) +#define memp_free(type, mem) mem_free(mem) + +#else /* MEMP_MEM_MALLOC */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ + memp_t poolnr; +}; +#endif /* MEM_USE_POOLS */ + +void memp_init(void)ICACHE_FLASH_ATTR; + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line)ICACHE_FLASH_ATTR; +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type)ICACHE_FLASH_ATTR; +#endif +void memp_free(memp_t type, void *mem)ICACHE_FLASH_ATTR; + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp_std.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp_std.h new file mode 100644 index 0000000..b20a240 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/memp_std.h @@ -0,0 +1,126 @@ +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + * 1) MEMPOOL - standard pools + * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. + The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size, attr) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */ + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc, attr) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc, attr) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB", DMEM_ATTR) +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB", DMEM_ATTR) +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB", DMEM_ATTR) +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN", DMEM_ATTR) +LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG", DMEM_ATTR) +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA", DMEM_ATTR) +#endif /* IP_REASSEMBLY */ +#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF", DMEM_ATTR) +#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +#if LWIP_NETCONN +LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") +LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") +#endif /* LWIP_NETCONN */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if !LWIP_TCPIP_CORE_LOCKING_INPUT +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ +#endif /* NO_SYS==0 */ + +#if ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE", DMEM_ATTR) +#endif /* ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP", DMEM_ATTR) +#endif /* LWIP_IGMP */ + +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ +LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT", DMEM_ATTR) +#endif /* LWIP_TIMERS */ + +#if LWIP_SNMP +LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") +LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") +LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") +LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") +#endif /* LWIP_SNMP */ +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#if PPP_SUPPORT && PPPOE_SUPPORT +LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + * creates a pool name MEMP_pool_name. description is used in stats.c + * This allocates enough space for the pbuf struct and a payload. + * (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM", DMEM_ATTR) + +/* XXX: need to align to 4 byte as memp strcut is 4-byte long. otherwise will crash */ +#define LWIP_MEM_ALIGN4_SIZE(size) (((size) + 4 - 1) & ~(4-1)) + +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, LWIP_MEM_ALIGN4_SIZE(PBUF_POOL_BUFSIZE), "PBUF_POOL", DMEM_ATTR) + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netbuf.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netbuf.h new file mode 100644 index 0000000..b554a57 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netbuf.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETBUF_H__ +#define __LWIP_NETBUF_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + +struct netbuf { + struct pbuf *p, *ptr; + ip_addr_t addr; + u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; +#if LWIP_NETBUF_RECVINFO + ip_addr_t toaddr; +#endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ +}; + +/* Network buffer functions: */ +struct netbuf * netbuf_new (void)ICACHE_FLASH_ATTR; +void netbuf_delete (struct netbuf *buf)ICACHE_FLASH_ATTR; +void * netbuf_alloc (struct netbuf *buf, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_free (struct netbuf *buf)ICACHE_FLASH_ATTR; +err_t netbuf_ref (struct netbuf *buf, + const void *dataptr, u16_t size)ICACHE_FLASH_ATTR; +void netbuf_chain (struct netbuf *head, + struct netbuf *tail)ICACHE_FLASH_ATTR; + +err_t netbuf_data (struct netbuf *buf, + void **dataptr, u16_t *len)ICACHE_FLASH_ATTR; +s8_t netbuf_next (struct netbuf *buf)ICACHE_FLASH_ATTR; +void netbuf_first (struct netbuf *buf)ICACHE_FLASH_ATTR; + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ + pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf) ((buf)->p->tot_len) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) +#define netbuf_fromport(buf) ((buf)->port) +#if LWIP_NETBUF_RECVINFO +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) +#endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netdb.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netdb.h new file mode 100644 index 0000000..7587e2f --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netdb.h @@ -0,0 +1,124 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef __LWIP_NETDB_H__ +#define __LWIP_NETDB_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include /* for size_t */ + +#include "lwip/inet.h" +#include "lwip/sockets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME 200 +#define EAI_SERVICE 201 +#define EAI_FAIL 202 +#define EAI_MEMORY 203 + +#define HOST_NOT_FOUND 210 +#define NO_DATA 211 +#define NO_RECOVERY 212 +#define TRY_AGAIN 213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { + char *h_name; /* Official name of the host. */ + char **h_aliases; /* A pointer to an array of pointers to alternative host names, + terminated by a null pointer. */ + int h_addrtype; /* Address type. */ + int h_length; /* The length, in bytes, of the address. */ + char **h_addr_list; /* A pointer to an array of pointers to network addresses (in + network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessable error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +#define gethostbyname(name) lwip_gethostbyname(name) +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ + lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) +#define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* __LWIP_NETDB_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netif.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netif.h new file mode 100644 index 0000000..8bf1375 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netif.h @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths + across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** Whether the network interface is 'up'. This is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + * It is set by the startup code (for static IP configuration) or + * by dhcp/autoip when an address has been assigned. + */ +#define NETIF_FLAG_UP 0x01U +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_BROADCAST 0x02U +/** If set, the netif is one end of a point-to-point connection. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_POINTTOPOINT 0x04U +/** If set, the interface is configured using DHCP. + * Set by the DHCP code when starting or stopping DHCP. */ +#define NETIF_FLAG_DHCP 0x08U +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ +#define NETIF_FLAG_LINK_UP 0x10U +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ +#define NETIF_FLAG_ETHARP 0x20U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x40U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x80U + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr); +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + ip_addr_t *group, u8_t action); + +/** Generic data structure used for all lwIP network interfaces. + * The following fields should be filled in by the initialization + * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ +struct netif { + /** pointer to next in linked list */ + struct netif *next; + + /** IP address configuration in network byte order */ + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; + + /** This function is called by the network device driver + * to pass a packet up the TCP/IP stack. ÏòIP²ãÊäÈëÊý¾Ý°ü*/ + netif_input_fn input; + /** This function is called by the IP module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. ·¢ËÍIPÊý¾Ý°ü*/ + netif_output_fn output; + /** This function is called by the ARP module when it wants + * to send a packet on the interface. This function outputs + * the pbuf as-is on the link medium. µ×²ãÊý¾Ý°ü·¢ËÍ*/ + netif_linkoutput_fn linkoutput; +#if LWIP_NETIF_STATUS_CALLBACK + /** This function is called when the netif state is set to up or down + */ + netif_status_callback_fn status_callback; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK + /** This function is called when the netif link is set to up or down + */ + netif_status_callback_fn link_callback; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + /** This field can be set by the device driver and could point + * to state information for the device. ×ÔÓÉÉèÖÃ×ֶΣ¬±ÈÈçÖ¸Ïòµ×²ãÉ豸Ïà¹ØÐÅÏ¢*/ + void *state; +#if LWIP_DHCP + /** the DHCP client state information for this netif */ + struct dhcp *dhcp; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + /** the AutoIP client state information for this netif */ + struct autoip *autoip; +#endif +#if LWIP_NETIF_HOSTNAME + /* the hostname for this netif, NULL is a valid value */ + char* hostname; +#endif /* LWIP_NETIF_HOSTNAME */ + /** maximum transfer unit (in bytes) ¸Ã½Ó¿ÚÔÊÐíµÄ×î´óÊý¾Ý°ü³¤¶È£¬¶àÊÇ1500*/ + u16_t mtu; + /** number of bytes used in hwaddr¸Ã½Ó¿ÚÎïÀíµØÖ·³¤¶È */ + u8_t hwaddr_len; + /** link level hardware address of this interface ¸Ã½Ó¿ÚÎïÀíµØÖ·*/ + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + /** flags (see NETIF_FLAG_ above) ¸Ã½Ó¿Ú״̬¡¢ÊôÐÔ×Ö¶Î*/ + u8_t flags; + /** descriptive abbreviation ¸Ã½Ó¿ÚµÄÃû×Ö*/ + char name[2]; + /** number of this interface ¸Ã½Ó¿ÚµÄ±àºÅ*/ + u8_t num; +#if LWIP_SNMP + /** link type (from "snmp_ifType" enum from snmp.h) */ + u8_t link_type; + /** (estimate) link speed */ + u32_t link_speed; + /** timestamp at last change made (up/down) */ + u32_t ts; + /** counters */ + u32_t ifinoctets; + u32_t ifinucastpkts; + u32_t ifinnucastpkts; + u32_t ifindiscards; + u32_t ifoutoctets; + u32_t ifoutucastpkts; + u32_t ifoutnucastpkts; + u32_t ifoutdiscards; +#endif /* LWIP_SNMP */ +#if LWIP_IGMP + /** This function could be called to add or delete a entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; +#endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT + u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK + /* List of packets to be queued for ourselves. Ö¸Ïò·¢Ë͸ø×Ô¼ºµÄÊý¾Ý°üµÄpbuf*/ + struct pbuf *loop_first;//µÚÒ»¸ö + struct pbuf *loop_last;//×îºóÒ»¸ö +#if LWIP_LOOPBACK_MAX_PBUFS + u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_SNMP +#define NETIF_INIT_SNMP(netif, type, speed) \ + /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ + (netif)->link_type = (type); \ + /* your link speed here (units: bits per second) */ \ + (netif)->link_speed = (speed); \ + (netif)->ts = 0; \ + (netif)->ifinoctets = 0; \ + (netif)->ifinucastpkts = 0; \ + (netif)->ifinnucastpkts = 0; \ + (netif)->ifindiscards = 0; \ + (netif)->ifoutoctets = 0; \ + (netif)->ifoutucastpkts = 0; \ + (netif)->ifoutnucastpkts = 0; \ + (netif)->ifoutdiscards = 0 +#else /* LWIP_SNMP */ +#define NETIF_INIT_SNMP(netif, type, speed) +#endif /* LWIP_SNMP */ + + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +void netif_init(void)ICACHE_FLASH_ATTR; + +struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)ICACHE_FLASH_ATTR; + +void +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw)ICACHE_FLASH_ATTR; +void netif_remove(struct netif * netif)ICACHE_FLASH_ATTR; + +/* Returns a network interface given its name. The name is of the form + "et0", where the first two letters are the "name" field in the + netif structure, and the digit is in the num field in the same + structure. */ +struct netif *netif_find(char *name)ICACHE_FLASH_ATTR; + +void netif_set_default(struct netif *netif)ICACHE_FLASH_ATTR; + +void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +void netif_set_netmask(struct netif *netif, ip_addr_t *netmask)ICACHE_FLASH_ATTR; +void netif_set_gw(struct netif *netif, ip_addr_t *gw)ICACHE_FLASH_ATTR; + +void netif_set_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if an interface is up */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_STATUS_CALLBACK +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +void netif_set_link_up(struct netif *netif)ICACHE_FLASH_ATTR; +void netif_set_link_down(struct netif *netif)ICACHE_FLASH_ATTR; +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)ICACHE_FLASH_ATTR; +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if LWIP_NETIF_HOSTNAME +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip)ICACHE_FLASH_ATTR; +void netif_poll(struct netif *netif)ICACHE_FLASH_ATTR; +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void)ICACHE_FLASH_ATTR; +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETIF_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netifapi.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netifapi.h new file mode 100644 index 0000000..33318ef --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/netifapi.h @@ -0,0 +1,108 @@ +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef __LWIP_NETIFAPI_H__ +#define __LWIP_NETIFAPI_H__ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + +struct netifapi_msg_msg { +#if !LWIP_TCPIP_CORE_LOCKING + sys_sem_t sem; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ + err_t err; + struct netif *netif; + union { + struct { + ip_addr_t *ipaddr; + ip_addr_t *netmask; + ip_addr_t *gw; + void *state; + netif_init_fn init; + netif_input_fn input; + } add; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; + } common; + } msg; +}; + +struct netifapi_msg { + void (* function)(struct netifapi_msg_msg *msg); + struct netifapi_msg_msg msg; +}; + + +/* API for application */ +err_t netifapi_netif_add ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, + void *state, + netif_init_fn init, + netif_input_fn input); + +err_t netifapi_netif_set_addr ( struct netif *netif, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw ); + +err_t netifapi_netif_common ( struct netif *netif, + netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); + +#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) +#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) +#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) +#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/opt.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/opt.h new file mode 100644 index 0000000..1a681c9 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/opt.h @@ -0,0 +1,2043 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you dont like! + */ +#include "include/lwipopts.h" +#include "lwip/debug.h" + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT 0 +#endif + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS 1 +#endif + +/** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 1 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC 0 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE 1600 +#endif + +/** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 0 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK 0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * inlude path somewhere. + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB 4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB 5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 5 +#endif + +/** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE 30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 3 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN 4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API 8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#endif + +/** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 50 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 30 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 2 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 3 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 16 +#endif + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE 10 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING 0 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC 0 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + */ +#ifndef ETHARP_SUPPORT_VLAN +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED 1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 0 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST 0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV 0 +#endif + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW 1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL (IP_DEFAULT_TTL) +#endif + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 0 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP 0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required. + * Does not have to be changed unless external MIBs answer request asynchronously + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 1 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS 1 +#endif + +/** + * SNMP_PRIVATE_MIB: + * When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB 0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS 1 +#endif + +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS 0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE 4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE 512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + * you have to define + * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + * (an array of structs name/address, where address is an u32_t in network + * byte order). + * + * Instead, you can also use an external function: + * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + * that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE 0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#ifndef LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX 12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX 6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 536 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF 256 +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. + */ +//#ifndef LWIP_EVENT_API +//#define LWIP_EVENT_API 0 +//#define LWIP_CALLBACK_API 1 +//#else +//#define LWIP_EVENT_API 1 +//#define LWIP_CALLBACK_API 0 +//#endif + + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 1 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF 1 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF 0 +#endif + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppInputThread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME "pppInputThread" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE 0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN 0 +#endif + +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS 1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES 1 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE 0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#ifndef SO_REUSE +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS 1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS 1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS (NO_SYS == 0) +#endif + +#else + +#define LINK_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 + +#endif /* LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT 0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT 0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP 1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT 0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT 0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT 0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT 0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT 0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT 0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT 0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL 0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS 3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + * limits. See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + * of living in lcp.h) + */ +#define PPP_MTU 1500 /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU 1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU 64 +#define PPP_MRU 1500 /* default MRU = max length of info field */ +#define PPP_MAXMRU 1500 /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU 296 /* Try for this */ +#endif +#define PPP_MINMRU 128 /* No MRUs below this */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 256 /* max length of hostname or name for auth */ +#endif +#ifndef MAXSECRETLEN +#define MAXSECRETLEN 256 /* max length of password or secret */ +#endif + +#endif /* PPP_SUPPORT */ + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 1 +#endif + +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 1 +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/pbuf.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/pbuf.h new file mode 100644 index 0000000..3d24db4 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/pbuf.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG */ +#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN 20 + +typedef enum { + PBUF_TRANSPORT, + PBUF_IP, + PBUF_LINK, + PBUF_RAW +} pbuf_layer; + +typedef enum { + PBUF_RAM, /* pbuf data is stored in RAM */ + PBUF_ROM, /* pbuf data is stored in ROM */ + PBUF_REF, /* pbuf comes from the pbuf pool */ + PBUF_POOL, /* pbuf payload refers to RAM */ +#ifdef EBUF_LWIP + PBUF_ESF_RX /* pbuf payload is from WLAN */ +#endif /* ESF_LWIP */ +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a + a pbuf differently */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U + +struct pbuf { + /** next pbuf in singly linked pbuf chain */ + struct pbuf *next; + + /** pointer to the actual data in the buffer */ + void *payload; + + /** + * total length of this buffer and all next buffers in chain + * belonging to the same packet. + * + * For non-queue packet chains this is the invariant: + * p->tot_len == p->len + (p->next? p->next->tot_len: 0) + */ + u16_t tot_len; + + /** length of this buffer */ + u16_t len; + + /** pbuf_type as u8_t instead of enum to save space */ + u8_t /*pbuf_type*/ type; + + /** misc flags */ + u8_t flags; + + /** + * the reference count always equals the number of pointers + * that refer to this pbuf. This can be pointers from an application, + * the stack itself, or pbuf->next pointers from a chain. + */ + u16_t ref; + + /* add a pointer for esf_buf */ + void * eb; +}; + +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)ICACHE_FLASH_ATTR; +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len)ICACHE_FLASH_ATTR; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +void pbuf_realloc(struct pbuf *p, u16_t size)ICACHE_FLASH_ATTR; +u8_t pbuf_header(struct pbuf *p, s16_t header_size)ICACHE_FLASH_ATTR; +void pbuf_ref(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_free(struct pbuf *p)ICACHE_FLASH_ATTR; +u8_t pbuf_clen(struct pbuf *p)ICACHE_FLASH_ATTR; +void pbuf_cat(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +void pbuf_chain(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_dechain(struct pbuf *p)ICACHE_FLASH_ATTR; +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)ICACHE_FLASH_ATTR; +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)ICACHE_FLASH_ATTR; +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)ICACHE_FLASH_ATTR; +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)ICACHE_FLASH_ATTR; +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +u8_t pbuf_get_at(struct pbuf* p, u16_t offset)ICACHE_FLASH_ATTR; +u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)ICACHE_FLASH_ATTR; +u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)ICACHE_FLASH_ATTR; +u16_t pbuf_strstr(struct pbuf* p, const char* substr)ICACHE_FLASH_ATTR; + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/raw.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/raw.h new file mode 100644 index 0000000..c9c4087 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/raw.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/def.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip_addr_t *addr); + +struct raw_pcb { + /* Common members of all PCB types */ + IP_PCB; + + struct raw_pcb *next; + + u8_t protocol; + + /** receive callback function */ + raw_recv_fn recv; + /* user-supplied argument for the recv callback */ + void *recv_arg; +}; + +/* The following functions is the application layer interface to the + RAW code. */ +struct raw_pcb * raw_new (u8_t proto)ICACHE_FLASH_ATTR; +void raw_remove (struct raw_pcb *pcb)ICACHE_FLASH_ATTR; +err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)ICACHE_FLASH_ATTR; +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR; +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t raw_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +#define raw_init() /* Compatibility define, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sio.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sio.h new file mode 100644 index 0000000..228c857 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sio.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef __SIO_H__ +#define __SIO_H__ + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, + define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file + or be implemented in your custom sio.c file. */ + +#ifndef sio_open +/** + * Opens a serial device for communication. + * + * @param devnum device number + * @return handle to serial device if successful, NULL otherwise + */ +sio_fd_t sio_open(u8_t devnum)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_send +/** + * Sends a single character to the serial device. + * + * @param c character to send + * @param fd serial device handle + * + * @note This function will block until the character can be sent. + */ +void sio_send(u8_t c, sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_recv +/** + * Receives a single character from the serial device. + * + * @param fd serial device handle + * + * @note This function will block until a character is received. + */ +u8_t sio_recv(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read +/** + * Reads from the serial device. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort + * + * @note This function will block until data can be received. The blocking + * can be cancelled by calling sio_read_abort(). + */ +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_tryread +/** + * Tries to read from the serial device. Same as sio_read but returns + * immediately if no data is available and never blocks. + * + * @param fd serial device handle + * @param data pointer to data buffer for receiving + * @param len maximum length (in bytes) of data to receive + * @return number of bytes actually received + */ +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_write +/** + * Writes to the serial device. + * + * @param fd serial device handle + * @param data pointer to data to send + * @param len length (in bytes) of data to send + * @return number of bytes actually sent + * + * @note This function will block until all data can be sent. + */ +u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR; +#endif + +#ifndef sio_read_abort +/** + * Aborts a blocking sio_read() call. + * + * @param fd serial device handle + */ +void sio_read_abort(sio_fd_t fd)ICACHE_FLASH_ATTR; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __SIO_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp.h new file mode 100644 index 0000000..2ed043d --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Leon Woestenberg + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/ip_addr.h" + +struct udp_pcb; +struct netif; + +/** + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { + snmp_ifType_other=1, /* none of the following */ + snmp_ifType_regular1822, + snmp_ifType_hdh1822, + snmp_ifType_ddn_x25, + snmp_ifType_rfc877_x25, + snmp_ifType_ethernet_csmacd, + snmp_ifType_iso88023_csmacd, + snmp_ifType_iso88024_tokenBus, + snmp_ifType_iso88025_tokenRing, + snmp_ifType_iso88026_man, + snmp_ifType_starLan, + snmp_ifType_proteon_10Mbit, + snmp_ifType_proteon_80Mbit, + snmp_ifType_hyperchannel, + snmp_ifType_fddi, + snmp_ifType_lapb, + snmp_ifType_sdlc, + snmp_ifType_ds1, /* T-1 */ + snmp_ifType_e1, /* european equiv. of T-1 */ + snmp_ifType_basicISDN, + snmp_ifType_primaryISDN, /* proprietary serial */ + snmp_ifType_propPointToPointSerial, + snmp_ifType_ppp, + snmp_ifType_softwareLoopback, + snmp_ifType_eon, /* CLNP over IP [11] */ + snmp_ifType_ethernet_3Mbit, + snmp_ifType_nsip, /* XNS over IP */ + snmp_ifType_slip, /* generic SLIP */ + snmp_ifType_ultra, /* ULTRA technologies */ + snmp_ifType_ds3, /* T-3 */ + snmp_ifType_sip, /* SMDS */ + snmp_ifType_frame_relay +}; + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** SNMP "sysuptime" Interval */ +#define SNMP_SYSUPTIME_INTERVAL 10 + +/** fixed maximum length for object identifier type */ +#define LWIP_SNMP_OBJ_ID_LEN 32 + +/** internal object identifier representation */ +struct snmp_obj_id +{ + u8_t len; + s32_t id[LWIP_SNMP_OBJ_ID_LEN]; +}; + +/* system */ +void snmp_set_sysdesr(u8_t* str, u8_t* len); +void snmp_set_sysobjid(struct snmp_obj_id *oid); +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); +void snmp_inc_sysuptime(void); +void snmp_add_sysuptime(u32_t value); +void snmp_get_sysuptime(u32_t *value); +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); + +/* network interface */ +void snmp_add_ifinoctets(struct netif *ni, u32_t value); +void snmp_inc_ifinucastpkts(struct netif *ni); +void snmp_inc_ifinnucastpkts(struct netif *ni); +void snmp_inc_ifindiscards(struct netif *ni); +void snmp_add_ifoutoctets(struct netif *ni, u32_t value); +void snmp_inc_ifoutucastpkts(struct netif *ni); +void snmp_inc_ifoutnucastpkts(struct netif *ni); +void snmp_inc_ifoutdiscards(struct netif *ni); +void snmp_inc_iflist(void); +void snmp_dec_iflist(void); + +/* ARP (for atTable and ipNetToMediaTable) */ +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipinhdrerrors(void); +void snmp_inc_ipinaddrerrors(void); +void snmp_inc_ipforwdatagrams(void); +void snmp_inc_ipinunknownprotos(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutnoroutes(void); +void snmp_inc_ipreasmreqds(void); +void snmp_inc_ipreasmoks(void); +void snmp_inc_ipreasmfails(void); +void snmp_inc_ipfragoks(void); +void snmp_inc_ipfragfails(void); +void snmp_inc_ipfragcreates(void); +void snmp_inc_iproutingdiscards(void); +void snmp_insert_ipaddridx_tree(struct netif *ni); +void snmp_delete_ipaddridx_tree(struct netif *ni); +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void); +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); +void snmp_insert_udpidx_tree(struct udp_pcb *pcb); +void snmp_delete_udpidx_tree(struct udp_pcb *pcb); + +/* SNMP */ +void snmp_inc_snmpinpkts(void); +void snmp_inc_snmpoutpkts(void); +void snmp_inc_snmpinbadversions(void); +void snmp_inc_snmpinbadcommunitynames(void); +void snmp_inc_snmpinbadcommunityuses(void); +void snmp_inc_snmpinasnparseerrs(void); +void snmp_inc_snmpintoobigs(void); +void snmp_inc_snmpinnosuchnames(void); +void snmp_inc_snmpinbadvalues(void); +void snmp_inc_snmpinreadonlys(void); +void snmp_inc_snmpingenerrs(void); +void snmp_add_snmpintotalreqvars(u8_t value); +void snmp_add_snmpintotalsetvars(u8_t value); +void snmp_inc_snmpingetrequests(void); +void snmp_inc_snmpingetnexts(void); +void snmp_inc_snmpinsetrequests(void); +void snmp_inc_snmpingetresponses(void); +void snmp_inc_snmpintraps(void); +void snmp_inc_snmpouttoobigs(void); +void snmp_inc_snmpoutnosuchnames(void); +void snmp_inc_snmpoutbadvalues(void); +void snmp_inc_snmpoutgenerrs(void); +void snmp_inc_snmpoutgetrequests(void); +void snmp_inc_snmpoutgetnexts(void); +void snmp_inc_snmpoutsetrequests(void); +void snmp_inc_snmpoutgetresponses(void); +void snmp_inc_snmpouttraps(void); +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); +void snmp_set_snmpenableauthentraps(u8_t *value); +void snmp_get_snmpenableauthentraps(u8_t *value); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* system */ +#define snmp_set_sysdesr(str, len) +#define snmp_set_sysobjid(oid); +#define snmp_get_sysobjid_ptr(oid) +#define snmp_inc_sysuptime() +#define snmp_add_sysuptime(value) +#define snmp_get_sysuptime(value) +#define snmp_set_syscontact(ocstr, ocstrlen); +#define snmp_set_sysname(ocstr, ocstrlen); +#define snmp_set_syslocation(ocstr, ocstrlen); + +/* network interface */ +#define snmp_add_ifinoctets(ni,value) +#define snmp_inc_ifinucastpkts(ni) +#define snmp_inc_ifinnucastpkts(ni) +#define snmp_inc_ifindiscards(ni) +#define snmp_add_ifoutoctets(ni,value) +#define snmp_inc_ifoutucastpkts(ni) +#define snmp_inc_ifoutnucastpkts(ni) +#define snmp_inc_ifoutdiscards(ni) +#define snmp_inc_iflist() +#define snmp_dec_iflist() + +/* ARP */ +#define snmp_insert_arpidx_tree(ni,ip) +#define snmp_delete_arpidx_tree(ni,ip) + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipinhdrerrors() +#define snmp_inc_ipinaddrerrors() +#define snmp_inc_ipforwdatagrams() +#define snmp_inc_ipinunknownprotos() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutnoroutes() +#define snmp_inc_ipreasmreqds() +#define snmp_inc_ipreasmoks() +#define snmp_inc_ipreasmfails() +#define snmp_inc_ipfragoks() +#define snmp_inc_ipfragfails() +#define snmp_inc_ipfragcreates() +#define snmp_inc_iproutingdiscards() +#define snmp_insert_ipaddridx_tree(ni) +#define snmp_delete_ipaddridx_tree(ni) +#define snmp_insert_iprteidx_tree(dflt, ni) +#define snmp_delete_iprteidx_tree(dflt, ni) + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors() +#define snmp_inc_icmpindestunreachs() +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs() +#define snmp_inc_icmpinsrcquenchs() +#define snmp_inc_icmpinredirects() +#define snmp_inc_icmpinechos() +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps() +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs() +#define snmp_inc_icmpouttimeexcds() +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects() +#define snmp_inc_icmpoutechos() +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() +#define snmp_insert_udpidx_tree(pcb) +#define snmp_delete_udpidx_tree(pcb) + +/* SNMP */ +#define snmp_inc_snmpinpkts() +#define snmp_inc_snmpoutpkts() +#define snmp_inc_snmpinbadversions() +#define snmp_inc_snmpinbadcommunitynames() +#define snmp_inc_snmpinbadcommunityuses() +#define snmp_inc_snmpinasnparseerrs() +#define snmp_inc_snmpintoobigs() +#define snmp_inc_snmpinnosuchnames() +#define snmp_inc_snmpinbadvalues() +#define snmp_inc_snmpinreadonlys() +#define snmp_inc_snmpingenerrs() +#define snmp_add_snmpintotalreqvars(value) +#define snmp_add_snmpintotalsetvars(value) +#define snmp_inc_snmpingetrequests() +#define snmp_inc_snmpingetnexts() +#define snmp_inc_snmpinsetrequests() +#define snmp_inc_snmpingetresponses() +#define snmp_inc_snmpintraps() +#define snmp_inc_snmpouttoobigs() +#define snmp_inc_snmpoutnosuchnames() +#define snmp_inc_snmpoutbadvalues() +#define snmp_inc_snmpoutgenerrs() +#define snmp_inc_snmpoutgetrequests() +#define snmp_inc_snmpoutgetnexts() +#define snmp_inc_snmpoutsetrequests() +#define snmp_inc_snmpoutgetresponses() +#define snmp_inc_snmpouttraps() +#define snmp_get_snmpgrpid_ptr(oid) +#define snmp_set_snmpenableauthentraps(value) +#define snmp_get_snmpenableauthentraps(value) + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_asn1.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_asn1.h new file mode 100644 index 0000000..605fa3f --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_asn1.h @@ -0,0 +1,101 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_ASN1_H__ +#define __LWIP_SNMP_ASN1_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" + +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ +#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ +#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ + +#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ +#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ + +/* universal tags */ +#define SNMP_ASN1_INTEG 2 +#define SNMP_ASN1_OC_STR 4 +#define SNMP_ASN1_NUL 5 +#define SNMP_ASN1_OBJ_ID 6 +#define SNMP_ASN1_SEQ 16 + +/* application specific (SNMP) tags */ +#define SNMP_ASN1_IPADDR 0 /* octet string size(4) */ +#define SNMP_ASN1_COUNTER 1 /* u32_t */ +#define SNMP_ASN1_GAUGE 2 /* u32_t */ +#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ +#define SNMP_ASN1_OPAQUE 4 /* octet string */ + +/* context specific (SNMP) tags */ +#define SNMP_ASN1_PDU_GET_REQ 0 +#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_PDU_GET_RESP 2 +#define SNMP_ASN1_PDU_SET_REQ 3 +#define SNMP_ASN1_PDU_TRAP 4 + +err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); +err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); +err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); +err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); +err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); +err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); +err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_msg.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_msg.h new file mode 100644 index 0000000..1183e3a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_msg.h @@ -0,0 +1,315 @@ +/** + * @file + * SNMP Agent message handling structures. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_MSG_H__ +#define __LWIP_SNMP_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/snmp.h" +#include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#if LWIP_SNMP + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to + this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't + work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +#define SNMP_ES_NOERROR 0 +#define SNMP_ES_TOOBIG 1 +#define SNMP_ES_NOSUCHNAME 2 +#define SNMP_ES_BADVALUE 3 +#define SNMP_ES_READONLY 4 +#define SNMP_ES_GENERROR 5 + +#define SNMP_GENTRAP_COLDSTART 0 +#define SNMP_GENTRAP_WARMSTART 1 +#define SNMP_GENTRAP_AUTHFAIL 4 +#define SNMP_GENTRAP_ENTERPRISESPC 6 + +struct snmp_varbind +{ + /* next pointer, NULL for last in list */ + struct snmp_varbind *next; + /* previous pointer, NULL for first in list */ + struct snmp_varbind *prev; + + /* object identifier length (in s32_t) */ + u8_t ident_len; + /* object identifier array */ + s32_t *ident; + + /* object value ASN1 type */ + u8_t value_type; + /* object value length (in u8_t) */ + u8_t value_len; + /* object value */ + void *value; + + /* encoding varbind seq length length */ + u8_t seqlenlen; + /* encoding object identifier length length */ + u8_t olenlen; + /* encoding object value length length */ + u8_t vlenlen; + /* encoding varbind seq length */ + u16_t seqlen; + /* encoding object identifier length */ + u16_t olen; + /* encoding object value length */ + u16_t vlen; +}; + +struct snmp_varbind_root +{ + struct snmp_varbind *head; + struct snmp_varbind *tail; + /* number of variable bindings in list */ + u8_t count; + /* encoding varbind-list seq length length */ + u8_t seqlenlen; + /* encoding varbind-list seq length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_resp_header_lengths +{ + /* encoding error-index length length */ + u8_t erridxlenlen; + /* encoding error-status length length */ + u8_t errstatlenlen; + /* encoding request id length length */ + u8_t ridlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding error-index length */ + u16_t erridxlen; + /* encoding error-status length */ + u16_t errstatlen; + /* encoding request id length */ + u16_t ridlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_trap_header_lengths +{ + /* encoding timestamp length length */ + u8_t tslenlen; + /* encoding specific-trap length length */ + u8_t strplenlen; + /* encoding generic-trap length length */ + u8_t gtrplenlen; + /* encoding agent-addr length length */ + u8_t aaddrlenlen; + /* encoding enterprise-id length length */ + u8_t eidlenlen; + /* encoding pdu length length */ + u8_t pdulenlen; + /* encoding community length length */ + u8_t comlenlen; + /* encoding version length length */ + u8_t verlenlen; + /* encoding sequence length length */ + u8_t seqlenlen; + + /* encoding timestamp length */ + u16_t tslen; + /* encoding specific-trap length */ + u16_t strplen; + /* encoding generic-trap length */ + u16_t gtrplen; + /* encoding agent-addr length */ + u16_t aaddrlen; + /* encoding enterprise-id length */ + u16_t eidlen; + /* encoding pdu length */ + u16_t pdulen; + /* encoding community length */ + u16_t comlen; + /* encoding version length */ + u16_t verlen; + /* encoding sequence length */ + u16_t seqlen; +}; + +/* Accepting new SNMP messages. */ +#define SNMP_MSG_EMPTY 0 +/* Search for matching object for variable binding. */ +#define SNMP_MSG_SEARCH_OBJ 1 +/* Perform SNMP operation on in-memory object. + Pass-through states, for symmetry only. */ +#define SNMP_MSG_INTERNAL_GET_OBJDEF 2 +#define SNMP_MSG_INTERNAL_GET_VALUE 3 +#define SNMP_MSG_INTERNAL_SET_TEST 4 +#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 +#define SNMP_MSG_INTERNAL_SET_VALUE 6 +/* Perform SNMP operation on object located externally. + In theory this could be used for building a proxy agent. + Practical use is for an enterprise spc. app. gateway. */ +#define SNMP_MSG_EXTERNAL_GET_OBJDEF 7 +#define SNMP_MSG_EXTERNAL_GET_VALUE 8 +#define SNMP_MSG_EXTERNAL_SET_TEST 9 +#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 +#define SNMP_MSG_EXTERNAL_SET_VALUE 11 + +#define SNMP_COMMUNITY_STR_LEN 64 +struct snmp_msg_pstat +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* source IP address */ + ip_addr_t sip; + /* source UDP port */ + u16_t sp; + /* request type */ + u8_t rt; + /* request ID */ + s32_t rid; + /* error status */ + s32_t error_status; + /* error index */ + s32_t error_index; + /* community name (zero terminated) */ + u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; + /* community string length (exclusive zero term) */ + u8_t com_strlen; + /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ + u8_t state; + /* saved arguments for MSG_EXTERNAL_x */ + struct mib_external_node *ext_mib_node; + struct snmp_name_ptr ext_name_ptr; + struct obj_def ext_object_def; + struct snmp_obj_id ext_oid; + /* index into input variable binding list */ + u8_t vb_idx; + /* ptr into input variable binding list */ + struct snmp_varbind *vb_ptr; + /* list of variable bindings from input */ + struct snmp_varbind_root invb; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output response lengths used in ASN encoding */ + struct snmp_resp_header_lengths rhl; +}; + +struct snmp_msg_trap +{ + /* lwIP local port (161) binding */ + struct udp_pcb *pcb; + /* destination IP address in network order */ + ip_addr_t dip; + + /* source enterprise ID (sysObjectID) */ + struct snmp_obj_id *enterprise; + /* source IP address, raw network order format */ + u8_t sip_raw[4]; + /* generic trap code */ + u32_t gen_trap; + /* specific trap code */ + u32_t spc_trap; + /* timestamp */ + u32_t ts; + /* list of variable bindings to output */ + struct snmp_varbind_root outvb; + /* output trap lengths used in ASN encoding */ + struct snmp_trap_header_lengths thl; +}; + +/** Agent Version constant, 0 = v1 oddity */ +extern const s32_t snmp_version; +/** Agent default "public" community string */ +extern const char snmp_publiccommunity[7]; + +extern struct snmp_msg_trap trap_msg; + +/** Agent setup, start listening to port 161. */ +void snmp_init(void); +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); + +/** Varbind-list functions. */ +struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); +void snmp_varbind_free(struct snmp_varbind *vb); +void snmp_varbind_list_free(struct snmp_varbind_root *root); +void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); +struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); + +/** Handle an internal (recv) or external (private response) event. */ +void snmp_msg_event(u8_t request_id); +err_t snmp_send_response(struct snmp_msg_pstat *m_stat); +err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_structs.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_structs.h new file mode 100644 index 0000000..0d3b46a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/snmp_structs.h @@ -0,0 +1,268 @@ +/** + * @file + * Generic MIB tree structures. + * + * @todo namespace prefixes + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons + */ + +#ifndef __LWIP_SNMP_STRUCTS_H__ +#define __LWIP_SNMP_STRUCTS_H__ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" + +#if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MIB object instance */ +#define MIB_OBJECT_NONE 0 +#define MIB_OBJECT_SCALAR 1 +#define MIB_OBJECT_TAB 2 + +/* MIB access types */ +#define MIB_ACCESS_READ 1 +#define MIB_ACCESS_WRITE 2 + +/* MIB object access */ +#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ +#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) +#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE +#define MIB_OBJECT_NOT_ACCESSIBLE 0 + +/** object definition returned by (get_object_def)() */ +struct obj_def +{ + /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ + u8_t instance; + /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ + u8_t access; + /* ASN type for this object */ + u8_t asn_type; + /* value length (host length) */ + u16_t v_len; + /* length of instance part of supplied object identifier */ + u8_t id_inst_len; + /* instance part of supplied object identifier */ + s32_t *id_inst_ptr; +}; + +struct snmp_name_ptr +{ + u8_t ident_len; + s32_t *ident; +}; + +/** MIB const scalar (.0) node */ +#define MIB_NODE_SC 0x01 +/** MIB const array node */ +#define MIB_NODE_AR 0x02 +/** MIB array node (mem_malloced from RAM) */ +#define MIB_NODE_RA 0x03 +/** MIB list root node (mem_malloced from RAM) */ +#define MIB_NODE_LR 0x04 +/** MIB node for external objects */ +#define MIB_NODE_EX 0x05 + +/** node "base class" layout, the mandatory fields for a node */ +struct mib_node +{ + /** returns struct obj_def for the given object identifier */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + /** returns object value for the given object identifier, + @note the caller must allocate at least len bytes for the value */ + void (*get_value)(struct obj_def *od, u16_t len, void *value); + /** tests length and/or range BEFORE setting */ + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + /** sets object value, only to be called when set_test() */ + void (*set_value)(struct obj_def *od, u16_t len, void *value); + /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ + u8_t node_type; + /* array or max list length */ + u16_t maxlength; +}; + +/** derived node for scalars .0 index */ +typedef struct mib_node mib_scalar_node; + +/** derived node, points to a fixed size const array + of sub-identifiers plus a 'child' pointer */ +struct mib_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + const s32_t *objid; + struct mib_node* const *nptr; +}; + +/** derived node, points to a fixed size mem_malloced array + of sub-identifiers plus a 'child' pointer */ +struct mib_ram_array_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* aditional struct members */ + s32_t *objid; + struct mib_node **nptr; +}; + +struct mib_list_node +{ + struct mib_list_node *prev; + struct mib_list_node *next; + s32_t objid; + struct mib_node *nptr; +}; + +/** derived node, points to a doubly linked list + of sub-identifiers plus a 'child' pointer */ +struct mib_list_rootnode +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + struct mib_list_node *head; + struct mib_list_node *tail; + /* counts list nodes in list */ + u16_t count; +}; + +/** derived node, has access functions for mib object in external memory or device + using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ +struct mib_external_node +{ + /* inherited "base class" members */ + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); + u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); + void (*set_value)(struct obj_def *od, u16_t len, void *value); + + u8_t node_type; + u16_t maxlength; + + /* additional struct members */ + /** points to an external (in memory) record of some sort of addressing + information, passed to and interpreted by the funtions below */ + void* addr_inf; + /** tree levels under this node */ + u8_t tree_levels; + /** number of objects at this level */ + u16_t (*level_length)(void* addr_inf, u8_t level); + /** compares object sub identifier with external id + return zero when equal, nonzero when unequal */ + s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); + void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); + + /** async Questions */ + void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_q)(u8_t rid, struct obj_def *od); + void (*set_test_q)(u8_t rid, struct obj_def *od); + void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Answers */ + void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + /** async Panic Close (agent returns error reply, + e.g. used for external transaction cleanup) */ + void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_pc)(u8_t rid, struct obj_def *od); + void (*set_test_pc)(u8_t rid, struct obj_def *od); + void (*set_value_pc)(u8_t rid, struct obj_def *od); +}; + +/** export MIB tree from mib2.c */ +extern const struct mib_array_node internet; + +/** dummy function pointers for non-leaf MIB nodes from mib2.c */ +void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +void noleafs_get_value(struct obj_def *od, u16_t len, void *value); +u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); +void noleafs_set_value(struct obj_def *od, u16_t len, void *value); + +void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); +void snmp_iptooid(ip_addr_t *ip, s32_t *ident); +void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); +void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); + +struct mib_list_node* snmp_mib_ln_alloc(s32_t id); +void snmp_mib_ln_free(struct mib_list_node *ln); +struct mib_list_rootnode* snmp_mib_lrn_alloc(void); +void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); + +s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); +s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); +struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); + +struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); +struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); +u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); +u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sockets.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sockets.h new file mode 100644 index 0000000..3c8fed2 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sockets.h @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* members are in network byte order */ +struct sockaddr_in { + u8_t sin_len; + u8_t sin_family; + u16_t sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr { + u8_t sa_len; + u8_t sa_family; + char sa_data[14]; +}; + +#ifndef socklen_t +# define socklen_t u32_t +#endif + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) + */ +#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ + +#define SO_DONTLINGER ((int)(~SO_LINGER)) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ +#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xfff /* options for socket level */ + + +#define AF_UNSPEC 0 +#define AF_INET 2 +#define PF_INET AF_INET +#define PF_UNSPEC AF_UNSPEC + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define IPPROTO_UDPLITE 136 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK 0x01 /* Peeks at an incoming message */ +#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ +#define MSG_MORE 0x10 /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired. These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network. Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load). The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service. In many networks + * better performance for one of these parameters is coupled with worse + * performance on another. Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only. The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + +/* + * Commands for ioctlsocket(), taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000UL /* no parameters */ +#define IOC_OUT 0x40000000UL /* copy out parameters */ +#define IOC_IN 0x80000000UL /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* 0x20000000 distinguishes new & + old ioctl's */ +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ +#endif + +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ +#ifndef O_NONBLOCK +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET + #undef FD_SETSIZE + /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ + #define FD_SETSIZE MEMP_NUM_NETCONN + #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) + #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) + #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) + #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) + + typedef struct fd_set { + unsigned char fd_bits [(FD_SETSIZE+7)/8]; + } fd_set; + +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c) lwip_accept(a,b,c) +#define bind(a,b,c) lwip_bind(a,b,c) +#define shutdown(a,b) lwip_shutdown(a,b) +#define closesocket(s) lwip_close(s) +#define connect(a,b,c) lwip_connect(a,b,c) +#define getsockname(a,b,c) lwip_getsockname(a,b,c) +#define getpeername(a,b,c) lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b) lwip_listen(a,b) +#define recv(a,b,c,d) lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d) lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c) lwip_socket(a,b,c) +#define select(a,b,c,d,e) lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c) lwip_read(a,b,c) +#define write(a,b,c) lwip_write(a,b,c) +#define close(s) lwip_close(s) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/stats.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/stats.h new file mode 100644 index 0000000..4388321 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/stats.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER u32_t +#define STAT_COUNTER_F U32_F +#else +#define STAT_COUNTER u16_t +#define STAT_COUNTER_F U16_F +#endif + +struct stats_proto { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER fw; /* Forwarded packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER rterr; /* Routing error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER opterr; /* Error in options. */ + STAT_COUNTER err; /* Misc error. */ + STAT_COUNTER cachehit; +}; + +struct stats_igmp { + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ + STAT_COUNTER chkerr; /* Checksum error. */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ +}; + +struct stats_mem { +#ifdef LWIP_DEBUG + const char *name; +#endif /* LWIP_DEBUG */ + mem_size_t avail; + mem_size_t used; + mem_size_t max; + STAT_COUNTER err; + STAT_COUNTER illegal; +}; + +struct stats_syselem { + STAT_COUNTER used; + STAT_COUNTER max; + STAT_COUNTER err; +}; + +struct stats_sys { + struct stats_syselem sem; + struct stats_syselem mutex; + struct stats_syselem mbox; +}; + +struct stats_ { +#if LINK_STATS + struct stats_proto link; +#endif +#if ETHARP_STATS + struct stats_proto etharp; +#endif +#if IPFRAG_STATS + struct stats_proto ip_frag; +#endif +#if IP_STATS + struct stats_proto ip; +#endif +#if ICMP_STATS + struct stats_proto icmp; +#endif +#if IGMP_STATS + struct stats_igmp igmp; +#endif +#if UDP_STATS + struct stats_proto udp; +#endif +#if TCP_STATS + struct stats_proto tcp; +#endif +#if MEM_STATS + struct stats_mem mem; +#endif +#if MEMP_STATS + struct stats_mem memp[MEMP_MAX]; +#endif +#if SYS_STATS + struct stats_sys sys; +#endif +}; + +extern struct stats_ lwip_stats; + +void stats_init(void)ICACHE_FLASH_ATTR; + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#else /* LWIP_STATS */ +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#define STATS_INC_USED(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) +#define SYS_STATS_DISPLAY() +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void)ICACHE_FLASH_ATTR; +void stats_display_proto(struct stats_proto *proto, char *name)ICACHE_FLASH_ATTR; +void stats_display_igmp(struct stats_igmp *igmp)ICACHE_FLASH_ATTR; +void stats_display_mem(struct stats_mem *mem, char *name)ICACHE_FLASH_ATTR; +void stats_display_memp(struct stats_mem *mem, int index)ICACHE_FLASH_ATTR; +void stats_display_sys(struct stats_sys *sys)ICACHE_FLASH_ATTR; +#else /* LWIP_STATS_DISPLAY */ +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_STATS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sys.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sys.h new file mode 100644 index 0000000..31a9dea --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/sys.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "lwip/opt.h" + +#include "eagle_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null + definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; +typedef u8_t sys_mbox_t; + +#define sys_sem_new(s, c) ERR_OK +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mbox_new(m, s) ERR_OK +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(n,t,a,s,p) + +#define sys_msleep(t) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** Set a mutex invalid so that sys_mutex_valid returns 0 */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** Signals a semaphore + * @param sem the semaphore to signal */ +void sys_sem_signal(sys_sem_t *sem); +/** Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** Delete a semaphore + * @param sem semaphore to delete */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** Set a semaphore invalid so that sys_sem_valid returns 0 */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif + +/* Mailbox functions. */ + +/** Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (miminum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); +#endif +/** For now, we map straight to sys_arch implementation. */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +/** Delete an mbox + * @param mbox mbox to delete */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** Set an mbox invalid so that sys_mbox_valid returns 0 */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif + +/** The only thread function: + * Creates a new thread + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/* sys_init() must be called before anthing else. */ +void sys_init(void)ICACHE_FLASH_ATTR; + +#ifndef sys_jiffies +/** Ticks/jiffies since power up. */ +u32_t sys_jiffies(void)ICACHE_FLASH_ATTR; +#endif + +/** Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. */ +static inline u32_t sys_now(void) ICACHE_FLASH_ATTR; +static inline u32_t sys_now(void) +{ + return NOW()/(TIMER_CLK_FREQ/1000); +} + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex. This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void)ICACHE_FLASH_ATTR; +void sys_arch_unprotect(sys_prot_t pval)ICACHE_FLASH_ATTR; + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) lev = os_intr_lock() //fix by ives at 2014.3.24 +#define SYS_ARCH_UNPROTECT(lev) lev = os_intr_unlock() + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var += val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var -= val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + ret = var; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ + SYS_ARCH_DECL_PROTECT(old_level); \ + SYS_ARCH_PROTECT(old_level); \ + var = val; \ + SYS_ARCH_UNPROTECT(old_level); \ + } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SYS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp.h new file mode 100644 index 0000000..909ff9b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); + +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); + +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); + +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); + +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); + +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) TODO! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); + +enum tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +#if LWIP_CALLBACK_API + /* Function to call when a listener has been connected. + * @param arg user-supplied argument (tcp_pcb.callback_arg) + * @param pcb a new tcp_pcb that now is connected + * @param err an error argument (TODO: that is current always ERR_OK?) + * @return ERR_OK: accept the new connection, + * any other err_t abortsthe new connection + */ +#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ + type *next; /* for the linked list */ \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ + void *callback_arg; \ + /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ + DEF_ACCEPT_CALLBACK \ + /* ports are in host byte order */ \ + u16_t local_port + + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ + IP_PCB; +/** protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb); + + /* ports are in host byte order */ + u16_t remote_port; + + u8_t flags; +#define TF_ACK_DELAY ((u8_t)0x01U) /* Delayed ACK. */ +#define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ +#define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ +#define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ +#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */ +#define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ + + /* the rest of the fields are in host byte order + as we have to do some math with them */ + /* receiver variables */ + u32_t rcv_nxt; /* next seqno expected */ + u16_t rcv_wnd; /* receiver window available */ + u16_t rcv_ann_wnd; /* receiver window to announce */ + u32_t rcv_ann_right_edge; /* announced right edge of window */ + + /* Timers */ + u32_t tmr; + u8_t polltmr, pollinterval; + + /* Retransmission timer. */ + s16_t rtime; + + u16_t mss; /* maximum segment size */ + + /* RTT (round trip time) estimation variables */ + u32_t rttest; /* RTT estimate in 500ms ticks */ + u32_t rtseq; /* sequence number being timed */ + s16_t sa, sv; /* @todo document this */ + + s16_t rto; /* retransmission time-out */ + u8_t nrtx; /* number of retransmissions */ + + /* fast retransmit/recovery */ + u32_t lastack; /* Highest acknowledged seqno. */ + u8_t dupacks; + + /* congestion avoidance/control variables */ + u16_t cwnd; + u16_t ssthresh; + + /* sender variables */ + u32_t snd_nxt; /* next new seqno to be sent */ + u16_t snd_wnd; /* sender window */ + u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last + window update. */ + u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + + u16_t acked; + + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) + u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + + /* These are ordered by sequence number: */ + struct tcp_seg *unsent; /* Unsent (queued) segments. */ + struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ + struct tcp_seg *ooseq; /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS + u32_t ts_lastacksent; + u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + + /* idle time before KEEPALIVE is sent */ + u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE + u32_t keep_intvl; + u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ + + /* Persist timer counter */ + u32_t persist_cnt; + /* Persist timer back-off */ + u8_t persist_backoff; + + /* KEEPALIVE counter */ + u8_t keep_cnt_sent; +}; + +struct tcp_pcb_listen { +/* Common members of all PCB types */ + IP_PCB; +/* Protocol specific PCB members */ + TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if TCP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { + LWIP_EVENT_ACCEPT, + LWIP_EVENT_SENT, + LWIP_EVENT_RECV, + LWIP_EVENT_CONNECTED, + LWIP_EVENT_POLL, + LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, + enum lwip_event, + struct pbuf *p, + u16_t size, + err_t err); + +#endif /* LWIP_EVENT_API */ + +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void)ICACHE_FLASH_ATTR; + +void tcp_arg (struct tcp_pcb *pcb, void *arg) ICACHE_FLASH_ATTR; +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept) ICACHE_FLASH_ATTR; +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv) ICACHE_FLASH_ATTR; +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent)ICACHE_FLASH_ATTR; +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)ICACHE_FLASH_ATTR; +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err)ICACHE_FLASH_ATTR; + +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#define tcp_sndbuf(pcb) ((pcb)->snd_buf) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) + +#if TCP_LISTEN_BACKLOG +#define tcp_accepted(pcb) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ + (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ + pcb->state == LISTEN) +#endif /* TCP_LISTEN_BACKLOG */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len)ICACHE_FLASH_ATTR; +err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected)ICACHE_FLASH_ATTR; + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)ICACHE_FLASH_ATTR; +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_close (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)ICACHE_FLASH_ATTR; + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags)ICACHE_FLASH_ATTR; + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio)ICACHE_FLASH_ATTR; + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +extern err_t tcp_output(struct tcp_pcb *pcb); + + +const char* tcp_debug_state_str(enum tcp_state s)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp_impl.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp_impl.h new file mode 100644 index 0000000..f906c0d --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcp_impl.h @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCP_IMPL_H__ +#define __LWIP_TCP_IMPL_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, no init needed. */ +void tcp_tmr (void)ICACHE_FLASH_ATTR; /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void)ICACHE_FLASH_ATTR; +void tcp_fasttmr (void)ICACHE_FLASH_ATTR; + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio)ICACHE_FLASH_ATTR; +void tcp_abandon (struct tcp_pcb *pcb, int reset)ICACHE_FLASH_ATTR; +err_t tcp_send_empty_ack(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_rto (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_rexmit_fast (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 3000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 1000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 3U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); //Ô´¶Ë¿Ú + PACK_STRUCT_FIELD(u16_t dest); //Ä¿µÄ¶Ë¿Ú + PACK_STRUCT_FIELD(u32_t seqno); //ÐòºÅ + PACK_STRUCT_FIELD(u32_t ackno); //Ó¦´ðÐòºÅ + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//Êײ¿³¤¶È+±£Áôλ+±ê־λ + PACK_STRUCT_FIELD(u16_t wnd); //´°¿Ú´óС + PACK_STRUCT_FIELD(u16_t chksum); //УÑéºÍ + PACK_STRUCT_FIELD(u16_t urgp); //½ô¼±Ö¸Õë +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ + LWIP_EVENT_ERR, NULL, 0, (err)) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + do { \ + if((pcb)->accept != NULL) \ + (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(errf,arg,err) \ + do { \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segements on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + void *dataptr; /* pointer to the TCP data in the pbuf */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversized only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ + (flags & TF_SEG_OPTS_TS ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ + ((u32_t)4 << 16) | \ + (((u32_t)TCP_MSS / 256) << 8) | \ + (TCP_MSS & 255)) + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for(tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_purge(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +void tcp_segs_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +void tcp_seg_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR; +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)ICACHE_FLASH_ATTR; + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg)ICACHE_FLASH_ATTR; + +void tcp_rst(u32_t seqno, u32_t ackno, + ip_addr_t *local_ip, ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port)ICACHE_FLASH_ATTR; + +u32_t tcp_next_iss(void)ICACHE_FLASH_ATTR; + +void tcp_keepalive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; +void tcp_zero_window_probe(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR; + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)ICACHE_FLASH_ATTR; +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)ICACHE_FLASH_ATTR; +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr)ICACHE_FLASH_ATTR; +void tcp_debug_print_flags(u8_t flags)ICACHE_FLASH_ATTR; +void tcp_debug_print_state(enum tcp_state s)ICACHE_FLASH_ATTR; +void tcp_debug_print_pcbs(void)ICACHE_FLASH_ATTR; +s16_t tcp_pcbs_sane(void)ICACHE_FLASH_ATTR; +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void)ICACHE_FLASH_ATTR; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcpip.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcpip.h new file mode 100644 index 0000000..995ba8a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/tcpip.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" +#include "lwip/netifapi.h" +#include "lwip/pbuf.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/timers.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. */ +#ifndef LWIP_TCPIP_THREAD_ALIVE +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_mutex_t lock_tcpip_core; +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) +#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m) +#define TCPIP_APIMSG_ACK(m) +#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) +#define TCPIP_NETIFAPI_ACK(m) +#else /* LWIP_TCPIP_CORE_LOCKING */ +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#define TCPIP_APIMSG(m) tcpip_apimsg(m) +#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) +#define TCPIP_NETIFAPI(m) tcpip_netifapi(m) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_apimsg_lock(struct api_msg *apimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +#if LWIP_NETIF_API +err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); +#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +#if LWIP_TCPIP_TIMEOUT +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT */ + +enum tcpip_msg_type { +#if LWIP_NETCONN + TCPIP_MSG_API, +#endif /* LWIP_NETCONN */ + TCPIP_MSG_INPKT, +#if LWIP_NETIF_API + TCPIP_MSG_NETIFAPI, +#endif /* LWIP_NETIF_API */ +#if LWIP_TCPIP_TIMEOUT + TCPIP_MSG_TIMEOUT, + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT */ + TCPIP_MSG_CALLBACK +}; + +struct tcpip_msg { + enum tcpip_msg_type type; + sys_sem_t *sem; + union { +#if LWIP_NETCONN + struct api_msg *apimsg; +#endif /* LWIP_NETCONN */ +#if LWIP_NETIF_API + struct netifapi_msg *netifapimsg; +#endif /* LWIP_NETIF_API */ + struct { + struct pbuf *p; + struct netif *netif; + } inp; + struct { + tcpip_callback_fn function; + void *ctx; + } cb; +#if LWIP_TCPIP_TIMEOUT + struct { + u32_t msecs; + sys_timeout_handler h; + void *arg; + } tmo; +#endif /* LWIP_TCPIP_TIMEOUT */ + } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/timers.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/timers.h new file mode 100644 index 0000000..e9db02a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/timers.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ +#ifndef __LWIP_TIMERS_H__ +#define __LWIP_TIMERS_H__ + +#include "lwip/opt.h" + +/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) + +#if LWIP_TIMERS + +#include "lwip/err.h" +#include "lwip/sys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void)ICACHE_FLASH_ATTR; + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)ICACHE_FLASH_ATTR; +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR; +#if NO_SYS +void sys_check_timeouts(void)ICACHE_FLASH_ATTR; +void sys_restart_timeouts(void)ICACHE_FLASH_ATTR; +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TIMERS */ +#endif /* __LWIP_TIMERS_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/udp.h b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/udp.h new file mode 100644 index 0000000..cb53d33 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/ESP8266WiFi/src/lwip/udp.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ + PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf + * makes 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *addr, u16_t port); + + +struct udp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + + struct udp_pcb *next; + + u8_t flags; + /** ports are in host byte order */ + u16_t local_port, remote_port; + +#if LWIP_IGMP + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; +#endif /* LWIP_IGMP */ + +#if LWIP_UDPLITE + /** used for UDP_LITE only */ + u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ + void *recv_arg; +}; +/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the + UDP code. */ +struct udp_pcb * udp_new (void)ICACHE_FLASH_ATTR; +void udp_remove (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port)ICACHE_FLASH_ATTR; +void udp_disconnect (struct udp_pcb *pcb)ICACHE_FLASH_ATTR; +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg)ICACHE_FLASH_ATTR; +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif)ICACHE_FLASH_ATTR; +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port)ICACHE_FLASH_ATTR; +err_t udp_send (struct udp_pcb *pcb, struct pbuf *p)ICACHE_FLASH_ATTR; + +#if LWIP_CHECKSUM_ON_COPY +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#define udp_flags(pcb) ((pcb)->flags) +#define udp_setflags(pcb, f) ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void udp_input (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR; + +#define udp_init() /* Compatibility define, not init needed. */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr)ICACHE_FLASH_ATTR; +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/README.adoc b/libraries/MySensors/drivers/ESP8266/Ethernet/README.adoc new file mode 100644 index 0000000..8f890f0 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/README.adoc @@ -0,0 +1,24 @@ += Ethernet Library for Arduino = + +With the Arduino Ethernet Shield, this library allows an Arduino board to connect to the internet. + +For more information about this library please visit us at +http://www.arduino.cc/en/Reference/Ethernet + +== License == + +Copyright (c) 2010 Arduino LLC. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino new file mode 100644 index 0000000..6fa2787 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -0,0 +1,108 @@ +/* + Advanced Chat Server + + A more advanced server that distributes any incoming messages + to all connected clients but the client the message comes from. + To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + redesigned to make use of operator== 25 Nov 2013 + by Norbert Truchsess + + */ + +#include +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,1, 177); +IPAddress gateway(192,168,1, 1); +IPAddress subnet(255, 255, 0, 0); + + +// telnet defaults to port 23 +EthernetServer server(23); + +EthernetClient clients[4]; + +void setup() { + // initialize the ethernet device + Ethernet.begin(mac, ip, gateway, subnet); + // start listening for clients + server.begin(); + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + // when the client sends the first byte, say hello: + if (client) { + + boolean newClient = true; + for (byte i=0;i<4;i++) { + //check whether this client refers to the same socket as one of the existing instances: + if (clients[i]==client) { + newClient = false; + break; + } + } + + if (newClient) { + //check which of the existing clients can be overridden: + for (byte i=0;i<4;i++) { + if (!clients[i] && clients[i]!=client) { + clients[i] = client; + // clead out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.print("Hello, client number: "); + client.print(i); + client.println(); + break; + } + } + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to all other connected clients: + for (byte i=0;i<4;i++) { + if (clients[i] && (clients[i]!=client)) { + clients[i].write(thisChar); + } + } + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } + for (byte i=0;i<4;i++) { + if (!(clients[i].connected())) { + // client.stop() invalidates the internal socket-descriptor, so next use of == will allways return false; + clients[i].stop(); + } + } +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino new file mode 100644 index 0000000..2c85ddd --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino @@ -0,0 +1,223 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Serves the output of a Barometric Pressure Sensor as a web page. + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6,7, and 11 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + by Tom Igoe + */ + +#include +// the sensor communicates using SPI, so include the library: +#include + + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +// assign an IP address for the controller: +IPAddress ip(192, 168, 1, 20); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 255, 0); + + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +EthernetServer server(80); + + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading + +// pins used for the connection with the sensor +// the others you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +float temperature = 0.0; +long pressure = 0; +long lastReadingTime = 0; + +void setup() { + // start the SPI library: + SPI.begin(); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + server.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + Serial.begin(9600); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + + // give the sensor and Ethernet shield time to set up: + delay(1000); + + //Set the sensor to high resolution mode tp start readings: + writeRegister(0x03, 0x0A); + +} + +void loop() { + // check for a reading no more than once a second. + if (millis() - lastReadingTime > 1000) { + // if there's a reading ready, read it: + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + getData(); + // timestamp the last time you got a reading: + lastReadingTime = millis(); + } + } + + // listen for incoming Ethernet connections: + listenForEthernetClients(); +} + + +void getData() { + Serial.println("Getting reading"); + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + temperature = (float)tempData / 20.0; + + //Read the pressure data highest 3 bits: + byte pressureDataHigh = readRegister(0x1F, 1); + pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressureDataLow = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + pressure = ((pressureDataHigh << 16) | pressureDataLow) / 4; + + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" degrees C"); + Serial.print("Pressure: " + String(pressure)); + Serial.println(" Pa"); +} + +void listenForEthernetClients() { + // listen for incoming clients + EthernetClient client = server.available(); + if (client) { + Serial.println("Got a client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println(); + // print the current readings, in HTML format: + client.print("Temperature: "); + client.print(temperature); + client.print(" degrees C"); + client.println("
    "); + client.print("Pressure: " + String(pressure)); + client.print(" Pa"); + client.println("
    "); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + // close the connection: + client.stop(); + } +} + + +//Send a write command to SCP1000 +void writeRegister(byte registerName, byte registerValue) { + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName |= 0b00000010; //Write command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(registerName); //Send register location + SPI.transfer(registerValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + + +//Read register from the SCP1000: +unsigned int readRegister(byte registerName, int numBytes) { + byte inByte = 0; // incoming from the SPI read + unsigned int result = 0; // result to return + + // SCP1000 expects the register name in the upper 6 bits + // of the byte: + registerName <<= 2; + // command (read or write) goes in the lower two bits: + registerName &= 0b11111100; //Read command + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + int command = SPI.transfer(registerName); + // send a value of 0 to read the first byte returned: + inByte = SPI.transfer(0x00); + + result = inByte; + // if there's more than one byte returned, + // shift the first byte then get the second byte: + if (numBytes > 1) { + result = inByte << 8; + inByte = SPI.transfer(0x00); + result = result | inByte; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/ChatServer/ChatServer.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/ChatServer/ChatServer.ino new file mode 100644 index 0000000..927a60e --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/ChatServer/ChatServer.ino @@ -0,0 +1,80 @@ +/* + Chat Server + + A simple server that distributes any incoming messages to all + connected clients. To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + + */ + +#include +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +IPAddress ip(192, 168, 1, 177); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 0, 0); + + +// telnet defaults to port 23 +EthernetServer server(23); +boolean alreadyConnected = false; // whether or not the client was connected previously + +void setup() { + // initialize the ethernet device + Ethernet.begin(mac, ip, gateway, subnet); + // start listening for clients + server.begin(); + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + // when the client sends the first byte, say hello: + if (client) { + if (!alreadyConnected) { + // clead out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + alreadyConnected = true; + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to the client: + server.write(thisChar); + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } +} + + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino new file mode 100644 index 0000000..a41b774 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino @@ -0,0 +1,60 @@ +/* + DHCP-based IP printer + + This sketch uses the DHCP extensions to the Ethernet library + to get an IP address via DHCP and print the address obtained. + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 12 April 2011 + modified 9 Apr 2012 + by Tom Igoe + + */ + +#include +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 +}; + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + // this check is only needed on the Leonardo: + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for (;;) + ; + } + // print your local IP address: + Serial.print("My IP address: "); + for (byte thisByte = 0; thisByte < 4; thisByte++) { + // print the value of each byte of the IP address: + Serial.print(Ethernet.localIP()[thisByte], DEC); + Serial.print("."); + } + Serial.println(); +} + +void loop() { + +} + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino new file mode 100644 index 0000000..73cde4b --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino @@ -0,0 +1,88 @@ +/* + DHCP Chat Server + + A simple server that distributes any incoming messages to all + connected clients. To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + THis version attempts to get an IP address using DHCP + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 21 May 2011 + modified 9 Apr 2012 + by Tom Igoe + Based on ChatServer example by David A. Mellis + + */ + +#include +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte mac[] = { + 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 +}; +IPAddress ip(192, 168, 1, 177); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 0, 0); + +// telnet defaults to port 23 +EthernetServer server(23); +boolean gotAMessage = false; // whether or not you got a message from the client yet + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + // this check is only needed on the Leonardo: + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // start the Ethernet connection: + Serial.println("Trying to get an IP address using DHCP"); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // initialize the ethernet device not using DHCP: + Ethernet.begin(mac, ip, gateway, subnet); + } + // print your local IP address: + Serial.print("My IP address: "); + ip = Ethernet.localIP(); + for (byte thisByte = 0; thisByte < 4; thisByte++) { + // print the value of each byte of the IP address: + Serial.print(ip[thisByte], DEC); + Serial.print("."); + } + Serial.println(); + // start listening for clients + server.begin(); + +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + // when the client sends the first byte, say hello: + if (client) { + if (!gotAMessage) { + Serial.println("We have a new client"); + client.println("Hello, client!"); + gotAMessage = true; + } + + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to the client: + server.write(thisChar); + // echo the bytes to the server as well: + Serial.print(thisChar); + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/TelnetClient/TelnetClient.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/TelnetClient/TelnetClient.ino new file mode 100644 index 0000000..dcf3e8a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/TelnetClient/TelnetClient.ino @@ -0,0 +1,94 @@ +/* + Telnet client + + This sketch connects to a a telnet server (http://www.google.com) + using an Arduino Wiznet Ethernet shield. You'll need a telnet server + to test this with. + Processing's ChatServer example (part of the network library) works well, + running on port 10002. It can be found as part of the examples + in the Processing application, available at + http://processing.org/ + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 14 Sep 2010 + modified 9 Apr 2012 + by Tom Igoe + + */ + +#include +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +IPAddress ip(192, 168, 1, 177); + +// Enter the IP address of the server you're connecting to: +IPAddress server(1, 1, 1, 1); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 23 is default for telnet; +// if you're using Processing's ChatServer, use port 10002): +EthernetClient client; + +void setup() { + // start the Ethernet connection: + Ethernet.begin(mac, ip); + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // give the Ethernet shield a second to initialize: + delay(1000); + Serial.println("connecting..."); + + // if you get a connection, report back via serial: + if (client.connect(server, 10002)) { + Serial.println("connected"); + } + else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } +} + +void loop() +{ + // if there are incoming bytes available + // from the server, read them and print them: + if (client.available()) { + char c = client.read(); + Serial.print(c); + } + + // as long as there are bytes in the serial queue, + // read them and send them out the socket if it's open: + while (Serial.available() > 0) { + char inChar = Serial.read(); + if (client.connected()) { + client.print(inChar); + } + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + // do nothing: + while (true); + } +} + + + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino new file mode 100644 index 0000000..99de765 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino @@ -0,0 +1,119 @@ +/* + UDPSendReceive.pde: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender + + A Processing sketch is included at the end of file that can be used to send + and received messages for testing with a computer. + + created 21 Aug 2010 + by Michael Margolis + + This code is in the public domain. + */ + + +#include // needed for Arduino versions later than 0018 +#include +#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +IPAddress ip(192, 168, 1, 177); + +unsigned int localPort = 8888; // local port to listen on + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, +char ReplyBuffer[] = "acknowledged"; // a string to send back + +// An EthernetUDP instance to let us send and receive packets over UDP +EthernetUDP Udp; + +void setup() { + // start the Ethernet and UDP: + Ethernet.begin(mac, ip); + Udp.begin(localPort); + + Serial.begin(9600); +} + +void loop() { + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) + { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remote = Udp.remoteIP(); + for (int i = 0; i < 4; i++) + { + Serial.print(remote[i], DEC); + if (i < 3) + { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } + delay(10); +} + + +/* + Processing sketch to run with this example + ===================================================== + + // Processing UDP example to send and receive string data from Arduino + // press any key to send the "Hello Arduino" message + + + import hypermedia.net.*; + + UDP udp; // define the UDP object + + + void setup() { + udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 + //udp.log( true ); // <-- printout the connection activity + udp.listen( true ); // and wait for incoming message + } + + void draw() + { + } + + void keyPressed() { + String ip = "192.168.1.177"; // the remote IP address + int port = 8888; // the destination port + + udp.send("Hello World", ip, port ); // the message to send + + } + + void receive( byte[] data ) { // <-- default handler + //void receive( byte[] data, String ip, int port ) { // <-- extended handler + + for(int i=0; i < data.length; i++) + print(char(data[i])); + println(); + } + */ + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino new file mode 100644 index 0000000..25c71c4 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino @@ -0,0 +1,142 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + + This code is in the public domain. + + */ + +#include +#include +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned int localPort = 8888; // local port to listen for UDP packets + +char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +EthernetUDP Udp; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // start Ethernet and UDP + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for (;;) + ; + } + Udp.begin(localPort); +} + +void loop() +{ + sendNTPpacket(timeServer); // send an NTP packet to a time server + + // wait to see if a reply is available + delay(1000); + if ( Udp.parsePacket() ) { + // We've received a packet, read the data from it + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = " ); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if ( ((epoch % 3600) / 60) < 10 ) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ( (epoch % 60) < 10 ) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(char* address) +{ + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); //NTP requests are to port 123 + Udp.write(packetBuffer, NTP_PACKET_SIZE); + Udp.endPacket(); +} + + + + + + + + + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClient/WebClient.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClient/WebClient.ino new file mode 100644 index 0000000..9afd40e --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClient/WebClient.ino @@ -0,0 +1,88 @@ +/* + Web client + + This sketch connects to a website (http://www.google.com) + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe, based on work by Adrian McEwen + + */ + +#include +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + // try to congifure using IP address instead of DHCP: + Ethernet.begin(mac, ip); + } + // give the Ethernet shield a second to initialize: + delay(1000); + Serial.println("connecting..."); + + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.println("connected"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } + else { + // kf you didn't get a connection to the server: + Serial.println("connection failed"); + } +} + +void loop() +{ + // if there are incoming bytes available + // from the server, read them and print them: + if (client.available()) { + char c = client.read(); + Serial.print(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino new file mode 100644 index 0000000..ad3f461 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino @@ -0,0 +1,108 @@ +/* + Repeating Web client + + This sketch connects to a a web server and makes a request + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. + + This example uses DNS, by assigning the Ethernet client with a MAC address, + IP address, and DNS address. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + + created 19 Apr 2012 + by Tom Igoe + modified 21 Jan 2014 + by Federico Vanzati + + http://www.arduino.cc/en/Tutorial/WebClientRepeating + This code is in the public domain. + + */ + +#include +#include + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(192, 168, 1, 177); + +// fill in your Domain Name Server address here: +IPAddress myDns(1, 1, 1, 1); + +// initialize the library instance: +EthernetClient client; + +char server[] = "www.arduino.cc"; +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds +// the "L" is needed to use long type numbers + +void setup() { + // start serial port: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + // give the ethernet module time to boot up: + delay(1000); + // start the Ethernet connection using a fixed IP address and DNS server: + Ethernet.begin(mac, ip, myDns); + // print the Ethernet board/shield's IP address: + Serial.print("My IP address: "); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + if (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } + +} + +// this method makes a HTTP connection to the server: +void httpRequest() { + // close any connection before send a new request. + // This will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection: + if (client.connect(server, 80)) { + Serial.println("connecting..."); + // send the HTTP PUT request: + client.println("GET /latest.txt HTTP/1.1"); + client.println("Host: www.arduino.cc"); + client.println("User-Agent: arduino-ethernet"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } + else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebServer/WebServer.ino b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebServer/WebServer.ino new file mode 100644 index 0000000..d0c585d --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/examples/WebServer/WebServer.ino @@ -0,0 +1,101 @@ +/* + Web Server + + A simple web server that shows the value of the analog input pins. + using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + + */ + +#include +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +IPAddress ip(192, 168, 1, 177); + +// Initialize the Ethernet server library +// with the IP address and port you want to use +// (port 80 is default for HTTP): +EthernetServer server(80); + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + server.begin(); + Serial.print("server is at "); + Serial.println(Ethernet.localIP()); +} + + +void loop() { + // listen for incoming clients + EthernetClient client = server.available(); + if (client) { + Serial.println("new client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println("Connection: close"); // the connection will be closed after completion of the response + client.println("Refresh: 5"); // refresh the page automatically every 5 sec + client.println(); + client.println(""); + client.println(""); + // output the value of each analog input pin + for (int analogChannel = 0; analogChannel < 6; analogChannel++) { + int sensorReading = analogRead(analogChannel); + client.print("analog input "); + client.print(analogChannel); + client.print(" is "); + client.print(sensorReading); + client.println("
    "); + } + client.println(""); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/keywords.txt b/libraries/MySensors/drivers/ESP8266/Ethernet/keywords.txt new file mode 100644 index 0000000..7b162a5 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For Ethernet +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Ethernet KEYWORD1 Ethernet +EthernetClient KEYWORD1 EthernetClient +EthernetServer KEYWORD1 EthernetServer +IPAddress KEYWORD1 EthernetIPAddress + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +status KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/library.properties b/libraries/MySensors/drivers/ESP8266/Ethernet/library.properties new file mode 100644 index 0000000..8fdc11d --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/library.properties @@ -0,0 +1,9 @@ +name=Ethernet +version=1.0.4 +author=Arduino +maintainer=Arduino +sentence=Enables network connection (local and Internet) using the Arduino Ethernet board or shield. For all Arduino boards. +paragraph=With this library you can use the Arduino Ethernet (shield or board) to connect to Internet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. +category=Communication +url=http://www.arduino.cc/en/Reference/Ethernet +architectures=* diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.cpp new file mode 100644 index 0000000..4402bad --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.cpp @@ -0,0 +1,481 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include "utility/w5100.h" + +#include +#include +#include "Dhcp.h" +#include "Arduino.h" +#include "utility/util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + _dhcpLeaseTime=0; + _dhcpT1=0; + _dhcpT2=0; + _lastCheck=0; + _timeout = timeout; + _responseTimeout = responseTimeout; + + // zero out _dhcpMacAddr + memset(_dhcpMacAddr, 0, 6); + reset_DHCP_lease(); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + _dhcp_state = STATE_DHCP_START; + return request_DHCP_lease(); +} + +void DhcpClass::reset_DHCP_lease(){ + // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpLocalIp, 0, 20); +} + +//return:0 on error, 1 if request is sent and response is received +int DhcpClass::request_DHCP_lease(){ + + uint8_t messageType = 0; + + + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + _dhcpUdpSocket.stop(); + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(_dhcp_state != STATE_DHCP_LEASED) + { + if(_dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_DISCOVER; + } + else if(_dhcp_state == STATE_DHCP_REREQUEST){ + _dhcpTransactionId++; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + else if(_dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(_dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_ACK) + { + _dhcp_state = STATE_DHCP_LEASED; + result = 1; + //use default lease time if we didn't get it + if(_dhcpLeaseTime == 0){ + _dhcpLeaseTime = DEFAULT_LEASE; + } + //calculate T1 & T2 if we didn't get it + if(_dhcpT1 == 0){ + //T1 should be 50% of _dhcpLeaseTime + _dhcpT1 = _dhcpLeaseTime >> 1; + } + if(_dhcpT2 == 0){ + //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime + _dhcpT2 = _dhcpT1 << 1; + } + _renewInSec = _dhcpT1; + _rebindInSec = _dhcpT2; + } + else if(messageType == DHCP_NAK) + _dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + _dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > _timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); + printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); + printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 30); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if ((_dhcpDhcpServerIp[0] == 0 && _dhcpDhcpServerIp[1] == 0 && + _dhcpDhcpServerIp[2] == 0 && _dhcpDhcpServerIp[3] == 0) || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpT1value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1)); + _dhcpT1 = ntohl(_dhcpT1); + break; + + case dhcpT2value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2)); + _dhcpT2 = ntohl(_dhcpT2); + break; + + case dhcpIPaddrLeaseTime : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); + _dhcpLeaseTime = ntohl(_dhcpLeaseTime); + _renewInSec = _dhcpLeaseTime; + break; + + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + + +/* + returns: + 0/DHCP_CHECK_NONE: nothing happened + 1/DHCP_CHECK_RENEW_FAIL: renew failed + 2/DHCP_CHECK_RENEW_OK: renew success + 3/DHCP_CHECK_REBIND_FAIL: rebind fail + 4/DHCP_CHECK_REBIND_OK: rebind success +*/ +int DhcpClass::checkLease(){ + //this uses a signed / unsigned trick to deal with millis overflow + unsigned long now = millis(); + signed long snow = (long)now; + int rc=DHCP_CHECK_NONE; + if (_lastCheck != 0){ + signed long factor; + //calc how many ms past the timeout we are + factor = snow - (long)_secTimeout; + //if on or passed the timeout, reduce the counters + if ( factor >= 0 ){ + //next timeout should be now plus 1000 ms minus parts of second in factor + _secTimeout = snow + 1000 - factor % 1000; + //how many seconds late are we, minimum 1 + factor = factor / 1000 +1; + + //reduce the counters by that mouch + //if we can assume that the cycle time (factor) is fairly constant + //and if the remainder is less than cycle time * 2 + //do it early instead of late + if(_renewInSec < factor*2 ) + _renewInSec = 0; + else + _renewInSec -= factor; + + if(_rebindInSec < factor*2 ) + _rebindInSec = 0; + else + _rebindInSec -= factor; + } + + //if we have a lease but should renew, do it + if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){ + _dhcp_state = STATE_DHCP_REREQUEST; + rc = 1 + request_DHCP_lease(); + } + + //if we have a lease or is renewing but should bind, do it + if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){ + //this should basically restart completely + _dhcp_state = STATE_DHCP_START; + reset_DHCP_lease(); + rc = 3 + request_DHCP_lease(); + } + } + else{ + _secTimeout = snow + 1000; + } + + _lastCheck = now; + return rc; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + +void DhcpClass::printByte(char * buf, uint8_t n ) { + char *str = &buf[1]; + buf[0]='0'; + do { + unsigned long m = n; + n /= 16; + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.h new file mode 100644 index 0000000..f59c7e7 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dhcp.h @@ -0,0 +1,178 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "EthernetUdp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "WIZnet" +#define DEFAULT_LEASE (900) //default lease time in seconds + +#define DHCP_CHECK_NONE (0) +#define DHCP_CHECK_RENEW_FAIL (1) +#define DHCP_CHECK_RENEW_OK (2) +#define DHCP_CHECK_REBIND_FAIL (3) +#define DHCP_CHECK_REBIND_OK (4) + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct __attribute__((packed)) _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + signed long _renewInSec; + signed long _rebindInSec; + signed long _lastCheck; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _secTimeout; + uint8_t _dhcp_state; + EthernetUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.cpp new file mode 100644 index 0000000..62e36f8 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.cpp @@ -0,0 +1,423 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "utility/w5100.h" +#include "EthernetUdp.h" +#include "utility/util.h" + +#include "Dns.h" +#include +//#include +#include "Arduino.h" + + +#define SOCKET_NONE 255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p =aIPAddrString; + while (*p && + ( (*p == '.') || (*p >= '0') || (*p <= '9') )) + { + p++; + } + + if (*p == '\0') + { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + int segment =0; + int segmentValue =0; + while (*p && (segment < 4)) + { + if (*p == '.') + { + // We've reached the end of a segment + if (segmentValue > 255) + { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + segment++; + segmentValue = 0; + } + } + else + { + // Next digit + segmentValue = (segmentValue*10)+(*p - '0'); + } + p++; + } + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) + { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + return 1; + } + } + else + { + return 0; + } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ + int ret =0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) + { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) + { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) + { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) + { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) + { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) + { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) + { + ret = ProcessResponse(5000, aResult); + wait_retries++; + } + } + } + } + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) + { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) + { + end++; + } + + if (end-start > 0) + { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return 1; +} + + +uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) +{ + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) + { + if((millis() - startTime) > aTimeout) + return TIMED_OUT; + delay(50); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || + (iUdp.remotePort() != DNS_PORT) ) + { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) + { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*)&header[2])); + // Check that it's a response to this request + if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || + ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) + { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) + { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*)&header[6])); + if (answerCount == 0 ) + { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) + { + // Skip over the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if (len > 0) + { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i =0; i < 4; i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (uint16_t i =0; i < answerCount; i++) + { + // Skip the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) + { + // It's just a normal label + if (len > 0) + { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + else + { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i =0; i < TTL_SIZE; i++) + { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) + { + if (htons(header_flags) != 4) + { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9;//INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); + return SUCCESS; + } + else + { + // This isn't an answer type we're after, move onto the next one + for (uint16_t i =0; i < htons(header_flags); i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10;//INVALID_RESPONSE; +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.h new file mode 100644 index 0000000..c99f5c3 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include + +class DNSClient +{ +public: + // ctor + void begin(const IPAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char *aIPAddrString, IPAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + uint16_t BuildRequest(const char* aName); + uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + EthernetUDP iUdp; +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.cpp new file mode 100644 index 0000000..3eea69a --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.cpp @@ -0,0 +1,136 @@ +#include "utility/w5100.h" +#include "Ethernet.h" +#include "Dhcp.h" + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { + 0, 0, 0, 0 }; +uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { + 0, 0, 0, 0 }; + +int EthernetClass::begin(uint8_t *mac_address) +{ + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + + + // Initialise the basic info + W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac_address); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + SPI.endTransaction(); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(mac_address, local_ip, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; + gateway[3] = 1; + begin(mac_address, local_ip, dns_server, gateway); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, dns_server, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setMACAddress(mac); + W5100.setIPAddress(local_ip.raw_address()); + W5100.setGatewayIp(gateway.raw_address()); + W5100.setSubnetMask(subnet.raw_address()); + SPI.endTransaction(); + _dnsServerAddress = dns_server; +} + +int EthernetClass::maintain(){ + int rc = DHCP_CHECK_NONE; + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); + W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); + W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); + _dnsServerAddress = _dhcp->getDnsServerIp(); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getIPAddress(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getSubnetMask(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.getGatewayIp(ret.raw_address()); + SPI.endTransaction(); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +EthernetClass Ethernet; diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.h new file mode 100644 index 0000000..2a07ff3 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/Ethernet.h @@ -0,0 +1,41 @@ +#ifndef ethernet_h +#define ethernet_h + +#include +//#include "w5100.h" +#include "IPAddress.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dhcp.h" + +#define MAX_SOCK_NUM 4 + +class EthernetClass { +private: + IPAddress _dnsServerAddress; + DhcpClass* _dhcp; +public: + static uint8_t _state[MAX_SOCK_NUM]; + static uint16_t _server_port[MAX_SOCK_NUM]; + // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + int maintain(); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + + friend class EthernetClient; + friend class EthernetServer; +}; + +extern EthernetClass Ethernet; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.cpp new file mode 100644 index 0000000..1feed4c --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.cpp @@ -0,0 +1,173 @@ +#include "utility/w5100.h" +#include "utility/socket.h" + +extern "C" { + #include "string.h" +} + +#include "Arduino.h" + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dns.h" + +uint16_t EthernetClient::_srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 + +EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) { +} + +EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) { +} + +int EthernetClient::connect(const char* host, uint16_t port) { + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } else { + return ret; + } +} + +int EthernetClient::connect(IPAddress ip, uint16_t port) { + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = socketStatus(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + _srcport++; + if (_srcport == 0) _srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 + socket(_sock, SnMR::TCP, _srcport, 0); + + if (!::connect(_sock, rawIPAddress(ip), port)) { + _sock = MAX_SOCK_NUM; + return 0; + } + + while (status() != SnSR::ESTABLISHED) { + delay(1); + if (status() == SnSR::CLOSED) { + _sock = MAX_SOCK_NUM; + return 0; + } + } + + return 1; +} + +size_t EthernetClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t EthernetClient::write(const uint8_t *buf, size_t size) { + if (_sock == MAX_SOCK_NUM) { + setWriteError(); + return 0; + } + if (!send(_sock, buf, size)) { + setWriteError(); + return 0; + } + return size; +} + +int EthernetClient::available() { + if (_sock != MAX_SOCK_NUM) + return recvAvailable(_sock); + return 0; +} + +int EthernetClient::read() { + uint8_t b; + if ( recv(_sock, &b, 1) > 0 ) + { + // recv worked + return b; + } + else + { + // No data available + return -1; + } +} + +int EthernetClient::read(uint8_t *buf, size_t size) { + return recv(_sock, buf, size); +} + +int EthernetClient::peek() { + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must + if (!available()) + return -1; + ::peek(_sock, &b); + return b; +} + +void EthernetClient::flush() { + ::flush(_sock); +} + +void EthernetClient::stop() { + if (_sock == MAX_SOCK_NUM) + return; + + // attempt to close the connection gracefully (send a FIN to other side) + disconnect(_sock); + unsigned long start = millis(); + + // wait up to a second for the connection to close + uint8_t s; + do { + s = status(); + if (s == SnSR::CLOSED) + break; // exit the loop + delay(1); + } while (millis() - start < 1000); + + // if it hasn't closed, close it forcefully + if (s != SnSR::CLOSED) + close(_sock); + + EthernetClass::_server_port[_sock] = 0; + _sock = MAX_SOCK_NUM; +} + +uint8_t EthernetClient::connected() { + if (_sock == MAX_SOCK_NUM) return 0; + + uint8_t s = status(); + return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT || + (s == SnSR::CLOSE_WAIT && !available())); +} + +uint8_t EthernetClient::status() { + if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; + return socketStatus(_sock); +} + +// the next function allows us to use the client returned by +// EthernetServer::available() as the condition in an if-statement. + +EthernetClient::operator bool() { + return _sock != MAX_SOCK_NUM; +} + +bool EthernetClient::operator==(const EthernetClient& rhs) { + return _sock == rhs._sock && _sock != MAX_SOCK_NUM && rhs._sock != MAX_SOCK_NUM; +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.h new file mode 100644 index 0000000..16e2500 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetClient.h @@ -0,0 +1,41 @@ +#ifndef ethernetclient_h +#define ethernetclient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class EthernetClient : public Client { + +public: + EthernetClient(); + EthernetClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + + friend class EthernetServer; + + using Print::write; + +private: + static uint16_t _srcport; + uint8_t _sock; +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.cpp new file mode 100644 index 0000000..cfa813e --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.cpp @@ -0,0 +1,92 @@ +#include "utility/w5100.h" +#include "utility/socket.h" +extern "C" { +#include "string.h" +} + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" + +EthernetServer::EthernetServer(uint16_t port) +{ + _port = port; +} + +void EthernetServer::begin() +{ + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + if (client.status() == SnSR::CLOSED) { + socket(sock, SnMR::TCP, _port, 0); + listen(sock); + EthernetClass::_server_port[sock] = _port; + break; + } + } +} + +void EthernetServer::accept() +{ + int listening = 0; + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + + if (EthernetClass::_server_port[sock] == _port) { + if (client.status() == SnSR::LISTEN) { + listening = 1; + } + else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) { + client.stop(); + } + } + } + + if (!listening) { + begin(); + } +} + +EthernetClient EthernetServer::available() +{ + accept(); + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + if (EthernetClass::_server_port[sock] == _port) { + uint8_t s = client.status(); + if (s == SnSR::ESTABLISHED || s == SnSR::CLOSE_WAIT) { + if (client.available()) { + // XXX: don't always pick the lowest numbered socket. + return client; + } + } + } + } + + return EthernetClient(MAX_SOCK_NUM); +} + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + + accept(); + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { + EthernetClient client(sock); + + if (EthernetClass::_server_port[sock] == _port && + client.status() == SnSR::ESTABLISHED) { + n += client.write(buffer, size); + } + } + + return n; +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.h new file mode 100644 index 0000000..86ccafe --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetServer.h @@ -0,0 +1,22 @@ +#ifndef ethernetserver_h +#define ethernetserver_h + +#include "Server.h" + +class EthernetClient; + +class EthernetServer : +public Server { +private: + uint16_t _port; + void accept(); +public: + EthernetServer(uint16_t); + EthernetClient available(); + virtual void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + using Print::write; +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.cpp new file mode 100644 index 0000000..b5dcb78 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.cpp @@ -0,0 +1,218 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#include "utility/w5100.h" +#include "utility/socket.h" +#include "Ethernet.h" +#include "Udp.h" +#include "Dns.h" + +/* Constructor */ +EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} + +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::begin(uint16_t port) { + if (_sock != MAX_SOCK_NUM) + return 0; + + for (int i = 0; i < MAX_SOCK_NUM; i++) { + uint8_t s = socketStatus(i); + if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { + _sock = i; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return 0; + + _port = port; + _remaining = 0; + socket(_sock, SnMR::UDP, _port, 0); + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int EthernetUDP::available() { + return _remaining; +} + +/* Release any resources being used by this EthernetUDP instance */ +void EthernetUDP::stop() +{ + if (_sock == MAX_SOCK_NUM) + return; + + close(_sock); + + EthernetClass::_server_port[_sock] = 0; + _sock = MAX_SOCK_NUM; +} + +int EthernetUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + +int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) +{ + _offset = 0; + return startUDP(_sock, rawIPAddress(ip), port); +} + +int EthernetUDP::endPacket() +{ + return sendUDP(_sock); +} + +size_t EthernetUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t EthernetUDP::write(const uint8_t *buffer, size_t size) +{ + uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); + _offset += bytes_written; + return bytes_written; +} + +int EthernetUDP::parsePacket() +{ + // discard any remaining bytes in the last packet + flush(); + + if (recvAvailable(_sock) > 0) + { + //HACK - hand-parse the UDP packet using TCP recv method + uint8_t tmpBuf[8]; + int ret =0; + //read 8 header bytes and get IP and port from it + ret = recv(_sock,tmpBuf,8); + if (ret > 0) + { + _remoteIP = tmpBuf; + _remotePort = tmpBuf[4]; + _remotePort = (_remotePort << 8) + tmpBuf[5]; + _remaining = tmpBuf[6]; + _remaining = (_remaining << 8) + tmpBuf[7]; + + // When we get here, any remaining bytes are the data + ret = _remaining; + } + return ret; + } + // There aren't any packets available + return 0; +} + +int EthernetUDP::read() +{ + uint8_t byte; + + if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) + { + // We read things without any problems + _remaining--; + return byte; + } + + // If we get here, there's no data available + return -1; +} + +int EthernetUDP::read(unsigned char* buffer, size_t len) +{ + + if (_remaining > 0) + { + + int got; + + if (_remaining <= len) + { + // data should fit in the buffer + got = recv(_sock, buffer, _remaining); + } + else + { + // too much data for the buffer, + // grab as much as will fit + got = recv(_sock, buffer, len); + } + + if (got > 0) + { + _remaining -= got; + return got; + } + + } + + // If we get here, there's no data available or recv failed + return -1; + +} + +int EthernetUDP::peek() +{ + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must. + // If the user hasn't called parsePacket yet then return nothing otherwise they + // may get the UDP header + if (!_remaining) + return -1; + ::peek(_sock, &b); + return b; +} + +void EthernetUDP::flush() +{ + // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? + // should only occur if recv fails after telling us the data is there, lets + // hope the w5100 always behaves :) + + while (_remaining) + { + read(); + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.h new file mode 100644 index 0000000..8a6b7ab --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/EthernetUdp.h @@ -0,0 +1,99 @@ +/* + * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + * This version only offers minimal wrapping of socket.c/socket.h + * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef ethernetudp_h +#define ethernetudp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent + uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: + EthernetUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() { return _remotePort; }; +}; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.cpp new file mode 100644 index 0000000..9254b74 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.cpp @@ -0,0 +1,469 @@ +#include "w5100.h" +#include "socket.h" + +static uint16_t local_port; + +/** + * @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it. + * @return 1 for success else 0. + */ +uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) +{ + if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) + { + close(s); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnMR(s, protocol | flag); + if (port != 0) { + W5100.writeSnPORT(s, port); + } + else { + local_port++; // if don't set the source port, set local_port number. + W5100.writeSnPORT(s, local_port); + } + + W5100.execCmdSn(s, Sock_OPEN); + SPI.endTransaction(); + return 1; + } + + return 0; +} + + +uint8_t socketStatus(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + uint8_t status = W5100.readSnSR(s); + SPI.endTransaction(); + return status; +} + + +/** + * @brief This function close the socket and parameter is "s" which represent the socket number + */ +void close(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_CLOSE); + W5100.writeSnIR(s, 0xFF); + SPI.endTransaction(); +} + + +/** + * @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer. + * @return 1 for success else 0. + */ +uint8_t listen(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + if (W5100.readSnSR(s) != SnSR::INIT) { + SPI.endTransaction(); + return 0; + } + W5100.execCmdSn(s, Sock_LISTEN); + SPI.endTransaction(); + return 1; +} + + +/** + * @brief This function established the connection for the channel in Active (client) mode. + * This function waits for the untill the connection is established. + * + * @return 1 for success else 0. + */ +uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) +{ + if + ( + ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) || + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + (port == 0x00) + ) + return 0; + + // set destination IP + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + W5100.execCmdSn(s, Sock_CONNECT); + SPI.endTransaction(); + + return 1; +} + + + +/** + * @brief This function used for disconnect the socket and parameter is "s" which represent the socket number + * @return 1 for success else 0. + */ +void disconnect(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_DISCON); + SPI.endTransaction(); +} + + +/** + * @brief This function used to send the data in TCP mode + * @return 1 for success else 0. + */ +uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) +{ + uint8_t status=0; + uint16_t ret=0; + uint16_t freesize=0; + + if (len > W5100.SSIZE) + ret = W5100.SSIZE; // check size not to exceed MAX size. + else + ret = len; + + // if freebuf is available, start. + do + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + freesize = W5100.getTXFreeSize(s); + status = W5100.readSnSR(s); + SPI.endTransaction(); + if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) + { + ret = 0; + break; + } + yield(); + } + while (freesize < ret); + + // copy data + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + /* m2008.01 [bj] : reduce code */ + if ( W5100.readSnSR(s) == SnSR::CLOSED ) + { + SPI.endTransaction(); + close(s); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + return ret; +} + + +/** + * @brief This function is an application I/F function which is used to receive the data in TCP mode. + * It continues to wait for data as much as the application wants to receive. + * + * @return received data size for success else -1. + */ +int16_t recv(SOCKET s, uint8_t *buf, int16_t len) +{ + // Check how much data is available + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + int16_t ret = W5100.getRXReceivedSize(s); + if ( ret == 0 ) + { + // No data available. + uint8_t status = W5100.readSnSR(s); + if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT ) + { + // The remote end has closed its side of the connection, so this is the eof state + ret = 0; + } + else + { + // The connection is still up, but there's no data waiting to be read + ret = -1; + } + } + else if (ret > len) + { + ret = len; + } + + if ( ret > 0 ) + { + W5100.recv_data_processing(s, buf, ret); + W5100.execCmdSn(s, Sock_RECV); + } + SPI.endTransaction(); + return ret; +} + + +int16_t recvAvailable(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + int16_t ret = W5100.getRXReceivedSize(s); + SPI.endTransaction(); + return ret; +} + + +/** + * @brief Returns the first byte in the receive queue (no checking) + * + * @return + */ +uint16_t peek(SOCKET s, uint8_t *buf) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.recv_data_processing(s, buf, 1, 1); + SPI.endTransaction(); + return 1; +} + + +/** + * @brief This function is an application I/F function which is used to send the data for other then TCP mode. + * Unlike TCP transmission, The peer's destination address and the port is needed. + * + * @return This function return send data size for success else -1. + */ +uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port) +{ + uint16_t ret=0; + + if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size. + else ret = len; + + if + ( + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + ((port == 0x00)) ||(ret == 0) + ) + { + /* +2008.01 [bj] : added return value */ + ret = 0; + } + else + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + + // copy data + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ + SPI.endTransaction(); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + } + return ret; +} + + +/** + * @brief This function is an application I/F function which is used to receive the data in other then + * TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well. + * + * @return This function return received data size for success else -1. + */ +uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port) +{ + uint8_t head[8]; + uint16_t data_len=0; + uint16_t ptr=0; + + if ( len > 0 ) + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + ptr = W5100.readSnRX_RD(s); + switch (W5100.readSnMR(s) & 0x07) + { + case SnMR::UDP : + W5100.read_data(s, ptr, head, 0x08); + ptr += 8; + // read peer's IP address, port number. + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + *port = head[4]; + *port = (*port << 8) + head[5]; + data_len = head[6]; + data_len = (data_len << 8) + head[7]; + + W5100.read_data(s, ptr, buf, data_len); // data copy. + ptr += data_len; + + W5100.writeSnRX_RD(s, ptr); + break; + + case SnMR::IPRAW : + W5100.read_data(s, ptr, head, 0x06); + ptr += 6; + + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + data_len = head[4]; + data_len = (data_len << 8) + head[5]; + + W5100.read_data(s, ptr, buf, data_len); // data copy. + ptr += data_len; + + W5100.writeSnRX_RD(s, ptr); + break; + + case SnMR::MACRAW: + W5100.read_data(s, ptr, head, 2); + ptr+=2; + data_len = head[0]; + data_len = (data_len<<8) + head[1] - 2; + + W5100.read_data(s, ptr, buf, data_len); + ptr += data_len; + W5100.writeSnRX_RD(s, ptr); + break; + + default : + break; + } + W5100.execCmdSn(s, Sock_RECV); + SPI.endTransaction(); + } + return data_len; +} + +/** + * @brief Wait for buffered transmission to complete. + */ +void flush(SOCKET s) { + // TODO +} + +uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) +{ + uint16_t ret=0; + + if (len > W5100.SSIZE) + ret = W5100.SSIZE; // check size not to exceed MAX size. + else + ret = len; + + if (ret == 0) + return 0; + + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.send_data_processing(s, (uint8_t *)buf, ret); + W5100.execCmdSn(s, Sock_SEND); + + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* in case of igmp, if send fails, then socket closed */ + /* if you want change, remove this code. */ + SPI.endTransaction(); + close(s); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + return ret; +} + +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) +{ + uint16_t ret =0; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + if (len > W5100.getTXFreeSize(s)) + { + ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. + } + else + { + ret = len; + } + W5100.send_data_processing_offset(s, offset, buf, ret); + SPI.endTransaction(); + return ret; +} + +int startUDP(SOCKET s, uint8_t* addr, uint16_t port) +{ + if + ( + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + ((port == 0x00)) + ) + { + return 0; + } + else + { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + SPI.endTransaction(); + return 1; + } +} + +int sendUDP(SOCKET s) +{ + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); + SPI.endTransaction(); + return 0; + } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + } + + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); + + /* Sent ok */ + return 1; +} + diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.h new file mode 100644 index 0000000..37ba854 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/socket.h @@ -0,0 +1,44 @@ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ + +#include "utility/w5100.h" + +extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) +extern uint8_t socketStatus(SOCKET s); +extern void close(SOCKET s); // Close socket +extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) +extern void disconnect(SOCKET s); // disconnect the connection +extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection) +extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) +extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP) +extern int16_t recvAvailable(SOCKET s); +extern uint16_t peek(SOCKET s, uint8_t *buf); +extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) +extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) +extern void flush(SOCKET s); // Wait for transmission to complete + +extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); + +// Functions to allow buffered UDP send (i.e. where the UDP datagram is built up over a +// number of calls before being sent +/* + @brief This function sets up a UDP datagram, the data for which will be provided by one + or more calls to bufferData and then finally sent with sendUDP. + @return 1 if the datagram was successfully set up, or 0 if there was an error +*/ +extern int startUDP(SOCKET s, uint8_t* addr, uint16_t port); +/* + @brief This function copies up to len bytes of data from buf into a UDP datagram to be + sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. + @return Number of bytes successfully buffered +*/ +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len); +/* + @brief Send a UDP datagram built up from a sequence of startUDP followed by one or more + calls to bufferData. + @return 1 if the datagram was successfully sent, or 0 if there was an error +*/ +int sendUDP(SOCKET s); + +#endif +/* _SOCKET_H_ */ diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/util.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/util.h new file mode 100644 index 0000000..33d32a9 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/util.h @@ -0,0 +1,14 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( ((x)<< 8 & 0xFF00) | \ + ((x)>> 8 & 0x00FF) ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.cpp b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.cpp new file mode 100644 index 0000000..d0a9bb2 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2010 by Arduino LLC. All rights reserved. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include +#include + +#include "w5100.h" + +// W5100 controller instance +W5100Class W5100; + +#define TX_RX_MAX_BUF_SIZE 2048 +#define TX_BUF 0x1100 +#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) + +#define TXBUF_BASE 0x4000 +#define RXBUF_BASE 0x6000 + +void W5100Class::init(void) +{ + delay(300); + +#if defined(ARDUINO_ARCH_AVR) + SPI.begin(); + initSS(); +#else + SPI.begin(SPI_CS); + // Set clock to 4Mhz (W5100 should support up to about 14Mhz) + SPI.setClockDivider(SPI_CS, 21); + SPI.setDataMode(SPI_CS, SPI_MODE0); +#endif + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + writeMR(1< SSIZE) + { + // Wrap around circular buffer + uint16_t size = SSIZE - offset; + write(dstAddr, data, size); + write(SBASE[s], data + size, len - size); + } + else { + write(dstAddr, data, len); + } + + ptr += len; + writeSnTX_WR(s, ptr); +} + + +void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) +{ + uint16_t ptr; + ptr = readSnRX_RD(s); + read_data(s, ptr, data, len); + if (!peek) + { + ptr += len; + writeSnRX_RD(s, ptr); + } +} + +void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len) +{ + uint16_t size; + uint16_t src_mask; + uint16_t src_ptr; + + src_mask = src & RMASK; + src_ptr = RBASE[s] + src_mask; + + if( (src_mask + len) > RSIZE ) + { + size = RSIZE - src_mask; + read(src_ptr, (uint8_t *)dst, size); + dst += size; + read(RBASE[s], (uint8_t *) dst, len - size); + } + else + read(src_ptr, (uint8_t *) dst, len); +} + + +uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) +{ +#if defined(ARDUINO_ARCH_AVR) + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + SPI.transfer(_data); + resetSS(); +#else + SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + SPI.transfer(SPI_CS, _data); +#endif + return 1; +} + +uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) +{ + for (uint16_t i=0; i<_len; i++) + { +#if defined(ARDUINO_ARCH_AVR) + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + SPI.transfer(_buf[i]); + resetSS(); +#else + SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + SPI.transfer(SPI_CS, _buf[i]); + _addr++; +#endif + } + return _len; +} + +uint8_t W5100Class::read(uint16_t _addr) +{ +#if defined(ARDUINO_ARCH_AVR) + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + uint8_t _data = SPI.transfer(0); + resetSS(); +#else + SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + uint8_t _data = SPI.transfer(SPI_CS, 0); +#endif + return _data; +} + +uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) +{ + for (uint16_t i=0; i<_len; i++) + { +#if defined(ARDUINO_ARCH_AVR) + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + _buf[i] = SPI.transfer(0); + resetSS(); +#else + SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); + SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); + _buf[i] = SPI.transfer(SPI_CS, 0); + _addr++; +#endif + } + return _len; +} + +void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { + // Send command to socket + writeSnCR(s, _cmd); + // Wait for command to complete + while (readSnCR(s)) + ; +} diff --git a/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.h b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.h new file mode 100644 index 0000000..fd9ea35 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/Ethernet/src/utility/w5100.h @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2010 by Arduino LLC. All rights reserved. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef W5100_H_INCLUDED +#define W5100_H_INCLUDED + +#include + +#define SPI_CS 10 + +#if defined(ARDUINO_ARCH_AVR) +#define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0) +#else +#define SPI_ETHERNET_SETTINGS SPI_CS,SPISettings(4000000, MSBFIRST, SPI_MODE0) +#endif + +#define MAX_SOCK_NUM 4 + +typedef uint8_t SOCKET; + +#define IDM_OR 0x8000 +#define IDM_AR0 0x8001 +#define IDM_AR1 0x8002 +#define IDM_DR 0x8003 +/* +class MR { +public: + static const uint8_t RST = 0x80; + static const uint8_t PB = 0x10; + static const uint8_t PPPOE = 0x08; + static const uint8_t LB = 0x04; + static const uint8_t AI = 0x02; + static const uint8_t IND = 0x01; +}; +*/ +/* +class IR { +public: + static const uint8_t CONFLICT = 0x80; + static const uint8_t UNREACH = 0x40; + static const uint8_t PPPoE = 0x20; + static const uint8_t SOCK0 = 0x01; + static const uint8_t SOCK1 = 0x02; + static const uint8_t SOCK2 = 0x04; + static const uint8_t SOCK3 = 0x08; + static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); }; +}; +*/ + +class SnMR { +public: + static const uint8_t CLOSE = 0x00; + static const uint8_t TCP = 0x01; + static const uint8_t UDP = 0x02; + static const uint8_t IPRAW = 0x03; + static const uint8_t MACRAW = 0x04; + static const uint8_t PPPOE = 0x05; + static const uint8_t ND = 0x20; + static const uint8_t MULTI = 0x80; +}; + +enum SockCMD { + Sock_OPEN = 0x01, + Sock_LISTEN = 0x02, + Sock_CONNECT = 0x04, + Sock_DISCON = 0x08, + Sock_CLOSE = 0x10, + Sock_SEND = 0x20, + Sock_SEND_MAC = 0x21, + Sock_SEND_KEEP = 0x22, + Sock_RECV = 0x40 +}; + +/*class SnCmd { +public: + static const uint8_t OPEN = 0x01; + static const uint8_t LISTEN = 0x02; + static const uint8_t CONNECT = 0x04; + static const uint8_t DISCON = 0x08; + static const uint8_t CLOSE = 0x10; + static const uint8_t SEND = 0x20; + static const uint8_t SEND_MAC = 0x21; + static const uint8_t SEND_KEEP = 0x22; + static const uint8_t RECV = 0x40; +}; +*/ + +class SnIR { +public: + static const uint8_t SEND_OK = 0x10; + static const uint8_t TIMEOUT = 0x08; + static const uint8_t RECV = 0x04; + static const uint8_t DISCON = 0x02; + static const uint8_t CON = 0x01; +}; + +class SnSR { +public: + static const uint8_t CLOSED = 0x00; + static const uint8_t INIT = 0x13; + static const uint8_t LISTEN = 0x14; + static const uint8_t SYNSENT = 0x15; + static const uint8_t SYNRECV = 0x16; + static const uint8_t ESTABLISHED = 0x17; + static const uint8_t FIN_WAIT = 0x18; + static const uint8_t CLOSING = 0x1A; + static const uint8_t TIME_WAIT = 0x1B; + static const uint8_t CLOSE_WAIT = 0x1C; + static const uint8_t LAST_ACK = 0x1D; + static const uint8_t UDP = 0x22; + static const uint8_t IPRAW = 0x32; + static const uint8_t MACRAW = 0x42; + static const uint8_t PPPOE = 0x5F; +}; + +class IPPROTO { +public: + static const uint8_t IP = 0; + static const uint8_t ICMP = 1; + static const uint8_t IGMP = 2; + static const uint8_t GGP = 3; + static const uint8_t TCP = 6; + static const uint8_t PUP = 12; + static const uint8_t UDP = 17; + static const uint8_t IDP = 22; + static const uint8_t ND = 77; + static const uint8_t RAW = 255; +}; + +class W5100Class { + +public: + void init(); + + /** + * @brief This function is being used for copy the data form Receive buffer of the chip to application buffer. + * + * It calculate the actual physical address where one has to read + * the data from Receive buffer. Here also take care of the condition while it exceed + * the Rx memory uper-bound of socket. + */ + void read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len); + + /** + * @brief This function is being called by send() and sendto() function also. + * + * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer + * register. User should read upper byte first and lower byte later to get proper value. + */ + void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); + /** + * @brief A copy of send_data_processing that uses the provided ptr for the + * write offset. Only needed for the "streaming" UDP API, where + * a single UDP packet is built up over a number of calls to + * send_data_processing_ptr, because TX_WR doesn't seem to get updated + * correctly in those scenarios + * @param ptr value to use in place of TX_WR. If 0, then the value is read + * in from TX_WR + * @return New value for ptr, to be used in the next call + */ +// FIXME Update documentation + void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); + + /** + * @brief This function is being called by recv() also. + * + * This function read the Rx read pointer register + * and after copy the data from receive buffer update the Rx write pointer register. + * User should read upper byte first and lower byte later to get proper value. + */ + void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); + + inline void setGatewayIp(uint8_t *_addr); + inline void getGatewayIp(uint8_t *_addr); + + inline void setSubnetMask(uint8_t *_addr); + inline void getSubnetMask(uint8_t *_addr); + + inline void setMACAddress(uint8_t * addr); + inline void getMACAddress(uint8_t * addr); + + inline void setIPAddress(uint8_t * addr); + inline void getIPAddress(uint8_t * addr); + + inline void setRetransmissionTime(uint16_t timeout); + inline void setRetransmissionCount(uint8_t _retry); + + void execCmdSn(SOCKET s, SockCMD _cmd); + + uint16_t getTXFreeSize(SOCKET s); + uint16_t getRXReceivedSize(SOCKET s); + + + // W5100 Registers + // --------------- +private: + static uint8_t write(uint16_t _addr, uint8_t _data); + static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); + static uint8_t read(uint16_t addr); + static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); + +#define __GP_REGISTER8(name, address) \ + static inline void write##name(uint8_t _data) { \ + write(address, _data); \ + } \ + static inline uint8_t read##name() { \ + return read(address); \ + } +#define __GP_REGISTER16(name, address) \ + static void write##name(uint16_t _data) { \ + write(address, _data >> 8); \ + write(address+1, _data & 0xFF); \ + } \ + static uint16_t read##name() { \ + uint16_t res = read(address); \ + res = (res << 8) + read(address + 1); \ + return res; \ + } +#define __GP_REGISTER_N(name, address, size) \ + static uint16_t write##name(uint8_t *_buff) { \ + return write(address, _buff, size); \ + } \ + static uint16_t read##name(uint8_t *_buff) { \ + return read(address, _buff, size); \ + } + +public: + __GP_REGISTER8 (MR, 0x0000); // Mode + __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address + __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address + __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address + __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address + __GP_REGISTER8 (IR, 0x0015); // Interrupt + __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask + __GP_REGISTER16(RTR, 0x0017); // Timeout address + __GP_REGISTER8 (RCR, 0x0019); // Retry count + __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size + __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size + __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode + __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer + __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number + __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode + __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode + +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + + // W5100 Socket registers + // ---------------------- +private: + static inline uint8_t readSn(SOCKET _s, uint16_t _addr); + static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); + static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + + static const uint16_t CH_BASE = 0x0400; + static const uint16_t CH_SIZE = 0x0100; + +#define __SOCKET_REGISTER8(name, address) \ + static inline void write##name(SOCKET _s, uint8_t _data) { \ + writeSn(_s, address, _data); \ + } \ + static inline uint8_t read##name(SOCKET _s) { \ + return readSn(_s, address); \ + } +#define __SOCKET_REGISTER16(name, address) \ + static void write##name(SOCKET _s, uint16_t _data) { \ + writeSn(_s, address, _data >> 8); \ + writeSn(_s, address+1, _data & 0xFF); \ + } \ + static uint16_t read##name(SOCKET _s) { \ + uint16_t res = readSn(_s, address); \ + uint16_t res2 = readSn(_s,address + 1); \ + res = res << 8; \ + res2 = res2 & 0xFF; \ + res = res | res2; \ + return res; \ + } +#define __SOCKET_REGISTER_N(name, address, size) \ + static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ + return writeSn(_s, address, _buff, size); \ + } \ + static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ + return readSn(_s, address, _buff, size); \ + } + +public: + __SOCKET_REGISTER8(SnMR, 0x0000) // Mode + __SOCKET_REGISTER8(SnCR, 0x0001) // Command + __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt + __SOCKET_REGISTER8(SnSR, 0x0003) // Status + __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port + __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr + __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr + __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port + __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size + __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode + __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS + __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL + __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size + __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer + __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer + __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size + __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer + __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) + +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + + +private: + static const uint8_t RST = 7; // Reset BIT + + static const int SOCKETS = 4; + static const uint16_t SMASK = 0x07FF; // Tx buffer MASK + static const uint16_t RMASK = 0x07FF; // Rx buffer MASK +public: + static const uint16_t SSIZE = 2048; // Max Tx buffer size +private: + static const uint16_t RSIZE = 2048; // Max Rx buffer size + uint16_t SBASE[SOCKETS]; // Tx buffer base address + uint16_t RBASE[SOCKETS]; // Rx buffer base address + +private: +#if defined(ARDUINO_ARCH_AVR) +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + inline static void initSS() { DDRB |= _BV(4); }; + inline static void setSS() { PORTB &= ~_BV(4); }; + inline static void resetSS() { PORTB |= _BV(4); }; +#elif defined(__AVR_ATmega32U4__) + inline static void initSS() { DDRB |= _BV(6); }; + inline static void setSS() { PORTB &= ~_BV(6); }; + inline static void resetSS() { PORTB |= _BV(6); }; +#elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__) + inline static void initSS() { DDRB |= _BV(0); }; + inline static void setSS() { PORTB &= ~_BV(0); }; + inline static void resetSS() { PORTB |= _BV(0); }; +#else + inline static void initSS() { DDRB |= _BV(2); }; + inline static void setSS() { PORTB &= ~_BV(2); }; + inline static void resetSS() { PORTB |= _BV(2); }; +#endif +#endif // ARDUINO_ARCH_AVR +}; + +extern W5100Class W5100; + +uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) { + return read(CH_BASE + _s * CH_SIZE + _addr); +} + +uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { + return write(CH_BASE + _s * CH_SIZE + _addr, _data); +} + +uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { + return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +void W5100Class::getGatewayIp(uint8_t *_addr) { + readGAR(_addr); +} + +void W5100Class::setGatewayIp(uint8_t *_addr) { + writeGAR(_addr); +} + +void W5100Class::getSubnetMask(uint8_t *_addr) { + readSUBR(_addr); +} + +void W5100Class::setSubnetMask(uint8_t *_addr) { + writeSUBR(_addr); +} + +void W5100Class::getMACAddress(uint8_t *_addr) { + readSHAR(_addr); +} + +void W5100Class::setMACAddress(uint8_t *_addr) { + writeSHAR(_addr); +} + +void W5100Class::getIPAddress(uint8_t *_addr) { + readSIPR(_addr); +} + +void W5100Class::setIPAddress(uint8_t *_addr) { + writeSIPR(_addr); +} + +void W5100Class::setRetransmissionTime(uint16_t _timeout) { + writeRTR(_timeout); +} + +void W5100Class::setRetransmissionCount(uint8_t _retry) { + writeRCR(_retry); +} + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/SPI/SPI.cpp b/libraries/MySensors/drivers/ESP8266/SPI/SPI.cpp new file mode 100644 index 0000000..4e73021 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/SPI/SPI.cpp @@ -0,0 +1,454 @@ +/* + SPI.cpp - SPI library for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SPI.h" +#include "HardwareSerial.h" + +typedef union { + uint32_t regValue; + struct { + unsigned regL :6; + unsigned regH :6; + unsigned regN :6; + unsigned regPre :13; + unsigned regEQU :1; + }; +} spiClk_t; + +SPIClass SPI; + +SPIClass::SPIClass() { + useHwCs = false; +} + +void SPIClass::begin() { + pinMode(SCK, SPECIAL); ///< GPIO14 + pinMode(MISO, SPECIAL); ///< GPIO12 + pinMode(MOSI, SPECIAL); ///< GPIO13 + + SPI1C = 0; + setFrequency(1000000); ///< 1MHz + SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE; + SPI1U1 = (7 << SPILMOSI) | (7 << SPILMISO); + SPI1C1 = 0; +} + +void SPIClass::end() { + pinMode(SCK, INPUT); + pinMode(MISO, INPUT); + pinMode(MOSI, INPUT); + if(useHwCs) { + pinMode(SS, INPUT); + } +} + +void SPIClass::setHwCs(bool use) { + if(use) { + pinMode(SS, SPECIAL); ///< GPIO15 + SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); + } else { + if(useHwCs) { + pinMode(SS, INPUT); + SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD); + } + } + useHwCs = use; +} + +void SPIClass::beginTransaction(SPISettings settings) { + while(SPI1CMD & SPIBUSY) {} + setFrequency(settings._clock); + setBitOrder(settings._bitOrder); + setDataMode(settings._dataMode); +} + +void SPIClass::endTransaction() { +} + +void SPIClass::setDataMode(uint8_t dataMode) { + + /** + SPI_MODE0 0x00 - CPOL: 0 CPHA: 0 + SPI_MODE1 0x01 - CPOL: 0 CPHA: 1 + SPI_MODE2 0x10 - CPOL: 1 CPHA: 0 + SPI_MODE3 0x11 - CPOL: 1 CPHA: 1 + */ + + bool CPOL = (dataMode & 0x10); ///< CPOL (Clock Polarity) + bool CPHA = (dataMode & 0x01); ///< CPHA (Clock Phase) + + if(CPHA) { + SPI1U |= (SPIUSME); + } else { + SPI1U &= ~(SPIUSME); + } + + if(CPOL) { + //todo How set CPOL??? + } + +} + +void SPIClass::setBitOrder(uint8_t bitOrder) { + if(bitOrder == MSBFIRST) { + SPI1C &= ~(SPICWBO | SPICRBO); + } else { + SPI1C |= (SPICWBO | SPICRBO); + } +} + +/** + * calculate the Frequency based on the register value + * @param reg + * @return + */ +static uint32_t ClkRegToFreq(spiClk_t * reg) { + return (ESP8266_CLOCK / ((reg->regPre + 1) * (reg->regN + 1))); +} + +void SPIClass::setFrequency(uint32_t freq) { + static uint32_t lastSetFrequency = 0; + static uint32_t lastSetRegister = 0; + + if(freq >= ESP8266_CLOCK) { + setClockDivider(0x80000000); + return; + } + + if(lastSetFrequency == freq && lastSetRegister == SPI1CLK) { + // do nothing (speed optimization) + return; + } + + const spiClk_t minFreqReg = { 0x7FFFF000 }; + uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); + if(freq < minFreq) { + // use minimum possible clock + setClockDivider(minFreqReg.regValue); + lastSetRegister = SPI1CLK; + lastSetFrequency = freq; + return; + } + + uint8_t calN = 1; + + spiClk_t bestReg = { 0 }; + int32_t bestFreq = 0; + + // find the best match + while(calN <= 0x3F) { // 0x3F max for N + + spiClk_t reg = { 0 }; + int32_t calFreq; + int32_t calPre; + int8_t calPreVari = -2; + + reg.regN = calN; + + while(calPreVari++ <= 1) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way) + calPre = (((ESP8266_CLOCK / (reg.regN + 1)) / freq) - 1) + calPreVari; + if(calPre > 0x1FFF) { + reg.regPre = 0x1FFF; // 8191 + } else if(calPre <= 0) { + reg.regPre = 0; + } else { + reg.regPre = calPre; + } + + reg.regL = ((reg.regN + 1) / 2); + // reg.regH = (reg.regN - reg.regL); + + // test calculation + calFreq = ClkRegToFreq(®); + //os_printf("-----[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d = %d\n", reg.regValue, freq, reg.regEQU, reg.regPre, reg.regN, reg.regH, reg.regL, calFreq); + + if(calFreq == (int32_t) freq) { + // accurate match use it! + memcpy(&bestReg, ®, sizeof(bestReg)); + break; + } else if(calFreq < (int32_t) freq) { + // never go over the requested frequency + if(abs(freq - calFreq) < abs(freq - bestFreq)) { + bestFreq = calFreq; + memcpy(&bestReg, ®, sizeof(bestReg)); + } + } + } + if(calFreq == (int32_t) freq) { + // accurate match use it! + break; + } + calN++; + } + + // os_printf("[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d\t - Real Frequency: %d\n", bestReg.regValue, freq, bestReg.regEQU, bestReg.regPre, bestReg.regN, bestReg.regH, bestReg.regL, ClkRegToFreq(&bestReg)); + + setClockDivider(bestReg.regValue); + lastSetRegister = SPI1CLK; + lastSetFrequency = freq; + +} + +void SPIClass::setClockDivider(uint32_t clockDiv) { + if(clockDiv == 0x80000000) { + GPMUX |= (1 << 9); // Set bit 9 if sysclock required + } else { + GPMUX &= ~(1 << 9); + } + SPI1CLK = clockDiv; +} + +inline void SPIClass::setDataBits(uint16_t bits) { + const uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); + bits--; + SPI1U1 = ((SPI1U1 & mask) | ((bits << SPILMOSI) | (bits << SPILMISO))); +} + +uint8_t SPIClass::transfer(uint8_t data) { + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} + return (uint8_t) (SPI1W0 & 0xff); +} + +uint16_t SPIClass::transfer16(uint16_t data) { + union { + uint16_t val; + struct { + uint8_t lsb; + uint8_t msb; + }; + } in, out; + in.val = data; + + if((SPI1C & (SPICWBO | SPICRBO))) { + //MSBFIRST + out.msb = transfer(in.msb); + out.lsb = transfer(in.lsb); + } else { + //LSBFIRST + out.lsb = transfer(in.lsb); + out.msb = transfer(in.msb); + } + return out.val; +} + +void SPIClass::write(uint8_t data) { + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write16(uint16_t data) { + write16(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write16(uint16_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 16Bits transfer + setDataBits(16); + if(msb) { + // MSBFIRST Byte first + SPI1W0 = (data >> 8) | (data << 8); + SPI1CMD |= SPIBUSY; + } else { + // LSBFIRST Byte first + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + } + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write32(uint32_t data) { + write32(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write32(uint32_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 32Bits transfer + setDataBits(32); + if(msb) { + union { + uint32_t l; + uint8_t b[4]; + } data_; + data_.l = data; + // MSBFIRST Byte first + SPI1W0 = (data_.b[3] | (data_.b[2] << 8) | (data_.b[1] << 16) | (data_.b[0] << 24)); + SPI1CMD |= SPIBUSY; + } else { + // LSBFIRST Byte first + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + } + while(SPI1CMD & SPIBUSY) {} +} + +/** + * Note: + * data need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param data uint8_t * + * @param size uint32_t + */ +void SPIClass::writeBytes(uint8_t * data, uint32_t size) { + while(size) { + if(size > 64) { + writeBytes_(data, 64); + size -= 64; + data += 64; + } else { + writeBytes_(data, size); + size = 0; + } + } +} + +void SPIClass::writeBytes_(uint8_t * data, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set Bits to transfer + setDataBits(size * 8); + + volatile uint32_t * fifoPtr = &SPI1W0; + uint32_t * dataPtr = (uint32_t*) data; + uint8_t dataSize = ((size + 3) / 4); + + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + + +/** + * Note: + * data need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param data uint8_t * + * @param size uint8_t max for size is 64Byte + * @param repeat uint32_t + */ +void SPIClass::writePattern(uint8_t * data, uint8_t size, uint32_t repeat) { + if(size > 64) return; //max Hardware FIFO + + uint32_t byte = (size * repeat); + uint8_t r = (64 / size); + + while(byte) { + if(byte > 64) { + writePattern_(data, size, r); + byte -= 64; + } else { + writePattern_(data, size, (byte / size)); + byte = 0; + } + } +} + +void SPIClass::writePattern_(uint8_t * data, uint8_t size, uint8_t repeat) { + uint8_t bytes = (size * repeat); + uint8_t buffer[64]; + uint8_t * bufferPtr = &buffer[0]; + uint8_t * dataPtr; + uint8_t dataSize = bytes; + for(uint8_t i = 0; i < repeat; i++) { + dataSize = size; + dataPtr = data; + while(dataSize--) { + *bufferPtr = *dataPtr; + dataPtr++; + bufferPtr++; + } + } + + writeBytes(&buffer[0], bytes); +} + +/** + * Note: + * in and out need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param out uint8_t * + * @param in uint8_t * + * @param size uint32_t + */ +void SPIClass::transferBytes(uint8_t * out, uint8_t * in, uint32_t size) { + while(size) { + if(size > 64) { + transferBytes_(out, in, 64); + size -= 64; + if(out) out += 64; + if(in) in += 64; + } else { + transferBytes_(out, in, size); + size = 0; + } + } +} + +void SPIClass::transferBytes_(uint8_t * out, uint8_t * in, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set in/out Bits to transfer + + setDataBits(size * 8); + + volatile uint32_t * fifoPtr = &SPI1W0; + uint8_t dataSize = ((size + 3) / 4); + + if(out) { + uint32_t * dataPtr = (uint32_t*) out; + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + } else { + // no out data only read fill with dummy data! + while(dataSize--) { + *fifoPtr = 0xFFFFFFFF; + fifoPtr++; + } + } + + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} + + if(in) { + volatile uint8_t * fifoPtr8 = (volatile uint8_t *) &SPI1W0; + dataSize = size; + while(dataSize--) { + *in = *fifoPtr8; + in++; + fifoPtr8++; + } + } +} + diff --git a/libraries/MySensors/drivers/ESP8266/SPI/SPI.h b/libraries/MySensors/drivers/ESP8266/SPI/SPI.h new file mode 100644 index 0000000..141f30e --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/SPI/SPI.h @@ -0,0 +1,85 @@ +/* + SPI.h - SPI library for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include +#include + +#define SPI_HAS_TRANSACTION + +// This defines are not representing the real Divider of the ESP8266 +// the Defines match to an AVR Arduino on 16MHz for better compatibility +#define SPI_CLOCK_DIV2 0x00101001 //8 MHz +#define SPI_CLOCK_DIV4 0x00241001 //4 MHz +#define SPI_CLOCK_DIV8 0x004c1001 //2 MHz +#define SPI_CLOCK_DIV16 0x009c1001 //1 MHz +#define SPI_CLOCK_DIV32 0x013c1001 //500 KHz +#define SPI_CLOCK_DIV64 0x027c1001 //250 KHz +#define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz + +const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0 +const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1 +const uint8_t SPI_MODE2 = 0x10; ///< CPOL: 1 CPHA: 0 +const uint8_t SPI_MODE3 = 0x11; ///< CPOL: 1 CPHA: 1 + +class SPISettings { +public: + SPISettings() :_clock(1000000), _bitOrder(LSBFIRST), _dataMode(SPI_MODE0){} + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) :_clock(clock), _bitOrder(bitOrder), _dataMode(dataMode){} + uint32_t _clock; + uint8_t _bitOrder; + uint8_t _dataMode; +}; + +class SPIClass { +public: + SPIClass(); + void begin(); + void end(); + void setHwCs(bool use); + void setBitOrder(uint8_t bitOrder); + void setDataMode(uint8_t dataMode); + void setFrequency(uint32_t freq); + void setClockDivider(uint32_t clockDiv); + void beginTransaction(SPISettings settings); + uint8_t transfer(uint8_t data); + uint16_t transfer16(uint16_t data); + void write(uint8_t data); + void write16(uint16_t data); + void write16(uint16_t data, bool msb); + void write32(uint32_t data); + void write32(uint32_t data, bool msb); + void writeBytes(uint8_t * data, uint32_t size); + void writePattern(uint8_t * data, uint8_t size, uint32_t repeat); + void transferBytes(uint8_t * out, uint8_t * in, uint32_t size); + void endTransaction(void); +private: + bool useHwCs; + void writeBytes_(uint8_t * data, uint8_t size); + void writePattern_(uint8_t * data, uint8_t size, uint8_t repeat); + void transferBytes_(uint8_t * out, uint8_t * in, uint8_t size); + inline void setDataBits(uint16_t bits); +}; + +extern SPIClass SPI; + +#endif diff --git a/libraries/MySensors/drivers/ESP8266/SPI/keywords.txt b/libraries/MySensors/drivers/ESP8266/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/libraries/MySensors/drivers/ESP8266/SPI/library.properties b/libraries/MySensors/drivers/ESP8266/SPI/library.properties new file mode 100644 index 0000000..bbe0ddb --- /dev/null +++ b/libraries/MySensors/drivers/ESP8266/SPI/library.properties @@ -0,0 +1,8 @@ +name=SPI +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. +paragraph= +url=http://arduino.cc/en/Reference/SPI +architectures=esp8266 diff --git a/libraries/MySensors/drivers/RF24/RF24_config.h b/libraries/MySensors/drivers/RF24/RF24_config.h index 08a23cc..23f78e4 100644 --- a/libraries/MySensors/drivers/RF24/RF24_config.h +++ b/libraries/MySensors/drivers/RF24/RF24_config.h @@ -39,7 +39,7 @@ #include #define _SPI uspi #elif defined MY_SOFTSPI - #include "drivers/DigitalIO/DigitalIO.h" + #include "drivers/AVR/DigitalIO/DigitalIO.h" // change these pins to your liking const uint8_t SOFT_SPI_MISO_PIN = MY_SOFT_SPI_MOSI_PIN; @@ -50,7 +50,7 @@ #define _SPI spi #else - #include "drivers/SPI/SPI.h" + #include "drivers/AVR/SPI/SPI.h" #define _SPI SPI #endif #endif diff --git a/libraries/MySensors/drivers/SPIFlash/SPIFlash.h b/libraries/MySensors/drivers/SPIFlash/SPIFlash.h index e6e1d04..0c0e827 100644 --- a/libraries/MySensors/drivers/SPIFlash/SPIFlash.h +++ b/libraries/MySensors/drivers/SPIFlash/SPIFlash.h @@ -42,7 +42,7 @@ #include "pins_arduino.h" #endif -#include "drivers/SPI/SPI.h" +#include "drivers/AVR/SPI/SPI.h" /// IMPORTANT: NAND FLASH memory requires erase before write, because /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 34ee906..687468c 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -92,7 +92,7 @@ #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 // The port you want to contact on controller (client mode) #define MY_CONTROLLER_PORT 5003 - + // The MAC address can be anything you want but should be unique on your network. // Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. // Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address. diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index 099226f..7687d7b 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -31,6 +31,10 @@ //#define MY_SOFTSPI //#define MY_OTA_FIRMWARE_FEATURE +#define MY_SIGNING_SOFT + +// #define MY_GATEWAY_SERIAL // REMOVE-ME +// #define MY_GATEWAY_PROTOCOL_DEFAULT // REMOVE-ME #define MY_RADIO_NRF24 // MY_RADIO_RFM69 #include @@ -49,8 +53,6 @@ MyMessage msg(CHILD_ID, V_TRIPPED); void setup() { - dataDallback(); - // Send the sketch version information to the gateway and Controller sendSketchInfo("Motion Sensor", "1.0"); From 76f208abe773a8edba1f8dee22f76f6f13fee6cb Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 13 Sep 2015 18:26:18 +0200 Subject: [PATCH 251/660] Clean up Ethernet defines a bit Setting MY_CONTROLLER_IP_ADDRESS turns on client mode. Setting MY_IP_ADDRESS turns off DHCP mode --- libraries/MySensors/MySensor.h | 17 ++++++++++------- .../core/MyGatewayTransportEthernet.cpp | 4 ++-- .../EthernetGateway/EthernetGateway.ino | 11 +++-------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 3327516..f368f9f 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -26,7 +26,7 @@ #include "MyConfig.h" -#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100_CLIENT) || defined(MY_GATEWAY_W5100_SERVER) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) #define MY_GATEWAY_FEATURE #define MY_NODE_TYPE "gateway" #elif defined(MY_REPEATER_FEATURE) @@ -102,7 +102,7 @@ // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif - #if defined(MY_GATEWAY_W5100_CLIENT) || defined(MY_GATEWAY_W5100_SERVER) + #if defined(MY_GATEWAY_W5100) #include "drivers/AVR/Ethernet_W5100/utility/socket.cpp" #include "drivers/AVR/Ethernet_W5100/utility/w5100.cpp" #include "drivers/AVR/Ethernet_W5100/DNS.cpp" @@ -110,19 +110,22 @@ #include "drivers/AVR/Ethernet_W5100/EthernetUdp.cpp" #include "drivers/AVR/Ethernet_W5100/IPAddress.cpp" + #if defined(MY_CONTROLLER_IP_ADDRESS) + #define MY_GATEWAY_CLIENT_MODE + #endif + #if !defined(MY_PORT) - #error You must define MY_PORT + #error You must define MY_PORT (cotroller or gatway port to open) #endif #if !defined(USE_UDP) #include "drivers/AVR/Ethernet_W5100/EthernetServer.cpp" #endif - #if defined(MY_GATEWAY_W5100_CLIENT) && !defined(MY_CONTROLLER_IP_ADDRESS) - #error You must define MY_CONTROLLER_IP_ADDRESS when acting as client - #endif - #if defined(MY_GATEWAY_W5100_CLIENT) + #if defined(MY_GATEWAY_CLIENT_MODE) #include "drivers/AVR/Ethernet_W5100/EthernetClient.cpp" #include "core/MyGatewayTransportEthernet.cpp" + #else + // What do we do here? #endif #elif defined(MY_GATEWAY_SERIAL) #include "core/MyGatewayTransportSerial.cpp" diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp index 83fa9b1..18bd233 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp @@ -66,13 +66,13 @@ bool gatewayTransportSend(MyMessage &message) else { _ethernetMsg = protocolFormat(message); #ifdef MY_USE_UDP - _ethernetServer.beginPacket(_ethernetControllerIP, MY_CONTROLLER_PORT); + _ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT); _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); // returns 1 if the packet was sent successfully return _ethernetServer.endPacket(); #else EthernetClient client; - if (client.connect(_ethernetControllerIP, MY_CONTROLLER_PORT)) { + if (client.connect(_ethernetControllerIP, MY_PORT)) { client.write(_ethernetMsg, strlen(_ethernetMsg)); client.stop(); return true; diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 687468c..3dd66d8 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -63,10 +63,8 @@ #define MY_RADIO_NRF24 -// W5100 Ethernet in client mode (node opens conmection to controller) -#define MY_GATEWAY_W5100_CLIENT -// W5100 Ethernet in client mode (controller opens conmection to node) -//#define MY_GATEWAY_W5100_SERVER +// W5100 Ethernet gateway +#define MY_GATEWAY_W5100 // Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) #define MY_GATEWAY_PROTOCOL_DEFAULT @@ -88,10 +86,8 @@ // The port to keep open on node server mode / or port to contact in client mode #define MY_PORT 5003 -// Controller ip address (client mode) +// Controller ip address (enables client mode). Undefine this to act as sever. #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 -// The port you want to contact on controller (client mode) -#define MY_CONTROLLER_PORT 5003 // The MAC address can be anything you want but should be unique on your network. // Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. @@ -124,7 +120,6 @@ void setup() { - dataCallback(); } void loop() { From 37f6b10176efd3df12e5c3fcd4b21f0e3934377b Mon Sep 17 00:00:00 2001 From: fleinze Date: Sun, 13 Sep 2015 19:01:11 +0200 Subject: [PATCH 252/660] channel and datarate in constructor --- libraries/MySensors/MyTransportNRF24.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/MyTransportNRF24.h b/libraries/MySensors/MyTransportNRF24.h index 8c582fb..feff4da 100644 --- a/libraries/MySensors/MyTransportNRF24.h +++ b/libraries/MySensors/MyTransportNRF24.h @@ -35,7 +35,7 @@ class MyTransportNRF24 : public MyTransport { public: - MyTransportNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL); + MyTransportNRF24(uint8_t ce=RF24_CE_PIN, uint8_t cs=RF24_CS_PIN, uint8_t paLevel=RF24_PA_LEVEL, uint8_t channel=RF24_CHANNEL, rf24_datarate_e datarate=RF24_DATARATE); bool init(); void setAddress(uint8_t address); uint8_t getAddress(); @@ -47,6 +47,9 @@ private: RF24 rf24; uint8_t _address; uint8_t _paLevel; + uint8_t _paLevel; + uint8_t _channel; + rf24_datarate_e _datarate; }; #endif From 58a6d5c67731a49e36cccbfac61118c8ff2827a1 Mon Sep 17 00:00:00 2001 From: fleinze Date: Sun, 13 Sep 2015 19:05:03 +0200 Subject: [PATCH 253/660] Update MyTransportNRF24.cpp --- libraries/MySensors/MyTransportNRF24.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/MySensors/MyTransportNRF24.cpp b/libraries/MySensors/MyTransportNRF24.cpp index d11545d..a01e8b3 100644 --- a/libraries/MySensors/MyTransportNRF24.cpp +++ b/libraries/MySensors/MyTransportNRF24.cpp @@ -20,11 +20,13 @@ #include "MyTransport.h" #include "MyTransportNRF24.h" -MyTransportNRF24::MyTransportNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel) +MyTransportNRF24::MyTransportNRF24(uint8_t ce, uint8_t cs, uint8_t paLevel, uint8_t channel, rf24_datarate_e datarate) : MyTransport(), rf24(ce, cs), - _paLevel(paLevel) + _paLevel(paLevel), + _channel(channel), + _datarate(datarate) { } @@ -38,9 +40,9 @@ bool MyTransportNRF24::init() { rf24.setAutoAck(1); rf24.setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast rf24.enableAckPayload(); - rf24.setChannel(RF24_CHANNEL); + rf24.setChannel(_channel); rf24.setPALevel(_paLevel); - rf24.setDataRate(RF24_DATARATE); + rf24.setDataRate(_datarate); rf24.setRetries(5,15); rf24.setCRCLength(RF24_CRC_16); rf24.enableDynamicPayloads(); From 46f425cad1a03644c00aef2c3f6c563065660d88 Mon Sep 17 00:00:00 2001 From: fleinze Date: Sun, 13 Sep 2015 19:19:43 +0200 Subject: [PATCH 254/660] Update MyTransportNRF24.h --- libraries/MySensors/MyTransportNRF24.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/MySensors/MyTransportNRF24.h b/libraries/MySensors/MyTransportNRF24.h index feff4da..19d15e1 100644 --- a/libraries/MySensors/MyTransportNRF24.h +++ b/libraries/MySensors/MyTransportNRF24.h @@ -47,7 +47,6 @@ private: RF24 rf24; uint8_t _address; uint8_t _paLevel; - uint8_t _paLevel; uint8_t _channel; rf24_datarate_e _datarate; }; From b66513affcd5e3ceaff58d3e085ce7c1225220ce Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 13 Sep 2015 23:51:10 +0200 Subject: [PATCH 255/660] ENC28J60 Ethernet gateway --- libraries/MySensors/MySensor.h | 33 ++++-- libraries/MySensors/core/MyProtocol.cpp | 23 ---- .../MySensors/drivers/AVR/Ethernet_UIP/README | 2 +- .../AdvancedChatServer/AdvancedChatServer.ino | 1 + .../examples/EchoServer/EchoServer.ino | 1 + .../examples/TcpClient/TcpClient.ino | 1 + .../examples/TcpServer/TcpServer.ino | 1 + .../examples/UdpClient/UdpClient.ino | 1 + .../examples/UdpServer/UdpServer.ino | 1 + .../AVR/Ethernet_UIP/library.properties | 4 +- .../AVR/Ethernet_UIP/{ => src}/Dhcp.cpp | 0 .../drivers/AVR/Ethernet_UIP/{ => src}/Dhcp.h | 0 .../AVR/Ethernet_UIP/{ => src}/Dns.cpp | 0 .../drivers/AVR/Ethernet_UIP/{ => src}/Dns.h | 2 +- .../AVR/Ethernet_UIP/{ => src}/UIPClient.cpp | 0 .../AVR/Ethernet_UIP/{ => src}/UIPClient.h | 0 .../Ethernet_UIP/{ => src}/UIPEthernet.cpp | 0 .../AVR/Ethernet_UIP/{ => src}/UIPEthernet.h | 0 .../AVR/Ethernet_UIP/{ => src}/UIPServer.cpp | 0 .../AVR/Ethernet_UIP/{ => src}/UIPServer.h | 0 .../AVR/Ethernet_UIP/{ => src}/UIPUdp.cpp | 0 .../AVR/Ethernet_UIP/{ => src}/UIPUdp.h | 0 .../Ethernet_UIP/{ => src}/ethernet_comp.h | 0 .../{ => src}/utility/Enc28J60Network.cpp | 112 ++++++++++++++++-- .../{ => src}/utility/Enc28J60Network.h | 9 +- .../{ => src}/utility/clock-arch.c | 0 .../{ => src}/utility/clock-arch.h | 0 .../Ethernet_UIP/{ => src}/utility/enc28j60.h | 0 .../{ => src}/utility/mempool.cpp | 0 .../Ethernet_UIP/{ => src}/utility/mempool.h | 0 .../{ => src}/utility/mempool_conf.h | 0 .../Ethernet_UIP/{ => src}/utility/uip-conf.h | 0 .../AVR/Ethernet_UIP/{ => src}/utility/uip.c | 112 +++++++++--------- .../AVR/Ethernet_UIP/{ => src}/utility/uip.h | 0 .../Ethernet_UIP/{ => src}/utility/uip_arch.h | 0 .../Ethernet_UIP/{ => src}/utility/uip_arp.c | 0 .../Ethernet_UIP/{ => src}/utility/uip_arp.h | 0 .../{ => src}/utility/uip_clock.h | 0 .../{ => src}/utility/uip_debug.cpp | 0 .../{ => src}/utility/uip_debug.h | 0 .../{ => src}/utility/uip_timer.c | 0 .../{ => src}/utility/uip_timer.h | 0 .../{ => src}/utility/uipethernet-conf.h | 0 .../Ethernet_UIP/{ => src}/utility/uipopt.h | 0 .../AVR/Ethernet_UIP/{ => src}/utility/util.h | 0 .../AVR/Ethernet_UIP/tests/perl/tcpclient.pl | 34 ------ .../AVR/Ethernet_UIP/tests/perl/tcpserver.pl | 53 --------- .../AVR/Ethernet_UIP/tests/perl/udpclient.pl | 26 ---- .../AVR/Ethernet_UIP/tests/perl/udpserver.pl | 40 ------- .../EthernetGateway/EthernetGateway.ino | 5 +- 50 files changed, 206 insertions(+), 255 deletions(-) delete mode 100644 libraries/MySensors/core/MyProtocol.cpp rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/Dhcp.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/Dhcp.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/Dns.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/Dns.h (98%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPClient.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPClient.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPEthernet.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPEthernet.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPServer.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPServer.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPUdp.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/UIPUdp.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/ethernet_comp.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/Enc28J60Network.cpp (87%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/Enc28J60Network.h (92%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/clock-arch.c (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/clock-arch.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/enc28j60.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/mempool.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/mempool.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/mempool_conf.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip-conf.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip.c (96%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_arch.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_arp.c (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_arp.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_clock.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_debug.cpp (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_debug.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_timer.c (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uip_timer.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uipethernet-conf.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/uipopt.h (100%) rename libraries/MySensors/drivers/AVR/Ethernet_UIP/{ => src}/utility/util.h (100%) delete mode 100644 libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl delete mode 100644 libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl delete mode 100644 libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl delete mode 100644 libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index f368f9f..4b54a51 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -26,7 +26,7 @@ #include "MyConfig.h" -#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) #define MY_GATEWAY_FEATURE #define MY_NODE_TYPE "gateway" #elif defined(MY_REPEATER_FEATURE) @@ -102,6 +102,13 @@ // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif + #if defined(MY_CONTROLLER_IP_ADDRESS) + #define MY_GATEWAY_CLIENT_MODE + #endif + #if !defined(MY_PORT) + #error You must define MY_PORT (cotroller or gatway port to open) + #endif + #if defined(MY_GATEWAY_W5100) #include "drivers/AVR/Ethernet_W5100/utility/socket.cpp" #include "drivers/AVR/Ethernet_W5100/utility/w5100.cpp" @@ -110,13 +117,6 @@ #include "drivers/AVR/Ethernet_W5100/EthernetUdp.cpp" #include "drivers/AVR/Ethernet_W5100/IPAddress.cpp" - #if defined(MY_CONTROLLER_IP_ADDRESS) - #define MY_GATEWAY_CLIENT_MODE - #endif - - #if !defined(MY_PORT) - #error You must define MY_PORT (cotroller or gatway port to open) - #endif #if !defined(USE_UDP) #include "drivers/AVR/Ethernet_W5100/EthernetServer.cpp" #endif @@ -127,6 +127,23 @@ #else // What do we do here? #endif + #elif defined(MY_GATEWAY_ENC28J60) + #undef MY_USE_UDP // Will not fit (or compile) on ENC28J60 + #include "drivers/AVR/Ethernet_UIP/src/utility/uipethernet-conf.h" + #include "drivers/AVR/Ethernet_UIP/src/utility/uip-conf.h" + #include "drivers/AVR/Ethernet_UIP/src/UIPEthernet.h" + #include "drivers/AVR/Ethernet_UIP/src/utility/Enc28J60Network.cpp" + #include "drivers/AVR/Ethernet_UIP/src/utility/mempool_conf.h" + #include "drivers/AVR/Ethernet_UIP/src/utility/mempool.cpp" + #include "drivers/AVR/Ethernet_UIP/src/UIPEthernet.cpp" + #include "drivers/AVR/Ethernet_UIP/src/UIPServer.cpp" + #include "drivers/AVR/Ethernet_UIP/src/UIPClient.cpp" + #include "drivers/AVR/Ethernet_UIP/src/utility/clock-arch.c" + #include "drivers/AVR/Ethernet_UIP/src/utility/uip_timer.c" + #include "drivers/AVR/Ethernet_UIP/src/utility/uip.c" + #include "drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c" + + #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_SERIAL) #include "core/MyGatewayTransportSerial.cpp" #endif diff --git a/libraries/MySensors/core/MyProtocol.cpp b/libraries/MySensors/core/MyProtocol.cpp deleted file mode 100644 index f0a473a..0000000 --- a/libraries/MySensors/core/MyProtocol.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB - * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include "MyProtocol.h" - -MyProtocol::MyProtocol() { -} diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/README b/libraries/MySensors/drivers/AVR/Ethernet_UIP/README index 321b334..c7368c6 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/README +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/README @@ -1,4 +1,4 @@ -This is UIPEthernet version 1.09 +This is UIPEthernet version 1.59 An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS. Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib! diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino index bc2f094..7b3b132 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -20,6 +20,7 @@ */ +#include #include // Enter a MAC address and IP address for your controller below. diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino index 62d66e4..8603001 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/EchoServer/EchoServer.ino @@ -18,6 +18,7 @@ * Adaption to Enc28J60 by Norbert Truchsess */ +#include #include // The connection_data struct needs to be defined in an external file. #include diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino index dca685c..444b36a 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpClient/TcpClient.ino @@ -16,6 +16,7 @@ * Copyright (C) 2013 by Norbert Truchsess */ +#include #include EthernetClient client; diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino index 10512ec..b8a1e6d 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/TcpServer/TcpServer.ino @@ -18,6 +18,7 @@ * Adaption to Enc28J60 by Norbert Truchsess */ +#include #include EthernetServer server = EthernetServer(1000); diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino index aad56b4..f549c48 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpClient/UdpClient.ino @@ -16,6 +16,7 @@ * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) */ +#include #include EthernetUDP udp; diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino index 3b12d75..06b94be 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/examples/UdpServer/UdpServer.ino @@ -14,6 +14,7 @@ * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) */ +#include #include EthernetUDP udp; diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties b/libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties index 158ae31..cd8c551 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/library.properties @@ -4,7 +4,7 @@ email=Norbert Truchsess sentence=Ethernet library for ENC28J60 paragraph=implements the same API as stock Ethernet-lib. Just replace the include of Ethernet.h with UIPEthernet.h url=https://github.com/ntruchsess/arduino_uip -architectures=avr -version=1.04 +architectures=* +version=1.50 dependencies= core-dependencies=arduino (>=1.5.0) diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dhcp.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dhcp.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dhcp.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/Dhcp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dhcp.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dns.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dns.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dns.h similarity index 98% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dns.h index 4913ca8..1b6bb3d 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/Dns.h +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/Dns.h @@ -5,7 +5,7 @@ #ifndef DNSClient_h #define DNSClient_h -#include +#include "UIPUdp.h" class DNSClient { diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPClient.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPEthernet.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPServer.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPUdp.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPUdp.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPUdp.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/UIPUdp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPUdp.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/ethernet_comp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/ethernet_comp.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/ethernet_comp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/ethernet_comp.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/Enc28J60Network.cpp similarity index 87% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/Enc28J60Network.cpp index c7c66fb..9c154cd 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/Enc28J60Network.cpp +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/Enc28J60Network.cpp @@ -25,8 +25,19 @@ #include "Enc28J60Network.h" #include "Arduino.h" +#if ENC28J60_USE_SPILIB +#include +#endif + extern "C" { -#include + #if defined(ARDUINO_ARCH_AVR) + // AVR-specific code + #include + #elif defined(ARDUINO_ARCH_SAM) + // SAM-specific code + #else + // generic, non-platform specific code + #endif #include "enc28j60.h" #include "uip.h" } @@ -40,7 +51,15 @@ extern "C" { // set CS to 1 = passive #define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH) // +#if defined(ARDUINO_ARCH_AVR) #define waitspi() while(!(SPSR&(1<tcpstateflags != UIP_CLOSED && conn->lport == htons(lastport)) { goto again; @@ -427,8 +427,8 @@ uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) } conn = 0; - for(c = 0; c < UIP_CONNS; ++c) { - cconn = &uip_conns[c]; + for(cc = 0; cc < UIP_CONNS; ++cc) { + cconn = &uip_conns[cc]; if(cconn->tcpstateflags == UIP_CLOSED) { conn = cconn; break; @@ -482,17 +482,17 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) lastport = 4096; } - for(c = 0; c < UIP_UDP_CONNS; ++c) { - if(uip_udp_conns[c].lport == htons(lastport)) { + for(cc = 0; cc < UIP_UDP_CONNS; ++cc) { + if(uip_udp_conns[cc].lport == htons(lastport)) { goto again; } } conn = 0; - for(c = 0; c < UIP_UDP_CONNS; ++c) { - if(uip_udp_conns[c].lport == 0) { - conn = &uip_udp_conns[c]; + for(cc = 0; cc < UIP_UDP_CONNS; ++cc) { + if(uip_udp_conns[cc].lport == 0) { + conn = &uip_udp_conns[cc]; break; } } @@ -517,9 +517,9 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) void uip_unlisten(u16_t port) { - for(c = 0; c < UIP_LISTENPORTS; ++c) { - if(uip_listenports[c] == port) { - uip_listenports[c] = 0; + for(cc = 0; cc < UIP_LISTENPORTS; ++cc) { + if(uip_listenports[cc] == port) { + uip_listenports[cc] = 0; return; } } @@ -528,9 +528,9 @@ uip_unlisten(u16_t port) void uip_listen(u16_t port) { - for(c = 0; c < UIP_LISTENPORTS; ++c) { - if(uip_listenports[c] == 0) { - uip_listenports[c] = port; + for(cc = 0; cc < UIP_LISTENPORTS; ++cc) { + if(uip_listenports[cc] == 0) { + uip_listenports[cc] = port; return; } } @@ -1206,8 +1206,8 @@ uip_process(u8_t flag) tmp16 = BUF->destport; /* Next, check listening connections. */ - for(c = 0; c < UIP_LISTENPORTS; ++c) { - if(tmp16 == uip_listenports[c]) + for(cc = 0; cc < UIP_LISTENPORTS; ++cc) { + if(tmp16 == uip_listenports[cc]) goto found_listen; } @@ -1227,21 +1227,21 @@ uip_process(u8_t flag) BUF->tcpoffset = 5 << 4; /* Flip the seqno and ackno fields in the TCP header. */ - c = BUF->seqno[3]; + cc = BUF->seqno[3]; BUF->seqno[3] = BUF->ackno[3]; - BUF->ackno[3] = c; + BUF->ackno[3] = cc; - c = BUF->seqno[2]; + cc = BUF->seqno[2]; BUF->seqno[2] = BUF->ackno[2]; - BUF->ackno[2] = c; + BUF->ackno[2] = cc; - c = BUF->seqno[1]; + cc = BUF->seqno[1]; BUF->seqno[1] = BUF->ackno[1]; - BUF->ackno[1] = c; + BUF->ackno[1] = cc; - c = BUF->seqno[0]; + cc = BUF->seqno[0]; BUF->seqno[0] = BUF->ackno[0]; - BUF->ackno[0] = c; + BUF->ackno[0] = cc; /* We also have to increase the sequence number we are acknowledging. If the least significant byte overflowed, we need @@ -1277,15 +1277,15 @@ uip_process(u8_t flag) CLOSED connections are found. Thanks to Eddie C. Dost for a very nice algorithm for the TIME_WAIT search. */ uip_connr = 0; - for(c = 0; c < UIP_CONNS; ++c) { - if(uip_conns[c].tcpstateflags == UIP_CLOSED) { - uip_connr = &uip_conns[c]; + for(cc = 0; cc < UIP_CONNS; ++cc) { + if(uip_conns[cc].tcpstateflags == UIP_CLOSED) { + uip_connr = &uip_conns[cc]; break; } - if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { + if(uip_conns[cc].tcpstateflags == UIP_TIME_WAIT) { if(uip_connr == 0 || - uip_conns[c].timer > uip_connr->timer) { - uip_connr = &uip_conns[c]; + uip_conns[cc].timer > uip_connr->timer) { + uip_connr = &uip_conns[cc]; } } } @@ -1325,19 +1325,19 @@ uip_process(u8_t flag) /* Parse the TCP MSS option, if present. */ if((BUF->tcpoffset & 0xf0) > 0x50) { - for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { - opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + for(cc = 0; cc < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + cc]; if(opt == TCP_OPT_END) { /* End of options. */ break; } else if(opt == TCP_OPT_NOOP) { - ++c; + ++cc; /* NOP option. */ } else if(opt == TCP_OPT_MSS && - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc] == TCP_OPT_MSS_LEN) { /* An MSS option with the right option length. */ - tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | - (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + cc] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + cc]; uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; @@ -1346,12 +1346,12 @@ uip_process(u8_t flag) } else { /* All other options have a length field, so that we easily can skip past them. */ - if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc] == 0) { /* If the length field is zero, the options are malformed and we don't process them further. */ break; } - c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + cc += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc]; } } } @@ -1395,11 +1395,11 @@ uip_process(u8_t flag) } /* Calculated the length of the data, if the application has sent any data to us. */ - c = (BUF->tcpoffset >> 4) << 2; + cc = (BUF->tcpoffset >> 4) << 2; /* uip_len will contain the length of the actual TCP data. This is calculated by subtracing the length of the TCP header (in c) and the length of the IP header (20 bytes). */ - uip_len = uip_len - c - UIP_IPH_LEN; + uip_len = uip_len - cc - UIP_IPH_LEN; /* First, check if the sequence number of the incoming packet is what we're expecting next. If not, we send out an ACK with the @@ -1494,19 +1494,19 @@ uip_process(u8_t flag) /* Parse the TCP MSS option, if present. */ if((BUF->tcpoffset & 0xf0) > 0x50) { - for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { - opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + for(cc = 0; cc < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + cc]; if(opt == TCP_OPT_END) { /* End of options. */ break; } else if(opt == TCP_OPT_NOOP) { - ++c; + ++cc; /* NOP option. */ } else if(opt == TCP_OPT_MSS && - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc] == TCP_OPT_MSS_LEN) { /* An MSS option with the right option length. */ - tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | - uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + cc] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + cc]; uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; @@ -1515,12 +1515,12 @@ uip_process(u8_t flag) } else { /* All other options have a length field, so that we easily can skip past them. */ - if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc] == 0) { /* If the length field is zero, the options are malformed and we don't process them further. */ break; } - c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + cc += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + cc]; } } } diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arch.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arch.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arch.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arch.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_arp.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_clock.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_clock.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_clock.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_clock.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_debug.cpp similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.cpp rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_debug.cpp diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_debug.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_debug.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_debug.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_timer.c similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.c rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_timer.c diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_timer.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uip_timer.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_timer.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipethernet-conf.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uipethernet-conf.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipethernet-conf.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uipethernet-conf.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipopt.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uipopt.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/uipopt.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uipopt.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/util.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/util.h similarity index 100% rename from libraries/MySensors/drivers/AVR/Ethernet_UIP/utility/util.h rename to libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/util.h diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl deleted file mode 100644 index e6884dc..0000000 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpclient.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -#tcpclient.pl - -use IO::Socket::INET; - -# flush after every write -$| = 1; - -my ($socket,$client_socket); - -# creating object interface of IO::Socket::INET modules which internally creates -# socket, binds and connects to the TCP server running on the specific port. -$socket = new IO::Socket::INET ( -PeerHost => '192.168.0.6', -PeerPort => '1000', -Proto => 'tcp', -) or die "ERROR in Socket Creation : $!\n"; - -print "TCP Connection Success.\n"; - -# write on the socket to server. -$data = "DATA from Client"; -print $socket "$data\n"; -# we can also send the data through IO::Socket::INET module, -# $socket->send($data); - -# read the socket data sent by server. -$data = <$socket>; -# we can also read from socket through recv() in IO::Socket::INET -# $socket->recv($data,1024); -print "Received from Server : $data\n"; - -sleep (10); -$socket->close(); \ No newline at end of file diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl deleted file mode 100644 index 17405a3..0000000 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/tcpserver.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl -#tcpserver.pl - -use IO::Socket::INET; - -# flush after every write -$| = 1; - -my ($socket,$client_socket); -my ($peeraddress,$peerport); - -# creating object interface of IO::Socket::INET modules which internally does -# socket creation, binding and listening at the specified port address. -$socket = new IO::Socket::INET ( -LocalHost => '192.168.0.1', -LocalPort => '5000', -Proto => 'tcp', -Listen => 5, -Reuse => 1 -) or die "ERROR in Socket Creation : $!\n"; - -print "SERVER Waiting for client connection on port 5000\n"; - -while(1) -{ - # waiting for new client connection. - $client_socket = $socket->accept(); - - # get the host and port number of newly connected client. - $peer_address = $client_socket->peerhost(); - $peer_port = $client_socket->peerport(); - - print "Accepted New Client Connection From : $peer_address, $peer_port\n "; - - # read operation on the newly accepted client - $data = <$client_socket>; - # we can also read from socket through recv() in IO::Socket::INET - # $client_socket->recv($data,1024); - print "Received from Client : $data\n"; - - # write operation on the newly accepted client. - $data = "DATA from Server"; - print $client_socket "$data\n"; - # we can also send the data through IO::Socket::INET module, - # $client_socket->send($data); - - sleep(1); - - $client_socket->close(); -} - -$socket->close(); - diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl deleted file mode 100644 index bc9e6a2..0000000 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpclient.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -#udpclient.pl - -use IO::Socket::INET; - -# flush after every write -$| = 1; - -my ($socket,$data); - -# We call IO::Socket::INET->new() to create the UDP Socket -# and bind with the PeerAddr. -$socket = new IO::Socket::INET ( -PeerAddr => '192.168.0.6:5000', -Proto => 'udp' -) or die "ERROR in Socket Creation : $!\n"; -#send operation -$data = "data from client"; -$socket->send($data); - -#read operation -$data = <$socket>; -print "Data received from socket : $data\n "; - -sleep(10); -$socket->close(); diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl b/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl deleted file mode 100644 index e728a46..0000000 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/tests/perl/udpserver.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl -#udpserver.pl - -use IO::Socket::INET; - -# flush after every write -$| = 1; - -my ($socket,$received_data); -my ($peeraddress,$peerport); - -# we call IO::Socket::INET->new() to create the UDP Socket and bound -# to specific port number mentioned in LocalPort and there is no need to provide -# LocalAddr explicitly as in TCPServer. -$socket = new IO::Socket::INET ( -LocalPort => '5000', -Proto => 'udp', -) or die "ERROR in Socket Creation : $!\n"; - -while(1) -{ -# read operation on the socket -$socket->recv($recieved_data,1024); - -#get the peerhost and peerport at which the recent data received. -$peer_address = $socket->peerhost(); -$peer_port = $socket->peerport(); -print "($peer_address , $peer_port) said : $recieved_data\n"; - -#send the data to the client at which the read/write operations done recently. -$data = "data from server\n"; - -$socket->send($data); - -print $socket "$data"; - -} - -$socket->close(); - diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 3dd66d8..79c1e08 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -63,8 +63,9 @@ #define MY_RADIO_NRF24 -// W5100 Ethernet gateway -#define MY_GATEWAY_W5100 +// Enable gateway type +//#define MY_GATEWAY_W5100 +#define MY_GATEWAY_ENC28J60 // Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) #define MY_GATEWAY_PROTOCOL_DEFAULT From ba9288506494ee318113514f63ea78027675f4e9 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 14 Sep 2015 15:52:43 +0200 Subject: [PATCH 256/660] Document MyConfig.h --- libraries/MySensors/MyConfig.h | 56 +++++++++++++++---- libraries/MySensors/MySensor.h | 17 +++--- .../EthernetGateway/EthernetGateway.ino | 4 +- .../examples/MotionSensor/MotionSensor.ino | 7 ++- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index c8323be..818eae5 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -22,6 +22,11 @@ #define MyConfig_h #include + +/********************************** +* Serial and debug options +***********************************/ + // Enables this in sketch to show debug prints. This option will add a lot to the size of the // final sketch but is helpful to see what is actually is happening during development //#define MY_DEBUG @@ -34,11 +39,21 @@ #undef MY_DEBUG #endif -// Serial output baud rate (for debug prints and serial gateway) +// Serial output baud rate (debug prints and serial gateway speed) #ifndef MY_BAUD_RATE #define MY_BAUD_RATE 115200 #endif +/********************************** +* Radio selection and modes +***********************************/ + +// Selecting radio transport is optional (for a gateway node). + +//#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + + // Node id defaults to AUTO (tries to fetch id from controller) #ifndef MY_NODE_ID #define MY_NODE_ID AUTO @@ -57,7 +72,7 @@ ***********************************/ // Enable MY_OTA_FIRMWARE_FEATURE in sketch to allow safe over-the-air firmware updates. -// This feature requires external flash and the DualOptiBoot bootloader. +// This feature requires external flash and the DualOptiBoot boot-loader. // Note: You can still have OTA FW updates without external flash but it // requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE //#define MY_OTA_FIRMWARE_FEATURE @@ -174,22 +189,22 @@ * NRF24L01 Driver Defaults ***********************************/ #ifndef MY_RF24_CE_PIN -#define MY_RF24_CE_PIN 9 +#define MY_RF24_CE_PIN 9 #endif #ifndef MY_RF24_CS_PIN -#define MY_RF24_CS_PIN 10 +#define MY_RF24_CS_PIN 10 #endif #ifndef MY_RF24_PA_LEVEL -#define MY_RF24_PA_LEVEL RF24_PA_MAX +#define MY_RF24_PA_LEVEL RF24_PA_MAX #endif // RF channel for the sensor net, 0-127 #ifndef MY_RF24_CHANNEL -#define MY_RF24_CHANNEL 76 +#define MY_RF24_CHANNEL 76 #endif //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps #ifndef MY_RF24_DATARATE -#define MY_RF24_DATARATE RF24_250KBPS +#define MY_RF24_DATARATE RF24_250KBPS #endif // This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network. #ifndef MY_RF24_BASE_RADIO_ID @@ -246,11 +261,26 @@ #endif /************************************** -* Gateway Transport Ethernet Defaults +* Ethernet Gateway Transport Defaults ***************************************/ -// Enable to use DHCP for getting IP address. If not defined, static IP is expected -//#define MY_IP_ADDRESS_VIA_DHCP +// The gateway options available +//#define MY_GATEWAY_W5100 +//#define MY_GATEWAY_ENC28J60 +//#define MY_GATEWAY_ESP8266 + +// The port to open on controller or gateway +#ifndef MY_PORT +#define MY_PORT 5003 +#endif + +// Static ip address of gateway (if this is disabled, DHCP will be used) +//#define MY_IP_ADDRESS 192,168,178,66 + +// Enables UDP mode for Ethernet gateway (W5100) +//#define MY_USE_UDP + +// DHCP, default renewal setting #ifndef MY_IP_RENEWAL_INTERVAL #define MY_IP_RENEWAL_INTERVAL 60000 #endif @@ -258,7 +288,9 @@ #ifndef MY_MAC_ADDRESS #define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED #endif -// Enable to use UDP instead of plain Ethernet -//#define MY_USE_UDP + +// Controller ip-address, if this is defined, gateway will act as a client trying to contact controller on MY_PORT. +// If MY_CONTROLLER_IP_ADDRESS is left un-defined, gateway acts as server allowing incoming connections. +//#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 #endif diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 4b54a51..7f80bda 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -35,8 +35,6 @@ #define MY_NODE_TYPE "sensor" #endif -// CORE - // HARDWARE #if defined(ARDUINO_ARCH_ESP8266) @@ -184,14 +182,17 @@ extern void setup(); extern void loop(); -// Initialize library and call sketch functions +#include +// Initialize library and handle sketch functions like we want to int main() { - begin(); - setup(); + init(); // Init Arduino + begin(); // Startup MySensors library + setup(); // Call sketch setup while(1) { - // We handle incoming message processing here - process(); - loop(); + process(); // Process incoming data + loop(); // Call sketch loop + if (serialEventRun) serialEventRun(); } + return 0; } #endif diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 79c1e08..29f6870 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -64,8 +64,8 @@ // Enable gateway type -//#define MY_GATEWAY_W5100 -#define MY_GATEWAY_ENC28J60 + + // Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) #define MY_GATEWAY_PROTOCOL_DEFAULT diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index 7687d7b..35483f6 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -28,14 +28,17 @@ */ //#define MY_DEBUG + +#define MY_RADIO_NRF24 // MY_RADIO_RFM69 + //#define MY_SOFTSPI //#define MY_OTA_FIRMWARE_FEATURE -#define MY_SIGNING_SOFT +//#define MY_SIGNING_SOFT +//#define MY_REPEATER_FEATURE // #define MY_GATEWAY_SERIAL // REMOVE-ME // #define MY_GATEWAY_PROTOCOL_DEFAULT // REMOVE-ME -#define MY_RADIO_NRF24 // MY_RADIO_RFM69 #include From 4f4f0605c09cc1222607d51343e16728ee0e7d67 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Tue, 15 Sep 2015 00:28:47 +0200 Subject: [PATCH 257/660] Split out some more components to make core class cleaner --- libraries/MySensors/MyConfig.h | 4 +- libraries/MySensors/MySensor.h | 75 +- .../MySensors/core/MyGatewayTransport.cpp | 56 ++ libraries/MySensors/core/MyGatewayTransport.h | 24 +- .../core/MyGatewayTransportEthernet.cpp | 2 +- .../core/MyGatewayTransportSerial.cpp | 2 +- libraries/MySensors/core/MyInclusionMode.cpp | 59 ++ libraries/MySensors/core/MyInclusionMode.h | 35 + libraries/MySensors/core/MyLeds.cpp | 99 +++ libraries/MySensors/core/MyLeds.h | 54 ++ libraries/MySensors/core/MySensorCore.cpp | 820 +----------------- libraries/MySensors/core/MySensorCore.h | 133 +-- libraries/MySensors/core/MySigning.cpp | 5 + libraries/MySensors/core/MySigning.h | 6 + libraries/MySensors/core/MyTransport.cpp | 547 ++++++++++++ libraries/MySensors/core/MyTransport.h | 78 +- libraries/MySensors/core/MyTransportNRF24.h | 8 - libraries/MySensors/core/MyTransportRFM69.h | 8 - libraries/MySensors/drivers/pubsubclient | 1 + .../EthernetGateway/EthernetGateway.ino | 6 +- .../examples/MotionSensor/MotionSensor.ino | 7 +- 21 files changed, 1096 insertions(+), 933 deletions(-) create mode 100644 libraries/MySensors/core/MyGatewayTransport.cpp create mode 100644 libraries/MySensors/core/MyInclusionMode.cpp create mode 100644 libraries/MySensors/core/MyInclusionMode.h create mode 100644 libraries/MySensors/core/MyLeds.cpp create mode 100644 libraries/MySensors/core/MyLeds.h create mode 100644 libraries/MySensors/core/MyTransport.cpp create mode 160000 libraries/MySensors/drivers/pubsubclient diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 818eae5..dc014fc 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -95,9 +95,9 @@ // but now can be used in any sensor node. Also the LEDs can now be // disabled in the gateway. -//#define MY_WITH_LEDS_BLINKING +//#define MY_LEDS_BLINKING_FEATURE -// The following setting allows you to inverse the blinking feature WITH_LEDS_BLINKING +// The following setting allows you to inverse the blinking feature MY_LEDS_BLINKING_FEATURE // When WITH_LEDS_BLINKING_INVERSE is enabled LEDSs are normally turned on and switches // off when blinking diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 7f80bda..62951a9 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -45,6 +45,19 @@ #include "core/MyHwATMega328.cpp" #endif +// LEDS +#if defined(MY_LEDS_BLINKING_FEATURE) + #include "core/MyLeds.cpp" +#else + #include "core/MyLeds.h" +#endif + +// INCLUSION MODE +#if defined(MY_INCLUSION_MODE_FEATURE) + #include "core/MyInclusionMode.cpp" +#endif + + // SIGNING #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) #include "MySigning.cpp" @@ -60,42 +73,21 @@ #endif #endif -// RADIO -#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) - #define MY_RADIO_FEATURE - // SOFTSPI - #ifdef MY_SOFTSPI - #if defined(ARDUINO_ARCH_ESP8266) - #error Soft SPI is not available on ESP8266 - #endif - #include "drivers/AVR/DigitalIO/SoftI2cMaster.cpp" - #include "drivers/AVR/DigitalIO/PinIO.cpp" - #endif - - // FLASH - #ifdef MY_OTA_FIRMWARE_FEATURE - #include "drivers/SPIFlash/SPIFlash.cpp" - SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); - #endif - - #if defined(MY_RADIO_NRF24) - #include "drivers/RF24/RF24.cpp" - #include "core/MyTransportNRF24.cpp" - #elif defined(MY_RADIO_RFM69) - #include "drivers/RFM69/RFM69.cpp" - #include "core/MyTransportRFM69.cpp" - #endif -#endif // GATEWAY - TRANSPORT #if defined(MY_GATEWAY_FEATURE) + // GATEWAY - COMMON FUNCTIONS + #include "core/MyGatewayTransport.cpp" + // GATEWAY - PROTOCOL #if defined(MY_GATEWAY_PROTOCOL_DEFAULT) #include "core/MyProtocolDefault.cpp" #else #error No gateway protocol specified! #endif + + // GATEWAY - CONFIGURATION #if defined(MY_RADIO_FEATURE) // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE @@ -108,6 +100,7 @@ #endif #if defined(MY_GATEWAY_W5100) + // GATEWAY - W5100 #include "drivers/AVR/Ethernet_W5100/utility/socket.cpp" #include "drivers/AVR/Ethernet_W5100/utility/w5100.cpp" #include "drivers/AVR/Ethernet_W5100/DNS.cpp" @@ -126,6 +119,7 @@ // What do we do here? #endif #elif defined(MY_GATEWAY_ENC28J60) + // GATEWAY - ENC28J60 #undef MY_USE_UDP // Will not fit (or compile) on ENC28J60 #include "drivers/AVR/Ethernet_UIP/src/utility/uipethernet-conf.h" #include "drivers/AVR/Ethernet_UIP/src/utility/uip-conf.h" @@ -143,6 +137,7 @@ #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_SERIAL) + // GATEWAY - SERIAL #include "core/MyGatewayTransportSerial.cpp" #endif #else @@ -175,6 +170,34 @@ #define MY_IS_GATEWAY false #endif +// RADIO +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) + #define MY_RADIO_FEATURE + // SOFTSPI + #ifdef MY_SOFTSPI + #if defined(ARDUINO_ARCH_ESP8266) + #error Soft SPI is not available on ESP8266 + #endif + #include "drivers/AVR/DigitalIO/SoftI2cMaster.cpp" + #include "drivers/AVR/DigitalIO/PinIO.cpp" + #endif + + // FLASH + #ifdef MY_OTA_FIRMWARE_FEATURE + #include "drivers/SPIFlash/SPIFlash.cpp" + SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); + #endif + #include "core/MyTransport.cpp" + #if defined(MY_RADIO_NRF24) + #include "drivers/RF24/RF24.cpp" + #include "core/MyTransportNRF24.cpp" + #elif defined(MY_RADIO_RFM69) + #include "drivers/RFM69/RFM69.cpp" + #include "core/MyTransportRFM69.cpp" + #endif +#endif + + #include "core/MyMessage.cpp" #include "core/MySensorCore.cpp" diff --git a/libraries/MySensors/core/MyGatewayTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.cpp new file mode 100644 index 0000000..0072946 --- /dev/null +++ b/libraries/MySensors/core/MyGatewayTransport.cpp @@ -0,0 +1,56 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Tomas Hozza + * Copyright (C) 2015 Tomas Hozza + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyGatewayTransport.h" + +inline void gatewayTransportProcess() { + if (gatewayTransportAvailable()) { + MyMessage &_msg = gatewayTransportReceive(); + if (_msg.destination == GATEWAY_ADDRESS) { + // Check if sender requests an ack back. + if (mGetRequestAck(_msg)) { + // Copy message + _msgTmp = _msg; + mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(_msgTmp, true); + _msgTmp.sender = _nc.nodeId; + _msgTmp.destination = _msg.sender; + gatewayTransportSend(_msgTmp); + } + if (mGetCommand(_msg) == C_INTERNAL) { + if (_msg.type == I_VERSION) { + // Request for version. Create the response + gatewayTransportSend(buildGw(_msg, I_VERSION).set(LIBRARY_VERSION)); + #ifdef MY_INCLUSION_MODE_FEATURE + } else if (_msg.type == I_INCLUSION_MODE) { + // Request to change inclusion mode + inclusionModeSet(atoi(_msg.data) == 1); + #endif + } else { + processInternalMessages(); + } + } else { + // Call incoming message callback if available + if (_msgCallback != NULL) { + _msgCallback(_msg); + } + } + } + } +} diff --git a/libraries/MySensors/core/MyGatewayTransport.h b/libraries/MySensors/core/MyGatewayTransport.h index 4df3244..e971bd1 100644 --- a/libraries/MySensors/core/MyGatewayTransport.h +++ b/libraries/MySensors/core/MyGatewayTransport.h @@ -23,19 +23,33 @@ #include "MyConfig.h" #include "MyMessage.h" #include "MyProtocol.h" +#include "MySensorCore.h" + +// Common gateway functions + +void gatewayTransportProcess(); +// Gateway "interface" functions -// initialize the driver -bool gatewayTransportBegin(); +/** + * initialize the driver + */ +bool gatewayTransportInit(); -// Send message to controller +/** + * Send message to controller + */ bool gatewayTransportSend(MyMessage &message); -// Check if a new message is available from controller +/* + * Check if a new message is available from controller + */ bool gatewayTransportAvailable(); -// Pick up last message received from controller +/* + * Pick up last message received from controller + */ MyMessage& gatewayTransportReceive(); #endif /* MyGatewayTransportEthernet_h */ diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp index 18bd233..8e661fd 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.cpp @@ -35,7 +35,7 @@ MyMessage _ethernetMsg; #endif /* USE_UDP */ -bool gatewayTransportBegin() { +bool gatewayTransportInit() { #ifdef MY_IP_ADDRESS Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP); #else diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.cpp b/libraries/MySensors/core/MyGatewayTransportSerial.cpp index 313efac..390dc17 100644 --- a/libraries/MySensors/core/MyGatewayTransportSerial.cpp +++ b/libraries/MySensors/core/MyGatewayTransportSerial.cpp @@ -26,7 +26,7 @@ MyMessage _serialMsg; -bool gatewayTransportBegin() { +bool gatewayTransportInit() { return true; } diff --git a/libraries/MySensors/core/MyInclusionMode.cpp b/libraries/MySensors/core/MyInclusionMode.cpp new file mode 100644 index 0000000..604983a --- /dev/null +++ b/libraries/MySensors/core/MyInclusionMode.cpp @@ -0,0 +1,59 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyInclusionMode.h" + +unsigned long _inclusionStartTime; +bool _inclusionMode; + +inline void inclusionInit() { + _inclusionMode = false; + #if defined(MY_INCLUSION_BUTTON_FEATURE) + // Setup digital in that triggers inclusion mode + pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); + digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); + #endif + +} + + +void inclusionModeSet(boolean newMode) { + if (newMode != inclusionMode) { + _inclusionMode = newMode; + // Send back mode change to controller + gatewayTransportSend(buildGw(_msg, I_INCLUSION_MODE).set(_inclusionMode?1:0)); + if (_inclusionMode) { + _inclusionStartTime = hwMillis(); + } + } +} + +inline void inclusionProcess() { + #ifdef MY_INCLUSION_BUTTON_FEATURE + if (!inclusionMode && digitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == LOW) { + // Start inclusion mode + inclusionModeSet(true); + } + #endif + + if (_inclusionMode && hwMillis()-_inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) { + // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode + inclusionModeSet(false); + } +} diff --git a/libraries/MySensors/core/MyInclusionMode.h b/libraries/MySensors/core/MyInclusionMode.h new file mode 100644 index 0000000..03ac12b --- /dev/null +++ b/libraries/MySensors/core/MyInclusionMode.h @@ -0,0 +1,35 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyInclusionMode_h +#define MyInclusionMode_h + +#include "MySensorCore.h" + +unsigned long inclusionStartTime; +bool inclusionMode; + +extern bool gatewayTransportSend(MyMessage &message); + +void inclusionInit(); +void inclusionModeSet(boolean newMode); +void inclusionProcess(); + + +#endif diff --git a/libraries/MySensors/core/MyLeds.cpp b/libraries/MySensors/core/MyLeds.cpp new file mode 100644 index 0000000..10ce2f5 --- /dev/null +++ b/libraries/MySensors/core/MyLeds.cpp @@ -0,0 +1,99 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyLeds.h" + +// these variables don't need to be volatile, since we are not using interrupts +uint8_t _countRx; +uint8_t _countTx; +uint8_t _countErr; +unsigned long _blink_next_time; + +inline void ledsInit() { + // Setup led pins + pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); + pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); + pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); + + // Set initial state of leds + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); + + // initialize counters + _countRx = 0; + _countTx = 0; + _countErr = 0; +} + +inline void ledsProcess() { + // Just return if it is not the time... + // http://playground.arduino.cc/Code/TimingRollover + if ((long)(hwMillis() - _blink_next_time) < 0) + return; + else + _blink_next_time = hwMillis() + MY_DEFAULT_LED_BLINK_PERIOD; + + // do the actual blinking + if(_countRx && _countRx != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON); + } + else if(!_countRx) { + // switching off + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); + } + if(_countRx != 255) + --_countRx; + + if(_countTx && _countTx != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON); + } + else if(!_countTx) { + // switching off + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); + } + if(_countTx != 255) + --_countTx; + + if(_countErr && _countErr != 255) { + // switch led on + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON); + } + else if(!_countErr) { + // switching off + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); + } + if(_countErr != 255) + --_countErr; +} + +void ledsBlinkRx(uint8_t cnt) { + if(_countRx == 255) { _countRx = cnt; } +} + +void ledsBlinkTx(uint8_t cnt) { + if(_countTx == 255) { _countTx = cnt; } +} + +void ledsBlinkErr(uint8_t cnt) { + if(_countErr == 255) { _countErr = cnt; } +} + diff --git a/libraries/MySensors/core/MyLeds.h b/libraries/MySensors/core/MyLeds.h new file mode 100644 index 0000000..6549f36 --- /dev/null +++ b/libraries/MySensors/core/MyLeds.h @@ -0,0 +1,54 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyLeds_h +#define MyLeds_h + + +#ifdef WITH_LEDS_BLINKING_INVERSE +#define LED_ON 0x1 +#define LED_OFF 0x0 +#else +#define LED_ON 0x0 +#define LED_OFF 0x1 +#endif + +#ifdef MY_LEDS_BLINKING_FEATURE + #define ledBlinkTx(x,...) ledsBlinkTx(x) + #define ledBlinkRx(x,...) ledsBlinkRx(x) + #define ledBlinkErr(x,...) ledsBlinkErr(x) + + /** + * Blink with LEDs + * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms + */ + void ledsInit(); + void ledsBlinkRx(uint8_t cnt); + void ledsBlinkTx(uint8_t cnt); + void ledsBlinkErr(uint8_t cnt); + void ledsProcess(); // do the actual blinking + +#else + // Remove led functions if feature is disabled + #define ledBlinkTx(x,...) + #define ledBlinkRx(x,...) + #define ledBlinkErr(x,...) +#endif + +#endif diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index 0d8b496..da576b6 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -17,41 +17,12 @@ * version 2 as published by the Free Software Foundation. */ - - #include "MySensorCore.h" - -NodeConfig _nc; // Essential settings for node to work ControllerConfig _cc; // Configuration coming from controller -#ifdef MY_OTA_FIRMWARE_FEATURE -NodeFirmwareConfig _fc; -bool _fwUpdateOngoing; -unsigned long _fwLastRequestTime; -uint16_t _fwBlock; -uint8_t _fwRetry; -#endif - -#ifdef MY_RADIO_FEATURE -bool _autoFindParent; -uint8_t _failedTransmissions; -#endif - +NodeConfig _nc; // Essential settings for node to work MyMessage _msg; // Buffer for incoming messages. -MyMessage _msgTmp ; // Buffer for temporary messages (acks and nonces among others). - -#ifdef MY_LEDS_BLINKING_FEATURE -// these variables don't need to be volatile, since we are not using interrupts -uint8_t _countRx; -uint8_t _countTx; -uint8_t _countErr; -unsigned long _blink_next_time; -#endif - -#ifdef MY_SIGNING_FEATURE -uint16_t _doSign[16]; // Bitfield indicating which sensors require signed communication -MyMessage _msgSign; // Buffer for message to sign. -#endif +MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). #ifdef MY_DEBUG char convBuf[MAX_PAYLOAD*2+1]; @@ -62,124 +33,30 @@ void (*_timeCallback)(unsigned long); // Callback for requested time messages void (*_msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. -#define DISTANCE_INVALID (0xFF) +void process() { + hwWatchdogReset(); -#ifdef MY_SIGNING_FEATURE -// Macros for manipulating signing requirement table -#define DO_SIGN(node) (node == 0 ? (~_doSign[0]&1) : (~_doSign[node>>4]&(node%16))) -#define SET_SIGN(node) (node == 0 ? (_doSign[0]&=~1) : (_doSign[node>>4]&=~(node%16))) -#define CLEAR_SIGN(node) (node == 0 ? (_doSign[0]|=1) : (_doSign[node>>4]|=(node%16))) -#endif + #if defined (MY_LEDS_BLINKING_FEATURE) + ledsProcess(); + #endif -// Inline function and macros -static inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { - msg.sender = sender; - msg.destination = destination; - msg.sensor = sensor; - msg.type = type; - mSetCommand(msg,command); - mSetRequestAck(msg,enableAck); - mSetAck(msg,false); - return msg; + #if defined(MY_INCLUSION_MODE_FEATURE) + inclusionProcess(); + #endif + + #if defined(MY_GATEWAY_FEATURE) + gatewayTransportProcess(); + #endif + + #if defined(MY_RADIO_FEATURE) + transportProcess(); + #endif } -static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { - msg.sender = GATEWAY_ADDRESS; - msg.destination = GATEWAY_ADDRESS; - msg.sensor = 0; - msg.type = type; - mSetCommand(msg, C_INTERNAL); - mSetRequestAck(msg, false); - mSetAck(msg, false); - return msg; -} static inline bool isValidParent( const uint8_t parent ) { return parent != AUTO; } -static inline bool isValidDistance( const uint8_t distance ) { - return distance != DISTANCE_INVALID; -} - - - -#ifdef MY_OTA_FIRMWARE_FEATURE -// do a crc16 on the whole received firmware -bool isValidFirmware() { - // init crc - uint16_t crc = ~0; - for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); - for (int8_t j = 0; j < 8; ++j) { - if (crc & 1) - crc = (crc >> 1) ^ 0xA001; - else - crc = (crc >> 1); - } - } - return crc == _fc.crc; -} - -#endif - -#ifdef MY_LEDS_BLINKING_FEATURE -void handleLedsBlinking() { - static unsigned long next_time = hwMillis() + MY_DEFAULT_LED_BLINK_PERIOD; - - // Just return if it is not the time... - // http://playground.arduino.cc/Code/TimingRollover - if ((long)(hwMillis() - _blink_next_time) < 0) - return; - else - _blink_next_time = hwMillis() + ledBlinkPeriod; - - // do the actual blinking - if(_countRx && _countRx != 255) { - // switch led on - hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON); - } - else if(!_countRx) { - // switching off - hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); - } - if(_countRx != 255) - --_countRx; - - if(_countTx && _countTx != 255) { - // switch led on - hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON); - } - else if(!_countTx) { - // switching off - hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); - } - if(_countTx != 255) - --_countTx; - - if(_countErr && _countErr != 255) { - // switch led on - hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON); - } - else if(!_countErr) { - // switching off - hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); - } - if(_countErr != 255) - --_countErr; -} - -void rxBlink(uint8_t cnt) { - if(_countRx == 255) { _countRx = cnt; } -} - -void txBlink(uint8_t cnt) { - if(_countTx == 255) { _countTx = cnt; } -} - -void errBlink(uint8_t cnt) { - if(_countErr == 255) { _countErr = cnt; } -} -#endif void dataCallback(void (*msgCallback)(const MyMessage &)) { @@ -187,29 +64,21 @@ void dataCallback(void (*msgCallback)(const MyMessage &)) { } void begin() { - - #if defined(MY_INCLUSION_MODE_FEATURE) - inclusionMode = false; - #endif - - #ifndef MY_DISABLED_SERIAL + #if defined(MY_DISABLED_SERIAL) hwInit(); #endif - #ifdef MY_GATEWAY_FEATURE - #if defined(MY_INCLUSION_MODE_FEATURE) && defined(MY_INCLUSION_BUTTON_FEATURE) - // Setup digital in that triggers inclusion mode - pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); - digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); + #if defined(MY_GATEWAY_FEATURE) + #if defined(MY_INCLUSION_BUTTON_FEATURE) + inclusionInit(); #endif - // initialize the transport driver - if (!gatewayTransportBegin()) { + + // initialize the transport driver + if (!gatewayTransportInit()) { debug(PSTR("transport driver init fail\n")); while(1); // Nothing more we can do } - #endif - #if defined(MY_GATEWAY_FEATURE) gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); #endif @@ -223,27 +92,14 @@ void begin() { } #endif - #ifdef MY_SIGNING_FEATURE + #if defined(MY_SIGNING_FEATURE) // Read out the signing requirements from EEPROM hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); #endif -#ifdef MY_LEDS_BLINKING_FEATURE - // Setup led pins - pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); - pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); - pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); - - // Set initial state of leds - hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF); - hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF); - hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF); - - // initialize counters - _countRx = 0; - _countTx = 0; - _countErr = 0; -#endif + #if defined(MY_LEDS_BLINKING_FEATURE) + ledsInit(); + #endif // Read latest received controller configuration from EEPROM hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); @@ -277,7 +133,7 @@ void begin() { _nc.distance = 1; } else if (!isValidParent(_nc.parentNodeId)) { // Auto find parent, but parent in eeprom is invalid. Try find one. - findParentNode(); + transportFindParentNode(); } if (MY_NODE_ID != AUTO) { @@ -287,12 +143,12 @@ void begin() { hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); } else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) { // Try to fetch node-id from gateway - requestNodeId(); + transportRequestNodeId(); } #endif #if defined(MY_RADIO_FEATURE) - setupNode(); + transportSetupNode(); #endif debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), MY_NODE_TYPE, _nc.nodeId, _nc.parentNodeId, _nc.distance); } @@ -308,271 +164,23 @@ ControllerConfig getConfig() { return _cc; } -#if defined(MY_RADIO_FEATURE) -void requestNodeId() { - debug(PSTR("req id\n")); - transportSetAddress(_nc.nodeId); - build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); - sendWrite(_nc.parentNodeId, _msg); - wait(2000); -} -#endif - -#if defined(MY_RADIO_FEATURE) - - -void setupNode() { - // Open reading pipe for messages directed to this node (set write pipe to same) - transportSetAddress(_nc.nodeId); - // Present node and request config - #ifndef MY_GATEWAY_FEATURE - if (_nc.nodeId != AUTO) { - #ifdef MY_SIGNING_FEATURE - // Notify gateway (and possibly controller) about the signing preferences of this node - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); - - // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages - if (signer.requestSignatures()) { - wait(2000); - } - #endif - - // Send presentation for this radio node - #ifdef MY_REPEATER_FEATURE - present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); - #else - present(NODE_SENSOR_ID, S_ARDUINO_NODE); - #endif - // Send a configuration exchange request to controller - // Node sends parent node. Controller answers with latest node configuration - // which is picked up in process() - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); - - // Wait configuration reply. - wait(2000); - - #ifdef MY_OTA_FIRMWARE_FEATURE - RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msg.data; - mSetLength(_msg, sizeof(RequestFirmwareConfig)); - mSetCommand(_msg, C_STREAM); - mSetPayloadType(_msg,P_CUSTOM); - // copy node settings to reqFWConfig - memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig)); - // add bootloader information - reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; - _fwUpdateOngoing = false; - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); - #endif - } - #endif -} -#endif - -#if defined(MY_RADIO_FEATURE) -void findParentNode() { - static boolean findingParentNode = false; - - if (findingParentNode) - return; - findingParentNode = true; - - _failedTransmissions = 0; - - // Set distance to max - _nc.distance = 255; - - // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) - debug(PSTR("find parent\n")); - - build(_msg, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); - // Write msg, but suppress recursive parent search - sendWrite(BROADCAST_ADDRESS, _msg); - - // Wait for ping response. - wait(2000); - findingParentNode = false; -} -#endif - - boolean sendRoute(MyMessage &message) { - #if defined(MY_GATEWAY_FEATURE) if (message.destination == _nc.nodeId) { // This is a message sent from a sensor attached on the gateway node. // Pass it directly to the gateway transport layer. - #ifdef MY_LEDS_BLINKING_FEATURE - txBlink(1); - #endif + ledBlinkTx(1); return gatewayTransportSend(message); } #endif - - #if defined(MY_RADIO_FEATURE) - uint8_t sender = message.sender; - uint8_t dest = message.destination; - uint8_t last = message.last; - bool ok; - - // If we still don't have any parent id, re-request and skip this message. - if (_nc.parentNodeId == AUTO) { - findParentNode(); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return false; - } - - // If we still don't have any node id, re-request and skip this message. - if (_nc.nodeId == AUTO) { - requestNodeId(); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return false; - } - - mSetVersion(message, PROTOCOL_VERSION); - - #ifdef MY_SIGNING_FEATURE - // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message - if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && mGetLength(message) && - (mGetCommand(message) != C_INTERNAL || - (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && - message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && - message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { - bool signOk = false; - // Send nonce-request - if (!sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { - debug(PSTR("nonce tr err\n")); - return false; - } - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hwMillis(); - _msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS) { - if (process()) { - if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - if (signer.putNonce(getLastMessage()) && signer.signMsg(_msgSign)) { - message = _msgSign; // Write the signed message back - signOk = true; - } - break; - } - } - } - if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { - debug(PSTR("nonce tmo\n")); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return false; - } - if (!signOk) { - debug(PSTR("sign fail\n")); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return false; - } - // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, - // or signature will become invalid and the message rejected by the receiver - } else mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned - #endif - - if (dest == GATEWAY_ADDRESS || !MY_IS_REPEATER) { - // Store this address in routing table (if repeater) - #if defined (MY_IS_REPEATER) - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - #endif - // If destination is the gateway or if we aren't a repeater, let - // our parent take care of the message - ok = sendWrite(_nc.parentNodeId, message); - } else { - // Relay the message - uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); - if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { - // This message should be forwarded to a child node. If we send message - // to this nodes pipe then all children will receive it because the are - // all listening to this nodes pipe. - // - // +----B - // -A - // +----C------D - // - // We're node C, Message comes from A and has destination D - // - // Message destination is not gateway and is in routing table for this node. - // Send it downstream - return sendWrite(route, message); - } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { - // Node has not yet received any id. We need to send it - // by doing a broadcast sending, - return sendWrite(BROADCAST_ADDRESS, message); - } else if (MY_IS_GATEWAY) { - // Destination isn't in our routing table and isn't a broadcast address - // Nothing to do here - return false; - } else { - // A message comes from a child node and we have no - // route for it. - // - // +----B - // -A - // +----C------D <-- Message comes from D - // - // We're node C - // - // Message should be passed to node A (this nodes relay) - - // This message should be routed back towards sensor net gateway - ok = sendWrite(_nc.parentNodeId, message); - // Add this child to our "routing table" if it not already exist - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - } - - if (!ok) { - // Failure when sending to parent node. The parent node might be down and we - // need to find another route to gateway. - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - _failedTransmissions++; - if (_autoFindParent && _failedTransmissions > SEARCH_FAILURES) { - findParentNode(); - } - } else { - _failedTransmissions = 0; - } - return ok; + transportSendRoute(message); #else return false; #endif } -#ifdef MY_RADIO_FEATURE -boolean sendWrite(uint8_t to, MyMessage &message) { - mSetVersion(message, PROTOCOL_VERSION); - uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); - message.last = _nc.nodeId; - #ifdef MY_LEDS_BLINKING_FEATURE - txBlink(1); - #endif - bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - - debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), - message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); - - return ok; -} -#endif - bool send(MyMessage &message, bool enableAck) { message.sender = _nc.nodeId; mSetCommand(message,C_SET); @@ -611,320 +219,7 @@ void requestTime(void (* timeCallback)(unsigned long)) { sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); } -void process() { - hwWatchdogReset(); - - #ifdef MY_LEDS_BLINKING_FEATURE - handleLedsBlinking(); - #endif - - #ifdef MY_INCLUSION_MODE_FEATURE - checkInclusionMode(); - #endif - - #if defined (MY_GATEWAY_FEATURE) - if (gatewayTransportAvailable()) { - MyMessage &_msg = gatewayTransportReceive(); - if (_msg.destination == GATEWAY_ADDRESS) { - // Check if sender requests an ack back. - if (mGetRequestAck(_msg)) { - // Copy message - _msgTmp = _msg; - mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(_msgTmp, true); - _msgTmp.sender = _nc.nodeId; - _msgTmp.destination = _msg.sender; - gatewayTransportSend(_msgTmp); - } - if (mGetCommand(_msg) == C_INTERNAL) { - if (_msg.type == I_VERSION) { - // Request for version. Create the response - gatewayTransportSend(buildGw(_msg, I_VERSION).set(LIBRARY_VERSION)); - #ifdef MY_INCLUSION_MODE_FEATURE - } else if (_msg.type == I_INCLUSION_MODE) { - // Request to change inclusion mode - setInclusionMode(atoi(_msg.data) == 1); - #endif - } else { - processInternalMessages(); - } - } else { - // Call incoming message callback if available - if (_msgCallback != NULL) { - _msgCallback(_msg); - } - } - } - } - #endif - - #if defined(MY_RADIO_FEATURE) - uint8_t to = 0; - if (!transportAvailable(&to)) - { - #ifdef MY_OTA_FIRMWARE_FEATURE - unsigned long enter = hwMillis(); - if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { - if (!_fwRetry) { - debug(PSTR("fw upd fail\n")); - // Give up. We have requested MY_OTA_RETRY times without any packet in return. - _fwUpdateOngoing = false; - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return; - } - _fwRetry--; - _fwLastRequestTime = enter; - // Time to (re-)request firmware block from controller - RequestFWBlock *firmwareRequest = (RequestFWBlock *)_msg.data; - mSetLength(_msg, sizeof(RequestFWBlock)); - firmwareRequest->type = _fc.type; - firmwareRequest->version = _fc.version; - firmwareRequest->block = (_fwBlock - 1); - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); - } - #endif - return; - } - - #ifdef MY_SIGNING_FEATURE - (void)signer.checkTimer(); // Manage signing timeout - #endif - - uint8_t len = transportReceive((uint8_t *)&_msg); - (void)len; //until somebody makes use of 'len' - #ifdef MY_LEDS_BLINKING_FEATURE - rxBlink(1); - #endif - - #ifdef MY_SIGNING_FEATURE - // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) - // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) - if (signer.requestSignatures() && _msg.destination == _nc.nodeId && mGetLength(_msg) && !mGetAck(_msg) && - (mGetCommand(_msg) != C_INTERNAL || - (_msg.type != I_GET_NONCE_RESPONSE && _msg.type != I_GET_NONCE && _msg.type != I_REQUEST_SIGNING && - _msg.type != I_ID_REQUEST && _msg.type != I_ID_RESPONSE && - _msg.type != I_FIND_PARENT && _msg.type != I_FIND_PARENT_RESPONSE))) { - if (!mGetSigned(_msg)) { - // Got unsigned message that should have been signed - debug(PSTR("no sign\n")); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return; - } - else if (!signer.verifyMsg(_msg)) { - debug(PSTR("verify fail\n")); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return; // This signed message has been tampered with! - } - } - #endif - - // Add string termination, good if we later would want to print it. - _msg.data[mGetLength(_msg)] = '\0'; - debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - _msg.sender, _msg.last, _msg.destination, _msg.sensor, mGetCommand(_msg), _msg.type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(convBuf)); - mSetSigned(_msg,0); // Clear the sign-flag now as verification (and debug printing) is completed - - if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) { - debug(PSTR("ver mismatch\n")); - #ifdef MY_LEDS_BLINKING_FEATURE - errBlink(1); - #endif - return; - } - - uint8_t command = mGetCommand(_msg); - uint8_t type = _msg.type; - uint8_t sender = _msg.sender; - uint8_t last = _msg.last; - uint8_t destination = _msg.destination; - - if (destination == _nc.nodeId) { - // This message is addressed to this node - - if (MY_IS_REPEATER && last != _nc.parentNodeId) { - // Message is from one of the child nodes. Add it to routing table. - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - - // Check if sender requests an ack back. - if (mGetRequestAck(_msg)) { - // Copy message - _msgTmp = _msg; - mSetRequestAck(_msgTmp,false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(_msgTmp,true); - _msgTmp.sender = _nc.nodeId; - _msgTmp.destination = _msg.sender; - sendRoute(_msgTmp); - } - - if (command == C_INTERNAL) { - if (type == I_FIND_PARENT_RESPONSE) { - if (_autoFindParent) { - // We've received a reply to a FIND_PARENT message. Check if the distance is - // shorter than we already have. - uint8_t distance = _msg.getByte(); - if (isValidDistance(distance)) - { - // Distance to gateway is one more for us w.r.t. parent - distance++; - if (isValidDistance(distance) && (distance < _nc.distance)) { - // Found a neighbor closer to GW than previously found - _nc.distance = distance; - _nc.parentNodeId = _msg.sender; - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _nc.parentNodeId); - hwWriteConfig(EEPROM_DISTANCE_ADDRESS, _nc.distance); - debug(PSTR("parent=%d, d=%d\n"), _nc.parentNodeId, _nc.distance); - } - } - } - return; - #ifdef MY_SIGNING_FEATURE - } else if (type == I_GET_NONCE) { - if (signer.getNonce(_msg)) { - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); - } - return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_REQUEST_SIGNING) { - if (_msg.getBool()) { - // We received an indicator that the sender require us to sign all messages we send to it - SET_SIGN(_msg.sender); - } else { - // We received an indicator that the sender does not require us to sign all messages we send to it - CLEAR_SIGN(_msg.sender); - } - // Save updated table - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); - - // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing - // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages - if (MY_GATEWAY_FEATURE) { - if (signer.requestSignatures() && DO_SIGN(_msg.sender)) - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); - else - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); - } - return; // Signing request is an internal MySensor protocol message, no need to inform caller about this - } else if (type == I_GET_NONCE_RESPONSE) { - return; // Just pass along nonce silently (no need to call callback for these) - #endif - } else if (sender == GATEWAY_ADDRESS) { - if (type == I_ID_RESPONSE && _nc.nodeId == AUTO) { - _nc.nodeId = _msg.getByte(); - if (_nc.nodeId == AUTO) { - // sensor net gateway will return max id if all sensor id are taken - debug(PSTR("full\n")); - while (1); // Wait here. Nothing else we can do... - } - setupNode(); - // Write id to EEPROM - hwWriteConfig(EEPROM_NODE_ID_ADDRESS, _nc.nodeId); - debug(PSTR("id=%d\n"), _nc.nodeId); - } else { - processInternalMessages(); - } - return; - } - } - #ifdef MY_OTA_FIRMWARE_FEATURE - else if (command == C_STREAM) { - if (type == ST_FIRMWARE_CONFIG_RESPONSE) { - NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; - // compare with current node configuration, if they differ, start fw fetch process - if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { - debug(PSTR("fw update\n")); - // copy new FW config - memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); - // Init flash - if (!_flash.initialize()) { - debug(PSTR("flash init fail\n")); - _fwUpdateOngoing = false; - } else { - // erase lower 32K -> max flash size for ATMEGA328 - _flash.blockErase32K(0); - // wait until flash erased - while ( _flash.busy() ); - _fwBlock = _fc.blocks; - _fwUpdateOngoing = true; - // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; - } - return ; - } else debug(PSTR("fw update skipped\n")); - } else if (type == ST_FIRMWARE_RESPONSE) { - if (_fwUpdateOngoing) { - // Save block to flash - debug(PSTR("fw block %d\n"), _fwBlock); - // extract FW block - ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; - // write to flash - _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); - // wait until flash written - while ( _flash.busy() ); - _fwBlock--; - if (!_fwBlock) { - // We're finished! Do a checksum and reboot. - _fwUpdateOngoing = false; - if (isValidFirmware()) { - debug(PSTR("fw checksum ok\n")); - // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; - uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; - _flash.writeBytes(0, OTAbuffer, 10); - // Write the new firmware config to eeprom - hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); - hwReboot(); - } else { - debug(PSTR("fw checksum fail\n")); - } - } - // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; - } else { - debug(PSTR("No fw update ongoing\n")); - } - return; - } - - } - #endif - // Call incoming message callback if available - if (_msgCallback != NULL) { - _msgCallback(_msg); - } - return; - } else if (MY_IS_REPEATER && _nc.nodeId != AUTO) { - // If this node have an id, relay the message - if (command == C_INTERNAL && type == I_FIND_PARENT) { - if (sender != _nc.parentNodeId) { - if (_nc.distance == DISTANCE_INVALID) - findParentNode(); - - if (_nc.distance != DISTANCE_INVALID) { - // Relaying nodes should always answer ping messages - // Wait a random delay of 0-2 seconds to minimize collision - // between ping ack messages from other relaying nodes - wait(hwMillis() & 0x3ff); - sendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); - } - } - } else if (to == _nc.nodeId) { - // We should try to relay this message to another node - sendRoute(_msg); - } - } - #endif -} - - +// Message delivered through _msg void processInternalMessages() { bool isMetric; uint8_t type = _msg.type; @@ -938,8 +233,12 @@ void processInternalMessages() { isMetric = _msg.getString()[0] == 'M' ; _cc.isMetric = isMetric; hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); - } else if (type == I_CHILDREN) { - if (MY_IS_REPEATER && _msg.getString()[0] == 'C') { + } else if (type == I_TIME && _timeCallback != NULL) { + // Deliver time to callback + _timeCallback(_msg.getULong()); + } + #if defined(MY_REPEATER_FEATURE) + if (type == I_CHILDREN && _msg.getString()[0] == 'C') { // Clears child relay data for this node debug(PSTR("clear\n")); uint8_t i = 255; @@ -950,26 +249,19 @@ void processInternalMessages() { hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, 0xFF); hwWriteConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); // Find parent node - findParentNode(); + transportFindParentNode(); sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } - } else if (type == I_TIME) { - if (_timeCallback != NULL) { - // Deliver time to callback - _timeCallback(_msg.getULong()); - } - } + #endif } -#if defined (MY_REPEATER_FEATURE) void saveState(uint8_t pos, uint8_t value) { hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); } uint8_t loadState(uint8_t pos) { return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos); } -#endif void wait(unsigned long ms) { unsigned long enter = hwMillis(); @@ -1029,31 +321,5 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode } -#ifdef MY_INCLUSION_MODE_FEATURE -void setInclusionMode(boolean newMode) { - if (newMode != inclusionMode) { - inclusionMode = newMode; - // Send back mode change to controller - gatewayTransportSend(buildGw(_msg, I_INCLUSION_MODE).set(inclusionMode?1:0)); - if (inclusionMode) { - inclusionStartTime = hwMillis(); - } - } -} - -void checkInclusionMode() { - #ifdef MY_INCLUSION_BUTTON_FEATURE - if (!inclusionMode && digitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == LOW) { - // Start inclusion mode - setInclusionMode(true); - } - #endif - - if (inclusionMode && hwMillis()-inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) { - // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode - setInclusionMode(false); - } -} -#endif diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index 24a7874..ce9ed5d 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -35,24 +35,12 @@ #include #include - - - #ifdef MY_DEBUG #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) #else #define debug(x,...) #endif -#ifdef WITH_LEDS_BLINKING_INVERSE -#define LED_ON 0x1 -#define LED_OFF 0x0 -#else -#define LED_ON 0x0 -#define LED_OFF 0x1 -#endif - - // EEPROM start address for mysensors library data #define EEPROM_START 0 // EEPROM location of node id @@ -70,8 +58,8 @@ #define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) #define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) // First free address for sketch static configuration -// Search for a new parent node after this many transmission failures -#define SEARCH_FAILURES 5 +// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). +#define GATEWAY_ADDRESS ((uint8_t)0) struct NodeConfig @@ -86,65 +74,15 @@ struct ControllerConfig { }; -// Size of each firmware block -#define FIRMWARE_BLOCK_SIZE 16 -// Number of times a firmware block should be requested before giving up -#define FIRMWARE_MAX_REQUESTS 5 -// Number of times to request a fw block before giving up -#define MY_OTA_RETRY 5 -// Number of millisecons before re-request a fw block -#define MY_OTA_RETRY_DELAY 500 -// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) -#define FIRMWARE_START_OFFSET 10 -// Bootloader version -#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 -#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 -#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) - - -// FW config structure, stored in eeprom -typedef struct { - uint16_t type; - uint16_t version; - uint16_t blocks; - uint16_t crc; -} __attribute__((packed)) NodeFirmwareConfig; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t blocks; - uint16_t crc; - uint16_t BLVersion; -} __attribute__((packed)) RequestFirmwareConfig; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t block; -} __attribute__((packed)) RequestFWBlock; - -typedef struct { - uint16_t type; - uint16_t version; - uint16_t block; - uint8_t data[FIRMWARE_BLOCK_SIZE]; -} __attribute__((packed)) ReplyFWBlock; - - - /** -* Begin operation of the MySensors library +* Set the callback method for incoming messages * -* Call this in setup(), before calling any other sensor net library methods. -* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL. +* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. */ - - void dataCallback(void (* msgCallback)(const MyMessage &)=NULL); /** - * Return the nodes nodeId. + * Return this nodes id. */ uint8_t getNodeId(); @@ -284,47 +222,46 @@ bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); - /****** PRIVATE ********/ + void begin(); void process(void); void processInternalMessages(); -#ifdef MY_LEDS_BLINKING_FEATURE - /** - * Blink with LEDs - * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms - */ - void rxBlink(uint8_t cnt); - void txBlink(uint8_t cnt); - void errBlink(uint8_t cnt); - void handleLedsBlinking(); // do the actual blinking -#endif - -#ifdef MY_OTA_FIRMWARE_FEATURE - // do a crc16 on the whole received firmware - bool isValidFirmware(); -#endif - - -#ifdef MY_INCLUSION_MODE_FEATURE - void setInclusionMode(bool newMode); - void checkInclusionMode(); - unsigned long inclusionStartTime; - bool inclusionMode; -#endif - - boolean sendRoute(MyMessage &message); -#if defined(MY_RADIO_FEATURE) - boolean sendWrite(uint8_t dest, MyMessage &message); - void requestNodeId(); - void setupNode(); - void findParentNode(); + +extern NodeConfig _nc; +extern MyMessage _msg; // Buffer for incoming messages. +extern MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). +extern void (*_msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. +#ifdef MY_DEBUG + extern char convBuf[MAX_PAYLOAD*2+1]; #endif +// Inline function and macros +static inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { + msg.sender = sender; + msg.destination = destination; + msg.sensor = sensor; + msg.type = type; + mSetCommand(msg,command); + mSetRequestAck(msg,enableAck); + mSetAck(msg,false); + return msg; +} + +static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { + msg.sender = GATEWAY_ADDRESS; + msg.destination = GATEWAY_ADDRESS; + msg.sensor = 0; + msg.type = type; + mSetCommand(msg, C_INTERNAL); + mSetRequestAck(msg, false); + mSetAck(msg, false); + return msg; +} #endif diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index 03c3ee3..ad0d78c 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -19,6 +19,11 @@ #include "MySigning.h" + +uint16_t _doSign[16]; // Bitfield indicating which sensors require signed communication +MyMessage _msgSign; // Buffer for message to sign. + + MySigning::MySigning(bool requestSignatures) : _requestSignatures(requestSignatures) { } diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index e65d546..637b281 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -30,6 +30,12 @@ #include #include "MyMessage.h" + +// Macros for manipulating signing requirement table +#define DO_SIGN(node) (node == 0 ? (~_doSign[0]&1) : (~_doSign[node>>4]&(node%16))) +#define SET_SIGN(node) (node == 0 ? (_doSign[0]&=~1) : (_doSign[node>>4]&=~(node%16))) +#define CLEAR_SIGN(node) (node == 0 ? (_doSign[0]|=1) : (_doSign[node>>4]|=(node%16))) + class MySigning { public: diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp new file mode 100644 index 0000000..309bc4d --- /dev/null +++ b/libraries/MySensors/core/MyTransport.cpp @@ -0,0 +1,547 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + + +#include "MyTransport.h" + +bool _autoFindParent; +uint8_t _failedTransmissions; + + +#ifdef MY_OTA_FIRMWARE_FEATURE + NodeFirmwareConfig _fc; + bool _fwUpdateOngoing; + unsigned long _fwLastRequestTime; + uint16_t _fwBlock; + uint8_t _fwRetry; +#endif + + +static inline bool isValidDistance( const uint8_t distance ) { + return distance != DISTANCE_INVALID; +} + + +inline void transportProcess() { + uint8_t to = 0; + if (!transportAvailable(&to)) + { + #ifdef MY_OTA_FIRMWARE_FEATURE + unsigned long enter = hwMillis(); + if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { + if (!_fwRetry) { + debug(PSTR("fw upd fail\n")); + // Give up. We have requested MY_OTA_RETRY times without any packet in return. + _fwUpdateOngoing = false; + ledBlinkErr(1); + return; + } + _fwRetry--; + _fwLastRequestTime = enter; + // Time to (re-)request firmware block from controller + RequestFWBlock *firmwareRequest = (RequestFWBlock *)_msg.data; + mSetLength(_msg, sizeof(RequestFWBlock)); + firmwareRequest->type = _fc.type; + firmwareRequest->version = _fc.version; + firmwareRequest->block = (_fwBlock - 1); + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); + } + #endif + return; + } + + #ifdef MY_SIGNING_FEATURE + (void)signer.checkTimer(); // Manage signing timeout + #endif + + uint8_t len = transportReceive((uint8_t *)&_msg); + (void)len; //until somebody makes use of 'len' + ledBlinkRx(1); + + #ifdef MY_SIGNING_FEATURE + // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) + // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) + if (signer.requestSignatures() && _msg.destination == _nc.nodeId && mGetLength(_msg) && !mGetAck(_msg) && + (mGetCommand(_msg) != C_INTERNAL || + (_msg.type != I_GET_NONCE_RESPONSE && _msg.type != I_GET_NONCE && _msg.type != I_REQUEST_SIGNING && + _msg.type != I_ID_REQUEST && _msg.type != I_ID_RESPONSE && + _msg.type != I_FIND_PARENT && _msg.type != I_FIND_PARENT_RESPONSE))) { + if (!mGetSigned(_msg)) { + // Got unsigned message that should have been signed + debug(PSTR("no sign\n")); + ledBlinkErr(1); + return; + } + else if (!signer.verifyMsg(_msg)) { + debug(PSTR("verify fail\n")); + ledBlinkErr(1); + return; // This signed message has been tampered with! + } + } + #endif + + // Add string termination, good if we later would want to print it. + _msg.data[mGetLength(_msg)] = '\0'; + debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), + _msg.sender, _msg.last, _msg.destination, _msg.sensor, mGetCommand(_msg), _msg.type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(convBuf)); + mSetSigned(_msg,0); // Clear the sign-flag now as verification (and debug printing) is completed + + if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) { + debug(PSTR("ver mismatch\n")); + ledBlinkErr(1); + return; + } + + uint8_t command = mGetCommand(_msg); + uint8_t type = _msg.type; + uint8_t sender = _msg.sender; + uint8_t last = _msg.last; + uint8_t destination = _msg.destination; + + if (destination == _nc.nodeId) { + // This message is addressed to this node + + #if defined(MY_REPEATER_FEATURE) + if (last != _nc.parentNodeId) { + // Message is from one of the child nodes. Add it to routing table. + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + } + #endif + + // Check if sender requests an ack back. + if (mGetRequestAck(_msg)) { + // Copy message + _msgTmp = _msg; + mSetRequestAck(_msgTmp,false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(_msgTmp,true); + _msgTmp.sender = _nc.nodeId; + _msgTmp.destination = _msg.sender; + sendRoute(_msgTmp); + } + + if (command == C_INTERNAL) { + if (type == I_FIND_PARENT_RESPONSE) { + if (_autoFindParent) { + // We've received a reply to a FIND_PARENT message. Check if the distance is + // shorter than we already have. + uint8_t distance = _msg.getByte(); + if (isValidDistance(distance)) + { + // Distance to gateway is one more for us w.r.t. parent + distance++; + if (isValidDistance(distance) && (distance < _nc.distance)) { + // Found a neighbor closer to GW than previously found + _nc.distance = distance; + _nc.parentNodeId = _msg.sender; + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _nc.parentNodeId); + hwWriteConfig(EEPROM_DISTANCE_ADDRESS, _nc.distance); + debug(PSTR("parent=%d, d=%d\n"), _nc.parentNodeId, _nc.distance); + } + } + } + return; + #ifdef MY_SIGNING_FEATURE + } else if (type == I_GET_NONCE) { + if (signer.getNonce(_msg)) { + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); + } + return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this + } else if (type == I_REQUEST_SIGNING) { + if (_msg.getBool()) { + // We received an indicator that the sender require us to sign all messages we send to it + SET_SIGN(_msg.sender); + } else { + // We received an indicator that the sender does not require us to sign all messages we send to it + CLEAR_SIGN(_msg.sender); + } + // Save updated table + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, sizeof(_doSign)); + + // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing + // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node + // to sign it's messages + if (MY_GATEWAY_FEATURE) { + if (signer.requestSignatures() && DO_SIGN(_msg.sender)) + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); + else + sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + } + return; // Signing request is an internal MySensor protocol message, no need to inform caller about this + } else if (type == I_GET_NONCE_RESPONSE) { + return; // Just pass along nonce silently (no need to call callback for these) + #endif + } else if (sender == GATEWAY_ADDRESS) { + if (type == I_ID_RESPONSE && _nc.nodeId == AUTO) { + _nc.nodeId = _msg.getByte(); + if (_nc.nodeId == AUTO) { + // sensor net gateway will return max id if all sensor id are taken + debug(PSTR("full\n")); + while (1); // Wait here. Nothing else we can do... + } + transportSetupNode(); + // Write id to EEPROM + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, _nc.nodeId); + debug(PSTR("id=%d\n"), _nc.nodeId); + } else { + processInternalMessages(); + } + return; + } + } + #ifdef MY_OTA_FIRMWARE_FEATURE + else if (command == C_STREAM) { + if (type == ST_FIRMWARE_CONFIG_RESPONSE) { + NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; + // compare with current node configuration, if they differ, start fw fetch process + if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + debug(PSTR("fw update\n")); + // copy new FW config + memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); + // Init flash + if (!_flash.initialize()) { + debug(PSTR("flash init fail\n")); + _fwUpdateOngoing = false; + } else { + // erase lower 32K -> max flash size for ATMEGA328 + _flash.blockErase32K(0); + // wait until flash erased + while ( _flash.busy() ); + _fwBlock = _fc.blocks; + _fwUpdateOngoing = true; + // reset flags + _fwRetry = MY_OTA_RETRY+1; + _fwLastRequestTime = 0; + } + return ; + } else debug(PSTR("fw update skipped\n")); + } else if (type == ST_FIRMWARE_RESPONSE) { + if (_fwUpdateOngoing) { + // Save block to flash + debug(PSTR("fw block %d\n"), _fwBlock); + // extract FW block + ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; + // write to flash + _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + // wait until flash written + while ( _flash.busy() ); + _fwBlock--; + if (!_fwBlock) { + // We're finished! Do a checksum and reboot. + _fwUpdateOngoing = false; + if (transportIsValidFirmware()) { + debug(PSTR("fw checksum ok\n")); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; + uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(fwsize >> 8),fwsize,':'}; + _flash.writeBytes(0, OTAbuffer, 10); + // Write the new firmware config to eeprom + hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hwReboot(); + } else { + debug(PSTR("fw checksum fail\n")); + } + } + // reset flags + _fwRetry = MY_OTA_RETRY+1; + _fwLastRequestTime = 0; + } else { + debug(PSTR("No fw update ongoing\n")); + } + return; + } + + } + #endif + // Call incoming message callback if available + if (_msgCallback != NULL) { + _msgCallback(_msg); + } + return; + } + #if defined(MY_REPEATER_FEATURE) + if (_nc.nodeId != AUTO) { + // If this node have an id, relay the message + if (command == C_INTERNAL && type == I_FIND_PARENT) { + if (sender != _nc.parentNodeId) { + if (_nc.distance == DISTANCE_INVALID) + transportFindParentNode(); + + if (_nc.distance != DISTANCE_INVALID) { + // Relaying nodes should always answer ping messages + // Wait a random delay of 0-2 seconds to minimize collision + // between ping ack messages from other relaying nodes + wait(hwMillis() & 0x3ff); + sendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + } + } + } else if (to == _nc.nodeId) { + // We should try to relay this message to another node + sendRoute(_msg); + } + } + #endif +} + +#ifdef MY_OTA_FIRMWARE_FEATURE +// do a crc16 on the whole received firmware +bool transportIsValidFirmware() { + // init crc + uint16_t crc = ~0; + for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { + crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); + for (int8_t j = 0; j < 8; ++j) { + if (crc & 1) + crc = (crc >> 1) ^ 0xA001; + else + crc = (crc >> 1); + } + } + return crc == _fc.crc; +} + +#endif + + +boolean transportSendWrite(uint8_t to, MyMessage &message) { + mSetVersion(message, PROTOCOL_VERSION); + uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); + message.last = _nc.nodeId; + ledBlinkTx(1); + bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); + + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), + message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, + mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); + + return ok; +} + + +boolean transportSendRoute(MyMessage &message) { + uint8_t sender = message.sender; + uint8_t dest = message.destination; + uint8_t last = message.last; + bool ok; + + // If we still don't have any parent id, re-request and skip this message. + if (_nc.parentNodeId == AUTO) { + transportFindParentNode(); + ledBlinkErr(1); + return false; + } + + // If we still don't have any node id, re-request and skip this message. + if (_nc.nodeId == AUTO) { + transportRequestNodeId(); + ledBlinkErr(1); + return false; + } + + mSetVersion(message, PROTOCOL_VERSION); + + #ifdef MY_SIGNING_FEATURE + // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message + if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && mGetLength(message) && + (mGetCommand(message) != C_INTERNAL || + (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && + message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && + message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { + bool signOk = false; + // Send nonce-request + if (!sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + debug(PSTR("nonce tr err\n")); + return false; + } + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust process() takes care of them + unsigned long enter = hwMillis(); + _msgSign = message; // Copy the message to sign since message buffer might be touched in process() + while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS) { + if (process()) { + if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + if (signer.putNonce(getLastMessage()) && signer.signMsg(_msgSign)) { + message = _msgSign; // Write the signed message back + signOk = true; + } + break; + } + } + } + if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { + debug(PSTR("nonce tmo\n")); + ledBlinkErr(1); + return false; + } + if (!signOk) { + debug(PSTR("sign fail\n")); + ledBlinkErr(1); + return false; + } + // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, + // or signature will become invalid and the message rejected by the receiver + } else { + mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned + } + #endif + + if (dest == GATEWAY_ADDRESS || !MY_IS_REPEATER) { + // Store this address in routing table (if repeater) + #if defined (MY_IS_REPEATER) + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + #endif + // If destination is the gateway or if we aren't a repeater, let + // our parent take care of the message + ok = transportSendWrite(_nc.parentNodeId, message); + } else { + // Relay the message + uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); + if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { + // This message should be forwarded to a child node. If we send message + // to this nodes pipe then all children will receive it because the are + // all listening to this nodes pipe. + // + // +----B + // -A + // +----C------D + // + // We're node C, Message comes from A and has destination D + // + // Message destination is not gateway and is in routing table for this node. + // Send it downstream + return transportSendWrite(route, message); + } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { + // Node has not yet received any id. We need to send it + // by doing a broadcast sending, + return transportSendWrite(BROADCAST_ADDRESS, message); + } else if (MY_IS_GATEWAY) { + // Destination isn't in our routing table and isn't a broadcast address + // Nothing to do here + return false; + } else { + // A message comes from a child node and we have no + // route for it. + // + // +----B + // -A + // +----C------D <-- Message comes from D + // + // We're node C + // + // Message should be passed to node A (this nodes relay) + + // This message should be routed back towards sensor net gateway + ok = transportSendWrite(_nc.parentNodeId, message); + // Add this child to our "routing table" if it not already exist + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + } + } + + if (!ok) { + // Failure when sending to parent node. The parent node might be down and we + // need to find another route to gateway. + ledBlinkErr(1); + _failedTransmissions++; + if (_autoFindParent && _failedTransmissions > SEARCH_FAILURES) { + transportFindParentNode(); + } + } else { + _failedTransmissions = 0; + } + return ok; +} + + +void transportRequestNodeId() { + debug(PSTR("req id\n")); + transportSetAddress(_nc.nodeId); + build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); + transportSendWrite(_nc.parentNodeId, _msg); + wait(2000); +} + +void transportSetupNode() { + // Open reading pipe for messages directed to this node (set write pipe to same) + transportSetAddress(_nc.nodeId); + // Present node and request config + #ifndef MY_GATEWAY_FEATURE + if (_nc.nodeId != AUTO) { + #ifdef MY_SIGNING_FEATURE + // Notify gateway (and possibly controller) about the signing preferences of this node + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); + + // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages + if (signer.requestSignatures()) { + wait(2000); + } + #endif + + // Send presentation for this radio node + #ifdef MY_REPEATER_FEATURE + present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + #else + present(NODE_SENSOR_ID, S_ARDUINO_NODE); + #endif + // Send a configuration exchange request to controller + // Node sends parent node. Controller answers with latest node configuration + // which is picked up in process() + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + + // Wait configuration reply. + wait(2000); + + #ifdef MY_OTA_FIRMWARE_FEATURE + RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msg.data; + mSetLength(_msg, sizeof(RequestFirmwareConfig)); + mSetCommand(_msg, C_STREAM); + mSetPayloadType(_msg,P_CUSTOM); + // copy node settings to reqFWConfig + memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig)); + // add bootloader information + reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; + _fwUpdateOngoing = false; + sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + #endif + } + #endif +} + +void transportFindParentNode() { + static boolean findingParentNode = false; + + if (findingParentNode) + return; + findingParentNode = true; + + _failedTransmissions = 0; + + // Set distance to max + _nc.distance = 255; + + // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) + debug(PSTR("find parent\n")); + + build(_msg, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); + // Write msg, but suppress recursive parent search + transportSendWrite(BROADCAST_ADDRESS, _msg); + + // Wait for ping response. + wait(2000); + findingParentNode = false; +} diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index 503f8c1..f72ea8f 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -21,13 +21,87 @@ #define MyTransport_h #include +#include "MySensorCore.h" + +// Size of each firmware block +#define FIRMWARE_BLOCK_SIZE 16 +// Number of times a firmware block should be requested before giving up +#define FIRMWARE_MAX_REQUESTS 5 +// Number of times to request a fw block before giving up +#define MY_OTA_RETRY 5 +// Number of millisecons before re-request a fw block +#define MY_OTA_RETRY_DELAY 500 +// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#define FIRMWARE_START_OFFSET 10 +// Bootloader version +#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 +#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 +#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) + +// Search for a new parent node after this many transmission failures +#define SEARCH_FAILURES 5 + + +// FW config structure, stored in eeprom +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; +} __attribute__((packed)) NodeFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t blocks; + uint16_t crc; + uint16_t BLVersion; +} __attribute__((packed)) RequestFirmwareConfig; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; +} __attribute__((packed)) RequestFWBlock; + +typedef struct { + uint16_t type; + uint16_t version; + uint16_t block; + uint8_t data[FIRMWARE_BLOCK_SIZE]; +} __attribute__((packed)) ReplyFWBlock; + + #define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. #define NODE_SENSOR_ID 0xFF // Node child id is always created for when a node -// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). -#define GATEWAY_ADDRESS ((uint8_t)0) #define BROADCAST_ADDRESS ((uint8_t)0xFF) +// invalid distance when searching for parent +#define DISTANCE_INVALID (0xFF) + +// Common functions in all radio drivers +#ifdef MY_OTA_FIRMWARE_FEATURE + // do a crc16 on the whole received firmware + bool transportIsValidFirmware(); +#endif + + +void transportProcess(); +void transportRequestNodeId(); +void transportSetupNode(); +void transportFindParentNode(); +boolean transportSendRoute(MyMessage &message); +boolean transportSendWrite(uint8_t to, MyMessage &message); + +// "Interface" functions for radio driver +bool transportInit(); +void transportSetAddress(uint8_t address); +uint8_t transportGetAddress(); +bool transportSend(uint8_t to, const void* data, uint8_t len); +bool transportAvailable(uint8_t *to); +uint8_t transportReceive(void* data); +void transportPowerDown(); #endif diff --git a/libraries/MySensors/core/MyTransportNRF24.h b/libraries/MySensors/core/MyTransportNRF24.h index 0d0bcf8..3f895c5 100644 --- a/libraries/MySensors/core/MyTransportNRF24.h +++ b/libraries/MySensors/core/MyTransportNRF24.h @@ -32,12 +32,4 @@ #define CURRENT_NODE_PIPE ((uint8_t)1) #define BROADCAST_PIPE ((uint8_t)2) -bool transportInit(); -void transportSetAddress(uint8_t address); -uint8_t transportGetAddress(); -bool transportSend(uint8_t to, const void* data, uint8_t len); -bool transportAvailable(uint8_t *to); -uint8_t transportReceive(void* data); -void transportPowerDown(); - #endif diff --git a/libraries/MySensors/core/MyTransportRFM69.h b/libraries/MySensors/core/MyTransportRFM69.h index 36ef1a9..ec3227d 100644 --- a/libraries/MySensors/core/MyTransportRFM69.h +++ b/libraries/MySensors/core/MyTransportRFM69.h @@ -27,12 +27,4 @@ #include "drivers/SPI/SPI.h" -bool transportInit(); -void transportSetAddress(uint8_t address); -uint8_t transportGetAddress(); -bool transportSend(uint8_t to, const void* data, uint8_t len); -bool transportAvailable(uint8_t *to); -uint8_t transportReceive(void* data); -void transportPowerDown(); - #endif diff --git a/libraries/MySensors/drivers/pubsubclient b/libraries/MySensors/drivers/pubsubclient new file mode 160000 index 0000000..2f97e4a --- /dev/null +++ b/libraries/MySensors/drivers/pubsubclient @@ -0,0 +1 @@ +Subproject commit 2f97e4a558a0fb38b4ac20a93b1a1b609771bb51 diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index 29f6870..f8e3992 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -64,8 +64,8 @@ // Enable gateway type - - +#define MY_GATEWAY_W5100 +//#define MY_GATEWAY_W5100 // Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) #define MY_GATEWAY_PROTOCOL_DEFAULT @@ -96,7 +96,7 @@ #define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED // Flash leds on rx/tx/err -#define MY_WITH_LEDS_BLINKING +#define MY_LEDS_BLINKING_FEATURE // Set blinking period #define MY_DEFAULT_LED_BLINK_PERIOD 300 diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index 35483f6..d07b2a7 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -37,8 +37,11 @@ //#define MY_SIGNING_SOFT //#define MY_REPEATER_FEATURE -// #define MY_GATEWAY_SERIAL // REMOVE-ME -// #define MY_GATEWAY_PROTOCOL_DEFAULT // REMOVE-ME +//#define MY_INCLUSION_MODE_FEATURE +//#define MY_INCLUSION_BUTTON_FEATURE +//#define MY_GATEWAY_SERIAL // REMOVE-ME +//#define MY_GATEWAY_PROTOCOL_DEFAULT // REMOVE-ME +//#define MY_LEDS_BLINKING_FEATURE #include From ada872f30f806926afcba036a6ed040b1dff072b Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Wed, 16 Sep 2015 00:18:26 +0200 Subject: [PATCH 258/660] Fixed: Software signing --- libraries/MySensors/MyConfig.h | 25 +- libraries/MySensors/MySensor.h | 60 ++-- .../MySensors/core/MyProtocolDefault.cpp | 8 +- libraries/MySensors/core/MySensorCore.cpp | 38 +-- libraries/MySensors/core/MySensorCore.h | 17 +- libraries/MySensors/core/MySigning.cpp | 8 - libraries/MySensors/core/MySigning.h | 90 +++--- .../MySensors/core/MySigningAtsha204.cpp | 29 +- libraries/MySensors/core/MySigningAtsha204.h | 20 +- .../MySensors/core/MySigningAtsha204Soft.cpp | 189 ++++++------ .../MySensors/core/MySigningAtsha204Soft.h | 44 +-- libraries/MySensors/core/MyTransport.cpp | 270 +++++++++--------- libraries/MySensors/core/MyTransport.h | 3 + .../examples/MotionSensor/MotionSensor.ino | 4 +- .../SecureActuator/SecureActuator.ino | 77 ++--- 15 files changed, 413 insertions(+), 469 deletions(-) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index dc014fc..f765a38 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -148,7 +148,7 @@ * Message Signing Settings ***********************************/ -// Enable one of these in sketch to use signing functionality +// Enable one of these in sketch to use the signing functionality //#define MY_SIGNING_ATSHA204 //#define MY_SIGNING_SOFT @@ -168,21 +168,26 @@ // Note that a node can still transmit a non-salted message (i.e. have white listing disabled) // to a node that has white listing enabled (assuming the receiver does not have a matching entry // for the sender in it's white list) -//#define MY_SECURE_NODE_WHITELISTING +//#define MY_SIGNING_NODE_WHITELIST {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} -// MySigningAtsha204 default setting -#ifndef MY_ATSHA204_PIN -#define MY_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached +// Atsha204 default pin setting +#ifndef MY_SIGNING_ATSHA204_PIN +#define MY_SIGNING_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached #endif -// MySigningAtsha204Soft default settings -#ifndef MY_RANDOMSEED_PIN -#define MY_RANDOMSEED_PIN 7 // A7 - Pin used for random generation (do not connect anything to this) +// Pin used for random generation in soft signing (do not connect anything to this when enabled) +#ifndef MY_SIGNING_SOFT_RANDOMSEED_PIN +#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 // A7 - +#endif + +// Set the soft_serial value to an arbitrary value for proper security +#ifndef MY_SIGNING_SOFT_SERIAL +#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 #endif // Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes) -#ifndef MY_HMAC_KEY -#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +#ifndef MY_SIGNING_SOFT_HMAC_KEY +#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 #endif /********************************** diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 62951a9..151ab7e 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -25,6 +25,7 @@ // #pragma message(VAR_NAME_VALUE(MY_GATEWAY_FEATURE)) #include "MyConfig.h" +#include "core/MySensorCore.h" #if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) #define MY_GATEWAY_FEATURE @@ -60,16 +61,19 @@ // SIGNING #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) - #include "MySigning.cpp" + // SIGNING COMMON FUNCTIONS + #include "core/MySigning.cpp" #define MY_SIGNING_FEATURE + #if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) + #error Only one signing engine can be activated + #endif + #if defined(MY_SIGNING_ATSHA204) - #include "MySigningAtsha204.cpp" + #include "core/MySigningAtsha204.cpp" #include "drivers/ATSHA204/ATSHA204.cpp" - MySigningAtsha204 signer; #elif defined(MY_SIGNING_SOFT) - #include "MySigningAtsha204Soft.cpp" + #include "core/MySigningAtsha204Soft.cpp" #include "drivers/ATSHA204/sha256.cpp" - MySigningAtsha204Soft signer; #endif #endif @@ -144,31 +148,6 @@ #undef MY_GATEWAY_FEATURE #endif -// Make sure to disable child features when parent feature is disabled -#if !defined(MY_RADIO_FEATURE) - #undef MY_OTA_FIRMWARE_FEATURE - #undef MY_REPEATER_FEATURE - #undef MY_SECURE_NODE_WHITELISTING - #undef MY_SIGNING_FEATURE -#endif - -#if !defined(MY_GATEWAY_FEATURE) - #undef MY_INCLUSION_MODE_FEATURE - #undef MY_INCLUSION_BUTTON_FEATURE -#endif - -// Defines used in code for if-statements -#if defined(MY_REPEATER_FEATURE) - #define MY_IS_REPEATER true -#else - #define MY_IS_REPEATER false -#endif - -#if defined(MY_GATEWAY_FEATURE) - #define MY_IS_GATEWAY true -#else - #define MY_IS_GATEWAY false -#endif // RADIO #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) @@ -188,6 +167,9 @@ SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); #endif #include "core/MyTransport.cpp" + #if defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69) + #error Only one radio driver can be activated + #endif #if defined(MY_RADIO_NRF24) #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" @@ -197,6 +179,20 @@ #endif #endif +// Make sure to disable child features when parent feature is disabled +#if !defined(MY_RADIO_FEATURE) + #undef MY_OTA_FIRMWARE_FEATURE + #undef MY_REPEATER_FEATURE + #undef MY_SIGNING_NODE_WHITELISTING + #undef MY_SIGNING_FEATURE +#endif + +#if !defined(MY_GATEWAY_FEATURE) + #undef MY_INCLUSION_MODE_FEATURE + #undef MY_INCLUSION_BUTTON_FEATURE +#endif + + #include "core/MyMessage.cpp" @@ -209,10 +205,10 @@ extern void loop(); // Initialize library and handle sketch functions like we want to int main() { init(); // Init Arduino - begin(); // Startup MySensors library + _begin(); // Startup MySensors library setup(); // Call sketch setup while(1) { - process(); // Process incoming data + _process(); // Process incoming data loop(); // Call sketch loop if (serialEventRun) serialEventRun(); } diff --git a/libraries/MySensors/core/MyProtocolDefault.cpp b/libraries/MySensors/core/MyProtocolDefault.cpp index 727b337..d4a54c1 100644 --- a/libraries/MySensors/core/MyProtocolDefault.cpp +++ b/libraries/MySensors/core/MyProtocolDefault.cpp @@ -21,8 +21,8 @@ #include "MyProtocolDefault.h" #include "MyTransport.h" -char fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; -char convBuffer[MAX_PAYLOAD*2+1]; +char _fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; +char _convBuffer[MAX_PAYLOAD*2+1]; bool protocolParse(MyMessage &message, char *inputString) { char *str, *p, *value=NULL; @@ -91,8 +91,8 @@ bool protocolParse(MyMessage &message, char *inputString) { } char * protocolFormat(MyMessage &message) { - snprintf_P(fmtBuffer, MAX_FORMAT_BUFFER_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuffer)); - return fmtBuffer; + snprintf_P(_fmtBuffer, MAX_FORMAT_BUFFER_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(_convBuffer)); + return _fmtBuffer; } uint8_t protocolH2i(char c) { diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index da576b6..e05db79 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -25,7 +25,7 @@ MyMessage _msg; // Buffer for incoming messages. MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). #ifdef MY_DEBUG - char convBuf[MAX_PAYLOAD*2+1]; + char _convBuf[MAX_PAYLOAD*2+1]; #endif uint16_t _heartbeat; @@ -33,9 +33,10 @@ void (*_timeCallback)(unsigned long); // Callback for requested time messages void (*_msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. -void process() { +void _process() { hwWatchdogReset(); + #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif @@ -59,11 +60,11 @@ static inline bool isValidParent( const uint8_t parent ) { } -void dataCallback(void (*msgCallback)(const MyMessage &)) { +void setIncomingCallback(void (*msgCallback)(const MyMessage &)) { _msgCallback = msgCallback; } -void begin() { +void _begin() { #if defined(MY_DISABLED_SERIAL) hwInit(); #endif @@ -165,7 +166,7 @@ ControllerConfig getConfig() { } -boolean sendRoute(MyMessage &message) { +boolean _sendRoute(MyMessage &message) { #if defined(MY_GATEWAY_FEATURE) if (message.destination == _nc.nodeId) { // This is a message sent from a sensor attached on the gateway node. @@ -185,42 +186,42 @@ bool send(MyMessage &message, bool enableAck) { message.sender = _nc.nodeId; mSetCommand(message,C_SET); mSetRequestAck(message,enableAck); - return sendRoute(message); + return _sendRoute(message); } void sendBatteryLevel(uint8_t value, bool enableAck) { - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } void sendHeartbeat(void) { - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT, false).set(_heartbeat++)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT, false).set(_heartbeat++)); } void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } void sendSketchInfo(const char *name, const char *version, bool enableAck) { if (name != NULL) { - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); } if (version != NULL) { - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); } } void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { - sendRoute(build(_msg, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); + _sendRoute(build(_msg, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); } void requestTime(void (* timeCallback)(unsigned long)) { _timeCallback = timeCallback; - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); } // Message delivered through _msg -void processInternalMessages() { +void _processInternalMessages() { bool isMetric; uint8_t type = _msg.type; @@ -250,7 +251,7 @@ void processInternalMessages() { hwWriteConfig(EEPROM_DISTANCE_ADDRESS, 0xFF); // Find parent node transportFindParentNode(); - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } #endif } @@ -266,7 +267,7 @@ uint8_t loadState(uint8_t pos) { void wait(unsigned long ms) { unsigned long enter = hwMillis(); while (hwMillis() - enter < ms) { - process(); + _process(); } } @@ -274,7 +275,8 @@ void sleep(unsigned long ms) { #if defined(MY_OTA_FIRMWARE_FEATURE) if (_fwUpdateOngoing) { // Do not sleep node while fw update is ongoing - process(); + _process(); + return; } else { #endif #if defined(MY_RADIO_FEATURE) @@ -290,7 +292,6 @@ bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { #if defined(MY_OTA_FIRMWARE_FEATURE) if (_fwUpdateOngoing) { // Do not sleep node while fw update is ongoing - process(); return false; } else { #endif @@ -307,7 +308,6 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode #if defined(MY_OTA_FIRMWARE_FEATURE) if (_fwUpdateOngoing) { // Do not sleep node while fw update is ongoing - process(); return -1; } else { #endif diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index ce9ed5d..202019b 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -79,7 +79,7 @@ struct ControllerConfig { * * @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. */ -void dataCallback(void (* msgCallback)(const MyMessage &)=NULL); +void setIncomingCallback(void (* msgCallback)(const MyMessage &)=NULL); /** * Return this nodes id. @@ -175,11 +175,6 @@ void saveState(uint8_t pos, uint8_t value); */ uint8_t loadState(uint8_t pos); -/** -* Returns the last received message -*/ -MyMessage& getLastMessage(void); - /** @@ -224,20 +219,20 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode /****** PRIVATE ********/ -void begin(); +void _begin(); -void process(void); +void _process(void); -void processInternalMessages(); +void _processInternalMessages(); -boolean sendRoute(MyMessage &message); +boolean _sendRoute(MyMessage &message); extern NodeConfig _nc; extern MyMessage _msg; // Buffer for incoming messages. extern MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). extern void (*_msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway. #ifdef MY_DEBUG - extern char convBuf[MAX_PAYLOAD*2+1]; + extern char _convBuf[MAX_PAYLOAD*2+1]; #endif // Inline function and macros diff --git a/libraries/MySensors/core/MySigning.cpp b/libraries/MySensors/core/MySigning.cpp index ad0d78c..e6350c8 100644 --- a/libraries/MySensors/core/MySigning.cpp +++ b/libraries/MySensors/core/MySigning.cpp @@ -23,11 +23,3 @@ uint16_t _doSign[16]; // Bitfield indicating which sensors require signed communication MyMessage _msgSign; // Buffer for message to sign. - -MySigning::MySigning(bool requestSignatures) : _requestSignatures(requestSignatures) { -} - - -bool MySigning::requestSignatures() { - return _requestSignatures; -} diff --git a/libraries/MySensors/core/MySigning.h b/libraries/MySensors/core/MySigning.h index 637b281..2e430c1 100644 --- a/libraries/MySensors/core/MySigning.h +++ b/libraries/MySensors/core/MySigning.h @@ -29,65 +29,57 @@ #include #include "MyMessage.h" +#include "drivers/ATSHA204/ATSHA204.h" +#ifdef MY_SIGNING_NODE_WHITELISTING +typedef struct { + uint8_t nodeId; + uint8_t serial[SHA204_SERIAL_SZ]; +} whitelist_entry_t; +#endif // Macros for manipulating signing requirement table #define DO_SIGN(node) (node == 0 ? (~_doSign[0]&1) : (~_doSign[node>>4]&(node%16))) #define SET_SIGN(node) (node == 0 ? (_doSign[0]&=~1) : (_doSign[node>>4]&=~(node%16))) #define CLEAR_SIGN(node) (node == 0 ? (_doSign[0]|=1) : (_doSign[node>>4]|=(node%16))) +#define NUM_OF(x) (sizeof(x)/sizeof(x[0])) -class MySigning -{ -public: - // MySigning constructor. - // Different parameters would be needed depending on signing backend (e.g. pins connected etc.). - // Keeping these parameters as #define's in MyConfig to streamline the driver interface. - // @param requestSignatures Set this to true if you want destination node to sign all messages sent to this node. Default is not to require signing. - MySigning(bool requestSignatures=false); +// Stores signing identifier and a new nonce in provided message for signing operations. +// All space in message payload buffer is used for signing identifier and nonce. +// Returns false if subsystem is busy processing an ongoing signing operation. +// If successful, this marks the start of a signing operation at the receiving side so +// implementation is expected to do any necessary initializations within this call. +bool signerGetNonce(MyMessage &msg); - // Returns the current requestSignature setting - bool requestSignatures(); +// Check timeout of verification session. +// Nonce will be purged if it takes too long for a signed message to be sent to the receiver. +// This function should be called on regular intervals. +bool signerCheckTimer(void); - // Stores signing identifier and a new nonce in provided message for signing operations. - // All space in message payload buffer is used for signing identifier and nonce. - // Returns false if subsystem is busy processing an ongoing signing operation. - // If successful, this marks the start of a signing operation at the receiving side so - // implementation is expected to do any necessary initializations within this call. - virtual bool getNonce(MyMessage &msg) = 0; +// Get nonce from provided message and store for signing operations. +// Returns false if subsystem is busy processing an ongoing signing operation. +// Returns false if signing identifier found in message is not supported by the used backend. +// If successful, this marks the start of a signing operation at the sending side so +// implementation is expected to do any necessary initializations within this call. +bool signerPutNonce(MyMessage &msg); - // Check timeout of verification session. - // Nonce will be purged if it takes too long for a signed message to be sent to the receiver. - // This function should be called on regular intervals. - virtual bool checkTimer(void) = 0; +// Signs provided message. All remaining space in message payload buffer is used for signing +// identifier and signature. +// Nonce used for signature calculation is the one generated previously using getNonce(). +// Nonce will be cleared when this function is called to prevent re-use of nonce. +// Returns false if subsystem is busy processing an ongoing signing operation. +// Returns false if not two bytes or more of free payload space is left in provided message. +// This ends a signing operation at the sending side so implementation is expected to do any +// deinitializations and enter a power saving state within this call. +bool signerSignMsg(MyMessage &msg); - // Get nonce from provided message and store for signing operations. - // Returns false if subsystem is busy processing an ongoing signing operation. - // Returns false if signing identifier found in message is not supported by the used backend. - // If successful, this marks the start of a signing operation at the sending side so - // implementation is expected to do any necessary initializations within this call. - virtual bool putNonce(MyMessage &msg) = 0; - - // Signs provided message. All remaining space in message payload buffer is used for signing - // identifier and signature. - // Nonce used for signature calculation is the one generated previously using getNonce(). - // Nonce will be cleared when this function is called to prevent re-use of nonce. - // Returns false if subsystem is busy processing an ongoing signing operation. - // Returns false if not two bytes or more of free payload space is left in provided message. - // This ends a signing operation at the sending side so implementation is expected to do any - // deinitializations and enter a power saving state within this call. - virtual bool signMsg(MyMessage &msg) = 0; - - // Verifies signature in provided message. - // Nonce used for verification is the one previously set using putNonce(). - // Nonce will be cleared when this function is called to prevent re-use of nonce. - // Returns false if subsystem is busy processing an ongoing signing operation. - // Returns false if signing identifier found in message is not supported by the used backend. - // This ends a signing operation at the receiving side so implementation is expected to do any - // deinitializations and enter a power saving state within this call. - virtual bool verifyMsg(MyMessage &msg) = 0; - - public: - bool _requestSignatures; -}; +// Verifies signature in provided message. +// Nonce used for verification is the one previously set using putNonce(). +// Nonce will be cleared when this function is called to prevent re-use of nonce. +// Returns false if subsystem is busy processing an ongoing signing operation. +// Returns false if signing identifier found in message is not supported by the used backend. +// This ends a signing operation at the receiving side so implementation is expected to do any +// deinitializations and enter a power saving state within this call. +bool signerVerifyMsg(MyMessage &msg); #endif diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index 06d1b45..4796388 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -34,6 +34,25 @@ // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING +uint8_t atshaPin=MY_ATSHA204_PIN); +ATSHA204Class atsha204; +unsigned long timestamp; +bool verification_ongoing; +uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1]; +uint8_t temp_message[SHA_MSG_SIZE]; +uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; +uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; +void calculateSignature(MyMessage &msg); +uint8_t* sha256(const uint8_t* data, size_t sz); + +#ifdef MY_SIGNING_NODE_WHITELISTING + uint8_t nof_whitelist_entries=0; + const uint8_t whitelist_entry_t* the_whitelist=NULL, + uint8_t whitlist_sz; + const whitelist_entry_t* whitelist; +#endif + + #ifdef DEBUG_SIGNING #define DEBUG_SIGNING_PRINTLN(args) Serial.println(args) #else @@ -60,14 +79,14 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, MySigningAtsha204::MySigningAtsha204(bool requestSignatures, -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, #endif uint8_t atshaPin) : MySigning(requestSignatures), atsha204(atshaPin), -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING whitelist(the_whitelist), whitlist_sz(nof_whitelist_entries), #endif @@ -142,7 +161,7 @@ bool MySigningAtsha204::signMsg(MyMessage &msg) { mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated calculateSignature(msg); -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING // Salt the signature with the senders nodeId and the unique serial of the ATSHA device memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed current_nonce[32] = msg.sender; @@ -180,7 +199,7 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("SIM:"), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); // SIM = Signature in message calculateSignature(msg); // Get signature of message -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING // Look up the senders nodeId in our whitelist and salt the signature with that data for (int j=0; j < whitlist_sz; j++) { if (whitelist[j].nodeId == msg.sender) { @@ -200,7 +219,7 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { // Compare the caluclated signature with the provided signature if (memcmp(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { DEBUG_SIGNING_PRINTBUF(F("SNOK:"), &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); // SNOK = Signature bad -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING DEBUG_SIGNING_PRINTLN(F("W?")); // W? = Is the sender whitelisted? #endif return false; diff --git a/libraries/MySensors/core/MySigningAtsha204.h b/libraries/MySensors/core/MySigningAtsha204.h index 1242db7..fe353f7 100644 --- a/libraries/MySensors/core/MySigningAtsha204.h +++ b/libraries/MySensors/core/MySigningAtsha204.h @@ -33,7 +33,7 @@ #include "drivers/ATSHA204/ATSHA204.h" #include -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING typedef struct { uint8_t nodeId; uint8_t serial[SHA204_SERIAL_SZ]; @@ -47,29 +47,13 @@ class MySigningAtsha204 : public MySigning { public: MySigningAtsha204(bool requestSignatures=true, -#ifdef MY_SECURE_NODE_WHITELISTING - uint8_t nof_whitelist_entries=0, const whitelist_entry_t* the_whitelist=NULL, -#endif - uint8_t atshaPin=MY_ATSHA204_PIN); + bool getNonce(MyMessage &msg); bool checkTimer(void); bool putNonce(MyMessage &msg); bool signMsg(MyMessage &msg); bool verifyMsg(MyMessage &msg); private: - ATSHA204Class atsha204; - unsigned long timestamp; - bool verification_ongoing; - uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1]; - uint8_t temp_message[SHA_MSG_SIZE]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - void calculateSignature(MyMessage &msg); - uint8_t* sha256(const uint8_t* data, size_t sz); -#ifdef MY_SECURE_NODE_WHITELISTING - uint8_t whitlist_sz; - const whitelist_entry_t* whitelist; -#endif }; #endif diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/libraries/MySensors/core/MySigningAtsha204Soft.cpp index fc52085..d5e8b09 100644 --- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp +++ b/libraries/MySensors/core/MySigningAtsha204Soft.cpp @@ -35,6 +35,20 @@ #define SIGNING_IDENTIFIER (1) + +Sha256Class _signing_sha256; +unsigned long _signing_timestamp; +bool _signing_verification_ongoing = false; +uint8_t _signing_current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; +uint8_t _signing_temp_message[32]; +static uint8_t _signing_hmac_key[32] = { MY_SIGNING_SOFT_HMAC_KEY }; +uint8_t _signing_hmac[32]; + +#ifdef MY_SIGNING_NODE_WHITELISTING + const uint8_t _signing_node_serial_info[SHA204_SERIAL_SZ] = {MY_SIGNING_SOFT_SERIAL}; + const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; +#endif + // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING @@ -63,81 +77,60 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif -// Initialize hmacKey from MyConfig.h (codebender didn't like static initialization in constructor) -uint8_t MySigningAtsha204Soft::hmacKey[32] = { MY_HMAC_KEY }; -MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures, -#ifdef MY_SECURE_NODE_WHITELISTING - uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, - const uint8_t* the_serial, -#endif - uint8_t randomseedPin) - : - MySigning(requestSignatures), -#ifdef MY_SECURE_NODE_WHITELISTING - whitlist_sz(nof_whitelist_entries), - whitelist(the_whitelist), - node_serial_info(the_serial), -#endif - Sha256(), - verification_ongoing(false), - rndPin(randomseedPin) -{ -} - -bool MySigningAtsha204Soft::getNonce(MyMessage &msg) { +bool signerGetNonce(MyMessage &msg) { // Set randomseed - randomSeed(analogRead(rndPin)); + randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce - Sha256.init(); + _signing_sha256.init(); for (int i = 0; i < 32; i++) { - Sha256.write(random(255)); + _signing_sha256.write(random(255)); } - memcpy(current_nonce, Sha256.result(), MAX_PAYLOAD); + memcpy(_signing_current_nonce, _signing_sha256.result(), MAX_PAYLOAD); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA - memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); + memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); // Replace the first byte in the nonce with our signing identifier - current_nonce[0] = SIGNING_IDENTIFIER; + _signing_current_nonce[0] = SIGNING_IDENTIFIER; // Transfer the first part of the nonce to the message - msg.set(current_nonce, MAX_PAYLOAD); - verification_ongoing = true; - timestamp = millis(); // Set timestamp to determine when to purge nonce + msg.set(_signing_current_nonce, MAX_PAYLOAD); + _signing_verification_ongoing = true; + _signing_timestamp = millis(); // Set timestamp to determine when to purge nonce // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; + if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) _signing_timestamp = 0; return true; } -bool MySigningAtsha204Soft::checkTimer() { - if (verification_ongoing) { - if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { +bool signerCheckTimer() { + if (_signing_verification_ongoing) { + if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_SIGNING_PRINTLN(F("VT")); // VT = Verification timeout // Purge nonce - memset(current_nonce, 0xAA, 32); - verification_ongoing = false; + memset(_signing_current_nonce, 0xAA, 32); + _signing_verification_ongoing = false; return false; } } return true; } -bool MySigningAtsha204Soft::putNonce(MyMessage &msg) { +bool signerPutNonce(MyMessage &msg) { if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier return false; } - memcpy(current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); + memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); return true; } -bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { +bool signerSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit @@ -146,38 +139,38 @@ bool MySigningAtsha204Soft::signMsg(MyMessage &msg) { // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated - calculateSignature(msg); + signerCalculateSignature(msg); -#ifdef MY_SECURE_NODE_WHITELISTING +#ifdef MY_SIGNING_NODE_WHITELISTING // Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided - Sha256.init(); - for (int i=0; i<32; i++) Sha256.write(hmac[i]); - Sha256.write(msg.sender); - for (int i=0; i -#ifdef MY_SECURE_NODE_WHITELISTING -typedef struct { - uint8_t nodeId; - uint8_t serial[SHA204_SERIAL_SZ]; -} whitelist_entry_t; -#endif + // This implementation is the pure software variant of the ATSHA204. // It is designed to work fully compliant with nodes using ATSHA204 in the network // and therefore uses the same signing identifier as ATSHA204. -// Because it is completly software based, the quality of the generated random numbers +// Because it is completely software based, the quality of the generated random numbers // is weaker though. Random numbers are generated using the Arduino library and seed // is sampled from an analog pin. This pin should unconnected in the hardware. -// The pin is selected using MY_RANDOMSEED_PIN in MyConfig.h. -class MySigningAtsha204Soft : public MySigning -{ -public: - MySigningAtsha204Soft(bool requestSignatures=true, -#ifdef MY_SECURE_NODE_WHITELISTING - uint8_t nof_whitelist_entries=0, const whitelist_entry_t* the_whitelist=NULL, - const uint8_t* the_serial=NULL, //SHA204_SERIAL_SZ sized buffer expected if provided -#endif - uint8_t randomseedPin=MY_RANDOMSEED_PIN); - bool getNonce(MyMessage &msg); - bool checkTimer(void); - bool putNonce(MyMessage &msg); - bool signMsg(MyMessage &msg); - bool verifyMsg(MyMessage &msg); -private: - Sha256Class Sha256; - unsigned long timestamp; - bool verification_ongoing; - uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH]; - uint8_t temp_message[32]; - static uint8_t hmacKey[32]; - uint8_t rndPin; - uint8_t hmac[32]; - void calculateSignature(MyMessage &msg); -#ifdef MY_SECURE_NODE_WHITELISTING - uint8_t whitlist_sz; - const whitelist_entry_t* whitelist; - const uint8_t* node_serial_info; -#endif -}; +// The pin is selected using MY_SIGNING_SOFT_RANDOMSEED_PIN in MyConfig.h. + +void signerCalculateSignature(MyMessage &msg); + #endif diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp index 309bc4d..626e9e8 100644 --- a/libraries/MySensors/core/MyTransport.cpp +++ b/libraries/MySensors/core/MyTransport.cpp @@ -23,6 +23,9 @@ bool _autoFindParent; uint8_t _failedTransmissions; +#ifdef MY_SIGNING_FEATURE + bool _signingNonceStatus; +#endif #ifdef MY_OTA_FIRMWARE_FEATURE NodeFirmwareConfig _fc; @@ -60,14 +63,14 @@ inline void transportProcess() { firmwareRequest->type = _fc.type; firmwareRequest->version = _fc.version; firmwareRequest->block = (_fwBlock - 1); - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false)); } #endif return; } #ifdef MY_SIGNING_FEATURE - (void)signer.checkTimer(); // Manage signing timeout + (void)signerCheckTimer(); // Manage signing timeout #endif uint8_t len = transportReceive((uint8_t *)&_msg); @@ -77,29 +80,31 @@ inline void transportProcess() { #ifdef MY_SIGNING_FEATURE // Before processing message, reject unsigned messages if signing is required and check signature (if it is signed and addressed to us) // Note that we do not care at all about any signature found if we do not require signing, nor do we care about ACKs (they are never signed) - if (signer.requestSignatures() && _msg.destination == _nc.nodeId && mGetLength(_msg) && !mGetAck(_msg) && - (mGetCommand(_msg) != C_INTERNAL || - (_msg.type != I_GET_NONCE_RESPONSE && _msg.type != I_GET_NONCE && _msg.type != I_REQUEST_SIGNING && - _msg.type != I_ID_REQUEST && _msg.type != I_ID_RESPONSE && - _msg.type != I_FIND_PARENT && _msg.type != I_FIND_PARENT_RESPONSE))) { - if (!mGetSigned(_msg)) { - // Got unsigned message that should have been signed - debug(PSTR("no sign\n")); - ledBlinkErr(1); - return; + #ifdef MY_SIGNING_REQUEST_SIGNATURES + if (_msg.destination == _nc.nodeId && mGetLength(_msg) && !mGetAck(_msg) && + (mGetCommand(_msg) != C_INTERNAL || + (_msg.type != I_GET_NONCE_RESPONSE && _msg.type != I_GET_NONCE && _msg.type != I_REQUEST_SIGNING && + _msg.type != I_ID_REQUEST && _msg.type != I_ID_RESPONSE && + _msg.type != I_FIND_PARENT && _msg.type != I_FIND_PARENT_RESPONSE))) { + if (!mGetSigned(_msg)) { + // Got unsigned message that should have been signed + debug(PSTR("no sign\n")); + ledBlinkErr(1); + return; + } + else if (!signerVerifyMsg(_msg)) { + debug(PSTR("verify fail\n")); + ledBlinkErr(1); + return; // This signed message has been tampered with! + } } - else if (!signer.verifyMsg(_msg)) { - debug(PSTR("verify fail\n")); - ledBlinkErr(1); - return; // This signed message has been tampered with! - } - } + #endif #endif // Add string termination, good if we later would want to print it. _msg.data[mGetLength(_msg)] = '\0'; debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - _msg.sender, _msg.last, _msg.destination, _msg.sensor, mGetCommand(_msg), _msg.type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(convBuf)); + _msg.sender, _msg.last, _msg.destination, _msg.sensor, mGetCommand(_msg), _msg.type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); mSetSigned(_msg,0); // Clear the sign-flag now as verification (and debug printing) is completed if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) { @@ -132,7 +137,7 @@ inline void transportProcess() { mSetAck(_msgTmp,true); _msgTmp.sender = _nc.nodeId; _msgTmp.destination = _msg.sender; - sendRoute(_msgTmp); + _sendRoute(_msgTmp); } if (command == C_INTERNAL) { @@ -158,10 +163,10 @@ inline void transportProcess() { return; #ifdef MY_SIGNING_FEATURE } else if (type == I_GET_NONCE) { - if (signer.getNonce(_msg)) { - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); + if (signerGetNonce(_msg)) { + _sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_GET_NONCE_RESPONSE, false)); } - return false; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this + return; // Nonce exchange is an internal MySensor protocol message, no need to inform caller about this } else if (type == I_REQUEST_SIGNING) { if (_msg.getBool()) { // We received an indicator that the sender require us to sign all messages we send to it @@ -176,14 +181,22 @@ inline void transportProcess() { // Inform sender about our preference if we are a gateway, but only require signing if the sender required signing // We do not currently want a gateway to require signing from all nodes in a network just because it wants one node // to sign it's messages - if (MY_GATEWAY_FEATURE) { - if (signer.requestSignatures() && DO_SIGN(_msg.sender)) - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); - else - sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); - } + #if defined (MY_GATEWAY_FEATURE) + #ifdef MY_SIGNING_REQUEST_SIGNATURES + if (DO_SIGN(_msg.sender)) + _sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); + else + _sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + #else + _sendRoute(build(_msg, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + #endif + #endif return; // Signing request is an internal MySensor protocol message, no need to inform caller about this } else if (type == I_GET_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + if (signerPutNonce(_msg) && signerSignMsg(_msgSign)) { + _signingNonceStatus = SIGN_OK; + } return; // Just pass along nonce silently (no need to call callback for these) #endif } else if (sender == GATEWAY_ADDRESS) { @@ -199,7 +212,7 @@ inline void transportProcess() { hwWriteConfig(EEPROM_NODE_ID_ADDRESS, _nc.nodeId); debug(PSTR("id=%d\n"), _nc.nodeId); } else { - processInternalMessages(); + _processInternalMessages(); } return; } @@ -292,7 +305,7 @@ inline void transportProcess() { } } else if (to == _nc.nodeId) { // We should try to relay this message to another node - sendRoute(_msg); + _sendRoute(_msg); } } #endif @@ -327,7 +340,7 @@ boolean transportSendWrite(uint8_t to, MyMessage &message) { debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); + mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(_convBuf)); return ok; } @@ -356,103 +369,101 @@ boolean transportSendRoute(MyMessage &message) { mSetVersion(message, PROTOCOL_VERSION); #ifdef MY_SIGNING_FEATURE - // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message - if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && mGetLength(message) && - (mGetCommand(message) != C_INTERNAL || - (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && - message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && - message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { - bool signOk = false; - // Send nonce-request - if (!sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { - debug(PSTR("nonce tr err\n")); - return false; - } - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust process() takes care of them - unsigned long enter = hwMillis(); - _msgSign = message; // Copy the message to sign since message buffer might be touched in process() - while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS) { - if (process()) { - if (mGetCommand(getLastMessage()) == C_INTERNAL && getLastMessage().type == I_GET_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - if (signer.putNonce(getLastMessage()) && signer.signMsg(_msgSign)) { - message = _msgSign; // Write the signed message back - signOk = true; - } - break; - } + // If destination is known to require signed messages and we are the sender, sign this message unless it is an ACK or a handshake message + if (DO_SIGN(message.destination) && message.sender == _nc.nodeId && !mGetAck(message) && mGetLength(message) && + (mGetCommand(message) != C_INTERNAL || + (message.type != I_GET_NONCE && message.type != I_GET_NONCE_RESPONSE && message.type != I_REQUEST_SIGNING && + message.type != I_ID_REQUEST && message.type != I_ID_RESPONSE && + message.type != I_FIND_PARENT && message.type != I_FIND_PARENT_RESPONSE))) { + bool signing = SIGN_WAITING_FOR_NONCE; + // Send nonce-request + if (!_sendRoute(build(_msgTmp, _nc.nodeId, message.destination, message.sensor, C_INTERNAL, I_GET_NONCE, false).set(""))) { + debug(PSTR("nonce tr err\n")); + return false; } + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust process() takes care of them + unsigned long enter = hwMillis(); + _msgSign = message; // Copy the message to sign since message buffer might be touched in process() + + while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { + _process(); + } + if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { + debug(PSTR("nonce tmo\n")); + ledBlinkErr(1); + return false; + } + if (_signingNonceStatus == SIGN_OK) { + message = _msgSign; // Write the signed message back + } else { + debug(PSTR("sign fail\n")); + ledBlinkErr(1); + return false; + } + // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, + // or signature will become invalid and the message rejected by the receiver + } else { + mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned } - if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { - debug(PSTR("nonce tmo\n")); - ledBlinkErr(1); - return false; - } - if (!signOk) { - debug(PSTR("sign fail\n")); - ledBlinkErr(1); - return false; - } - // After this point, only the 'last' member of the message structure is allowed to be altered if the message has been signed, - // or signature will become invalid and the message rejected by the receiver - } else { - mSetSigned(message, 0); // Message is not supposed to be signed, make sure it is marked unsigned - } #endif - if (dest == GATEWAY_ADDRESS || !MY_IS_REPEATER) { - // Store this address in routing table (if repeater) - #if defined (MY_IS_REPEATER) - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - #endif - // If destination is the gateway or if we aren't a repeater, let - // our parent take care of the message + + #if !defined(MY_REPEATER_FEATURE) + // None repeating node... We can only send to our parent ok = transportSendWrite(_nc.parentNodeId, message); - } else { - // Relay the message - uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); - if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { - // This message should be forwarded to a child node. If we send message - // to this nodes pipe then all children will receive it because the are - // all listening to this nodes pipe. - // - // +----B - // -A - // +----C------D - // - // We're node C, Message comes from A and has destination D - // - // Message destination is not gateway and is in routing table for this node. - // Send it downstream - return transportSendWrite(route, message); - } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { - // Node has not yet received any id. We need to send it - // by doing a broadcast sending, - return transportSendWrite(BROADCAST_ADDRESS, message); - } else if (MY_IS_GATEWAY) { - // Destination isn't in our routing table and isn't a broadcast address - // Nothing to do here - return false; - } else { - // A message comes from a child node and we have no - // route for it. - // - // +----B - // -A - // +----C------D <-- Message comes from D - // - // We're node C - // - // Message should be passed to node A (this nodes relay) - - // This message should be routed back towards sensor net gateway - ok = transportSendWrite(_nc.parentNodeId, message); - // Add this child to our "routing table" if it not already exist + #else + if (dest == GATEWAY_ADDRESS) { + // Store this address in routing table (if repeater) hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - } + // If destination is the gateway or if we aren't a repeater, let + // our parent take care of the message + ok = transportSendWrite(_nc.parentNodeId, message); + } else { + // Relay the message + uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); + if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { + // This message should be forwarded to a child node. If we send message + // to this nodes pipe then all children will receive it because the are + // all listening to this nodes pipe. + // + // +----B + // -A + // +----C------D + // + // We're node C, Message comes from A and has destination D + // + // Message destination is not gateway and is in routing table for this node. + // Send it downstream + return transportSendWrite(route, message); + } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { + // Node has not yet received any id. We need to send it + // by doing a broadcast sending, + return transportSendWrite(BROADCAST_ADDRESS, message); + } + #if defined (MY_GATEWAY_FEATURE) + // Destination isn't in our routing table and isn't a broadcast address + // Nothing to do here + return false; + # else + // A message comes from a child node and we have no + // route for it. + // + // +----B + // -A + // +----C------D <-- Message comes from D + // + // We're node C + // + // Message should be passed to node A (this nodes relay) + // This message should be routed back towards sensor net gateway + ok = transportSendWrite(_nc.parentNodeId, message); + // Add this child to our "routing table" if it not already exist + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); + #endif + } + #endif if (!ok) { // Failure when sending to parent node. The parent node might be down and we // need to find another route to gateway. @@ -484,12 +495,13 @@ void transportSetupNode() { if (_nc.nodeId != AUTO) { #ifdef MY_SIGNING_FEATURE // Notify gateway (and possibly controller) about the signing preferences of this node - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(signer.requestSignatures())); - - // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages - if (signer.requestSignatures()) { + #if defined(MY_SIGNING_REQUEST_SIGNATURES) + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(true)); + // If we do require signing, wait for the gateway to tell us how it prefer us to transmit our messages wait(2000); - } + #else + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REQUEST_SIGNING, false).set(false)); + #endif #endif // Send presentation for this radio node @@ -501,7 +513,7 @@ void transportSetupNode() { // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration // which is picked up in process() - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); // Wait configuration reply. wait(2000); @@ -516,7 +528,7 @@ void transportSetupNode() { // add bootloader information reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; _fwUpdateOngoing = false; - sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); #endif } #endif diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index f72ea8f..827430b 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -41,6 +41,9 @@ // Search for a new parent node after this many transmission failures #define SEARCH_FAILURES 5 +// Status when waiting for signing nonce in process +enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; + // FW config structure, stored in eeprom typedef struct { diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index d07b2a7..d48131c 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -29,7 +29,9 @@ //#define MY_DEBUG -#define MY_RADIO_NRF24 // MY_RADIO_RFM69 +// Enable and select radio type +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 //#define MY_SOFTSPI //#define MY_OTA_FIRMWARE_FEATURE diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index cb69354..76a80ea 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -25,79 +25,62 @@ * Example sketch showing how to securely control locks. * This example will remember lock state even after power failure. */ + +// Enable and select radio type +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 +// Select soft/hardware signing method +#define MY_SIGNING_SOFT // Software signing enabled +//#define MY_SIGNING_ATSHA204 // Hardware signing using ATSHA204A + +// Enable node whitelisting +#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} +// Enable this if you want destination node to sign all messages sent to this node. Default is not to require signing. +#define MY_SIGNING_REQUEST_SIGNATURES + + +// SETTINGS FOR MY_SIGNING_SOFT +// Set the soft_serial value to an arbitrary value for proper security (9 bytes) +#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 +// Key to use for HMAC calculation in soft signing (32 bytes) +#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 + +// SETTINGS FOR MY_SIGNING_ATSHA204 +#define MY_SIGNING_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached -#define USE_SOFTWARE_ATSHA // Disable to use ATSHA204A circuit -#include -#include #include -#include -#ifdef USE_SOFTWARE_ATSHA -#include -#else -#include -#endif + #define LOCK_1 3 // Arduino Digital I/O pin number for first lock (second on pin+1 etc) #define NOF_LOCKS 1 // Total number of attached locks #define LOCK_LOCK 1 // GPIO value to write to lock attached lock #define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock -MyTransportNRF24 radio; // NRFRF24L01 radio driver -MyHwATMega328 hw; // Select AtMega328 hardware profile -#ifdef MY_SIGNING_FEATURE -#ifdef MY_SECURE_NODE_WHITELISTING -#ifdef USE_SOFTWARE_ATSHA -// Change the soft_serial value to an arbitrary value for proper security -uint8_t soft_serial[SHA204_SERIAL_SZ] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}; -#endif -// We only use one whitelist entry (the gateway) -whitelist_entry_t node_whitelist[] = { - { .nodeId = GATEWAY_ADDRESS, - .serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01} } -}; -#ifdef USE_SOFTWARE_ATSHA -MySigningAtsha204Soft signer(true, 1, node_whitelist, soft_serial); // Message signing driver -#else -MySigningAtsha204 signer(true, 1, node_whitelist); -#endif -#else -#ifdef USE_SOFTWARE_ATSHA -MySigningAtsha204Soft signer; -#else -MySigningAtsha204 signer; -#endif -#endif -MySensor gw(radio, hw, signer); -#else -// WARNING! SecureActuator cannot possibly be secure without signing enabled -MySensor gw(radio, hw); -#endif void setup() { // Initialize library and add callback for incoming messages (signing is required) - gw.begin(incomingMessage, AUTO); + setIncomingCallback(incomingMessage); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Secure Lock", "1.0"); + sendSketchInfo("Secure Lock", "1.0"); // Fetch lock status for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) { // Register all locks to gw (they will be created as child devices) - gw.present(lock, S_LOCK, "SecureActuator", false); + present(lock, S_LOCK, "SecureActuator", false); // Then set lock pins in output mode pinMode(pin, OUTPUT); // Set lock to last known state (using eeprom storage) - digitalWrite(pin, gw.loadState(lock)?LOCK_LOCK:LOCK_UNLOCK); + digitalWrite(pin, loadState(lock)?LOCK_LOCK:LOCK_UNLOCK); } } - void loop() { - // Alway process incoming messages whenever possible - gw.process(); } void incomingMessage(const MyMessage &message) { @@ -106,7 +89,7 @@ void incomingMessage(const MyMessage &message) { // Change relay state digitalWrite(message.sensor-1+LOCK_1, message.getBool()?LOCK_LOCK:LOCK_UNLOCK); // Store state in eeprom - gw.saveState(message.sensor, message.getBool()); + saveState(message.sensor, message.getBool()); // Write some debug info Serial.print("Incoming change for lock:"); Serial.print(message.sensor); From 6cf6255e5041f91eff2dfef1c054dffba183c606 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 17 Sep 2015 07:24:12 +0200 Subject: [PATCH 259/660] Fix: ATSHA204, serial gw, ethernet warnings --- libraries/MySensors/MySensor.h | 26 ++- .../MySensors/core/MyGatewayTransport.cpp | 2 +- .../core/MyGatewayTransportEthernet.h | 2 +- .../MySensors/core/MyGatewayTransportSerial.h | 2 +- ...colDefault.cpp => MyProtocolMySensors.cpp} | 2 +- ...rotocolDefault.h => MyProtocolMySensors.h} | 0 libraries/MySensors/core/MySensorCore.cpp | 31 ++-- libraries/MySensors/core/MySensorCore.h | 2 + .../MySensors/core/MySigningAtsha204.cpp | 171 ++++++++---------- libraries/MySensors/core/MySigningAtsha204.h | 21 +-- libraries/MySensors/core/MySigningNone.cpp | 13 +- libraries/MySensors/core/MySigningNone.h | 10 - libraries/MySensors/core/MyTransport.cpp | 2 +- libraries/MySensors/core/MyTransport.h | 1 - libraries/MySensors/core/MyTransportRFM69.h | 1 - libraries/MySensors/core/Version.h | 2 +- .../AVR/Ethernet_UIP/src/UIPClient.cpp | 8 +- .../drivers/AVR/Ethernet_UIP/src/UIPClient.h | 6 +- .../AVR/Ethernet_UIP/src/UIPEthernet.h | 1 + .../drivers/AVR/Ethernet_UIP/src/UIPServer.h | 4 +- .../AVR/Ethernet_UIP/src/utility/uip.c | 1 + .../AVR/Ethernet_UIP/src/utility/uip_arp.c | 1 + libraries/MySensors/drivers/RFM69/RFM69.cpp | 2 +- .../AirQualitySensor/AirQualitySensor.ino | 20 +- .../EthernetGateway/EthernetGateway.ino | 15 +- .../examples/RelayActuator/RelayActuator.ino | 39 ++-- .../SecureActuator/SecureActuator.ino | 10 +- .../examples/SerialGateway/SerialGateway.ino | 65 +++---- 28 files changed, 206 insertions(+), 254 deletions(-) rename libraries/MySensors/core/{MyProtocolDefault.cpp => MyProtocolMySensors.cpp} (98%) rename libraries/MySensors/core/{MyProtocolDefault.h => MyProtocolMySensors.h} (100%) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 151ab7e..b4ef368 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -19,15 +19,14 @@ #ifndef MySensor_h #define MySensor_h -#define VALUE_TO_STRING(x) #x -#define VALUE(x) VALUE_TO_STRING(x) -#define VAR_NAME_VALUE(var) #var "=" VALUE(var) -// #pragma message(VAR_NAME_VALUE(MY_GATEWAY_FEATURE)) +/* { dg-warning "import is a deprecated GCC extension" "deprecated" {target *-*-* } 0 } */ + + #include "MyConfig.h" #include "core/MySensorCore.h" -#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(ARDUINO_ARCH_ESP8266) #define MY_GATEWAY_FEATURE #define MY_NODE_TYPE "gateway" #elif defined(MY_REPEATER_FEATURE) @@ -41,6 +40,8 @@ #if defined(ARDUINO_ARCH_ESP8266) #include "drivers/ESP8266/SPI/SPI.cpp" #include "core/MyHwESP8266.cpp" + // For ESP8266, we always enable gateway feature + #define MY_GATEWAY_ESP8266 #elif defined(ARDUINO_ARCH_AVR) #include "drivers/AVR/SPI/SPI.cpp" #include "core/MyHwATMega328.cpp" @@ -84,9 +85,14 @@ // GATEWAY - COMMON FUNCTIONS #include "core/MyGatewayTransport.cpp" + // We currently only support one protocol, enable it. + #if !defined(MY_GATEWAY_PROTOCOL_DEFAULT) + #define MY_GATEWAY_PROTOCOL_DEFAULT + #endif + // GATEWAY - PROTOCOL #if defined(MY_GATEWAY_PROTOCOL_DEFAULT) - #include "core/MyProtocolDefault.cpp" + #include "core/MyProtocolMySensors.cpp" #else #error No gateway protocol specified! #endif @@ -102,8 +108,10 @@ #if !defined(MY_PORT) #error You must define MY_PORT (cotroller or gatway port to open) #endif + #if defined(MY_GATEWAY_ESP8266) + // GATEWAY - ESP8266 - #if defined(MY_GATEWAY_W5100) + #elif defined(MY_GATEWAY_W5100) // GATEWAY - W5100 #include "drivers/AVR/Ethernet_W5100/utility/socket.cpp" #include "drivers/AVR/Ethernet_W5100/utility/w5100.cpp" @@ -192,7 +200,9 @@ #undef MY_INCLUSION_BUTTON_FEATURE #endif - +#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RADIO_FEATURE) + #error No radio or gateway feature activated. This means nowhere to send messages! Pretty pointless. +#endif #include "core/MyMessage.cpp" diff --git a/libraries/MySensors/core/MyGatewayTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.cpp index 0072946..d0615cc 100644 --- a/libraries/MySensors/core/MyGatewayTransport.cpp +++ b/libraries/MySensors/core/MyGatewayTransport.cpp @@ -43,7 +43,7 @@ inline void gatewayTransportProcess() { inclusionModeSet(atoi(_msg.data) == 1); #endif } else { - processInternalMessages(); + _processInternalMessages(); } } else { // Call incoming message callback if available diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.h b/libraries/MySensors/core/MyGatewayTransportEthernet.h index c7cd7f9..c949d81 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernet.h +++ b/libraries/MySensors/core/MyGatewayTransportEthernet.h @@ -23,7 +23,7 @@ #include "MyConfig.h" #include "MyMessage.h" #include "MyProtocol.h" -#include "MyProtocolDefault.h" +#include "MyProtocolMySensors.h" #include "MyGatewayTransport.h" diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.h b/libraries/MySensors/core/MyGatewayTransportSerial.h index 7dabf02..8b81905 100644 --- a/libraries/MySensors/core/MyGatewayTransportSerial.h +++ b/libraries/MySensors/core/MyGatewayTransportSerial.h @@ -23,7 +23,7 @@ #include "MyMessage.h" #include "MyGatewayTransport.h" #include "MyProtocol.h" -#include "MyProtocolDefault.h" +#include "MyProtocolMySensors.h" #define MAX_RECEIVE_LENGTH 100 // Maximum message length for messages coming from controller diff --git a/libraries/MySensors/core/MyProtocolDefault.cpp b/libraries/MySensors/core/MyProtocolMySensors.cpp similarity index 98% rename from libraries/MySensors/core/MyProtocolDefault.cpp rename to libraries/MySensors/core/MyProtocolMySensors.cpp index d4a54c1..2fa527a 100644 --- a/libraries/MySensors/core/MyProtocolDefault.cpp +++ b/libraries/MySensors/core/MyProtocolMySensors.cpp @@ -18,7 +18,7 @@ */ #include "MyProtocol.h" -#include "MyProtocolDefault.h" +#include "MyProtocolMySensors.h" #include "MyTransport.h" char _fmtBuffer[MAX_FORMAT_BUFFER_LENGTH]; diff --git a/libraries/MySensors/core/MyProtocolDefault.h b/libraries/MySensors/core/MyProtocolMySensors.h similarity index 100% rename from libraries/MySensors/core/MyProtocolDefault.h rename to libraries/MySensors/core/MyProtocolMySensors.h diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index e05db79..3452c66 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -54,21 +54,32 @@ void _process() { #endif } - +#if defined(MY_RADIO_FEATURE) static inline bool isValidParent( const uint8_t parent ) { return parent != AUTO; } - +#endif void setIncomingCallback(void (*msgCallback)(const MyMessage &)) { _msgCallback = msgCallback; } void _begin() { - #if defined(MY_DISABLED_SERIAL) + #if !defined(MY_DISABLED_SERIAL) hwInit(); #endif + #if defined(MY_RADIO_FEATURE) + _failedTransmissions = 0; + + // Setup radio + if (!transportInit()) { + debug(PSTR("radio init fail\n")); + while(1); // Nothing more we can do + } + #endif + + #if defined(MY_GATEWAY_FEATURE) #if defined(MY_INCLUSION_BUTTON_FEATURE) inclusionInit(); @@ -83,15 +94,6 @@ void _begin() { gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); #endif - #if defined(MY_RADIO_FEATURE) - _failedTransmissions = 0; - - // Setup radio - if (!transportInit()) { - debug(PSTR("radio init fail\n")); - while(1); // Nothing more we can do - } - #endif #if defined(MY_SIGNING_FEATURE) // Read out the signing requirements from EEPROM @@ -114,7 +116,7 @@ void _begin() { _nc.parentNodeId = GATEWAY_ADDRESS; _nc.distance = 0; _nc.nodeId = GATEWAY_ADDRESS; - #else + #elif defined(MY_RADIO_FEATURE) // Read settings from eeprom hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // Read latest received controller configuration from EEPROM @@ -151,6 +153,7 @@ void _begin() { #if defined(MY_RADIO_FEATURE) transportSetupNode(); #endif + debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), MY_NODE_TYPE, _nc.nodeId, _nc.parentNodeId, _nc.distance); } @@ -176,7 +179,7 @@ boolean _sendRoute(MyMessage &message) { } #endif #if defined(MY_RADIO_FEATURE) - transportSendRoute(message); + return transportSendRoute(message); #else return false; #endif diff --git a/libraries/MySensors/core/MySensorCore.h b/libraries/MySensors/core/MySensorCore.h index 202019b..e2665e3 100644 --- a/libraries/MySensors/core/MySensorCore.h +++ b/libraries/MySensors/core/MySensorCore.h @@ -60,6 +60,8 @@ // This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). #define GATEWAY_ADDRESS ((uint8_t)0) +// Node child is always created/presented when a node is started +#define NODE_SENSOR_ID 0xFF struct NodeConfig diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/libraries/MySensors/core/MySigningAtsha204.cpp index 4796388..ae32dc2 100644 --- a/libraries/MySensors/core/MySigningAtsha204.cpp +++ b/libraries/MySensors/core/MySigningAtsha204.cpp @@ -34,25 +34,20 @@ // Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected) //#define DEBUG_SIGNING -uint8_t atshaPin=MY_ATSHA204_PIN); -ATSHA204Class atsha204; -unsigned long timestamp; -bool verification_ongoing; -uint8_t current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1]; -uint8_t temp_message[SHA_MSG_SIZE]; -uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; -uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; -void calculateSignature(MyMessage &msg); -uint8_t* sha256(const uint8_t* data, size_t sz); +ATSHA204Class atsha204(MY_SIGNING_ATSHA204_PIN); +unsigned long _signing_timestamp; +bool _signing_verification_ongoing = false; +uint8_t _signing_current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1]; +uint8_t _signing_temp_message[SHA_MSG_SIZE]; +uint8_t _singning_rx_buffer[SHA204_RSP_SIZE_MAX]; +uint8_t _singning_tx_buffer[SHA204_CMD_SIZE_MAX]; #ifdef MY_SIGNING_NODE_WHITELISTING - uint8_t nof_whitelist_entries=0; - const uint8_t whitelist_entry_t* the_whitelist=NULL, - uint8_t whitlist_sz; - const whitelist_entry_t* whitelist; + const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif + #ifdef DEBUG_SIGNING #define DEBUG_SIGNING_PRINTLN(args) Serial.println(args) #else @@ -78,79 +73,63 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #endif -MySigningAtsha204::MySigningAtsha204(bool requestSignatures, -#ifdef MY_SIGNING_NODE_WHITELISTING - uint8_t nof_whitelist_entries, const whitelist_entry_t* the_whitelist, -#endif - uint8_t atshaPin) - : - MySigning(requestSignatures), - atsha204(atshaPin), -#ifdef MY_SIGNING_NODE_WHITELISTING - whitelist(the_whitelist), - whitlist_sz(nof_whitelist_entries), -#endif - verification_ongoing(false) -{ -} - -bool MySigningAtsha204::getNonce(MyMessage &msg) { +bool signerGetNonce(MyMessage &msg) { // Generate random number for use as nonce // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce for (int i = 0; i < 32; i++) { if (atsha204.sha204m_execute(SHA204_RANDOM, RANDOM_NO_SEED_UPDATE, 0, 0, NULL, - RANDOM_COUNT, tx_buffer, RANDOM_RSP_SIZE, rx_buffer) != SHA204_SUCCESS) { + RANDOM_COUNT, _singning_tx_buffer, RANDOM_RSP_SIZE, _singning_rx_buffer) != SHA204_SUCCESS) { DEBUG_SIGNING_PRINTLN(F("FTGN")); // FTGN = Failed to generate nonce return false; } - current_nonce[i] = rx_buffer[SHA204_BUFFER_POS_DATA]; + _signing_current_nonce[i] = _singning_rx_buffer[SHA204_BUFFER_POS_DATA]; } - memcpy(current_nonce, sha256(current_nonce, 32), MAX_PAYLOAD); + memcpy(_signing_current_nonce, signerSha256(_signing_current_nonce, 32), MAX_PAYLOAD); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA - memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); + memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); // Replace the first byte in the nonce with our signing identifier - current_nonce[0] = SIGNING_IDENTIFIER; + _signing_current_nonce[0] = SIGNING_IDENTIFIER; // Transfer the first part of the nonce to the message - msg.set(current_nonce, MAX_PAYLOAD); - verification_ongoing = true; - timestamp = millis(); // Set timestamp to determine when to purge nonce + msg.set(_signing_current_nonce, MAX_PAYLOAD); + _signing_verification_ongoing = true; + _signing_timestamp = millis(); // Set timestamp to determine when to purge nonce // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) timestamp = 0; + if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) _signing_timestamp = 0; return true; } -bool MySigningAtsha204::checkTimer() { - if (verification_ongoing) { - if (millis() < timestamp || millis() > timestamp + MY_VERIFICATION_TIMEOUT_MS) { +bool signerCheckTimer() { + if (_signing_verification_ongoing) { + if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_SIGNING_PRINTLN(F("VT")); // VT = Verification timeout // Purge nonce - memset(current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); - verification_ongoing = false; + memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); + _signing_verification_ongoing = false; return false; } } return true; } -bool MySigningAtsha204::putNonce(MyMessage &msg) { +bool signerPutNonce(MyMessage &msg) { if (((uint8_t*)msg.getCustom())[0] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier return false; } - memcpy(current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); + memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA - memset(¤t_nonce[MAX_PAYLOAD], 0xAA, sizeof(current_nonce)-MAX_PAYLOAD); + memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); return true; } -bool MySigningAtsha204::signMsg(MyMessage &msg) { +bool signerSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit @@ -159,37 +138,37 @@ bool MySigningAtsha204::signMsg(MyMessage &msg) { // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated - calculateSignature(msg); + signerCalculateSignature(msg); #ifdef MY_SIGNING_NODE_WHITELISTING // Salt the signature with the senders nodeId and the unique serial of the ATSHA device - memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed - current_nonce[32] = msg.sender; - atsha204.getSerialNumber(¤t_nonce[33]); - (void)sha256(current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + memcpy(_signing_current_nonce, &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + _signing_current_nonce[32] = msg.sender; + atsha204.getSerialNumber(&_signing_current_nonce[33]); + (void)signerSha256(_signing_current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place DEBUG_SIGNING_PRINTLN(F("SWS")); // SWS = Signature whitelist salted #endif // Overwrite the first byte in the signature with the signing identifier - rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; + _singning_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; // Transfer as much signature data as the remaining space in the message permits - memcpy(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); + memcpy(&msg.data[mGetLength(msg)], &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); return true; } -bool MySigningAtsha204::verifyMsg(MyMessage &msg) { - if (!verification_ongoing) { +bool signerVerifyMsg(MyMessage &msg) { + if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTLN(F("NAVS")); // NAVS = No active verification session return false; } else { // Make sure we have not expired - if (!checkTimer()) { + if (!signerCheckTimer()) { return false; } - verification_ongoing = false; + _signing_verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTLN(F("ISI")); // ISI = Incorrect signing identifier @@ -197,28 +176,28 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { } DEBUG_SIGNING_PRINTBUF(F("SIM:"), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); // SIM = Signature in message - calculateSignature(msg); // Get signature of message + signerCalculateSignature(msg); // Get signature of message #ifdef MY_SIGNING_NODE_WHITELISTING // Look up the senders nodeId in our whitelist and salt the signature with that data - for (int j=0; j < whitlist_sz; j++) { - if (whitelist[j].nodeId == msg.sender) { + for (int j=0; j < NUM_OF(_signing_whitelist); j++) { + if (_signing_whitelist[j].nodeId == msg.sender) { DEBUG_SIGNING_PRINTLN(F("SIW")); // SIW = Sender found in whitelist - memcpy(current_nonce, &rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed - current_nonce[32] = msg.sender; - memcpy(¤t_nonce[33], whitelist[j].serial, SHA204_SERIAL_SZ); - (void)sha256(current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + memcpy(_signing_current_nonce, &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + _signing_current_nonce[32] = msg.sender; + memcpy(&_signing_current_nonce[33], _signing_whitelist[j].serial, SHA204_SERIAL_SZ); + (void)signerSha256(_signing_current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place break; } } #endif // Overwrite the first byte in the signature with the signing identifier - rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; + _singning_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; // Compare the caluclated signature with the provided signature - if (memcmp(&msg.data[mGetLength(msg)], &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { - DEBUG_SIGNING_PRINTBUF(F("SNOK:"), &rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); // SNOK = Signature bad + if (memcmp(&msg.data[mGetLength(msg)], &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { + DEBUG_SIGNING_PRINTBUF(F("SNOK:"), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); // SNOK = Signature bad #ifdef MY_SIGNING_NODE_WHITELISTING DEBUG_SIGNING_PRINTLN(F("W?")); // W? = Is the sender whitelisted? #endif @@ -230,60 +209,60 @@ bool MySigningAtsha204::verifyMsg(MyMessage &msg) { } } -// Helper to calculate signature of msg (returned in rx_buffer[SHA204_BUFFER_POS_DATA]) -void MySigningAtsha204::calculateSignature(MyMessage &msg) { - memset(temp_message, 0, 32); - memcpy(temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); +// Helper to calculate signature of msg (returned in _singning_rx_buffer[SHA204_BUFFER_POS_DATA]) +void signerCalculateSignature(MyMessage &msg) { + memset(_signing_temp_message, 0, 32); + memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // Program the data to sign into the ATSHA204 DEBUG_SIGNING_PRINTBUF(F("MSG:"), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // MSG = Message to sign - DEBUG_SIGNING_PRINTBUF(F("CNC:"), current_nonce, 32); // CNC = Current nonce - (void)atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, temp_message, - WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); + DEBUG_SIGNING_PRINTBUF(F("CNC:"), _signing_current_nonce, 32); // CNC = Current nonce + (void)atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, _signing_temp_message, + WRITE_COUNT_LONG, _singning_tx_buffer, WRITE_RSP_SIZE, _singning_rx_buffer); // Program the nonce to use for the signature (has to be done just before GENDIG due to chip limitations) - (void)atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, current_nonce, - NONCE_COUNT_LONG, tx_buffer, NONCE_RSP_SIZE_SHORT, rx_buffer); + (void)atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, _signing_current_nonce, + NONCE_COUNT_LONG, _singning_tx_buffer, NONCE_RSP_SIZE_SHORT, _singning_rx_buffer); // Purge nonce when used - memset(current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); + memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); // Generate digest of data and nonce (void)atsha204.sha204m_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL, - GENDIG_COUNT_DATA, tx_buffer, GENDIG_RSP_SIZE, rx_buffer); + GENDIG_COUNT_DATA, _singning_tx_buffer, GENDIG_RSP_SIZE, _singning_rx_buffer); // Calculate HMAC of message+nonce digest and secret key (void)atsha204.sha204m_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, - HMAC_COUNT, tx_buffer, HMAC_RSP_SIZE, rx_buffer); + HMAC_COUNT, _singning_tx_buffer, HMAC_RSP_SIZE, _singning_rx_buffer); // Put device back to sleep atsha204.sha204c_sleep(); - DEBUG_SIGNING_PRINTBUF(F("HMAC:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); + DEBUG_SIGNING_PRINTBUF(F("HMAC:"), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); } // Helper to calculate a generic SHA256 digest of provided buffer (only supports one block) -// The pointer to the hash is returned, but the hash is also stored in rx_buffer[SHA204_BUFFER_POS_DATA]) -uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) { +// The pointer to the hash is returned, but the hash is also stored in _singning_rx_buffer[SHA204_BUFFER_POS_DATA]) +uint8_t* signerSha256(const uint8_t* data, size_t sz) { // Initiate SHA256 calculator (void)atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, - SHA_COUNT_SHORT, tx_buffer, SHA_RSP_SIZE_SHORT, rx_buffer); + SHA_COUNT_SHORT, _singning_tx_buffer, SHA_RSP_SIZE_SHORT, _singning_rx_buffer); // Calculate a hash - memset(temp_message, 0x00, SHA_MSG_SIZE); - memcpy(temp_message, data, sz); - temp_message[sz] = 0x80; + memset(_signing_temp_message, 0x00, SHA_MSG_SIZE); + memcpy(_signing_temp_message, data, sz); + _signing_temp_message[sz] = 0x80; // Write length data to the last bytes - temp_message[SHA_MSG_SIZE-2] = (sz >> 5); - temp_message[SHA_MSG_SIZE-1] = (sz << 3); - DEBUG_SIGNING_PRINTBUF(F("DTH:"), temp_message, SHA_MSG_SIZE); // DTH = Data to hash - (void)atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, temp_message, - SHA_COUNT_LONG, tx_buffer, SHA_RSP_SIZE_LONG, rx_buffer); + _signing_temp_message[SHA_MSG_SIZE-2] = (sz >> 5); + _signing_temp_message[SHA_MSG_SIZE-1] = (sz << 3); + DEBUG_SIGNING_PRINTBUF(F("DTH:"), _signing_temp_message, SHA_MSG_SIZE); // DTH = Data to hash + (void)atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, _signing_temp_message, + SHA_COUNT_LONG, _singning_tx_buffer, SHA_RSP_SIZE_LONG, _singning_rx_buffer); // Put device back to sleep atsha204.sha204c_sleep(); - DEBUG_SIGNING_PRINTBUF(F("SHA:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32); - return &rx_buffer[SHA204_BUFFER_POS_DATA]; + DEBUG_SIGNING_PRINTBUF(F("SHA:"), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); + return &_singning_rx_buffer[SHA204_BUFFER_POS_DATA]; } #endif // #if defined(ARDUINO_ARCH_AVR) diff --git a/libraries/MySensors/core/MySigningAtsha204.h b/libraries/MySensors/core/MySigningAtsha204.h index fe353f7..da9bee3 100644 --- a/libraries/MySensors/core/MySigningAtsha204.h +++ b/libraries/MySensors/core/MySigningAtsha204.h @@ -33,27 +33,14 @@ #include "drivers/ATSHA204/ATSHA204.h" #include -#ifdef MY_SIGNING_NODE_WHITELISTING -typedef struct { - uint8_t nodeId; - uint8_t serial[SHA204_SERIAL_SZ]; -} whitelist_entry_t; -#endif + // The ATSHA204 is capable of generating proper random numbers for nonce // and can calculate HMAC-SHA256 signatures. This is enterprise- // level of security and ought to implement the signing needs for anybody. -class MySigningAtsha204 : public MySigning -{ -public: - MySigningAtsha204(bool requestSignatures=true, - bool getNonce(MyMessage &msg); - bool checkTimer(void); - bool putNonce(MyMessage &msg); - bool signMsg(MyMessage &msg); - bool verifyMsg(MyMessage &msg); -private: -}; +void signerCalculateSignature(MyMessage &msg); +uint8_t* signerSha256(const uint8_t* data, size_t sz); + #endif diff --git a/libraries/MySensors/core/MySigningNone.cpp b/libraries/MySensors/core/MySigningNone.cpp index d9aa5ab..7edbad6 100644 --- a/libraries/MySensors/core/MySigningNone.cpp +++ b/libraries/MySensors/core/MySigningNone.cpp @@ -59,24 +59,21 @@ static void DEBUG_NONE_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, ui #define DEBUG_NONE_PRINTBUF(str, buf, sz) #endif -MySigningNone::MySigningNone() : MySigning() { -} - -bool MySigningNone::getNonce(MyMessage &msg) { +bool signerGetNonce(MyMessage &msg) { (void)msg; return true; } -bool MySigningNone::checkTimer() { +bool signerCheckTimer() { return true; } -bool MySigningNone::putNonce(MyMessage &msg) { +bool signerPutNonce(MyMessage &msg) { (void)msg; return true; } -bool MySigningNone::signMsg(MyMessage &msg) { +bool signerSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTLN(F("MTOL")); // Message too large for signature to fit @@ -87,7 +84,7 @@ bool MySigningNone::signMsg(MyMessage &msg) { return true; } -bool MySigningNone::verifyMsg(MyMessage &msg) { +bool signerVerifyMsg(MyMessage &msg) { if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) return false; else diff --git a/libraries/MySensors/core/MySigningNone.h b/libraries/MySensors/core/MySigningNone.h index 4b27103..4f7a32f 100644 --- a/libraries/MySensors/core/MySigningNone.h +++ b/libraries/MySensors/core/MySigningNone.h @@ -37,15 +37,5 @@ // It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in // the network (as seen by this node) and it does verify proper execution order on the API. // The "none" driver rejects all other back-ends. -class MySigningNone : public MySigning -{ -public: - MySigningNone(); - bool getNonce(MyMessage &msg); - bool checkTimer(void); - bool putNonce(MyMessage &msg); - bool signMsg(MyMessage &msg); - bool verifyMsg(MyMessage &msg); -}; #endif diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp index 626e9e8..8e21b94 100644 --- a/libraries/MySensors/core/MyTransport.cpp +++ b/libraries/MySensors/core/MyTransport.cpp @@ -300,7 +300,7 @@ inline void transportProcess() { // Wait a random delay of 0-2 seconds to minimize collision // between ping ack messages from other relaying nodes wait(hwMillis() & 0x3ff); - sendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + transportSendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); } } } else if (to == _nc.nodeId) { diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index 827430b..c9b540d 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -77,7 +77,6 @@ typedef struct { #define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. -#define NODE_SENSOR_ID 0xFF // Node child id is always created for when a node #define BROADCAST_ADDRESS ((uint8_t)0xFF) diff --git a/libraries/MySensors/core/MyTransportRFM69.h b/libraries/MySensors/core/MyTransportRFM69.h index ec3227d..967a7b3 100644 --- a/libraries/MySensors/core/MyTransportRFM69.h +++ b/libraries/MySensors/core/MyTransportRFM69.h @@ -24,7 +24,6 @@ #include "MyTransport.h" #include #include "drivers/RFM69/RFM69.h" -#include "drivers/SPI/SPI.h" #endif diff --git a/libraries/MySensors/core/Version.h b/libraries/MySensors/core/Version.h index c782265..5f64530 100644 --- a/libraries/MySensors/core/Version.h +++ b/libraries/MySensors/core/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define LIBRARY_VERSION "1.5" +#define LIBRARY_VERSION "1.6" #endif diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp index d199cfe..b832d0a 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.cpp @@ -19,10 +19,10 @@ extern "C" { -#import "utility/uip-conf.h" -#import "utility/uip.h" -#import "utility/uip_arp.h" -#import "string.h" +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "string.h" } #include "UIPEthernet.h" #include "UIPClient.h" diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h index 6c0c006..40838bb 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPClient.h @@ -22,11 +22,11 @@ #include "ethernet_comp.h" #include "Print.h" -#import "Client.h" -#import "utility/mempool.h" +#include "Client.h" +#include "utility/mempool.h" extern "C" { - #import "utility/uip.h" + #include "utility/uip.h" } #define UIP_SOCKET_DATALEN UIP_TCP_MSS diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h index c68d578..dd3f412 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPEthernet.h @@ -58,6 +58,7 @@ extern "C" uip_ethaddr.addr[4] = eaddr[4];\ uip_ethaddr.addr[5] = eaddr[5];} while(0) +#undef BUF #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) class UIPEthernetClass diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h index 0cc0619..eea81d2 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/UIPServer.h @@ -20,8 +20,8 @@ #define UIPSERVER_H #include "ethernet_comp.h" -#import "Server.h" -#import "UIPClient.h" +#include "Server.h" +#include "UIPClient.h" class UIPServer : public Server { diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.c index 8421bda..c8ea98d 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.c +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip.c @@ -223,6 +223,7 @@ static u16_t tmp16; /* Macros. */ +#undef BUF #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) #define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) #define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) diff --git a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c index 44ca7c4..f220ff5 100644 --- a/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c +++ b/libraries/MySensors/drivers/AVR/Ethernet_UIP/src/utility/uip_arp.c @@ -113,6 +113,7 @@ static u8_t i, c; static u8_t arptime; static u8_t tmpage; +#undef BUF #define BUF ((struct arp_hdr *)&uip_buf[0]) #define IPBUF ((struct ethip_hdr *)&uip_buf[0]) /*-----------------------------------------------------------------------------------*/ diff --git a/libraries/MySensors/drivers/RFM69/RFM69.cpp b/libraries/MySensors/drivers/RFM69/RFM69.cpp index f7e63e7..8d154f0 100644 --- a/libraries/MySensors/drivers/RFM69/RFM69.cpp +++ b/libraries/MySensors/drivers/RFM69/RFM69.cpp @@ -31,7 +31,7 @@ // ********************************************************************************** #include "RFM69.h" #include "RFM69registers.h" -#include "drivers/SPI/SPI.h" +#include "drivers/AVR/SPI/SPI.h" volatile byte RFM69::DATA[RF69_MAX_DATA_LEN]; volatile byte RFM69::_mode; // current transceiver state diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino index c956655..310295c 100644 --- a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino +++ b/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino @@ -34,9 +34,14 @@ * */ -#include +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + #include -#include #define CHILD_ID_MQ 0 /************************Hardware Related Macros************************************/ @@ -76,19 +81,16 @@ float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) -MySensor gw; MyMessage msg(CHILD_ID_MQ, V_LEVEL); void setup() { - gw.begin(); - // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Air Quality Sensor", "1.0"); + sendSketchInfo("Air Quality Sensor", "1.0"); // Register all sensors to gateway (they will be created as child devices) - gw.present(CHILD_ID_MQ, S_AIR_QUALITY); + present(CHILD_ID_MQ, S_AIR_QUALITY); Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air //when you perform the calibration @@ -113,11 +115,11 @@ void loop() Serial.print("\n"); if (valMQ != lastMQ) { - gw.send(msg.set((int)ceil(valMQ))); + send(msg.set((int)ceil(valMQ))); lastMQ = ceil(valMQ); } - gw.sleep(SLEEP_TIME); //sleep for: sleepTime + sleep(SLEEP_TIME); //sleep for: sleepTime } /****************** MQResistanceCalculation **************************************** diff --git a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino index f8e3992..9fd07aa 100644 --- a/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino +++ b/libraries/MySensors/examples/EthernetGateway/EthernetGateway.ino @@ -56,19 +56,16 @@ * */ -// Enable debug prints to console +// Enable debug prints to serial monitor #define MY_DEBUG -// This node has a NR24L01+ radio attached -#define MY_RADIO_NRF24 +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 - -// Enable gateway type +// Enable gateway transportation type #define MY_GATEWAY_W5100 -//#define MY_GATEWAY_W5100 - -// Set default gateway protocol (http://www.mysensors.org/download/serial_api_15) -#define MY_GATEWAY_PROTOCOL_DEFAULT +//#define MY_GATEWAY_ENC28J60 // Enable Soft SPI for radio (note different radio wiring required) // Useful for W5100 which sometimes have hard time co-operate with radio on the same spi bus. diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index db05836..c652166 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -27,51 +27,46 @@ * http://www.mysensors.org/build/relay */ -#include -#include -#include -#include +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + +// Enable repeater functionality for this node +#define MY_REPEATER_FEATURE + #include -#include #define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc) #define NUMBER_OF_RELAYS 1 // Total number of attached relays #define RELAY_ON 1 // GPIO value to write to turn on attached relay #define RELAY_OFF 0 // GPIO value to write to turn off attached relay -// NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRFM69 radio; -// Message signing driver (none default) -//MySigningNone signer; -// Select AtMega328 hardware profile -MyHwATMega328 hw; -// Construct MySensors library -MySensor gw(radio, hw); - void setup() { // Initialize library and add callback for incoming messages - gw.begin(incomingMessage, AUTO, true); + setIncomingCallback(incomingMessage); + // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Relay", "1.0"); + sendSketchInfo("Relay", "1.0"); // Fetch relay status for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) { // Register all sensors to gw (they will be created as child devices) - gw.present(sensor, S_LIGHT); + present(sensor, S_LIGHT); // Then set relay pins in output mode pinMode(pin, OUTPUT); // Set relay to last known state (using eeprom storage) - digitalWrite(pin, gw.loadState(sensor)?RELAY_ON:RELAY_OFF); + digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF); } } void loop() { - // Alway process incoming messages whenever possible - gw.process(); + } void incomingMessage(const MyMessage &message) { @@ -80,7 +75,7 @@ void incomingMessage(const MyMessage &message) { // Change relay state digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF); // Store state in eeprom - gw.saveState(message.sensor, message.getBool()); + saveState(message.sensor, message.getBool()); // Write some debug info Serial.print("Incoming change for sensor:"); Serial.print(message.sensor); diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino index 76a80ea..589c0bc 100644 --- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino +++ b/libraries/MySensors/examples/SecureActuator/SecureActuator.ino @@ -26,7 +26,10 @@ * This example will remember lock state even after power failure. */ -// Enable and select radio type +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 @@ -35,9 +38,9 @@ //#define MY_SIGNING_ATSHA204 // Hardware signing using ATSHA204A // Enable node whitelisting -#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} +//#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} // Enable this if you want destination node to sign all messages sent to this node. Default is not to require signing. -#define MY_SIGNING_REQUEST_SIGNATURES +//#define MY_SIGNING_REQUEST_SIGNATURES // SETTINGS FOR MY_SIGNING_SOFT @@ -51,7 +54,6 @@ // SETTINGS FOR MY_SIGNING_ATSHA204 #define MY_SIGNING_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached - #include diff --git a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino index 0566f3c..6e94b95 100644 --- a/libraries/MySensors/examples/SerialGateway/SerialGateway.ino +++ b/libraries/MySensors/examples/SerialGateway/SerialGateway.ino @@ -1,4 +1,4 @@ -/** + /** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -36,57 +36,44 @@ * */ -#include -#include -#include -#include -#include -#include +// Enable debug prints to serial monitor +#define MY_DEBUG -#include -#include -#include -#include +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 -#define INCLUSION_MODE_TIME 60 // Number of seconds inclusion mode is enabled -#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button -#define RADIO_ERROR_LED_PIN 4 // Error led pin -#define RADIO_RX_LED_PIN 6 // Receive led pin -#define RADIO_TX_LED_PIN 5 // the PCB, on board LED +// Enable serial gateway +#define MY_GATEWAY_SERIAL -// NRFRF24L01 radio driver (set low transmit power by default) -MyTransportNRF24 transport(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW); -//MyTransportRFM69 transport; +// Flash leds on rx/tx/err +#define MY_LEDS_BLINKING_FEATURE +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 -// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -//MySigningNone signer; -//MySigningAtsha204Soft signer; -//MySigningAtsha204 signer; +// Enable inclusion mode +#define MY_INCLUSION_MODE_FEATURE +// Enable Inclusion mode button on gateway +#define MY_INCLUSION_BUTTON_FEATURE +// Set inclusion mode duration (in seconds) +#define MY_INCLUSION_MODE_DURATION 60 +// Digital pin used for inclusion mode button +#define MY_INCLUSION_MODE_BUTTON_PIN 3 -// Hardware profile -MyHwATMega328 hw; +#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin +#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin +#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED -// Controller Transport profile -MyProtocolDefault protocol; -MyGatewayTransportSerial ctrlTransport(protocol); - -// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h) -// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h -#ifdef MY_LEDS_BLINKING_FEATURE -MyGateway gw(ctrlTransport, transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); -#else -MyGateway gw(ctrlTransport, transport, hw /*, signer*/); -#endif +#include void setup() { - gw.begin(NULL); - + // Nothing to do here } void loop() { - gw.process(); + // Nothing to do here } From 5c39f022c0db5e0280be1c1412f51be7d435cd60 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 17 Sep 2015 22:04:38 +0200 Subject: [PATCH 260/660] Add: NRF24L01 AES Encryption Thanks @fleinze. Source: https://github.com/fleinze/MySensors/tree/Encryption/libraries/MySensors --- libraries/MySensors/MyConfig.h | 10 + libraries/MySensors/MySensor.h | 3 + libraries/MySensors/core/MyTransportNRF24.cpp | 29 +- libraries/MySensors/core/MyTransportNRF24.h | 3 + libraries/MySensors/drivers/AES/AES.cpp | 598 ++ libraries/MySensors/drivers/AES/AES.h | 415 ++ libraries/MySensors/drivers/AES/AES_config.h | 44 + libraries/MySensors/drivers/AES/Doxyfile | 2372 ++++++++ libraries/MySensors/drivers/AES/Makefile | 62 + libraries/MySensors/drivers/AES/README.MD | 91 + .../drivers/AES/examples/aes/aes.pde | 63 + .../AES/examples/test_vectors/RESOURCES | 16 + .../examples/test_vectors/known_answers.txt | 5321 +++++++++++++++++ .../examples/test_vectors/test_vectors.pde | 191 + .../drivers/AES/examples_Rpi/Makefile | 39 + .../drivers/AES/examples_Rpi/RESOURCES | 16 + .../drivers/AES/examples_Rpi/aes.cpp | 47 + .../AES/examples_Rpi/known_answers.txt | 5321 +++++++++++++++++ .../drivers/AES/examples_Rpi/test_vectors.cpp | 183 + libraries/MySensors/drivers/AES/keywords.txt | 7 + libraries/MySensors/drivers/AES/printf.h | 59 + .../EthernetGateway/EthernetGateway.ino | 6 +- 22 files changed, 14893 insertions(+), 3 deletions(-) create mode 100644 libraries/MySensors/drivers/AES/AES.cpp create mode 100644 libraries/MySensors/drivers/AES/AES.h create mode 100644 libraries/MySensors/drivers/AES/AES_config.h create mode 100644 libraries/MySensors/drivers/AES/Doxyfile create mode 100644 libraries/MySensors/drivers/AES/Makefile create mode 100644 libraries/MySensors/drivers/AES/README.MD create mode 100644 libraries/MySensors/drivers/AES/examples/aes/aes.pde create mode 100644 libraries/MySensors/drivers/AES/examples/test_vectors/RESOURCES create mode 100644 libraries/MySensors/drivers/AES/examples/test_vectors/known_answers.txt create mode 100644 libraries/MySensors/drivers/AES/examples/test_vectors/test_vectors.pde create mode 100644 libraries/MySensors/drivers/AES/examples_Rpi/Makefile create mode 100644 libraries/MySensors/drivers/AES/examples_Rpi/RESOURCES create mode 100644 libraries/MySensors/drivers/AES/examples_Rpi/aes.cpp create mode 100644 libraries/MySensors/drivers/AES/examples_Rpi/known_answers.txt create mode 100644 libraries/MySensors/drivers/AES/examples_Rpi/test_vectors.cpp create mode 100644 libraries/MySensors/drivers/AES/keywords.txt create mode 100644 libraries/MySensors/drivers/AES/printf.h diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index f765a38..ff46d42 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -193,6 +193,16 @@ /********************************** * NRF24L01 Driver Defaults ***********************************/ + +// Enables RF24 encryption (all nodes and gateway must have this enabled) +//#define MY_RF24_ENABLE_ENCRYPTION + +// Default encrytion key. Override in sketch if needed. +#ifndef MY_RF24_CE_PIN +#define MY_RF24_ENCRYPTKEY 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16 +#endif + +// Default pin settings. Override in sketch if needed. #ifndef MY_RF24_CE_PIN #define MY_RF24_CE_PIN 9 #endif diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index b4ef368..4ba828d 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -179,6 +179,9 @@ #error Only one radio driver can be activated #endif #if defined(MY_RADIO_NRF24) + #if defined(MY_RF24_ENABLE_ENCRYPTION) + #include "drivers/AES/AES.cpp" + #endif #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" #elif defined(MY_RADIO_RFM69) diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index 91e9fc2..ab44888 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -22,6 +22,11 @@ RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN); uint8_t _address; uint8_t _paLevel; +#if defined(MY_RF24_ENABLE_ENCRYPTION) + AES _aes; + uint8_t _dataenc[32] = {0}; + uint8_t _psk[] = { MY_RF24_ENCRYPTKEY }; +#endif bool transportInit() { // Start up the radio library @@ -42,6 +47,12 @@ bool transportInit() { // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) _rf24.openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); + + + #if defined(MY_RF24_ENABLE_ENCRYPTION) + _aes.set_key(_psk, 16); //set up AES-key + #endif + return true; } @@ -57,11 +68,23 @@ uint8_t transportGetAddress() { } bool transportSend(uint8_t to, const void* data, uint8_t len) { + #if defined(MY_RF24_ENABLE_ENCRYPTION) + memcpy(_dataenc,data,len); // copy input data because it is read-only + + _aes.set_IV(0);//not sure if necessary + len = len > 16 ? 32 : 16; + _aes.cbc_encrypt(_dataenc, _dataenc, len/16); //encrypt + #endif + // Make sure radio has powered up _rf24.powerUp(); _rf24.stopListening(); _rf24.openWritingPipe(TO_ADDR(to)); - bool ok = _rf24.write(data, len, to == BROADCAST_ADDRESS); + #if defined(MY_RF24_ENABLE_ENCRYPTION) + bool ok = _rf24.write(_dataenc, len, to == BROADCAST_ADDRESS); + #else + bool ok = _rf24.write(data, len, to == BROADCAST_ADDRESS); + #endif _rf24.startListening(); return ok; } @@ -80,6 +103,10 @@ bool transportAvailable(uint8_t *to) { uint8_t transportReceive(void* data) { uint8_t len = _rf24.getDynamicPayloadSize(); _rf24.read(data, len); + #if defined(MY_RF24_ENABLE_ENCRYPTION) + _aes.set_IV(0);//not sure if necessary + _aes.cbc_decrypt((byte*)(data), (byte*)(data), len>16?2:1); // decrypt + #endif return len; } diff --git a/libraries/MySensors/core/MyTransportNRF24.h b/libraries/MySensors/core/MyTransportNRF24.h index 3f895c5..a852848 100644 --- a/libraries/MySensors/core/MyTransportNRF24.h +++ b/libraries/MySensors/core/MyTransportNRF24.h @@ -25,6 +25,9 @@ #include #include "drivers/RF24/RF24.h" #include "drivers/RF24/RF24_config.h" +#if defined(MY_RF24_ENABLE_ENCRYPTION) +#include "drivers/AES/AES.h" +#endif #define TO_ADDR(x) (MY_RF24_BASE_RADIO_ID + x) diff --git a/libraries/MySensors/drivers/AES/AES.cpp b/libraries/MySensors/drivers/AES/AES.cpp new file mode 100644 index 0000000..cd5d306 --- /dev/null +++ b/libraries/MySensors/drivers/AES/AES.cpp @@ -0,0 +1,598 @@ +#include "AES.h" + +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state (there are options to use 32-bit types if available). + + The combination of mix columns and byte substitution used here is based on + that developed by Karl Malbrain. His contribution is acknowledged. + */ + +/* This version derived by Mark Tillotson 2012-01-23, tidied up, slimmed down + and tailored to 8-bit microcontroller abilities and Arduino datatypes. + + The s-box and inverse s-box were retained as tables (0.5kB PROGMEM) but all + the other transformations are coded to save table space. Many efficiency + improvments to the routines mix_sub_columns() and inv_mix_sub_columns() + (mainly common sub-expression elimination). + + Only the routines with precalculated subkey schedule are retained (together + with set_key() - this does however mean each AES object takes 240 bytes of + RAM, alas) + + The CBC routines side-effect the iv argument (so that successive calls work + together correctly). + + All the encryption and decryption routines work with plain == cipher for + in-place encryption, note. + +*/ + + +/* functions for finite field multiplication in the AES Galois field */ + +/* code was modified by george spanos + * 16/12/14 + */ + +// GF(2^8) stuff + +#define WPOLY 0x011B +#define DPOLY 0x008D + +const static byte s_fwd [0x100] PROGMEM = +{ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +} ; + +const static byte s_inv [0x100] PROGMEM = +{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +} ; + +// times 2 in the GF(2^8) +#define f2(x) ((x) & 0x80 ? (x << 1) ^ WPOLY : x << 1) +#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) + +static byte s_box (byte x) +{ + // return fwd_affine (pgm_read_byte (&inv [x])) ; + return pgm_read_byte (& s_fwd [x]) ; +} + +// Inverse Sbox +static byte is_box (byte x) +{ + // return pgm_read_byte (&inv [inv_affine (x)]) ; + return pgm_read_byte (& s_inv [x]) ; +} + + +static void xor_block (byte * d, byte * s) +{ + for (byte i = 0 ; i < N_BLOCK ; i += 4) + { + *d++ ^= *s++ ; // some unrolling + *d++ ^= *s++ ; + *d++ ^= *s++ ; + *d++ ^= *s++ ; + } +} + +static void copy_and_key (byte * d, byte * s, byte * k) +{ + for (byte i = 0 ; i < N_BLOCK ; i += 4) + { + *d++ = *s++ ^ *k++ ; // some unrolling + *d++ = *s++ ^ *k++ ; + *d++ = *s++ ^ *k++ ; + *d++ = *s++ ^ *k++ ; + } +} + +// #define add_round_key(d, k) xor_block (d, k) + +/* SUB ROW PHASE */ + +static void shift_sub_rows (byte st [N_BLOCK]) +{ + st [0] = s_box (st [0]) ; st [4] = s_box (st [4]) ; + st [8] = s_box (st [8]) ; st [12] = s_box (st [12]) ; + + byte tt = st [1] ; + st [1] = s_box (st [5]) ; st [5] = s_box (st [9]) ; + st [9] = s_box (st [13]) ; st [13] = s_box (tt) ; + + tt = st[2] ; st [2] = s_box (st [10]) ; st [10] = s_box (tt) ; + tt = st[6] ; st [6] = s_box (st [14]) ; st [14] = s_box (tt) ; + + tt = st[15] ; + st [15] = s_box (st [11]) ; st [11] = s_box (st [7]) ; + st [7] = s_box (st [3]) ; st [3] = s_box (tt) ; +} + +static void inv_shift_sub_rows (byte st[N_BLOCK]) +{ + st [0] = is_box (st[0]) ; st [4] = is_box (st [4]); + st [8] = is_box (st[8]) ; st [12] = is_box (st [12]); + + byte tt = st[13] ; + st [13] = is_box (st [9]) ; st [9] = is_box (st [5]) ; + st [5] = is_box (st [1]) ; st [1] = is_box (tt) ; + + tt = st [2] ; st [2] = is_box (st [10]) ; st [10] = is_box (tt) ; + tt = st [6] ; st [6] = is_box (st [14]) ; st [14] = is_box (tt) ; + + tt = st [3] ; + st [3] = is_box (st [7]) ; st [7] = is_box (st [11]) ; + st [11] = is_box (st [15]) ; st [15] = is_box (tt) ; +} + +/* SUB COLUMNS PHASE */ + +static void mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) +{ + byte j = 5 ; + byte k = 10 ; + byte l = 15 ; + for (byte i = 0 ; i < N_BLOCK ; i += N_COL) + { + byte a = st [i] ; + byte b = st [j] ; j = (j+N_COL) & 15 ; + byte c = st [k] ; k = (k+N_COL) & 15 ; + byte d = st [l] ; l = (l+N_COL) & 15 ; + byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ; + byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; + dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ; + dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ; + dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ; + dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ; + } +} + +static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) +{ + for (byte i = 0 ; i < N_BLOCK ; i += N_COL) + { + byte a1 = st [i] ; + byte b1 = st [i+1] ; + byte c1 = st [i+2] ; + byte d1 = st [i+3] ; + byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; + byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ; + byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ; + byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ; + byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ; + + dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ; + dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ; + dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ; + dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ; + } +} + +/******************************************************************************/ + +AES::AES(){ + byte ar_iv[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; + memcpy(iv,ar_iv,8); + memcpy(iv+8,ar_iv,8); + arr_pad[0] = 0x01; + arr_pad[1] = 0x02; + arr_pad[2] = 0x03; + arr_pad[3] = 0x04; + arr_pad[4] = 0x05; + arr_pad[5] = 0x06; + arr_pad[6] = 0x07; + arr_pad[7] = 0x08; + arr_pad[8] = 0x09; + arr_pad[9] = 0x0a; + arr_pad[10] = 0x0b; + arr_pad[11] = 0x0c; + arr_pad[12] = 0x0d; + arr_pad[13] = 0x0e; + arr_pad[14] = 0x0f; +} + +/******************************************************************************/ + +byte AES::set_key (byte key [], int keylen) +{ + byte hi ; + switch (keylen) + { + case 16: + case 128: + keylen = 16; // 10 rounds + round = 10 ; + break; + case 24: + case 192: + keylen = 24; // 12 rounds + round = 12 ; + break; + case 32: + case 256: + keylen = 32; // 14 rounds + round = 14 ; + break; + default: + round = 0; + return AES_FAILURE; + } + hi = (round + 1) << 4 ; + copy_n_bytes (key_sched, key, keylen) ; + byte t[4] ; + byte next = keylen ; + for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) + { + for (byte i = 0 ; i < N_COL ; i++) + t[i] = key_sched [cc-4+i] ; + if (cc == next) + { + next += keylen ; + byte ttt = t[0] ; + t[0] = s_box (t[1]) ^ rc ; + t[1] = s_box (t[2]) ; + t[2] = s_box (t[3]) ; + t[3] = s_box (ttt) ; + rc = f2 (rc) ; + } + else if (keylen == 32 && (cc & 31) == 16) + { + for (byte i = 0 ; i < 4 ; i++) + t[i] = s_box (t[i]) ; + } + byte tt = cc - keylen ; + for (byte i = 0 ; i < N_COL ; i++) + key_sched [cc + i] = key_sched [tt + i] ^ t[i] ; + } + return AES_SUCCESS ; +} + +/******************************************************************************/ + +void AES::clean () +{ + for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) + key_sched [i] = 0 ; + round = 0 ; +} + +/******************************************************************************/ + +void AES::copy_n_bytes (byte * d, byte * s, byte nn) +{ + while (nn >= 4) + { + *d++ = *s++ ; // some unrolling + *d++ = *s++ ; + *d++ = *s++ ; + *d++ = *s++ ; + nn -= 4 ; + } + while (nn--) + *d++ = *s++ ; +} + +/******************************************************************************/ + +byte AES::encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) +{ + if (round) + { + byte s1 [N_BLOCK], r ; + copy_and_key (s1, plain, (byte*) (key_sched)) ; + + for (r = 1 ; r < round ; r++) + { + byte s2 [N_BLOCK] ; + mix_sub_columns (s2, s1) ; + copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ; + } + shift_sub_rows (s1) ; + copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ; + } + else + return AES_FAILURE ; + return AES_SUCCESS ; +} + +/******************************************************************************/ + +byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) +{ + while (n_block--) + { + xor_block (iv, plain) ; + if (encrypt (iv, iv) != AES_SUCCESS) + return AES_FAILURE ; + copy_n_bytes (cipher, iv, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK ; + } + return AES_SUCCESS ; +} + +/******************************************************************************/ + +byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block) +{ + while (n_block--) + { + xor_block (iv, plain) ; + if (encrypt (iv, iv) != AES_SUCCESS) + return AES_FAILURE ; + copy_n_bytes (cipher, iv, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK ; + } + return AES_SUCCESS ; +} + +/******************************************************************************/ + +byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) +{ + if (round) + { + byte s1 [N_BLOCK] ; + copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ; + inv_shift_sub_rows (s1) ; + + for (byte r = round ; --r ; ) + { + byte s2 [N_BLOCK] ; + copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ; + inv_mix_sub_columns (s1, s2) ; + } + copy_and_key (cipher, s1, (byte*) (key_sched)) ; + } + else + return AES_FAILURE ; + return AES_SUCCESS ; +} + +/******************************************************************************/ + +byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) +{ + while (n_block--) + { + byte tmp [N_BLOCK] ; + copy_n_bytes (tmp, cipher, N_BLOCK) ; + if (decrypt (cipher, plain) != AES_SUCCESS) + return AES_FAILURE ; + xor_block (plain, iv) ; + copy_n_bytes (iv, tmp, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK; + } + return AES_SUCCESS ; +} + +/******************************************************************************/ + +byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block) +{ + while (n_block--) + { + byte tmp [N_BLOCK] ; + copy_n_bytes (tmp, cipher, N_BLOCK) ; + if (decrypt (cipher, plain) != AES_SUCCESS) + return AES_FAILURE ; + xor_block (plain, iv) ; + copy_n_bytes (iv, tmp, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK; + } + return AES_SUCCESS ; +} + +/*****************************************************************************/ + +void AES::set_IV(unsigned long long int IVCl){ + memcpy(iv,&IVCl,8); + memcpy(iv+8,&IVCl,8); + IVC = IVCl; +} + +/******************************************************************************/ + +void AES::iv_inc(){ + IVC += 1; + memcpy(iv,&IVC,8); + memcpy(iv+8,&IVC,8); +} + +/******************************************************************************/ + +int AES::get_size(){ + return size; +} + +/******************************************************************************/ + +void AES::set_size(int sizel){ + size = sizel; +} + + +/******************************************************************************/ + +void AES::get_IV(byte *out){ + memcpy(out,&IVC,8); + memcpy(out+8,&IVC,8); +} + +/******************************************************************************/ + +void AES::calc_size_n_pad(int p_size){ + int s_of_p = p_size - 1; + if ( s_of_p % N_BLOCK == 0){ + size = s_of_p; + }else{ + size = s_of_p + (N_BLOCK-(s_of_p % N_BLOCK)); + } + pad = size - s_of_p; +} + +/******************************************************************************/ + +void AES::padPlaintext(void* in,byte* out) +{ + memcpy(out,in,size); + for (int i = size-pad; i < size; i++){; + out[i] = arr_pad[pad - 1]; + } +} + +/******************************************************************************/ + +bool AES::CheckPad(byte* in,int lsize){ + if (in[lsize-1] <= 0x0f){ + int lpad = (int)in[lsize-1]; + for (int i = lsize - 1; i >= lsize-lpad; i--){ + if (arr_pad[lpad - 1] != in[i]){ + return false; + } + } + }else{ + return true; + } +return true; +} + +/******************************************************************************/ + +void AES::printArray(byte output[],bool p_pad) +{ +uint8_t i,j; +uint8_t loops = size/N_BLOCK; +uint8_t outp = N_BLOCK; +for (j = 0; j < loops; j += 1){ + if (p_pad && (j == (loops - 1)) ) { outp = N_BLOCK - pad; } + for (i = 0; i < outp; i++) + { + printf_P(PSTR("%c"),output[j*N_BLOCK + i]); + } +} + printf_P(PSTR("\n")); +} + +/******************************************************************************/ + +void AES::printArray(byte output[],int sizel) +{ + for (int i = 0; i < sizel; i++) + { + printf_P(PSTR("%x"),output[i]); + } + printf_P(PSTR("\n")); +} + + +/******************************************************************************/ + +void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]){ + calc_size_n_pad(size_p); + byte plain_p[get_size()]; + padPlaintext(plain,plain_p); + int blocks = get_size() / N_BLOCK; + set_key (key, bits) ; + cbc_encrypt (plain_p, cipher, blocks, ivl); +} + +/******************************************************************************/ + +void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits){ + calc_size_n_pad(size_p); + byte plain_p[get_size()]; + padPlaintext(plain,plain_p); + int blocks = get_size() / N_BLOCK; + set_key (key, bits) ; + cbc_encrypt (plain_p, cipher, blocks); +} + +/******************************************************************************/ + +void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]){ + set_size(size_c); + int blocks = size_c / N_BLOCK; + set_key (key, bits); + cbc_decrypt (cipher,plain, blocks, ivl); +} + +/******************************************************************************/ + +void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits){ + set_size(size_c); + int blocks = size_c / N_BLOCK; + set_key (key, bits); + cbc_decrypt (cipher,plain, blocks); +} + + +/******************************************************************************/ + +#if defined(AES_LINUX) +double AES::millis(){ + gettimeofday(&tv, NULL); + return (tv.tv_sec + 0.000001 * tv.tv_usec); +} +#endif diff --git a/libraries/MySensors/drivers/AES/AES.h b/libraries/MySensors/drivers/AES/AES.h new file mode 100644 index 0000000..ec7b8a6 --- /dev/null +++ b/libraries/MySensors/drivers/AES/AES.h @@ -0,0 +1,415 @@ +#ifndef __AES_H__ +#define __AES_H__ + +#include "AES_config.h" +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state. + */ + + /* code was modified by george spanos + * 16/12/14 + */ + +class AES +{ + public: + +/* The following calls are for a precomputed key schedule + + NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + /** \fn AES() + * \brief AES constructor + * + * This function initialized an instance of AES. + */ + AES(); + + /** Set the cipher key for the pre-keyed version. + * @param key[] pointer to the key string. + * @param keylen Integer that indicates the length of the key. + * @note NOTE: If the length_type used for the key length is an unsigned 8-bit character, + * a key length of 256 bits must be entered as a length in bytes + * (valid inputs are hence 128, 192, 16, 24 and 32). + * + */ + byte set_key (byte key[], int keylen) ; + + /** clean up subkeys after use. + * + */ + void clean () ; // delete key schedule after use + + /** copying and xoring utilities. + * @param *AESt byte pointer of the AEStination array. + * @param *src byte pointer of the source array. + * @param n byte, indicating the sizeof the bytes to be copied. + * @note this is an alternative for memcpy(void *s1,const void *s2, site_t n), + * i have not updated the function in the implementation yet, but it is considered a future plan. + * + */ + void copy_n_bytes (byte * AESt, byte * src, byte n) ; + + /** Encrypt a single block of 16 bytes . + * @param plain[N_BLOCK] Array of the plaintext. + * @param cipher[N_BLOCK] Array of the ciphertext. + * @note The N_BLOCK is defined in AES_config.h as, + * @code #define N_ROW 4 + * #define N_COL 4 + * #define N_BLOCK (N_ROW * N_COL) + * @endcode + * Changed to that will change the Block_size. + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ; + + /** CBC encrypt a number of blocks (input and return an IV). + * + * @param *plain Pointer, points to the plaintex. + * @param *cipher Pointer, points to the ciphertext that will be created. + * @param n_block integer, indicated the number of blocks to be ciphered. + * @param iv[N_BLOCK] byte Array that holds the IV (initialization vector). + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ; + + /** CBC encrypt a number of blocks (input and return an IV). + * + * @param *plain Pointer, points to the plaintex. + * @param *cipher Pointer, points to the ciphertext that will be created. + * @param n_block integer, indicated the number of blocks to be ciphered. + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte cbc_encrypt (byte * plain, byte * cipher, int n_block) ; + + + /** Decrypt a single block of 16 bytes + * @param cipher[N_BLOCK] Array of the ciphertext. + * @param plain[N_BLOCK] Array of the plaintext. + * @note The N_BLOCK is defined in AES_config.h as, + * @code #define N_ROW 4 + * #define N_COL 4 + * #define N_BLOCK (N_ROW * N_COL) + * @endcode + * Changed to that will change the Block_size. + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ; + + /** CBC decrypt a number of blocks (input and return an IV) + * + * @param *cipher Pointer, points to the ciphertext that will be created. + * @param *plain Pointer, points to the plaintex. + * @param n_block integer, indicated the number of blocks to be ciphered. + * @param iv[N_BLOCK] byte Array that holds the IV (initialization vector). + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ; + + /** CBC decrypt a number of blocks (input and return an IV) + * + * @param *cipher Pointer, points to the ciphertext that will be created. + * @param *plain Pointer, points to the plaintex. + * @param n_block integer, indicated the number of blocks to be ciphered. + * @Return 0 if SUCCESS or -1 if FAILURE + * + */ + byte cbc_decrypt (byte * cipher, byte * plain, int n_block) ; + + /** Sets IV (initialization vector) and IVC (IV counter). + * This function changes the ivc and iv variables needed for AES. + * + * @param IVCl int or hex value of iv , ex. 0x0000000000000001 + * @note example: + * @code unsigned long long int my_iv = 01234567; @endcode + */ + void set_IV(unsigned long long int IVCl); + + /** increase the iv (initialization vector) and IVC (IV counter) by 1 + * + * This function increased the VI by one step in order to have a different IV each time + * + */ + void iv_inc(); + + /** Getter method for size + * + * This function return the size + * @return an integer, that is the size of the of the padded plaintext, + * thus, the size of the ciphertext. + */ + int get_size(); + + /** Setter method for size + * + * This function sets the size of the plaintext+pad + * + */ + void set_size(int sizel); + + /** Getter method for IV + * + * This function return the IV + * @param out byte pointer that gets the IV. + * @return none, the IV is writed to the out pointer. + */ + void get_IV(byte *out); + + /** Calculates the size of the plaintext and the padding. + * + * Calculates the size of theplaintext with the padding + * and the size of the padding needed. Moreover it stores them in their class variables. + * + * @param p_size the size of the byte array ex sizeof(plaintext) + */ + void calc_size_n_pad(int p_size); + + /** Pads the plaintext + * + * This function pads the plaintext and returns an char array with the + * plaintext and the padding in order for the plaintext to be compatible with + * 16bit size blocks required by AES + * + * @param in the string of the plaintext in a byte array + * @param out The string of the out array. + * @return no return, The padded plaintext is stored in the out pointer. + */ + void padPlaintext(void* in,byte* out); + + /** Check the if the padding is correct. + * + * This functions checks the padding of the plaintext. + * + * @param in the string of the plaintext in a byte array + * @param size the size of the string + * @return true if correct / false if not + */ + bool CheckPad(byte* in,int size); + + /** Prints the array given. + * + * This function prints the given array and pad, + * It is mainlly used for debugging purpuses or to output the string. + * + * @param output[] the string of the text in a byte array + * @param p_pad optional, used to print with out the padding characters + */ + void printArray(byte output[],bool p_pad = true); + + /** Prints the array given. + * + * This function prints the given array in Hexadecimal. + * + * @param output[] the string of the text in a byte array + * @param sizel the size of the array. + */ + void printArray(byte output[],int sizel); + + /** User friendly implementation of AES-CBC encryption. + * + * @param *plain pointer to the plaintext + * @param size_p size of the plaintext + * @param *cipher pointer to the ciphertext + * @param *key pointer to the key that will be used. + * @param bits bits of the encryption/decrpytion + * @param ivl[N_BLOCK] the initialization vector IV that will be used for encryption. + * @note The key will be stored in class variable. + */ + void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]); + + /** User friendly implementation of AES-CBC encryption. + * + * @param *plain pointer to the plaintext + * @param size_p size of the plaintext + * @param *cipher pointer to the ciphertext + * @param *key pointer to the key that will be used. + * @param bits bits of the encryption/decrpytion + * @note The key will be stored in class variable. + */ + void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits); + + /** User friendly implementation of AES-CBC decryption. + * + * @param *cipher pointer to the ciphertext + * @param size_c size of the ciphertext + * @param *plain pointer to the plaintext + * @param *key pointer to the key that will be used. + * @param bits bits of the encryption/decrpytion + * @param ivl[N_BLOCK] the initialization vector IV that will be used for decryption. + * @note The key will be stored in class variable. + */ + void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]); + + /** User friendly implementation of AES-CBC decryption. + * + * @param *cipher pointer to the ciphertext + * @param size_c size of the ciphertext + * @param *plain pointer to the plaintext + * @param *key pointer to the key that will be used. + * @param bits bits of the encryption/decrpytion + * @note The key will be stored in class variable. + */ + void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits); + + #if defined(AES_LINUX) + /** + * used in linux in order to retrieve the time in milliseconds. + * + * @return returns the milliseconds in a double format. + */ + double millis(); + #endif + private: + int round ;/**< holds the number of rounds to be used. */ + byte key_sched [KEY_SCHEDULE_BYTES] ;/**< holds the pre-computed key for the encryption/decrpytion. */ + unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */ + byte iv[16];/**< holds the initialization vector that will be used in the cipher. */ + int pad;/**< holds the size of the padding. */ + int size;/**< hold the size of the plaintext to be ciphered */ + #if defined(AES_LINUX) + timeval tv;/**< holds the time value on linux */ + byte arr_pad[15];/**< holds the hexadecimal padding values on linux */ + #else + byte arr_pad[15];// = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };/**< holds the hexadecimal padding values */ + #endif +} ; + + +#endif + +/** + * @example aes.ino + * For Arduino
    + * Updated: spaniakos 2015
    + * + * This is an example of how to use AES in CBC mode easily. + * The text and keys can be either in HEX or String format.
    + */ + + /** + * @example aes.cpp + * For Rasberry pi
    + * Updated: spaniakos 2015
    + * + * This is an example of how to use AES in CBC mode easily. + * The text and keys can be either in HEX or String format.
    + */ + + /** + * @example test_vectors.ino + * For Arduino
    + * Updated: spaniakos 2015
    + * + * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
    + * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. + */ + + /** + * @example test_vectors.cpp + * For Rasberry pi
    + * Updated: spaniakos 2015
    + * + * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
    + * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. + */ + +/** + * @mainpage AES library for Arduino and Raspberry pi. + * + * @section Goals design Goals + * + * This library is AESigned to be... + * @li Fast and efficient. + * @li Able to effectively encrypt and decrypt any size of string. + * @li Able to encrypt and decrypt using AES + * @li Able to encrypt and decrypt using AES-CBC + * @li Easy for the user to use in his programs. + * + * @section Acknowledgements Acknowledgements + * This is an AES library for the Arduino, based on tzikis's AES library, which you can find here:.
    + * Tzikis library was based on scottmac`s library, which you can find here:
    + * + * @section Installation Installation + *

    Arduino

    + * Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the + * libraries folder doesn't exist, create it. Then copy everything inside. (re)launch the Arduino IDE.
    + * You're done. Time for a mojito + * + *

    Raspberry pi

    + * install

    + * + * sudo make install
    + * cd examples_Rpi
    + * make

    + * + * What to do after changes to the library

    + * sudo make clean
    + * sudo make install
    + * cd examples_Rpi
    + * make clean
    + * make

    + * What to do after changes to a sketch

    + * cd examples_Rpi
    + * make

    + * or
    + * make clean
    + * make


    + * How to start a sketch

    + * cd examples_Rpi
    + * sudo ./

    + * + * @section News News + * + * If issues are discovered with the documentation, please report them here + * @section Useful Useful References + * + * Please refer to: + * + * @li AES Class Documentation + * @li Download + * @li Source Code + * @li All spaniakos Documentation Main Page + * + * @section Board_Support Board Support + * + * Most standard Arduino based boards are supported: + * - Arduino + * - Intel Galileo support + * - Raspberry Pi Support + * + * - The library has not been tested to other boards, but it should suppport ATMega 328 based boards,Mega Boards,Arduino Due,ATTiny board + */ diff --git a/libraries/MySensors/drivers/AES/AES_config.h b/libraries/MySensors/drivers/AES/AES_config.h new file mode 100644 index 0000000..242c841 --- /dev/null +++ b/libraries/MySensors/drivers/AES/AES_config.h @@ -0,0 +1,44 @@ +/* code was modified by george spanos + * 16/12/14 + */ + +#ifndef __AES_CONFIG_H__ +#define __AES_CONFIG_H__ + +#if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__) + + #define AES_LINUX + + #include + #include + #include + #include + #include + #include +#else + #include +#endif + +#include +#include + +#if defined(__ARDUINO_X86__) || (defined (__linux) || defined (linux)) + #undef PROGMEM + #define PROGMEM __attribute__(( section(".progmem.data") )) + #define pgm_read_byte(p) (*(p)) + typedef unsigned char byte; + #define printf_P printf + #define PSTR(x) (x) +#else + #include +#endif + +#define N_ROW 4 +#define N_COL 4 +#define N_BLOCK (N_ROW * N_COL) +#define N_MAX_ROUNDS 14 +#define KEY_SCHEDULE_BYTES ((N_MAX_ROUNDS + 1) * N_BLOCK) +#define AES_SUCCESS (0) +#define AES_FAILURE (-1) + +#endif diff --git a/libraries/MySensors/drivers/AES/Doxyfile b/libraries/MySensors/drivers/AES/Doxyfile new file mode 100644 index 0000000..79cf3b7 --- /dev/null +++ b/libraries/MySensors/drivers/AES/Doxyfile @@ -0,0 +1,2372 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "AES Encryption Library for Arduino and Raspberry Pi" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Spaniakos - AES Encryption Library for Arduino and Raspberry Pi" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = "../Documentations/AES" + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = ino=c \ + pde=c + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ./ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = examples \ + examples_RPi \ + examples_Rpi + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more acurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 10 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = doxygen-custom.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /