diff --git a/AVR/lib/RF24/examples/scanner/output/scanner.hex b/AVR/lib/RF24/examples/scanner/output/scanner.hex index 00a3175..45c37db 100644 --- a/AVR/lib/RF24/examples/scanner/output/scanner.hex +++ b/AVR/lib/RF24/examples/scanner/output/scanner.hex @@ -1,325 +1,325 @@ -:100000000C9463000C948B000C948B000C948B006C -:100010000C948B000C948B000C948B000C948B0034 -:100020000C948B000C948B000C948B000C948B0024 -:100030000C948B000C948B000C948B000C948B0014 -:100040000C948F050C948B000C9423060C948B005D -:100050000C948B000C948B000C948B000C948B00F4 -:100060000C948B000C948B000000000024002700EF -:100070002A0000000000250028002B0000000000DE -:1000800023002600290004040404040404040202DA -:100090000202020203030303030301020408102007 -:1000A0004080010204081020010204081020000012 -:1000B0000007000201000003040600000000000029 -:1000C000000090043B0711241FBECFEFD8E0DEBF35 -:1000D000CDBF11E0A0E0B1E0E6EFF3E102C0059092 -:1000E0000D92AA33B107D9F712E0AAE3B1E001C03B -:1000F0001D92A13FB107E1F710E0C6ECD0E004C0CB -:100100002297FE010E94F509C23CD107C9F70E945F -:100110001C060C94F9090C9400000F931F93CF93C5 -:10012000DF938C01EB01009731F46115710519F42F -:1001300020E030E038C081E090E06EE070E00E94A6 -:10014000CB02FC019C01009771F180E8838320972A -:1001500071F0D387C28781E883838091E702909111 -:10016000E802892B21F4F093E802E093E7020115FD -:100170001105C9F011870087838182608383809194 -:10018000E9029091EA02892B71F4F093EA02E0937C -:10019000E9028091EB029091EC02892B21F4F0931B -:1001A000EC02E093EB02C901DF91CF911F910F9117 -:1001B0000895A0E0B0E0EFEDF0E00C94CC09FE0172 -:1001C0003596619171918091E9029091EA02AF01B7 -:1001D0000E94EE002096E2E00C94E809ABE0B0E06B -:1001E000E4EFF0E00C94BC093C012B015A01FC0146 -:1001F00017821682838181FD03C06FEF7FEFC6C136 -:100200009AE0892E1E010894211C311CF3012381E0 -:10021000F20123FD859123FF81912F01882309F4A9 -:10022000B2C1853239F423FD859123FF81912F01DD -:10023000853229F490E0B3010E940604E7CF982F9D -:10024000FF24EE249924FFE1FF15D0F09B3269F0E2 -:100250009C3228F4903259F0933291F40EC09D32C2 -:1002600049F0903369F441E024C052E0F52A84E07B -:10027000F82A28C098E0F92A25C0E0E1FE2A22C029 -:10028000F7FC29C0892F80538A3070F4F6FE05C030 -:10029000989C902C1124980E15C0E89CE02C1124F9 -:1002A000E80EF0E2FF2A0EC09E3229F4F6FC6BC184 -:1002B00040E4F42A07C09C3619F450E8F52A02C03D -:1002C000983649F4F20123FD959123FF91912F0176 -:1002D000992309F0B8CF892F8554833018F08052C4 -:1002E000833038F444E050E0A40EB51E5FE3598338 -:1002F0000FC0933631F0933779F0933509F056C03B -:1003000020C0F5018081898342E050E0A40EB51E33 -:10031000610101E010E012C0F501C080D180F6FC5F -:1003200003C06FEF7FEF02C0692D70E042E050E044 -:10033000A40EB51EC6010E94FB038C015FE7F522E7 -:1003400014C0F501C080D180F6FC03C06FEF7FEFD1 -:1003500002C0692D70E042E050E0A40EB51EC60157 -:100360000E94E9038C0150E8F52AF3FE07C01AC089 -:1003700080E290E0B3010E940604EA948E2D90E0A2 -:1003800008171907A8F30EC0F601F7FC8591F7FED0 -:1003900081916F0190E0B3010E940604E110EA949C -:1003A000015010400115110579F7EAC0943611F09B -:1003B000993669F5F7FE08C0F50120813181428147 -:1003C000538184E090E00AC0F501808191819C0115 -:1003D000442737FD4095542F82E090E0A80EB91EC7 -:1003E0009FE6F92257FF09C0509540953095219519 -:1003F0003F4F4F4F5F4FE0E8FE2ACA01B901A1010C -:100400002AE030E00E943204D82ED21840C095373E -:1004100029F41F2D1F7E2AE030E01DC01F2D197FFB -:100420009F3661F0903720F4983509F0ACC00FC0CA -:10043000903739F0983709F0A6C004C028E030E0C2 -:100440000AC0106114FD146020E130E004C014FD06 -:10045000166020E132E017FF08C0F501608171816C -:100460008281938144E050E008C0F5018081918150 -:10047000BC0180E090E042E050E0A40EB51EA10176 -:100480000E943204D82ED2188FE7F82EF122F6FE01 -:100490000BC05EEFF522D91438F4F4FE07C0F2FC6D -:1004A00005C08FEEF82202C01D2D01C0192DF4FEEB -:1004B0000DC0FE01ED0DF11D8081803319F499EE20 -:1004C000F92208C01F5FF2FE05C003C08F2D867899 -:1004D00009F01F5F0F2DF3FC14C0F0FE0FC01E15B6 -:1004E00010F09D2C0BC09D2C9E0C911A1E2D06C049 -:1004F00080E290E0B3010E9406041F5F1E15C0F366 -:1005000004C01E1510F4E11A01C0EE2404FF0FC050 -:1005100080E390E0B3010E94060402FF1DC001FDCC -:1005200003C088E790E00EC088E590E00BC0802F04 -:10053000867891F001FF02C08BE201C080E2F7FCF7 -:100540008DE290E0B3010E94060406C080E390E0D3 -:10055000B3010E9406049A94D914C0F3DA94F1010D -:10056000ED0DF11D808190E0B3010E940604DD20B5 -:10057000A9F706C080E290E0B3010E940604EA9465 -:10058000EE20C1F743CEF30166817781CB012B9634 -:10059000E2E10C94D8090F931F93CF93DF93689FE8 -:1005A0008001699F100D789F100D1124C8010E94D1 -:1005B000E702EC01009729F060E070E0A8010E94DA -:1005C000F403CE01DF91CF911F910F910895CF9346 -:1005D000DF93BC018230910510F462E070E0A091DD -:1005E000EF02B091F002ED01E0E0F0E040E050E019 -:1005F00021C0888199818617970769F48A819B8138 -:10060000309719F09383828304C09093F002809313 -:10061000EF02FE0134C06817790738F4411551051F -:1006200019F08417950708F4AC01FE018A819B81BB -:100630009C01E9012097E9F641155105A9F1CA018C -:10064000861B970B049708F4BA01E0E0F0E02AC09B -:100650008D919C91119784179507F9F4641775078C -:1006600081F412968D919C911397309719F0938392 -:10067000828304C09093F0028093EF02FD013296D2 -:100680004CC0CA01861B970BFD01E80FF91F61934F -:10069000719302978D939C9340C0FD018281938159 -:1006A0009C01D9011097A1F68091ED029091EE0284 -:1006B000892B41F480912301909124019093EE02C3 -:1006C0008093ED024091250150912601411551057D -:1006D00041F44DB75EB78091210190912201481BF2 -:1006E000590B2091ED023091EE02CA01821B930B4F -:1006F0008617970780F0AB014E5F5F4F8417950711 -:1007000050F0420F531F5093EE024093ED02F90157 -:100710006193719302C0E0E0F0E0CF01DF91CF91EF -:100720000895CF93DF93009709F450C0EC0122970E -:100730001B821A82A091EF02B091F002109709F18A -:1007400040E050E0AC17BD0708F1BB83AA83FE016F -:1007500021913191E20FF31FAE17BF0779F48D910C -:100760009C911197280F391F2E5F3F4F39832883A3 -:1007700012968D919C9113979B838A834115510505 -:1007800071F4D093F002C093EF0220C012968D91C5 -:100790009C911397AD01009711F0DC01D3CFFA01C2 -:1007A000D383C28321913191E20FF31FCE17DF076C -:1007B00069F488819981280F391F2E5F3F4FFA0114 -:1007C000318320838A819B8193838283DF91CF91C0 -:1007D0000895FC010590615070400110D8F7809594 -:1007E00090958E0F9F1F0895DC0101C06D934150BD -:1007F0005040E0F70895FC016150704001900110F5 -:10080000D8F7809590958E0F9F1F08950F931F9393 -:10081000CF93DF938C01EB018B8181FF1BC082FFA3 -:100820000DC02E813F818C819D812817390764F48A -:10083000E881F9810193F983E88306C0E885F985A9 -:10084000802F0995892B31F48E819F8101969F839A -:100850008E8302C00FEF1FEFC801DF91CF911F9170 -:100860000F910895FA01AA27283051F1203181F122 -:10087000E8946F936E7F6E5F7F4F8F4F9F4FAF4FA8 -:10088000B1E03ED0B4E03CD0670F781F891F9A1FBB -:10089000A11D680F791F8A1F911DA11D6A0F711D6F -:1008A000811D911DA11D20D009F468943F912AE07B -:1008B000269F11243019305D3193DEF6CF01089563 -:1008C000462F4770405D4193B3E00FD0C9F7F6CF94 -:1008D000462F4F70405D4A3318F0495D31FD40525C -:1008E000419302D0A9F7EACFB4E0A69597958795F2 -:1008F00077956795BA95C9F70097610571050895D1 -:100900009B01AC010A2E069457954795379527957C -:10091000BA95C9F7620F731F841F951FA01D089514 -:100920008AE391E068E049E00E9475070895FF922C -:100930000F931F93CF93DF9380E8E7E4F1E0DF01AB -:100940001D928A95E9F704E610E021C08AE391E060 -:100950006F2D0E94F2078AE391E00E94840880E8EC -:1009600090E00E94D7058AE391E00E947C078AE329 -:1009700091E00E944608882329F088819981019698 -:10098000998388832297FA94BFEFFB16F9F60150FA -:100990001040EFEF0F3F1E0729F0C5E4D2E08FE7CC -:1009A000F82ED4CFC7E4D1E000E011E000D000D0B1 -:1009B000ADB7BEB712961C930E931197899199917A -:1009C0008F70907014969C938E9313970E94D90009 -:1009D0000F900F900F900F90B2E0C734DB0731F704 -:1009E00000D083E091E0EDB7FEB7928381830E944F -:1009F000D9000F900F90DF91CF911F910F91FF9031 -:100A0000089580E895E060E070E00E948D00089510 -:100A10000F931F93CF93DF9384ED92E040E051EE6C -:100A200060E070E00E9454060E94010500D086E05C -:100A300091E0EDB7FEB7928381830E94D9000F90B9 -:100A40000F908AE391E00E944B088AE391E060E016 -:100A50000E94E8078AE391E00E9484088AE391E01B -:100A60000E947C07C0E0D0E000E011E000D000D0A0 -:100A7000EDB7FEB712830183CE0124E095958795EB -:100A80002A95E1F7948383830E94D90021960F90E1 -:100A90000F900F900F90C038D10541F700D083E040 -:100AA00091E0EDB7FEB7928381830E94D900C0E048 -:100AB000D0E00F900F9000D000D0EDB7FEB70183CB -:100AC0001283CE018F709070948383830E94D9002B -:100AD00021960F900F900F900F90C038D10559F7C5 -:100AE00000D083E091E0EDB7FEB7928381830E944E -:100AF000D9000F900F90DF91CF911F910F91089522 -:100B00000F931F93082F84ED92E0602F0E94280717 -:100B1000112707FD1095C8011F910F9108951F928D -:100B20000F920FB60F9211242F933F938F939F93A1 -:100B3000AF93BF9380914B0290914C02A0914D02D4 -:100B4000B0914E0230914F020196A11DB11D232F8D -:100B50002D5F2D3720F02D570196A11DB11D20933B -:100B60004F0280934B0290934C02A0934D02B0939E -:100B70004E028091470290914802A0914902B091A3 -:100B80004A020196A11DB11D80934702909348022D -:100B9000A0934902B0934A02BF91AF919F918F9168 -:100BA0003F912F910F900FBE0F901F9018950197B6 -:100BB00039F0880F991F880F991F02970197F1F755 -:100BC0000895789484B5826084BD84B5816084BDC5 -:100BD00085B5826085BD85B5816085BDEEE6F0E0B6 -:100BE000808181608083E1E8F0E010828081826012 -:100BF0008083808181608083E0E8F0E08081816093 -:100C00008083E1EBF0E0808184608083E0EBF0E0C2 -:100C1000808181608083EAE7F0E080818460808366 -:100C20008081826080838081816080838081806810 -:100C300080831092C10008950E94E1050E9408057A -:100C40000E949704FDCF1F920F920FB60F921124AE -:100C50002F933F934F938F939F93EF93FF934091E5 -:100C6000C600E091D002F091D10231969F012F771A -:100C7000307031978091D2029091D30228173907B2 -:100C800039F0E05BFD4F40833093D1022093D002D6 -:100C9000FF91EF919F918F914F913F912F910F90E5 -:100CA0000FBE0F901F901895AF92BF92DF92EF92F8 -:100CB000FF920F931F93CF93DF93EC017A018B0187 -:100CC000DD24403081EE580780E0680780E0780737 -:100CD00011F0DD24D39491E0A92EB12CE885F9859B -:100CE000DD2069F0C5010A8802C0880F991F0A94A7 -:100CF000E2F7808360E079E08DE390E005C0108248 -:100D000060E874E88EE190E0A80197010E949A09DA -:100D10002150304040405040569547953795279593 -:100D200080E12030380720F0DD2011F0DD24D6CF1F -:100D3000EC81FD813083EE81FF812083EA85FB8594 -:100D4000208141E050E0CA010E8402C0880F991F43 -:100D50000A94E2F7282B2083EA85FB852081CA01CB -:100D60000F8402C0880F991F0A94E2F7282B208372 -:100D7000EA85FB858081088802C0440F551F0A94CC -:100D8000E2F7842B8083DF91CF911F910F91FF9029 -:100D9000EF90DF90BF90AF900895DC011296ED9137 -:100DA000FC911397E058FF4F2191319180819181FF -:100DB000281B390B2F773070C9010895DC0112967A -:100DC000ED91FC911397EE57FF4F20813181929165 -:100DD0008291E058F0408217930719F42FEF3FEF0C -:100DE00005C0E20FF31F8081282F30E0C90108956C -:100DF000DC011296ED91FC911397DF01AE57BF4FC6 -:100E00002D913C911197E058FF4F80819181E058DE -:100E1000F0408217930719F42FEF3FEF0BC0E20F5A -:100E2000F31F80812F5F3F4F2F7730702D933C93BE -:100E3000282F30E0C9010895DC011296ED91FC9154 -:100E40001397EE57FF4F808191819293829308957B -:100E5000FC01A085B18521898C9190E0022E02C011 -:100E6000959587950A94E2F780FFF6CF0484F5857F -:100E7000E02D608308958BE291E09093D5028093FA -:100E8000D40280E592E09093D7028093D60285EC5D -:100E900090E09093D9028093D80284EC90E09093F4 -:100EA000DB028093DA0280EC90E09093DD02809385 -:100EB000DC0281EC90E09093DF028093DE0286EC0E -:100EC00090E09093E1028093E00284E08093E2025C -:100ED00083E08093E30287E08093E40285E08093DF -:100EE000E50281E08093E6020895FC01608341837E -:100EF00080E2828313820895FC01808160E00E9479 -:100F0000CD080895FF920F931F938C01F62E80E079 -:100F10000E94650985E00E946A09F80181816F2DB0 -:100F20000E94CD081F910F91FF9008951F93CF93BA -:100F3000DF93EC0160E070E00E94820781EE8EBDDD -:100F40000DB407FEFDCF1EB5CE0161E070E00E943A -:100F50008207812FDF91CF911F9108951F93CF9327 -:100F6000DF93EC0160E070E00E94820782EE8EBDAC -:100F70000DB407FEFDCF1EB5CE0161E070E00E940A -:100F80008207812FDF91CF911F9108950F931F93B7 -:100F9000CF93DF93EC01162F042F60E070E00E94E6 -:100FA00082071F7110621EBD0DB407FEFDCF1EB576 -:100FB0000EBD0DB407FEFDCF8EB5CE0161E070E031 -:100FC0000E948207812FDF91CF911F910F91089589 -:100FD000662319F061E04FE302C061E040E00E9447 -:100FE000C6070895462F603808F04FE765E00E9475 -:100FF000C6070895EF92FF920F931F93CF93DF934D -:101000007C01162FEA01022F60E070E00E94820747 -:101010001F7110621EBD0DB407FEFDCF1EB508C0C6 -:1010200088818EBD0DB407FEFDCF21968EB501508F -:101030000023B1F7C70161E070E00E948207812FB1 -:10104000DF91CF911F910F91FF90EF9008951F9323 -:10105000CF93DF93EC01162F60E070E00E948207CF -:101060001F711EBD0DB407FEFDCF8EB58FEF8EBD77 -:101070000DB407FEFDCF1EB5CE0161E070E00E9409 -:101080008207812FDF91CF911F91089569E00E941F -:101090002708817008950F931F938C01FC018081B4 -:1010A00061E00E94A708F801818161E00E94A70821 -:1010B000F801808160E00E94CD08C80161E070E025 -:1010C0000E9482070E947B0981E00E945C0980E007 -:1010D0000E94650985E00E946A09C80164E04FEF3B -:1010E0000E94C607C80167E040E70E94C607C80122 -:1010F0000E94AE07C8010E949607C80161E00E94E5 -:10110000F2071F910F9108950F931F938C0160E0D8 -:101110004BE00E94C607C80167E040E70E94C6078F -:10112000A8014B5F5F4FC8016AE025E00E94FA0703 -:10113000C8010E94AE07F801808161E00E94CD08DD -:1011400082E890E00E94D7051F910F910895482FE3 -:1011500050E0CA0186569F4FFC0124914A575F4FC9 -:10116000FA0184918823C1F0E82FF0E0EE0FFF1F11 -:10117000E859FF4FA591B491662341F49FB7F894C5 -:101180008C91209582238C939FBF08959FB7F894EC -:101190008C91822B8C939FBF0895482F50E0CA01F9 -:1011A00082559F4FFC012491CA0186569F4FFC0136 -:1011B00034914A575F4FFA019491992309F444C03E -:1011C000222351F1233071F0243028F42130A1F092 -:1011D000223011F514C02630B1F02730C1F0243090 -:1011E000D9F404C0809180008F7703C08091800083 -:1011F0008F7D8093800010C084B58F7702C084B546 -:101200008F7D84BD09C08091B0008F7703C080912D -:10121000B0008F7D8093B000E92FF0E0EE0FFF1F4C -:10122000EE58FF4FA591B491662341F49FB7F8940F -:101230008C91309583238C939FBF08959FB7F8942A -:101240008C91832B8C939FBF08950F931F93CF9303 -:10125000DF938C01EB0109C02196D801ED91FC913F -:101260000190F081E02DC801099568816623A1F7FE -:10127000DF91CF911F910F910895EF92FF920F93FD -:101280001F93CF93DF938C017B01EA010CC0D70140 -:101290006D917D01D801ED91FC910190F081E02DDF -:1012A000C80109952197209791F7DF91CF911F9160 -:1012B0000F91FF90EF900895882319F48CB5806208 -:1012C00002C08CB58F7D8CBD08959CB5937F982B03 -:1012D0009CBD08952CB5382F33702C7F322B3CBD2C -:1012E0002DB590E0959587959595879581702E7F82 -:1012F000822B8DBD08958DE061E00E94A7088BE0F0 -:1013000061E00E94A7088AE061E00E94A7088DE0E2 -:1013100060E00E94CD088BE060E00E94CD088AE08A -:1013200061E00E94CD088CB580618CBD8CB5806475 -:101330008CBD0895A1E21A2EAA1BBB1BFD010DC096 -:10134000AA1FBB1FEE1FFF1FA217B307E407F50775 -:1013500020F0A21BB30BE40BF50B661F771F881F51 -:10136000991F1A9469F760957095809590959B01E7 -:10137000AC01BD01CF0108952F923F924F925F9231 -:101380006F927F928F929F92AF92BF92CF92DF9295 -:10139000EF92FF920F931F93CF93DF93CDB7DEB7FA -:1013A000CA1BDB0B0FB6F894DEBF0FBECDBF09948E -:1013B0002A88398848885F846E847D848C849B84E5 -:1013C000AA84B984C884DF80EE80FD800C811B81F3 -:1013D000AA81B981CE0FD11D0FB6F894DEBF0FBE22 -:1013E000CDBFED010895EE0FFF1F0590F491E02DA4 -:0613F0000994F894FFCF00 -:1013F6002578000A0D000A0D524632342F657861B1 -:101406006D706C65732F7363616E6E65722F0A0D56 -:10141600002000F102000000000000280725093D19 -:0A14260009CD06F806DE061C0700DB -:00000001FF +:100000000C9463000C948B000C948B000C948B006C +:100010000C948B000C948B000C948B000C948B0034 +:100020000C948B000C948B000C948B000C948B0024 +:100030000C948B000C948B000C948B000C948B0014 +:100040000C948F050C948B000C9423060C948B005D +:100050000C948B000C948B000C948B000C948B00F4 +:100060000C948B000C948B000000000024002700EF +:100070002A0000000000250028002B0000000000DE +:1000800023002600290004040404040404040202DA +:100090000202020203030303030301020408102007 +:1000A0004080010204081020010204081020000012 +:1000B0000007000201000003040600000000000029 +:1000C000000090043B0711241FBECFEFD8E0DEBF35 +:1000D000CDBF11E0A0E0B1E0E6EFF3E102C0059092 +:1000E0000D92AA33B107D9F712E0AAE3B1E001C03B +:1000F0001D92A13FB107E1F710E0C6ECD0E004C0CB +:100100002297FE010E94F509C23CD107C9F70E945F +:100110001C060C94F9090C9400000F931F93CF93C5 +:10012000DF938C01EB01009731F46115710519F42F +:1001300020E030E038C081E090E06EE070E00E94A6 +:10014000CB02FC019C01009771F180E8838320972A +:1001500071F0D387C28781E883838091E702909111 +:10016000E802892B21F4F093E802E093E7020115FD +:100170001105C9F011870087838182608383809194 +:10018000E9029091EA02892B71F4F093EA02E0937C +:10019000E9028091EB029091EC02892B21F4F0931B +:1001A000EC02E093EB02C901DF91CF911F910F9117 +:1001B0000895A0E0B0E0EFEDF0E00C94CC09FE0172 +:1001C0003596619171918091E9029091EA02AF01B7 +:1001D0000E94EE002096E2E00C94E809ABE0B0E06B +:1001E000E4EFF0E00C94BC093C012B015A01FC0146 +:1001F00017821682838181FD03C06FEF7FEFC6C136 +:100200009AE0892E1E010894211C311CF3012381E0 +:10021000F20123FD859123FF81912F01882309F4A9 +:10022000B2C1853239F423FD859123FF81912F01DD +:10023000853229F490E0B3010E940604E7CF982F9D +:10024000FF24EE249924FFE1FF15D0F09B3269F0E2 +:100250009C3228F4903259F0933291F40EC09D32C2 +:1002600049F0903369F441E024C052E0F52A84E07B +:10027000F82A28C098E0F92A25C0E0E1FE2A22C029 +:10028000F7FC29C0892F80538A3070F4F6FE05C030 +:10029000989C902C1124980E15C0E89CE02C1124F9 +:1002A000E80EF0E2FF2A0EC09E3229F4F6FC6BC184 +:1002B00040E4F42A07C09C3619F450E8F52A02C03D +:1002C000983649F4F20123FD959123FF91912F0176 +:1002D000992309F0B8CF892F8554833018F08052C4 +:1002E000833038F444E050E0A40EB51E5FE3598338 +:1002F0000FC0933631F0933779F0933509F056C03B +:1003000020C0F5018081898342E050E0A40EB51E33 +:10031000610101E010E012C0F501C080D180F6FC5F +:1003200003C06FEF7FEF02C0692D70E042E050E044 +:10033000A40EB51EC6010E94FB038C015FE7F522E7 +:1003400014C0F501C080D180F6FC03C06FEF7FEFD1 +:1003500002C0692D70E042E050E0A40EB51EC60157 +:100360000E94E9038C0150E8F52AF3FE07C01AC089 +:1003700080E290E0B3010E940604EA948E2D90E0A2 +:1003800008171907A8F30EC0F601F7FC8591F7FED0 +:1003900081916F0190E0B3010E940604E110EA949C +:1003A000015010400115110579F7EAC0943611F09B +:1003B000993669F5F7FE08C0F50120813181428147 +:1003C000538184E090E00AC0F501808191819C0115 +:1003D000442737FD4095542F82E090E0A80EB91EC7 +:1003E0009FE6F92257FF09C0509540953095219519 +:1003F0003F4F4F4F5F4FE0E8FE2ACA01B901A1010C +:100400002AE030E00E943204D82ED21840C095373E +:1004100029F41F2D1F7E2AE030E01DC01F2D197FFB +:100420009F3661F0903720F4983509F0ACC00FC0CA +:10043000903739F0983709F0A6C004C028E030E0C2 +:100440000AC0106114FD146020E130E004C014FD06 +:10045000166020E132E017FF08C0F501608171816C +:100460008281938144E050E008C0F5018081918150 +:10047000BC0180E090E042E050E0A40EB51EA10176 +:100480000E943204D82ED2188FE7F82EF122F6FE01 +:100490000BC05EEFF522D91438F4F4FE07C0F2FC6D +:1004A00005C08FEEF82202C01D2D01C0192DF4FEEB +:1004B0000DC0FE01ED0DF11D8081803319F499EE20 +:1004C000F92208C01F5FF2FE05C003C08F2D867899 +:1004D00009F01F5F0F2DF3FC14C0F0FE0FC01E15B6 +:1004E00010F09D2C0BC09D2C9E0C911A1E2D06C049 +:1004F00080E290E0B3010E9406041F5F1E15C0F366 +:1005000004C01E1510F4E11A01C0EE2404FF0FC050 +:1005100080E390E0B3010E94060402FF1DC001FDCC +:1005200003C088E790E00EC088E590E00BC0802F04 +:10053000867891F001FF02C08BE201C080E2F7FCF7 +:100540008DE290E0B3010E94060406C080E390E0D3 +:10055000B3010E9406049A94D914C0F3DA94F1010D +:10056000ED0DF11D808190E0B3010E940604DD20B5 +:10057000A9F706C080E290E0B3010E940604EA9465 +:10058000EE20C1F743CEF30166817781CB012B9634 +:10059000E2E10C94D8090F931F93CF93DF93689FE8 +:1005A0008001699F100D789F100D1124C8010E94D1 +:1005B000E702EC01009729F060E070E0A8010E94DA +:1005C000F403CE01DF91CF911F910F910895CF9346 +:1005D000DF93BC018230910510F462E070E0A091DD +:1005E000EF02B091F002ED01E0E0F0E040E050E019 +:1005F00021C0888199818617970769F48A819B8138 +:10060000309719F09383828304C09093F002809313 +:10061000EF02FE0134C06817790738F4411551051F +:1006200019F08417950708F4AC01FE018A819B81BB +:100630009C01E9012097E9F641155105A9F1CA018C +:10064000861B970B049708F4BA01E0E0F0E02AC09B +:100650008D919C91119784179507F9F4641775078C +:1006600081F412968D919C911397309719F0938392 +:10067000828304C09093F0028093EF02FD013296D2 +:100680004CC0CA01861B970BFD01E80FF91F61934F +:10069000719302978D939C9340C0FD018281938159 +:1006A0009C01D9011097A1F68091ED029091EE0284 +:1006B000892B41F480912301909124019093EE02C3 +:1006C0008093ED024091250150912601411551057D +:1006D00041F44DB75EB78091210190912201481BF2 +:1006E000590B2091ED023091EE02CA01821B930B4F +:1006F0008617970780F0AB014E5F5F4F8417950711 +:1007000050F0420F531F5093EE024093ED02F90157 +:100710006193719302C0E0E0F0E0CF01DF91CF91EF +:100720000895CF93DF93009709F450C0EC0122970E +:100730001B821A82A091EF02B091F002109709F18A +:1007400040E050E0AC17BD0708F1BB83AA83FE016F +:1007500021913191E20FF31FAE17BF0779F48D910C +:100760009C911197280F391F2E5F3F4F39832883A3 +:1007700012968D919C9113979B838A834115510505 +:1007800071F4D093F002C093EF0220C012968D91C5 +:100790009C911397AD01009711F0DC01D3CFFA01C2 +:1007A000D383C28321913191E20FF31FCE17DF076C +:1007B00069F488819981280F391F2E5F3F4FFA0114 +:1007C000318320838A819B8193838283DF91CF91C0 +:1007D0000895FC010590615070400110D8F7809594 +:1007E00090958E0F9F1F0895DC0101C06D934150BD +:1007F0005040E0F70895FC016150704001900110F5 +:10080000D8F7809590958E0F9F1F08950F931F9393 +:10081000CF93DF938C01EB018B8181FF1BC082FFA3 +:100820000DC02E813F818C819D812817390764F48A +:10083000E881F9810193F983E88306C0E885F985A9 +:10084000802F0995892B31F48E819F8101969F839A +:100850008E8302C00FEF1FEFC801DF91CF911F9170 +:100860000F910895FA01AA27283051F1203181F122 +:10087000E8946F936E7F6E5F7F4F8F4F9F4FAF4FA8 +:10088000B1E03ED0B4E03CD0670F781F891F9A1FBB +:10089000A11D680F791F8A1F911DA11D6A0F711D6F +:1008A000811D911DA11D20D009F468943F912AE07B +:1008B000269F11243019305D3193DEF6CF01089563 +:1008C000462F4770405D4193B3E00FD0C9F7F6CF94 +:1008D000462F4F70405D4A3318F0495D31FD40525C +:1008E000419302D0A9F7EACFB4E0A69597958795F2 +:1008F00077956795BA95C9F70097610571050895D1 +:100900009B01AC010A2E069457954795379527957C +:10091000BA95C9F7620F731F841F951FA01D089514 +:100920008AE391E068E049E00E9475070895FF922C +:100930000F931F93CF93DF9380E8E7E4F1E0DF01AB +:100940001D928A95E9F704E610E021C08AE391E060 +:100950006F2D0E94F2078AE391E00E94840880E8EC +:1009600090E00E94D7058AE391E00E947C078AE329 +:1009700091E00E944608882329F088819981019698 +:10098000998388832297FA94BFEFFB16F9F60150FA +:100990001040EFEF0F3F1E0729F0C5E4D2E08FE7CC +:1009A000F82ED4CFC7E4D1E000E011E000D000D0B1 +:1009B000ADB7BEB712961C930E931197899199917A +:1009C0008F70907014969C938E9313970E94D90009 +:1009D0000F900F900F900F90B2E0C734DB0731F704 +:1009E00000D083E091E0EDB7FEB7928381830E944F +:1009F000D9000F900F90DF91CF911F910F91FF9031 +:100A0000089580E895E060E070E00E948D00089510 +:100A10000F931F93CF93DF9384ED92E040E051EE6C +:100A200060E070E00E9454060E94010500D086E05C +:100A300091E0EDB7FEB7928381830E94D9000F90B9 +:100A40000F908AE391E00E944B088AE391E060E016 +:100A50000E94E8078AE391E00E9484088AE391E01B +:100A60000E947C07C0E0D0E000E011E000D000D0A0 +:100A7000EDB7FEB712830183CE0124E095958795EB +:100A80002A95E1F7948383830E94D90021960F90E1 +:100A90000F900F900F90C038D10541F700D083E040 +:100AA00091E0EDB7FEB7928381830E94D900C0E048 +:100AB000D0E00F900F9000D000D0EDB7FEB70183CB +:100AC0001283CE018F709070948383830E94D9002B +:100AD00021960F900F900F900F90C038D10559F7C5 +:100AE00000D083E091E0EDB7FEB7928381830E944E +:100AF000D9000F900F90DF91CF911F910F91089522 +:100B00000F931F93082F84ED92E0602F0E94280717 +:100B1000112707FD1095C8011F910F9108951F928D +:100B20000F920FB60F9211242F933F938F939F93A1 +:100B3000AF93BF9380914B0290914C02A0914D02D4 +:100B4000B0914E0230914F020196A11DB11D232F8D +:100B50002D5F2D3720F02D570196A11DB11D20933B +:100B60004F0280934B0290934C02A0934D02B0939E +:100B70004E028091470290914802A0914902B091A3 +:100B80004A020196A11DB11D80934702909348022D +:100B9000A0934902B0934A02BF91AF919F918F9168 +:100BA0003F912F910F900FBE0F901F9018950197B6 +:100BB00039F0880F991F880F991F02970197F1F755 +:100BC0000895789484B5826084BD84B5816084BDC5 +:100BD00085B5826085BD85B5816085BDEEE6F0E0B6 +:100BE000808181608083E1E8F0E010828081826012 +:100BF0008083808181608083E0E8F0E08081816093 +:100C00008083E1EBF0E0808184608083E0EBF0E0C2 +:100C1000808181608083EAE7F0E080818460808366 +:100C20008081826080838081816080838081806810 +:100C300080831092C10008950E94E1050E9408057A +:100C40000E949704FDCF1F920F920FB60F921124AE +:100C50002F933F934F938F939F93EF93FF934091E5 +:100C6000C600E091D002F091D10231969F012F771A +:100C7000307031978091D2029091D30228173907B2 +:100C800039F0E05BFD4F40833093D1022093D002D6 +:100C9000FF91EF919F918F914F913F912F910F90E5 +:100CA0000FBE0F901F901895AF92BF92DF92EF92F8 +:100CB000FF920F931F93CF93DF93EC017A018B0187 +:100CC000DD24403081EE580780E0680780E0780737 +:100CD00011F0DD24D39491E0A92EB12CE885F9859B +:100CE000DD2069F0C5010A8802C0880F991F0A94A7 +:100CF000E2F7808360E079E08DE390E005C0108248 +:100D000060E874E88EE190E0A80197010E949A09DA +:100D10002150304040405040569547953795279593 +:100D200080E12030380720F0DD2011F0DD24D6CF1F +:100D3000EC81FD813083EE81FF812083EA85FB8594 +:100D4000208141E050E0CA010E8402C0880F991F43 +:100D50000A94E2F7282B2083EA85FB852081CA01CB +:100D60000F8402C0880F991F0A94E2F7282B208372 +:100D7000EA85FB858081088802C0440F551F0A94CC +:100D8000E2F7842B8083DF91CF911F910F91FF9029 +:100D9000EF90DF90BF90AF900895DC011296ED9137 +:100DA000FC911397E058FF4F2191319180819181FF +:100DB000281B390B2F773070C9010895DC0112967A +:100DC000ED91FC911397EE57FF4F20813181929165 +:100DD0008291E058F0408217930719F42FEF3FEF0C +:100DE00005C0E20FF31F8081282F30E0C90108956C +:100DF000DC011296ED91FC911397DF01AE57BF4FC6 +:100E00002D913C911197E058FF4F80819181E058DE +:100E1000F0408217930719F42FEF3FEF0BC0E20F5A +:100E2000F31F80812F5F3F4F2F7730702D933C93BE +:100E3000282F30E0C9010895DC011296ED91FC9154 +:100E40001397EE57FF4F808191819293829308957B +:100E5000FC01A085B18521898C9190E0022E02C011 +:100E6000959587950A94E2F780FFF6CF0484F5857F +:100E7000E02D608308958BE291E09093D5028093FA +:100E8000D40280E592E09093D7028093D60285EC5D +:100E900090E09093D9028093D80284EC90E09093F4 +:100EA000DB028093DA0280EC90E09093DD02809385 +:100EB000DC0281EC90E09093DF028093DE0286EC0E +:100EC00090E09093E1028093E00284E08093E2025C +:100ED00083E08093E30287E08093E40285E08093DF +:100EE000E50281E08093E6020895FC01608341837E +:100EF00080E2828313820895FC01808160E00E9479 +:100F0000CD080895FF920F931F938C01F62E80E079 +:100F10000E94650985E00E946A09F80181816F2DB0 +:100F20000E94CD081F910F91FF9008951F93CF93BA +:100F3000DF93EC0160E070E00E94820781EE8EBDDD +:100F40000DB407FEFDCF1EB5CE0161E070E00E943A +:100F50008207812FDF91CF911F9108951F93CF9327 +:100F6000DF93EC0160E070E00E94820782EE8EBDAC +:100F70000DB407FEFDCF1EB5CE0161E070E00E940A +:100F80008207812FDF91CF911F9108950F931F93B7 +:100F9000CF93DF93EC01162F042F60E070E00E94E6 +:100FA00082071F7110621EBD0DB407FEFDCF1EB576 +:100FB0000EBD0DB407FEFDCF8EB5CE0161E070E031 +:100FC0000E948207812FDF91CF911F910F91089589 +:100FD000662319F061E04FE302C061E040E00E9447 +:100FE000C6070895462F603808F04FE765E00E9475 +:100FF000C6070895EF92FF920F931F93CF93DF934D +:101000007C01162FEA01022F60E070E00E94820747 +:101010001F7110621EBD0DB407FEFDCF1EB508C0C6 +:1010200088818EBD0DB407FEFDCF21968EB501508F +:101030000023B1F7C70161E070E00E948207812FB1 +:10104000DF91CF911F910F91FF90EF9008951F9323 +:10105000CF93DF93EC01162F60E070E00E948207CF +:101060001F711EBD0DB407FEFDCF8EB58FEF8EBD77 +:101070000DB407FEFDCF1EB5CE0161E070E00E9409 +:101080008207812FDF91CF911F91089569E00E941F +:101090002708817008950F931F938C01FC018081B4 +:1010A00061E00E94A708F801818161E00E94A70821 +:1010B000F801808160E00E94CD08C80161E070E025 +:1010C0000E9482070E947B0981E00E945C0980E007 +:1010D0000E94650985E00E946A09C80164E04FEF3B +:1010E0000E94C607C80167E040E70E94C607C80122 +:1010F0000E94AE07C8010E949607C80161E00E94E5 +:10110000F2071F910F9108950F931F938C0160E0D8 +:101110004BE00E94C607C80167E040E70E94C6078F +:10112000A8014B5F5F4FC8016AE025E00E94FA0703 +:10113000C8010E94AE07F801808161E00E94CD08DD +:1011400082E890E00E94D7051F910F910895482FE3 +:1011500050E0CA0186569F4FFC0124914A575F4FC9 +:10116000FA0184918823C1F0E82FF0E0EE0FFF1F11 +:10117000E859FF4FA591B491662341F49FB7F894C5 +:101180008C91209582238C939FBF08959FB7F894EC +:101190008C91822B8C939FBF0895482F50E0CA01F9 +:1011A00082559F4FFC012491CA0186569F4FFC0136 +:1011B00034914A575F4FFA019491992309F444C03E +:1011C000222351F1233071F0243028F42130A1F092 +:1011D000223011F514C02630B1F02730C1F0243090 +:1011E000D9F404C0809180008F7703C08091800083 +:1011F0008F7D8093800010C084B58F7702C084B546 +:101200008F7D84BD09C08091B0008F7703C080912D +:10121000B0008F7D8093B000E92FF0E0EE0FFF1F4C +:10122000EE58FF4FA591B491662341F49FB7F8940F +:101230008C91309583238C939FBF08959FB7F8942A +:101240008C91832B8C939FBF08950F931F93CF9303 +:10125000DF938C01EB0109C02196D801ED91FC913F +:101260000190F081E02DC801099568816623A1F7FE +:10127000DF91CF911F910F910895EF92FF920F93FD +:101280001F93CF93DF938C017B01EA010CC0D70140 +:101290006D917D01D801ED91FC910190F081E02DDF +:1012A000C80109952197209791F7DF91CF911F9160 +:1012B0000F91FF90EF900895882319F48CB5806208 +:1012C00002C08CB58F7D8CBD08959CB5937F982B03 +:1012D0009CBD08952CB5382F33702C7F322B3CBD2C +:1012E0002DB590E0959587959595879581702E7F82 +:1012F000822B8DBD08958DE061E00E94A7088BE0F0 +:1013000061E00E94A7088AE061E00E94A7088DE0E2 +:1013100060E00E94CD088BE060E00E94CD088AE08A +:1013200061E00E94CD088CB580618CBD8CB5806475 +:101330008CBD0895A1E21A2EAA1BBB1BFD010DC096 +:10134000AA1FBB1FEE1FFF1FA217B307E407F50775 +:1013500020F0A21BB30BE40BF50B661F771F881F51 +:10136000991F1A9469F760957095809590959B01E7 +:10137000AC01BD01CF0108952F923F924F925F9231 +:101380006F927F928F929F92AF92BF92CF92DF9295 +:10139000EF92FF920F931F93CF93DF93CDB7DEB7FA +:1013A000CA1BDB0B0FB6F894DEBF0FBECDBF09948E +:1013B0002A88398848885F846E847D848C849B84E5 +:1013C000AA84B984C884DF80EE80FD800C811B81F3 +:1013D000AA81B981CE0FD11D0FB6F894DEBF0FBE22 +:1013E000CDBFED010895EE0FFF1F0590F491E02DA4 +:0613F0000994F894FFCF00 +:1013F6002578000A0D000A0D524632342F657861B1 +:101406006D706C65732F7363616E6E65722F0A0D56 +:10141600002000F102000000000000280725093D19 +:0A14260009CD06F806DE061C0700DB +:00000001FF diff --git a/AVR/lib/RF24/uart.c b/AVR/lib/RF24/uart.c index d9c42df..3bf2b42 100644 --- a/AVR/lib/RF24/uart.c +++ b/AVR/lib/RF24/uart.c @@ -1,651 +1,651 @@ -/************************************************************************* -Title: Interrupt UART library with receive/transmit circular buffers -Author: Peter Fleury http://jump.to/fleury -File: $Id: uart.c,v 1.6.2.2 2009/11/29 08:56:12 Peter Exp $ -Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher -Hardware: any AVR with built-in UART, -License: GNU General Public License - -DESCRIPTION: - An interrupt is generated when the UART has finished transmitting or - receiving a byte. The interrupt handling routines use circular buffers - for buffering received and transmitted data. - - The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define - the buffer size in bytes. Note that these variables must be a - power of 2. - -USAGE: - Refere to the header file uart.h for a description of the routines. - See also example test_uart.c. - -NOTES: - Based on Atmel Application Note AVR306 - -LICENSE: - Copyright (C) 2006 Peter Fleury - - 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 - 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 -#include -#include -#include "uart.h" - - -/* - * constants and macros - */ - -/* size of RX/TX buffers */ -#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) -#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) - -#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) -#error RX buffer size is not a power of 2 -#endif -#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) -#error TX buffer size is not a power of 2 -#endif - -#if defined(__AVR_AT90S2313__) \ - || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ - || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ - || defined(__AVR_ATmega103__) - /* old AVR classic or ATmega103 with one UART */ - #define AT90_UART - #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA - #define UART0_STATUS USR - #define UART0_CONTROL UCR - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) - /* old AVR classic with one UART */ - #define AT90_UART - #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA - #define UART0_STATUS UCSRA - #define UART0_CONTROL UCSRB - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ - || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \ - || defined(__AVR_ATmega323__) - /* ATmega with one USART */ - #define ATMEGA_USART - #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA - #define UART0_STATUS UCSRA - #define UART0_CONTROL UCSRB - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_ATmega163__) - /* ATmega163 with one UART */ - #define ATMEGA_UART - #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA - #define UART0_STATUS UCSRA - #define UART0_CONTROL UCSRB - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_ATmega162__) - /* ATmega with two USART */ - #define ATMEGA_USART0 - #define ATMEGA_USART1 - #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV - #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA - #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 - #define UART1_STATUS UCSR1A - #define UART1_CONTROL UCSR1B - #define UART1_DATA UDR1 - #define UART1_UDRIE UDRIE1 -#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) - /* ATmega with two USART */ - #define ATMEGA_USART0 - #define ATMEGA_USART1 - #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV - #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA - #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 - #define UART1_STATUS UCSR1A - #define UART1_CONTROL UCSR1B - #define UART1_DATA UDR1 - #define UART1_UDRIE UDRIE1 -#elif defined(__AVR_ATmega161__) - /* ATmega with UART */ - #error "AVR ATmega161 currently not supported by this libaray !" -#elif defined(__AVR_ATmega169__) - /* ATmega with one USART */ - #define ATMEGA_USART - #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA - #define UART0_STATUS UCSRA - #define UART0_CONTROL UCSRB - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) - /* ATmega with one USART */ - #define ATMEGA_USART0 - #define UART0_RECEIVE_INTERRUPT USART_RX_vect - #define UART0_TRANSMIT_INTERRUPT USART_TX_vect - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 -#elif defined(__AVR_ATtiny2313__) - #define ATMEGA_USART - #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX - #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE - #define UART0_STATUS UCSRA - #define UART0_CONTROL UCSRB - #define UART0_DATA UDR - #define UART0_UDRIE UDRIE -#elif defined(__AVR_ATmega329__) ||defined(__AVR_ATmega3290__) ||\ - defined(__AVR_ATmega649__) ||defined(__AVR_ATmega6490__) ||\ - defined(__AVR_ATmega325__) ||defined(__AVR_ATmega3250__) ||\ - defined(__AVR_ATmega645__) ||defined(__AVR_ATmega6450__) - /* ATmega with one USART */ - #define ATMEGA_USART0 - #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 -#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) -/* ATmega with two USART */ - #define ATMEGA_USART0 - #define ATMEGA_USART1 - #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV - #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA - #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 - #define UART1_STATUS UCSR1A - #define UART1_CONTROL UCSR1B - #define UART1_DATA UDR1 - #define UART1_UDRIE UDRIE1 -#elif defined(__AVR_ATmega644__) - /* ATmega with one USART */ - #define ATMEGA_USART0 - #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 -#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) - /* ATmega with two USART */ - #define ATMEGA_USART0 - #define ATMEGA_USART1 - #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV - #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV - #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA - #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA - #define UART0_STATUS UCSR0A - #define UART0_CONTROL UCSR0B - #define UART0_DATA UDR0 - #define UART0_UDRIE UDRIE0 - #define UART1_STATUS UCSR1A - #define UART1_CONTROL UCSR1B - #define UART1_DATA UDR1 - #define UART1_UDRIE UDRIE1 -#else - #error "no UART definition for MCU available" -#endif - - -/* - * module global variables - */ -static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; -static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; -static volatile unsigned char UART_TxHead; -static volatile unsigned char UART_TxTail; -static volatile unsigned char UART_RxHead; -static volatile unsigned char UART_RxTail; -static volatile unsigned char UART_LastRxError; - -#if defined( ATMEGA_USART1 ) -static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; -static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; -static volatile unsigned char UART1_TxHead; -static volatile unsigned char UART1_TxTail; -static volatile unsigned char UART1_RxHead; -static volatile unsigned char UART1_RxTail; -static volatile unsigned char UART1_LastRxError; -#endif - - - -ISR(UART0_RECEIVE_INTERRUPT) -/************************************************************************* -Function: UART Receive Complete interrupt -Purpose: called when the UART has received a character -**************************************************************************/ -{ - unsigned char tmphead; - unsigned char data; - unsigned char usr; - unsigned char lastRxError; - - - /* read UART status register and UART data register */ - usr = UART0_STATUS; - data = UART0_DATA; - - /* */ -#if defined( AT90_UART ) - lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); -#elif defined( ATMEGA_USART ) - lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); -#elif defined( ATMEGA_USART0 ) - lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); -#elif defined ( ATMEGA_UART ) - lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); -#endif - - /* calculate buffer index */ - tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; - - if ( tmphead == UART_RxTail ) { - /* error: receive buffer overflow */ - lastRxError = UART_BUFFER_OVERFLOW >> 8; - }else{ - /* store new index */ - UART_RxHead = tmphead; - /* store received data in buffer */ - UART_RxBuf[tmphead] = data; - } - UART_LastRxError = lastRxError; -} - - -ISR(UART0_TRANSMIT_INTERRUPT) -/************************************************************************* -Function: UART Data Register Empty interrupt -Purpose: called when the UART is ready to transmit the next byte -**************************************************************************/ -{ - unsigned char tmptail; - - - if ( UART_TxHead != UART_TxTail) { - /* calculate and store new buffer index */ - tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; - UART_TxTail = tmptail; - /* get one byte from buffer and write it to UART */ - UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ - }else{ - /* tx buffer empty, disable UDRE interrupt */ - UART0_CONTROL &= ~_BV(UART0_UDRIE); - } -} - - -/************************************************************************* -Function: uart_init() -Purpose: initialize UART and set baudrate -Input: baudrate using macro UART_BAUD_SELECT() -Returns: none -**************************************************************************/ -void uart_init(unsigned int baudrate) -{ - UART_TxHead = 0; - UART_TxTail = 0; - UART_RxHead = 0; - UART_RxTail = 0; - -#if defined( AT90_UART ) - /* set baud rate */ - UBRR = (unsigned char)baudrate; - - /* enable UART receiver and transmmitter and receive complete interrupt */ - UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); - -#elif defined (ATMEGA_USART) - /* Set baud rate */ - if ( baudrate & 0x8000 ) - { - UART0_STATUS = (1<>8); - UBRRL = (unsigned char) baudrate; - - /* Enable USART receiver and transmitter and receive complete interrupt */ - UART0_CONTROL = _BV(RXCIE)|(1<>8); - UBRR0L = (unsigned char) baudrate; - - /* Enable USART receiver and transmitter and receive complete interrupt */ - UART0_CONTROL = _BV(RXCIE0)|(1<>8); - UBRR = (unsigned char) baudrate; - - /* Enable UART receiver and transmitter and receive complete interrupt */ - UART0_CONTROL = _BV(RXCIE)|(1<> 8; - }else{ - /* store new index */ - UART1_RxHead = tmphead; - /* store received data in buffer */ - UART1_RxBuf[tmphead] = data; - } - UART1_LastRxError = lastRxError; -} - - -ISR(UART1_TRANSMIT_INTERRUPT) -/************************************************************************* -Function: UART1 Data Register Empty interrupt -Purpose: called when the UART1 is ready to transmit the next byte -**************************************************************************/ -{ - unsigned char tmptail; - - - if ( UART1_TxHead != UART1_TxTail) { - /* calculate and store new buffer index */ - tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; - UART1_TxTail = tmptail; - /* get one byte from buffer and write it to UART */ - UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ - }else{ - /* tx buffer empty, disable UDRE interrupt */ - UART1_CONTROL &= ~_BV(UART1_UDRIE); - } -} - - -/************************************************************************* -Function: uart1_init() -Purpose: initialize UART1 and set baudrate -Input: baudrate using macro UART_BAUD_SELECT() -Returns: none -**************************************************************************/ -void uart1_init(unsigned int baudrate) -{ - UART1_TxHead = 0; - UART1_TxTail = 0; - UART1_RxHead = 0; - UART1_RxTail = 0; - - - /* Set baud rate */ - if ( baudrate & 0x8000 ) - { - UART1_STATUS = (1<>8); - UBRR1L = (unsigned char) baudrate; - - /* Enable USART receiver and transmitter and receive complete interrupt */ - UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.c,v 1.6.2.2 2009/11/29 08:56:12 Peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + 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 +#include +#include +#include "uart.h" + + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_TX_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) ||defined(__AVR_ATmega3290__) ||\ + defined(__AVR_ATmega649__) ||defined(__AVR_ATmega6490__) ||\ + defined(__AVR_ATmega325__) ||defined(__AVR_ATmega3250__) ||\ + defined(__AVR_ATmega645__) ||defined(__AVR_ATmega6450__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#else + #error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +ISR(UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#endif + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError = lastRxError; +} + + +ISR(UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART_TxHead != UART_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV(UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart_init(unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char)baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART0_STATUS = (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError = lastRxError; +} + + +ISR(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury -File: $Id: uart.h,v 1.8.2.1 2007/07/01 11:14:38 peter Exp $ -Software: AVR-GCC 4.1, AVR Libc 1.4 -Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz -License: GNU General Public License -Usage: see Doxygen manual - -LICENSE: - Copyright (C) 2006 Peter Fleury - - 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 - 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. - -************************************************************************/ - -/** - * @defgroup pfleury_uart UART Library - * @code #include @endcode - * - * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. - * - * This library can be used to transmit and receive data through the built in UART. - * - * An interrupt is generated when the UART has finished transmitting or - * receiving a byte. The interrupt handling routines use circular buffers - * for buffering received and transmitted data. - * - * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define - * the size of the circular buffers in bytes. Note that these constants must be a power of 2. - * You may need to adapt this constants to your target and your application by adding - * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. - * - * @note Based on Atmel Application Note AVR306 - * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury - */ - -/**@{*/ - - -#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 -#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" -#endif - - -/* -** constants and macros -*/ - -/** @brief UART Baudrate Expression - * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz - * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 - */ -#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) - -/** @brief UART Baudrate Expression for ATmega double speed mode - * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz - * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 - */ -#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000) - - -/** Size of the circular receive buffer, must be power of 2 */ -#ifndef UART_RX_BUFFER_SIZE -#define UART_RX_BUFFER_SIZE 32 -#endif -/** Size of the circular transmit buffer, must be power of 2 */ -#ifndef UART_TX_BUFFER_SIZE -#define UART_TX_BUFFER_SIZE 32 -#endif - -/* test if the size of the circular buffers fits into SRAM */ -#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) -#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" -#endif - -/* -** high byte error return code of uart_getc() -*/ -#define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ -#define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ -#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ -#define UART_NO_DATA 0x0100 /* no receive data available */ - - -/* -** function prototypes -*/ - -/** - @brief Initialize UART and set baudrate - @param baudrate Specify baudrate using macro UART_BAUD_SELECT() - @return none -*/ -extern void uart_init(unsigned int baudrate); - - -/** - * @brief Get received byte from ringbuffer - * - * Returns in the lower byte the received character and in the - * higher byte the last receive error. - * UART_NO_DATA is returned when no data is available. - * - * @param void - * @return lower byte: received byte from ringbuffer - * @return higher byte: last receive status - * - \b 0 successfully received data from UART - * - \b UART_NO_DATA - *
no receive data available - * - \b UART_BUFFER_OVERFLOW - *
Receive ringbuffer overflow. - * We are not reading the receive buffer fast enough, - * one or more received character have been dropped - * - \b UART_OVERRUN_ERROR - *
Overrun condition by UART. - * A character already present in the UART UDR register was - * not read by the interrupt handler before the next character arrived, - * one or more received characters have been dropped. - * - \b UART_FRAME_ERROR - *
Framing Error by UART - */ -extern unsigned int uart_getc(void); - - -/** - * @brief Put byte to ringbuffer for transmitting via UART - * @param data byte to be transmitted - * @return none - */ -extern void uart_putc(unsigned char data); - - -/** - * @brief Put string to ringbuffer for transmitting via UART - * - * The string is buffered by the uart library in a circular buffer - * and one character at a time is transmitted to the UART using interrupts. - * Blocks if it can not write the whole string into the circular buffer. - * - * @param s string to be transmitted - * @return none - */ -extern void uart_puts(const char *s ); - - -/** - * @brief Put string from program memory to ringbuffer for transmitting via UART. - * - * The string is buffered by the uart library in a circular buffer - * and one character at a time is transmitted to the UART using interrupts. - * Blocks if it can not write the whole string into the circular buffer. - * - * @param s program memory string to be transmitted - * @return none - * @see uart_puts_P - */ -extern void uart_puts_p(const char *s ); - -/** - * @brief Macro to automatically put a string constant into program memory - */ -#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) - - - -/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ -extern void uart1_init(unsigned int baudrate); -/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ -extern unsigned int uart1_getc(void); -/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ -extern void uart1_putc(unsigned char data); -/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ -extern void uart1_puts(const char *s ); -/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ -extern void uart1_puts_p(const char *s ); -/** @brief Macro to automatically put a string constant into program memory */ -#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) - -/**@}*/ - -#include "uart.c" -#endif // UART_H - +#ifndef UART_H +#define UART_H +/************************************************************************ +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.h,v 1.8.2.1 2007/07/01 11:14:38 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4 +Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz +License: GNU General Public License +Usage: see Doxygen manual + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + 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. + +************************************************************************/ + +/** + * @defgroup pfleury_uart UART Library + * @code #include @endcode + * + * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. + * + * This library can be used to transmit and receive data through the built in UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define + * the size of the circular buffers in bytes. Note that these constants must be a power of 2. + * You may need to adapt this constants to your target and your application by adding + * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + */ + +/**@{*/ + + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + + +/* +** constants and macros +*/ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000) + + +/** Size of the circular receive buffer, must be power of 2 */ +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 32 +#endif +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 32 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) +#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was + * not read by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ +extern void uart1_init(unsigned int baudrate); +/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ +extern unsigned int uart1_getc(void); +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ +extern void uart1_putc(unsigned char data); +/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ +extern void uart1_puts(const char *s ); +/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ +extern void uart1_puts_p(const char *s ); +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + +#include "uart.c" +#endif // UART_H + diff --git a/AVR/lib/Vera/VeraAVR.c b/AVR/lib/Vera/VeraAVR.c index 3bfcb43..564cf05 100644 --- a/AVR/lib/Vera/VeraAVR.c +++ b/AVR/lib/Vera/VeraAVR.c @@ -1,252 +1,252 @@ -/* - Vera Arduino library is used to communicate sensor data to your Vera receiver sketch using RF24 library. - The maximum amount of transferrable data is 336 characters from a sensor to receiver. - - Created by Henrik Ekblad - Version 1.0 - - 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. - - modification by axillent@gmail.com to run on pure AVR - */ - -#include "VeraAVR.h" -#include -#include -#include - -uint8_t ee_radio_id EEMEM = 255; - -struct { - uint16_t radioId; - uint16_t relayId; - message_s msg; // Buffer for incoming messages. - char convBuffer[20]; -} _veraavr_data; - -/*uint8_t VeraAVR_eeprom_radioid() { - return eeprom_read_byte(&ee_radio_id); -}*/ -/*static void VeraAVR_delay_ms(uint16_t delay) { - for(; delay >= 50; delay -= 50) { - _delay_ms(50); - wdt_reset(); - } - wdt_reset(); -}*/ - -void VeraAVR_begin(uint16_t _radioId) { - VeraAVR_begin2(_radioId, GATEWAY_ADDRESS); -} - -void VeraAVR_begin2(uint16_t _radioId, uint16_t _relayId) { - _veraavr_data.radioId = _radioId; - _veraavr_data.relayId = _relayId; - // Start up the radio library - nrf24_begin(); - nrf24_enableDynamicPayloads(); - nrf24_setAutoAck(1) ; - nrf24_setRetries(15, 15); - nrf24_setChannel(VERA_CHANNEL); - nrf24_setDataRate(RF24_1MBPS); - nrf24_setCRCLength(RF24_CRC_16); - if (_veraavr_data.radioId == GATEWAY_ADDRESS) { - nrf24_openReadingPipe(1, BASE_RADIO_ID); - } else { - if (_veraavr_data.radioId == AUTO) { - _veraavr_data.radioId = eeprom_read_byte(&ee_radio_id); - if (_veraavr_data.radioId == 0xFFF || _veraavr_data.radioId == 0x00) { - // No radio id has been fetched yet. EEPROM is unwritten. - // Request new id from Vera. Use radio address 255 temporarily. - //nrf24_openReadingPipe(0,0); // Don't listen to other nodes - nrf24_openReadingPipe(1, BASE_RADIO_ID+_veraavr_data.radioId); - nrf24_openWritingPipe(BASE_RADIO_ID); - _veraavr_data.radioId = atoi(VeraAVR_getConfiguration(V_REQUEST_ID)); - // Write id to EEPROM - if (_veraavr_data.radioId == AUTO) { // Vera will return 255 if all sensor id are taken - // wait a minute before possible wdt reset - for(uint8_t i=0; i < 120; i++) { - wdt_reset(); - _delay_ms(500); - } - // wait for a while ot until wdt reset - while (1) {} - } else { - eeprom_write_byte(&ee_radio_id, _veraavr_data.radioId); - } - } - } - //eeprom_write_byte(&ee_radio_id, _veraavr_data.radioId); - nrf24_openReadingPipe(1, BASE_RADIO_ID+_veraavr_data.radioId); - } - nrf24_startListening(); - wdt_reset(); -} - -uint8_t VeraAVR_sendDataGW(uint8_t childId, messageType messageType, uint8_t type, const char *data) { - return VeraAVR_sendData(_veraavr_data.radioId, _veraavr_data.relayId, GATEWAY_ADDRESS, childId, messageType, type, data); -} - -uint8_t VeraAVR_sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data) { - uint8_t ok = 0; - if (strlen(data) < sizeof(_veraavr_data.msg.data)) { - _veraavr_data.msg.header.version = PROTOCOL_VERSION; - _veraavr_data.msg.header.binary = 0; - _veraavr_data.msg.header.from = from; - _veraavr_data.msg.header.to = to; - _veraavr_data.msg.header.childId = childId; - _veraavr_data.msg.header.messageType = messageType; - _veraavr_data.msg.header.type = type; - - strncpy(_veraavr_data.msg.data, data, sizeof(_veraavr_data.msg.data)-1); - _veraavr_data.msg.header.crc = VeraAVR_crc8Message(_veraavr_data.msg); - - - nrf24_stopListening(); - nrf24_openWritingPipe(BASE_RADIO_ID + next); - uint8_t retry = 5; - do { - ok = nrf24_write(&_veraavr_data.msg, min(MAX_MESSAGE_LENGTH, sizeof(_veraavr_data.msg.header) + strlen(_veraavr_data.msg.data) + 1)); - wdt_reset(); - } - while ( !ok && --retry ); - nrf24_startListening(); - } - return ok; -} - -void VeraAVR_sendVariable_char(uint8_t childId, uint8_t variableType, - const char *value) { - VeraAVR_sendDataGW(childId, M_VARIABLE, variableType, value); -} - -void VeraAVR_sendVariable_float(uint8_t childId, uint8_t variableType, float value, int decimals) { - VeraAVR_sendVariable_char(childId, variableType, dtostrf(value,2,decimals,_veraavr_data.convBuffer)); -} - -void VeraAVR_sendVariable_int(uint8_t childId, uint8_t variableType, int value) { - VeraAVR_sendVariable_char(childId, variableType, itoa(value, _veraavr_data.convBuffer, 10)); -} -void VeraAVR_sendVariable_long(uint8_t childId, uint8_t variableType, long value) { - VeraAVR_sendVariable_char(childId, variableType, ltoa(value, _veraavr_data.convBuffer, 10)); -} - -void VeraAVR_requestStatus(uint8_t childId, uint8_t variableType) { - VeraAVR_sendDataGW(childId, M_STATUS, variableType, ""); -} - -char* VeraAVR_getStatus(uint8_t childId, uint8_t variableType) { - while (1) { - VeraAVR_requestStatus(childId, variableType); - uint8_t i = 0; - while (i < 100) { // 5 seconds timeout before re-sending status request - while (VeraAVR_messageAvailable()) { - // Check that it is right type of message and not a routing message - if ((_veraavr_data.msg.header.messageType == M_REQUEST_STATUS_RESPONSE) && - (_veraavr_data.msg.header.type == variableType) && - (_veraavr_data.msg.header.to == childId)) { - return _veraavr_data.msg.data; - } - } - _delay_ms(50); - wdt_reset(); - i++; - } - } - return NULL; -} - -void VeraAVR_requestConfiguration(uint8_t variableType) { - VeraAVR_requestStatus(NODE_CHILD_ID, variableType); -} - -char* VeraAVR_getConfiguration(uint8_t variableType) { - return VeraAVR_getStatus(NODE_CHILD_ID, variableType); -} - -unsigned long VeraAVR_getTime() { - return atol(VeraAVR_getConfiguration(V_TIME)); -} - -void VeraAVR_sendSensorPresentation(uint8_t childId, uint8_t sensorType) { - VeraAVR_sendDataGW(childId, M_PRESENTATION, sensorType, LIBRARY_VERSION); -} - - -uint8_t VeraAVR_messageAvailable() { - while (nrf24_available()) { - VeraAVR_readMessage(); - // Check that message was addressed for me. Could be a message from some other sensor - // as we«re automatically listening to pipe 0 (our writing pipe) where all sensors - // send their data - if (_veraavr_data.msg.header.to == _veraavr_data.radioId && VeraAVR_validate() == VALIDATE_OK) - return 1; - wdt_reset(); - } - return 0; -} - - -message_s VeraAVR_waitForMessage() { - while (1) { - if (VeraAVR_messageAvailable()) { - return _veraavr_data.msg; - } - wdt_reset(); - } -} - -message_s VeraAVR_getMessage() { - return _veraavr_data.msg; -} - - -message_s VeraAVR_readMessage() { - uint8_t len = nrf24_getDynamicPayloadSize(); - //uint8_t done = - nrf24_read(&_veraavr_data.msg, len); - // Make sure string gets terminated ok. - _veraavr_data.msg.data[sizeof(_veraavr_data.msg.data)-1] = '\0'; - return _veraavr_data.msg; -} - -/* - * calculate CRC8 on message_s data taking care of data structure and protocol version - */ -uint8_t VeraAVR_crc8Message(message_s var_msg) { - struct { - message_s msg; - uint8_t protocol_version; - } crc_data; - memcpy(&crc_data, &var_msg, sizeof(var_msg)); - crc_data.protocol_version = PROTOCOL_VERSION; - // some clean up needed for repeated result - crc_data.msg.header.crc = 0; - // fill unused space by zeroes for string data only - if(!crc_data.msg.header.binary) { - uint8_t len = strlen(crc_data.msg.data); - if(len < sizeof(crc_data.msg.data)-1) { - memset(&crc_data.msg.data[len], 0, sizeof(crc_data.msg.data) - 1 - len); - } - } - return crc8((uint8_t*)&crc_data, (uint8_t)sizeof(crc_data)); -} -/* - * true if message is consistent * - */ -uint8_t VeraAVR_checkCRCMessage(message_s var_msg) { - return (var_msg.header.crc == VeraAVR_crc8Message(var_msg))?1:0; -} -uint8_t VeraAVR_checkCRC() { - return VeraAVR_checkCRCMessage(_veraavr_data.msg); -} - -uint8_t VeraAVR_validate() { - uint8_t crc_check = VeraAVR_checkCRC(); - uint8_t version_check = (_veraavr_data.msg.header.version == PROTOCOL_VERSION); - if(crc_check && version_check) return VALIDATE_OK; - if(!crc_check) return VALIDATE_BAD_CRC; - return VALIDATE_BAD_VERSION; -} +/* + Vera Arduino library is used to communicate sensor data to your Vera receiver sketch using RF24 library. + The maximum amount of transferrable data is 336 characters from a sensor to receiver. + + Created by Henrik Ekblad + Version 1.0 + + 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. + + modification by axillent@gmail.com to run on pure AVR + */ + +#include "VeraAVR.h" +#include +#include +#include + +uint8_t ee_radio_id EEMEM = 255; + +struct { + uint16_t radioId; + uint16_t relayId; + message_s msg; // Buffer for incoming messages. + char convBuffer[20]; +} _veraavr_data; + +/*uint8_t VeraAVR_eeprom_radioid() { + return eeprom_read_byte(&ee_radio_id); +}*/ +/*static void VeraAVR_delay_ms(uint16_t delay) { + for(; delay >= 50; delay -= 50) { + _delay_ms(50); + wdt_reset(); + } + wdt_reset(); +}*/ + +void VeraAVR_begin(uint16_t _radioId) { + VeraAVR_begin2(_radioId, GATEWAY_ADDRESS); +} + +void VeraAVR_begin2(uint16_t _radioId, uint16_t _relayId) { + _veraavr_data.radioId = _radioId; + _veraavr_data.relayId = _relayId; + // Start up the radio library + nrf24_begin(); + nrf24_enableDynamicPayloads(); + nrf24_setAutoAck(1) ; + nrf24_setRetries(15, 15); + nrf24_setChannel(VERA_CHANNEL); + nrf24_setDataRate(RF24_1MBPS); + nrf24_setCRCLength(RF24_CRC_16); + if (_veraavr_data.radioId == GATEWAY_ADDRESS) { + nrf24_openReadingPipe(1, BASE_RADIO_ID); + } else { + if (_veraavr_data.radioId == AUTO) { + _veraavr_data.radioId = eeprom_read_byte(&ee_radio_id); + if (_veraavr_data.radioId == 0xFFF || _veraavr_data.radioId == 0x00) { + // No radio id has been fetched yet. EEPROM is unwritten. + // Request new id from Vera. Use radio address 255 temporarily. + //nrf24_openReadingPipe(0,0); // Don't listen to other nodes + nrf24_openReadingPipe(1, BASE_RADIO_ID+_veraavr_data.radioId); + nrf24_openWritingPipe(BASE_RADIO_ID); + _veraavr_data.radioId = atoi(VeraAVR_getConfiguration(V_REQUEST_ID)); + // Write id to EEPROM + if (_veraavr_data.radioId == AUTO) { // Vera will return 255 if all sensor id are taken + // wait a minute before possible wdt reset + for(uint8_t i=0; i < 120; i++) { + wdt_reset(); + _delay_ms(500); + } + // wait for a while ot until wdt reset + while (1) {} + } else { + eeprom_write_byte(&ee_radio_id, _veraavr_data.radioId); + } + } + } + //eeprom_write_byte(&ee_radio_id, _veraavr_data.radioId); + nrf24_openReadingPipe(1, BASE_RADIO_ID+_veraavr_data.radioId); + } + nrf24_startListening(); + wdt_reset(); +} + +uint8_t VeraAVR_sendDataGW(uint8_t childId, messageType messageType, uint8_t type, const char *data) { + return VeraAVR_sendData(_veraavr_data.radioId, _veraavr_data.relayId, GATEWAY_ADDRESS, childId, messageType, type, data); +} + +uint8_t VeraAVR_sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data) { + uint8_t ok = 0; + if (strlen(data) < sizeof(_veraavr_data.msg.data)) { + _veraavr_data.msg.header.version = PROTOCOL_VERSION; + _veraavr_data.msg.header.binary = 0; + _veraavr_data.msg.header.from = from; + _veraavr_data.msg.header.to = to; + _veraavr_data.msg.header.childId = childId; + _veraavr_data.msg.header.messageType = messageType; + _veraavr_data.msg.header.type = type; + + strncpy(_veraavr_data.msg.data, data, sizeof(_veraavr_data.msg.data)-1); + _veraavr_data.msg.header.crc = VeraAVR_crc8Message(_veraavr_data.msg); + + + nrf24_stopListening(); + nrf24_openWritingPipe(BASE_RADIO_ID + next); + uint8_t retry = 5; + do { + ok = nrf24_write(&_veraavr_data.msg, min(MAX_MESSAGE_LENGTH, sizeof(_veraavr_data.msg.header) + strlen(_veraavr_data.msg.data) + 1)); + wdt_reset(); + } + while ( !ok && --retry ); + nrf24_startListening(); + } + return ok; +} + +void VeraAVR_sendVariable_char(uint8_t childId, uint8_t variableType, + const char *value) { + VeraAVR_sendDataGW(childId, M_VARIABLE, variableType, value); +} + +void VeraAVR_sendVariable_float(uint8_t childId, uint8_t variableType, float value, int decimals) { + VeraAVR_sendVariable_char(childId, variableType, dtostrf(value,2,decimals,_veraavr_data.convBuffer)); +} + +void VeraAVR_sendVariable_int(uint8_t childId, uint8_t variableType, int value) { + VeraAVR_sendVariable_char(childId, variableType, itoa(value, _veraavr_data.convBuffer, 10)); +} +void VeraAVR_sendVariable_long(uint8_t childId, uint8_t variableType, long value) { + VeraAVR_sendVariable_char(childId, variableType, ltoa(value, _veraavr_data.convBuffer, 10)); +} + +void VeraAVR_requestStatus(uint8_t childId, uint8_t variableType) { + VeraAVR_sendDataGW(childId, M_STATUS, variableType, ""); +} + +char* VeraAVR_getStatus(uint8_t childId, uint8_t variableType) { + while (1) { + VeraAVR_requestStatus(childId, variableType); + uint8_t i = 0; + while (i < 100) { // 5 seconds timeout before re-sending status request + while (VeraAVR_messageAvailable()) { + // Check that it is right type of message and not a routing message + if ((_veraavr_data.msg.header.messageType == M_REQUEST_STATUS_RESPONSE) && + (_veraavr_data.msg.header.type == variableType) && + (_veraavr_data.msg.header.to == childId)) { + return _veraavr_data.msg.data; + } + } + _delay_ms(50); + wdt_reset(); + i++; + } + } + return NULL; +} + +void VeraAVR_requestConfiguration(uint8_t variableType) { + VeraAVR_requestStatus(NODE_CHILD_ID, variableType); +} + +char* VeraAVR_getConfiguration(uint8_t variableType) { + return VeraAVR_getStatus(NODE_CHILD_ID, variableType); +} + +unsigned long VeraAVR_getTime() { + return atol(VeraAVR_getConfiguration(V_TIME)); +} + +void VeraAVR_sendSensorPresentation(uint8_t childId, uint8_t sensorType) { + VeraAVR_sendDataGW(childId, M_PRESENTATION, sensorType, LIBRARY_VERSION); +} + + +uint8_t VeraAVR_messageAvailable() { + while (nrf24_available()) { + VeraAVR_readMessage(); + // Check that message was addressed for me. Could be a message from some other sensor + // as we«re automatically listening to pipe 0 (our writing pipe) where all sensors + // send their data + if (_veraavr_data.msg.header.to == _veraavr_data.radioId && VeraAVR_validate() == VALIDATE_OK) + return 1; + wdt_reset(); + } + return 0; +} + + +message_s VeraAVR_waitForMessage() { + while (1) { + if (VeraAVR_messageAvailable()) { + return _veraavr_data.msg; + } + wdt_reset(); + } +} + +message_s VeraAVR_getMessage() { + return _veraavr_data.msg; +} + + +message_s VeraAVR_readMessage() { + uint8_t len = nrf24_getDynamicPayloadSize(); + //uint8_t done = + nrf24_read(&_veraavr_data.msg, len); + // Make sure string gets terminated ok. + _veraavr_data.msg.data[sizeof(_veraavr_data.msg.data)-1] = '\0'; + return _veraavr_data.msg; +} + +/* + * calculate CRC8 on message_s data taking care of data structure and protocol version + */ +uint8_t VeraAVR_crc8Message(message_s var_msg) { + struct { + message_s msg; + uint8_t protocol_version; + } crc_data; + memcpy(&crc_data, &var_msg, sizeof(var_msg)); + crc_data.protocol_version = PROTOCOL_VERSION; + // some clean up needed for repeated result + crc_data.msg.header.crc = 0; + // fill unused space by zeroes for string data only + if(!crc_data.msg.header.binary) { + uint8_t len = strlen(crc_data.msg.data); + if(len < sizeof(crc_data.msg.data)-1) { + memset(&crc_data.msg.data[len], 0, sizeof(crc_data.msg.data) - 1 - len); + } + } + return crc8((uint8_t*)&crc_data, (uint8_t)sizeof(crc_data)); +} +/* + * true if message is consistent * + */ +uint8_t VeraAVR_checkCRCMessage(message_s var_msg) { + return (var_msg.header.crc == VeraAVR_crc8Message(var_msg))?1:0; +} +uint8_t VeraAVR_checkCRC() { + return VeraAVR_checkCRCMessage(_veraavr_data.msg); +} + +uint8_t VeraAVR_validate() { + uint8_t crc_check = VeraAVR_checkCRC(); + uint8_t version_check = (_veraavr_data.msg.header.version == PROTOCOL_VERSION); + if(crc_check && version_check) return VALIDATE_OK; + if(!crc_check) return VALIDATE_BAD_CRC; + return VALIDATE_BAD_VERSION; +} diff --git a/AVR/lib/Vera/VeraAVR.h b/AVR/lib/Vera/VeraAVR.h index befa07c..f6fb3a9 100644 --- a/AVR/lib/Vera/VeraAVR.h +++ b/AVR/lib/Vera/VeraAVR.h @@ -1,157 +1,157 @@ -/* - Vera Arduino library is used to communicate sensor data to your Vera receiver sketch using RF24 library. - - Created by Henrik Ekblad - Version 1.0 - - 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. - - modification by axillent@gmail.com to run on pure AVR - - before running this you need to configure properly RF24-avrlib -*/ - -#ifndef Vera_h -#define Vera_h - -#include -#include -#include -#include - -#define LIBRARY_VERSION "1.2+" -#define PROTOCOL_VERSION 1 -#define BAUD_RATE 115200 -#define AUTO 0xFFF // Id 4095 is reserved for auto initialization of radioId. -#define NODE_CHILD_ID 0xFF // Node child id is always created for when a new sensor is detected - -#define VERA_CHANNEL 76 - -// This is the radioId for Vera receiver sketch (where all sensors should send their data). -// This is also act as base value for sensor radioId -#define BASE_RADIO_ID 0xABCDABC000LL -#define GATEWAY_ADDRESS ((uint16_t)0) - -#define MAX_MESSAGE_LENGTH 32 - -#define CRC8INIT 0x00 -#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 - -typedef enum { M_PRESENTATION = 0, M_VARIABLE, M_STATUS, M_CUSTOM, M_GATEWAY_MESSAGE, M_REQUEST_STATUS_RESPONSE } messageType; - -// Adding new variable- and device types should be done at the end of enum -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_BATTERY_LEVEL, V_BATTERY_DATE, - V_ARMED, V_TRIPPED, V_LAST_TRIP, 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_TIME, V_VERSION, - V_REQUEST_ID, V_INCLUSION_MODE, V_INCLUSION_COUNT, V_INCLUSION_RESULT, V_NEIGHBORS, - V_RELAY_MODE, V_LAST_UPDATE} variable; - -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} senosr; - -// result of validate() -enum { VALIDATE_OK=0, VALIDATE_BAD_CRC, VALIDATE_BAD_VERSION }; - - -typedef struct { - uint8_t crc : 8; // 8 bits crc - uint8_t version : 3; // 3 bits protocol version - uint8_t binary : 1; // 1 bit. Data is binary and should be encoded when sent to vera - uint16_t from : 12; // 12 bits. RadioId of sender node - uint16_t to : 12; // 12 bits. RadioId of destination node - uint8_t childId : 8; // 1 byte. Up to MAX_CHILD_DEVICES child sensors per radioId - uint8_t messageType : 4; // 4 bits. Type of message. See messageType - uint8_t type : 8; // 8 bits. variableType or deviceType depending on messageType -} header_s; - -typedef struct { - header_s header; - char data[MAX_MESSAGE_LENGTH - sizeof(header_s) + 1]; // Each message can transfer a payload. Add one extra byte for \0 -} message_s; - - - -/** -* Begin operation of the vera library -* -* Call this in setup(), before calling any other vera library methods. -*/ -void VeraAVR_begin(uint16_t _radioId); -void VeraAVR_begin2(uint16_t _radioId, uint16_t _relayId); - -/** -* Sends a variable change to vera -* -* @param childId The child id for which to update variable. Value can be 0-127. -* @param variableType The variableType to update -* @param value New value of the variable -*/ -void VeraAVR_sendVariable_char (uint8_t childId, uint8_t variableType, const char *value); -void VeraAVR_sendVariable_float (uint8_t childId, uint8_t variableType, float value, int decimals); -void VeraAVR_sendVariable_long(uint8_t childId, uint8_t variableType, long value); -void VeraAVR_sendVariable_int(uint8_t childId, uint8_t variableType, int value); - -/** -* Requests status for a vera variable (sent from an actuator) -* -* @param childId The unique child id for the different sensors connected to this arduino. 0-127. -* @param variableType The variableType to update -*/ -void VeraAVR_requestStatus (uint8_t childId, uint8_t variableType); - -/** -* Requests configuration parameter -* -* @param variableType The variableType to fetch -*/ -void VeraAVR_requestConfiguration(uint8_t variableType); -char * VeraAVR_getConfiguration(uint8_t variableType); -/** - * Fetches time from vera - */ -unsigned long VeraAVR_getTime(); -/* -* The arduino must send a presentation of all the sensors connected before any variable changes will be registrered on Vera side. -* Usually it's good to present all sensors when Arduino starts up (setup). -* Waits until all data has been transmitted and acknowledged by Vera receiver (retries RESEND_PRESENTATION times). -* -* @param childId The unique child id for the different sensors connected to this arduino. 0-254. -* @param sensorType Sensor types to create. They will be numbered from 0 up to 127. -*/ -void VeraAVR_sendSensorPresentation (uint8_t childId, uint8_t sensorType); - -/** -* Registers this arduino device as a relay. This requires this node to call -* api methods regularly to relay messages that could be passing this node and -* answer to any neighbor-discovery messages. -* Basically all api methods relays messages (waitForMessage, messageAvailable, ..) -* When this method is called vera will be informed that this node acts as relay. -*/ -void VeraAVR_registerNodeAsRelay(); -/** -* Busy waits until there is a message available to be read (used for actuators, like relays) -*/ -message_s VeraAVR_waitForVeraMessage(void); -/** -* Returns true if there is a message addressed for this node is available to be read (used by VeraGateway) -*/ -uint8_t VeraAVR_messageAvailable(); - /** - * Returns the last received message - */ -message_s VeraAVR_getMessage(); -uint8_t sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data); -uint8_t VeraAVR_validate(); -uint8_t VeraAVR_crc8Message(message_s); -uint8_t VeraAVR_checkCRCMessage(message_s); -uint8_t VeraAVR_checkCRC(); -message_s VeraAVR_readMessage(void); -uint8_t VeraAVR_sendDataGW(uint8_t childId, messageType messageType, uint8_t type, const char *data); -uint8_t VeraAVR_sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data); - -#include "VeraAVR.c" - -#endif +/* + Vera Arduino library is used to communicate sensor data to your Vera receiver sketch using RF24 library. + + Created by Henrik Ekblad + Version 1.0 + + 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. + + modification by axillent@gmail.com to run on pure AVR + + before running this you need to configure properly RF24-avrlib +*/ + +#ifndef Vera_h +#define Vera_h + +#include +#include +#include +#include + +#define LIBRARY_VERSION "1.2+" +#define PROTOCOL_VERSION 1 +#define BAUD_RATE 115200 +#define AUTO 0xFFF // Id 4095 is reserved for auto initialization of radioId. +#define NODE_CHILD_ID 0xFF // Node child id is always created for when a new sensor is detected + +#define VERA_CHANNEL 76 + +// This is the radioId for Vera receiver sketch (where all sensors should send their data). +// This is also act as base value for sensor radioId +#define BASE_RADIO_ID 0xABCDABC000LL +#define GATEWAY_ADDRESS ((uint16_t)0) + +#define MAX_MESSAGE_LENGTH 32 + +#define CRC8INIT 0x00 +#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 + +typedef enum { M_PRESENTATION = 0, M_VARIABLE, M_STATUS, M_CUSTOM, M_GATEWAY_MESSAGE, M_REQUEST_STATUS_RESPONSE } messageType; + +// Adding new variable- and device types should be done at the end of enum +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_BATTERY_LEVEL, V_BATTERY_DATE, + V_ARMED, V_TRIPPED, V_LAST_TRIP, 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_TIME, V_VERSION, + V_REQUEST_ID, V_INCLUSION_MODE, V_INCLUSION_COUNT, V_INCLUSION_RESULT, V_NEIGHBORS, + V_RELAY_MODE, V_LAST_UPDATE} variable; + +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} senosr; + +// result of validate() +enum { VALIDATE_OK=0, VALIDATE_BAD_CRC, VALIDATE_BAD_VERSION }; + + +typedef struct { + uint8_t crc : 8; // 8 bits crc + uint8_t version : 3; // 3 bits protocol version + uint8_t binary : 1; // 1 bit. Data is binary and should be encoded when sent to vera + uint16_t from : 12; // 12 bits. RadioId of sender node + uint16_t to : 12; // 12 bits. RadioId of destination node + uint8_t childId : 8; // 1 byte. Up to MAX_CHILD_DEVICES child sensors per radioId + uint8_t messageType : 4; // 4 bits. Type of message. See messageType + uint8_t type : 8; // 8 bits. variableType or deviceType depending on messageType +} header_s; + +typedef struct { + header_s header; + char data[MAX_MESSAGE_LENGTH - sizeof(header_s) + 1]; // Each message can transfer a payload. Add one extra byte for \0 +} message_s; + + + +/** +* Begin operation of the vera library +* +* Call this in setup(), before calling any other vera library methods. +*/ +void VeraAVR_begin(uint16_t _radioId); +void VeraAVR_begin2(uint16_t _radioId, uint16_t _relayId); + +/** +* Sends a variable change to vera +* +* @param childId The child id for which to update variable. Value can be 0-127. +* @param variableType The variableType to update +* @param value New value of the variable +*/ +void VeraAVR_sendVariable_char (uint8_t childId, uint8_t variableType, const char *value); +void VeraAVR_sendVariable_float (uint8_t childId, uint8_t variableType, float value, int decimals); +void VeraAVR_sendVariable_long(uint8_t childId, uint8_t variableType, long value); +void VeraAVR_sendVariable_int(uint8_t childId, uint8_t variableType, int value); + +/** +* Requests status for a vera variable (sent from an actuator) +* +* @param childId The unique child id for the different sensors connected to this arduino. 0-127. +* @param variableType The variableType to update +*/ +void VeraAVR_requestStatus (uint8_t childId, uint8_t variableType); + +/** +* Requests configuration parameter +* +* @param variableType The variableType to fetch +*/ +void VeraAVR_requestConfiguration(uint8_t variableType); +char * VeraAVR_getConfiguration(uint8_t variableType); +/** + * Fetches time from vera + */ +unsigned long VeraAVR_getTime(); +/* +* The arduino must send a presentation of all the sensors connected before any variable changes will be registrered on Vera side. +* Usually it's good to present all sensors when Arduino starts up (setup). +* Waits until all data has been transmitted and acknowledged by Vera receiver (retries RESEND_PRESENTATION times). +* +* @param childId The unique child id for the different sensors connected to this arduino. 0-254. +* @param sensorType Sensor types to create. They will be numbered from 0 up to 127. +*/ +void VeraAVR_sendSensorPresentation (uint8_t childId, uint8_t sensorType); + +/** +* Registers this arduino device as a relay. This requires this node to call +* api methods regularly to relay messages that could be passing this node and +* answer to any neighbor-discovery messages. +* Basically all api methods relays messages (waitForMessage, messageAvailable, ..) +* When this method is called vera will be informed that this node acts as relay. +*/ +void VeraAVR_registerNodeAsRelay(); +/** +* Busy waits until there is a message available to be read (used for actuators, like relays) +*/ +message_s VeraAVR_waitForVeraMessage(void); +/** +* Returns true if there is a message addressed for this node is available to be read (used by VeraGateway) +*/ +uint8_t VeraAVR_messageAvailable(); + /** + * Returns the last received message + */ +message_s VeraAVR_getMessage(); +uint8_t sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data); +uint8_t VeraAVR_validate(); +uint8_t VeraAVR_crc8Message(message_s); +uint8_t VeraAVR_checkCRCMessage(message_s); +uint8_t VeraAVR_checkCRC(); +message_s VeraAVR_readMessage(void); +uint8_t VeraAVR_sendDataGW(uint8_t childId, messageType messageType, uint8_t type, const char *data); +uint8_t VeraAVR_sendData(uint16_t from, uint16_t next, uint16_t to, uint8_t childId, messageType messageType, uint8_t type, const char *data); + +#include "VeraAVR.c" + +#endif diff --git a/AVR/lib/crc8/crc8.c b/AVR/lib/crc8/crc8.c index ef30f71..6a0fc00 100644 --- a/AVR/lib/crc8/crc8.c +++ b/AVR/lib/crc8/crc8.c @@ -1,63 +1,63 @@ -/* please read copyright-notice at EOF */ - -#include - -#define CRC8INIT 0x00 -#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 - -uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data ) -{ - uint8_t crc; - uint16_t loop_count; - uint8_t bit_counter; - uint8_t b; - uint8_t feedback_bit; - - crc = CRC8INIT; - - for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) - { - b = data[loop_count]; - - bit_counter = 8; - do { - feedback_bit = (crc ^ b) & 0x01; - - if ( feedback_bit == 0x01 ) { - crc = crc ^ CRC8POLY; - } - crc = (crc >> 1) & 0x7F; - if ( feedback_bit == 0x01 ) { - crc = crc | 0x80; - } - - b = b >> 1; - bit_counter--; - - } while (bit_counter > 0); - } - - return crc; -} - -/* -This code is from Colin O'Flynn - Copyright (c) 2002 -only minor changes by M.Thomas 9/2004 - -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. -*/ +/* please read copyright-notice at EOF */ + +#include + +#define CRC8INIT 0x00 +#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 + +uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data ) +{ + uint8_t crc; + uint16_t loop_count; + uint8_t bit_counter; + uint8_t b; + uint8_t feedback_bit; + + crc = CRC8INIT; + + for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) + { + b = data[loop_count]; + + bit_counter = 8; + do { + feedback_bit = (crc ^ b) & 0x01; + + if ( feedback_bit == 0x01 ) { + crc = crc ^ CRC8POLY; + } + crc = (crc >> 1) & 0x7F; + if ( feedback_bit == 0x01 ) { + crc = crc | 0x80; + } + + b = b >> 1; + bit_counter--; + + } while (bit_counter > 0); + } + + return crc; +} + +/* +This code is from Colin O'Flynn - Copyright (c) 2002 +only minor changes by M.Thomas 9/2004 + +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/AVR/lib/crc8/crc8.h b/AVR/lib/crc8/crc8.h index 34292b2..1b27cd4 100644 --- a/AVR/lib/crc8/crc8.h +++ b/AVR/lib/crc8/crc8.h @@ -1,42 +1,42 @@ -#ifndef CRC8_H_ -#define CRC8_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data ); - -#ifdef __cplusplus -} -#endif - -#include "crc8.c" - -#endif - -/* -This is based on code from : - -Copyright (c) 2002 Colin O'Flynn - -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. -*/ - +#ifndef CRC8_H_ +#define CRC8_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data ); + +#ifdef __cplusplus +} +#endif + +#include "crc8.c" + +#endif + +/* +This is based on code from : + +Copyright (c) 2002 Colin O'Flynn + +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/AVR/lib/spi/Arduino/SPI/examples/DS1305_Alarm/DS1305_Alarm.pde b/AVR/lib/spi/Arduino/SPI/examples/DS1305_Alarm/DS1305_Alarm.pde index 4196791..601672a 100644 --- a/AVR/lib/spi/Arduino/SPI/examples/DS1305_Alarm/DS1305_Alarm.pde +++ b/AVR/lib/spi/Arduino/SPI/examples/DS1305_Alarm/DS1305_Alarm.pde @@ -1,79 +1,79 @@ -#include -#include - -#define DS1305_PIN 4 -#define LED_PIN 3 - -// following two methods required by DS1305 library to select/deselect device -void select_ds1305(void) -{ - digitalWrite(DS1305_PIN, HIGH); -} - -void deselect_ds1305(void) -{ - digitalWrite(DS1305_PIN, LOW); -} - -// flash led that's connected to pin 3 -void flash_led(void) -{ - pinMode(LED_PIN, OUTPUT); - for (int i=0; i<10; i++) { - digitalWrite(LED_PIN, i%2==0); - delay(50); - } -} - -// called when pin INT0 goes from 1 to 0 -ISR(INT0_vect) -{ - // get alarm value to clear alarm interrupt flag on DS1305 - DS1305_DATETIME alarm; - get_alarm0(&alarm); - flash_led(); -} - -void setup() -{ - // flash LED at start to indicate were about to start - flash_led(); - flash_led(); - - // pin used to enable DS1305 - pinMode(DS1305_PIN, OUTPUT); - - // Make sure ADC is unselected and setup spi - deselect_ds1305(); - setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16); - set_control(0); - - // set current date/time to Thursday 06/05/09 20:32:30 - DS1305_DATETIME current = {0x30, 0x32, 0x20, 0x05, 0x06, 0x05, 0x09}; - set_time(¤t); - - // change the value of alarm to the required time/granularity: - // raise alarm every day (at 20:32:00): - // DS1305_DATETIME alarm = {0x00, 0x32, 0x20, 0x00 | DS1305_ALARM_SET}; - // raise alarm every minute (when seconds = 00): - // DS1305_DATETIME alarm = {0x00, 0x32 | DS1305_ALARM_SET, - // 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET}; - // raise alarm every second: - DS1305_DATETIME alarm = {0x55 | DS1305_ALARM_SET, 0x32 | DS1305_ALARM_SET, - 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET}; - set_alarm0(&alarm); - // turn on timer and make alarm0 lower INT0 pin when alarm is triggered - set_control(DS1305_EOSC | DS1305_INTCN | DS1305_AIE0); - - // raise interrupt when INT0 pin falls (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX (arduino pin 2)) - // the code in ISR(INT0_vect) above will be called - EICRA = (1< +#include + +#define DS1305_PIN 4 +#define LED_PIN 3 + +// following two methods required by DS1305 library to select/deselect device +void select_ds1305(void) +{ + digitalWrite(DS1305_PIN, HIGH); +} + +void deselect_ds1305(void) +{ + digitalWrite(DS1305_PIN, LOW); +} + +// flash led that's connected to pin 3 +void flash_led(void) +{ + pinMode(LED_PIN, OUTPUT); + for (int i=0; i<10; i++) { + digitalWrite(LED_PIN, i%2==0); + delay(50); + } +} + +// called when pin INT0 goes from 1 to 0 +ISR(INT0_vect) +{ + // get alarm value to clear alarm interrupt flag on DS1305 + DS1305_DATETIME alarm; + get_alarm0(&alarm); + flash_led(); +} + +void setup() +{ + // flash LED at start to indicate were about to start + flash_led(); + flash_led(); + + // pin used to enable DS1305 + pinMode(DS1305_PIN, OUTPUT); + + // Make sure ADC is unselected and setup spi + deselect_ds1305(); + setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK16); + set_control(0); + + // set current date/time to Thursday 06/05/09 20:32:30 + DS1305_DATETIME current = {0x30, 0x32, 0x20, 0x05, 0x06, 0x05, 0x09}; + set_time(¤t); + + // change the value of alarm to the required time/granularity: + // raise alarm every day (at 20:32:00): + // DS1305_DATETIME alarm = {0x00, 0x32, 0x20, 0x00 | DS1305_ALARM_SET}; + // raise alarm every minute (when seconds = 00): + // DS1305_DATETIME alarm = {0x00, 0x32 | DS1305_ALARM_SET, + // 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET}; + // raise alarm every second: + DS1305_DATETIME alarm = {0x55 | DS1305_ALARM_SET, 0x32 | DS1305_ALARM_SET, + 0x20 | DS1305_ALARM_SET, 0x05 | DS1305_ALARM_SET}; + set_alarm0(&alarm); + // turn on timer and make alarm0 lower INT0 pin when alarm is triggered + set_control(DS1305_EOSC | DS1305_INTCN | DS1305_AIE0); + + // raise interrupt when INT0 pin falls (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX (arduino pin 2)) + // the code in ISR(INT0_vect) above will be called + EICRA = (1< - -Make sure viewing this text in a fixed width font for the tables and diagrams - - ----------------------------------- -Arduino ----------------------------------- -The Arduino Directory contains all code required to run on the Arduino. -Simply copy the Arduino/SPI and Arduino/DS1305 directories to the -"hardware/libraries" directory of your Arduino IDE installation and -restart the Arduino IDE. Once restarted there should be -"Sketch->Import Library->SPI" and "Sketch->Import Library->DS1305" menu -entries which can be used to include the spi header files into your project. -"File->Sketchbook->Examples->Library SPI" contains 3 example projects - - ----------------------------------- -AVR GCC ----------------------------------- -To use, just copy spi.h and spi.c (and ds1305.c and ds1305.h if using -the DS1305 Real Time Clock chip) to your own project and compile. - -Makefile.mf - 'standard' generated make file from AVR GCC -Makefile - Makefile "make examples" will make example programs below: - -spi-test-adc.c MC3201 Analogue to Digital convertor example -spi-test-rtc.c DS1305 - Real-Time-Clock/Alarm example -spi-test-masterslave.c Master/Slave communication example - - ----------------------------------- -PINS ----------------------------------- -Following are the AVR pins used in the circuits below - - ATmegaXXX Arduino AT90usbXXX -MISO PB4 12 PB3 -MOSI PB3 11 PB2 -SCK PB5 13 PB1 -SS PB2 10 PB0 - -INT0 PD2 2 PD0 - - ----------------------------------- -MC3201 12-bit ADC Circuit ----------------------------------- -See http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf for full details. - - +-----------------+ - | MC3201 | - +5V [| Vref Vdd |] +5V - | | -Analogue In [| IN+ CLK |] AVR SCK - | | - Ground [| IN- Dout |] AVR MOSI - | | - Ground [| Vss ^CS |] AVR CE - +-----------------+ - - -For testing purposes "Analogue In" can be connected to the middle wire -of a potentiometer with one outer wire being connected to +5 and the -other to Ground. A 1uF Capacitor should be placed between the analogue -input and ground, and +5V and ground as close to the chip as possible, -but in a pinch the circuit will likely work without. - - -MOSI/SLCK/CE to the relevant pin on the AVR (MISO is not used) - see above. - ----------------------------------- -DS1305 Real Time Clock Circuit ----------------------------------- -See http://datasheets.maxim-ic.com/en/ds/DS1305.pdf for full details. - -Without a battery the following connections can be used: - - +-----------------+ - | DS1305 | - Ground [| Vcc2 Vcc1 |] +5V - | | - Ground [| Vbat ^PF |] Not Connected - | | - Crystal [| X1 Vccif |] +5V - | | - Crystal [| X2 SDO |] AVR MISO - | | - Not Connected [| N.C. SDI |] AVR MOSI - | | - AVR INT0 [| INT0 SLCK |] AVR SLCK - | | - Not Connected [| INT1 CE |] AVR CE - | | - Ground [| GND SERMODE |] +5V - +-----------------+ - - -MISO/MOSI/SLCK/CE/INT0 to the relevant pin on the AVR - see above. - - - - - +This directory contains a simple AVR spi helper library that should +run on most AVR microcontrollers which support SPI. + +The code is further described at: +http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/ (basics & ADC) +http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/ (RTC) + +Any comments/questions to + +Make sure viewing this text in a fixed width font for the tables and diagrams + + +---------------------------------- +Arduino +---------------------------------- +The Arduino Directory contains all code required to run on the Arduino. +Simply copy the Arduino/SPI and Arduino/DS1305 directories to the +"hardware/libraries" directory of your Arduino IDE installation and +restart the Arduino IDE. Once restarted there should be +"Sketch->Import Library->SPI" and "Sketch->Import Library->DS1305" menu +entries which can be used to include the spi header files into your project. +"File->Sketchbook->Examples->Library SPI" contains 3 example projects + + +---------------------------------- +AVR GCC +---------------------------------- +To use, just copy spi.h and spi.c (and ds1305.c and ds1305.h if using +the DS1305 Real Time Clock chip) to your own project and compile. + +Makefile.mf - 'standard' generated make file from AVR GCC +Makefile - Makefile "make examples" will make example programs below: + +spi-test-adc.c MC3201 Analogue to Digital convertor example +spi-test-rtc.c DS1305 - Real-Time-Clock/Alarm example +spi-test-masterslave.c Master/Slave communication example + + +---------------------------------- +PINS +---------------------------------- +Following are the AVR pins used in the circuits below + + ATmegaXXX Arduino AT90usbXXX +MISO PB4 12 PB3 +MOSI PB3 11 PB2 +SCK PB5 13 PB1 +SS PB2 10 PB0 + +INT0 PD2 2 PD0 + + +---------------------------------- +MC3201 12-bit ADC Circuit +---------------------------------- +See http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf for full details. + + +-----------------+ + | MC3201 | + +5V [| Vref Vdd |] +5V + | | +Analogue In [| IN+ CLK |] AVR SCK + | | + Ground [| IN- Dout |] AVR MOSI + | | + Ground [| Vss ^CS |] AVR CE + +-----------------+ + + +For testing purposes "Analogue In" can be connected to the middle wire +of a potentiometer with one outer wire being connected to +5 and the +other to Ground. A 1uF Capacitor should be placed between the analogue +input and ground, and +5V and ground as close to the chip as possible, +but in a pinch the circuit will likely work without. + + +MOSI/SLCK/CE to the relevant pin on the AVR (MISO is not used) - see above. + +---------------------------------- +DS1305 Real Time Clock Circuit +---------------------------------- +See http://datasheets.maxim-ic.com/en/ds/DS1305.pdf for full details. + +Without a battery the following connections can be used: + + +-----------------+ + | DS1305 | + Ground [| Vcc2 Vcc1 |] +5V + | | + Ground [| Vbat ^PF |] Not Connected + | | + Crystal [| X1 Vccif |] +5V + | | + Crystal [| X2 SDO |] AVR MISO + | | + Not Connected [| N.C. SDI |] AVR MOSI + | | + AVR INT0 [| INT0 SLCK |] AVR SLCK + | | + Not Connected [| INT1 CE |] AVR CE + | | + Ground [| GND SERMODE |] +5V + +-----------------+ + + +MISO/MOSI/SLCK/CE/INT0 to the relevant pin on the AVR - see above. + + + + + diff --git a/libraries/DallasTemperature/DallasTemperature.cpp b/libraries/DallasTemperature/DallasTemperature.cpp index 1f0a51f..ea5b1e5 100644 --- a/libraries/DallasTemperature/DallasTemperature.cpp +++ b/libraries/DallasTemperature/DallasTemperature.cpp @@ -1,618 +1,618 @@ -// 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. - -#include "DallasTemperature.h" - -extern "C" { - #include "Arduino.h" -} - -DallasTemperature::DallasTemperature(OneWire* _oneWire) - #if REQUIRESALARMS - : _AlarmHandler(&defaultAlarmHandler) - #endif -{ - _wire = _oneWire; - devices = 0; - parasite = false; - conversionDelay = TEMP_9_BIT; -} - -// initialize the bus -void DallasTemperature::begin(void) -{ - DeviceAddress deviceAddress; - +// 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. + +#include "DallasTemperature.h" + +extern "C" { + #include "Arduino.h" +} + +DallasTemperature::DallasTemperature(OneWire* _oneWire) + #if REQUIRESALARMS + : _AlarmHandler(&defaultAlarmHandler) + #endif +{ + _wire = _oneWire; + devices = 0; + parasite = false; + conversionDelay = TEMP_9_BIT; +} + +// initialize the bus +void DallasTemperature::begin(void) +{ + DeviceAddress deviceAddress; + _wire->reset_search(); - devices = 0; // Reset the number of devices when we enumerate wire devices - - while (_wire->search(deviceAddress)) - { - if (validAddress(deviceAddress)) - { - if (!parasite && readPowerSupply(deviceAddress)) parasite = true; - - ScratchPad scratchPad; - - readScratchPad(deviceAddress, scratchPad); - - if (deviceAddress[0] == DS18S20MODEL) conversionDelay = TEMP_12_BIT; // 750 ms - else if (scratchPad[CONFIGURATION] > conversionDelay) conversionDelay = scratchPad[CONFIGURATION]; - - devices++; - } - } -} - -// returns the number of devices found on the bus -uint8_t DallasTemperature::getDeviceCount(void) -{ - return devices; -} - -// returns true if address is valid -bool DallasTemperature::validAddress(uint8_t* deviceAddress) -{ - 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; - - _wire->reset_search(); - - while (depth <= index && _wire->search(deviceAddress)) - { - if (depth == index && validAddress(deviceAddress)) return true; - depth++; - } - - return false; -} - -// attempt to determine if the device at the given address is connected to the bus -bool DallasTemperature::isConnected(uint8_t* deviceAddress) -{ - 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) -{ - 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) -{ - // send the command - _wire->reset(); - _wire->select(deviceAddress); - _wire->write(READSCRATCH); - - // read the response - - // byte 0: temperature LSB - scratchPad[TEMP_LSB] = _wire->read(); - - // byte 1: temperature MSB - scratchPad[TEMP_MSB] = _wire->read(); - - // byte 2: high alarm temp - scratchPad[HIGH_ALARM_TEMP] = _wire->read(); - - // byte 3: low alarm temp - scratchPad[LOW_ALARM_TEMP] = _wire->read(); - - // byte 4: - // DS18S20: store for crc - // DS18B20 & DS1822: configuration register - scratchPad[CONFIGURATION] = _wire->read(); - - // byte 5: - // internal use & crc - scratchPad[INTERNAL_BYTE] = _wire->read(); - - // byte 6: - // DS18S20: COUNT_REMAIN - // DS18B20 & DS1822: store for crc - scratchPad[COUNT_REMAIN] = _wire->read(); - - // 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) -{ - _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(); -} - -// reads the device's power requirements -bool DallasTemperature::readPowerSupply(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; -} - -// 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 a device to 9, 10, 11, or 12 bits -void DallasTemperature::setResolution(uint8_t* deviceAddress, uint8_t newResolution) -{ - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) - { - // DS18S20 has a fixed 9-bit resolution - if (deviceAddress[0] != DS18S20MODEL) - { - switch (newResolution) - { - case 12: - scratchPad[CONFIGURATION] = TEMP_12_BIT; - break; - case 11: - scratchPad[CONFIGURATION] = TEMP_11_BIT; - break; - case 10: - scratchPad[CONFIGURATION] = TEMP_10_BIT; - break; - case 9: - default: - scratchPad[CONFIGURATION] = TEMP_9_BIT; - break; - } - writeScratchPad(deviceAddress, scratchPad); - } - } -} - -// sends command for all devices on the bus to perform a temperature -void DallasTemperature::requestTemperatures(void) -{ - _wire->reset(); - _wire->skip(); - _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: - default: - delay(750); - break; - } -} - -// sends command for one device to perform a temperature by address -void DallasTemperature::requestTemperaturesByAddress(uint8_t* deviceAddress) -{ - _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: - default: - delay(750); - break; - } -} - -// sends command for one device to perform a temp conversion by index -void DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) -{ - DeviceAddress deviceAddress; - getAddress(deviceAddress, deviceIndex); - requestTemperaturesByAddress(deviceAddress); -} - - -// Fetch temperature for device index -float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) -{ - DeviceAddress deviceAddress; - getAddress(deviceAddress, deviceIndex); - return getTempC((uint8_t*)deviceAddress); -} - -// Fetch temperature for device index -float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) -{ - return DallasTemperature::toFahrenheit(getTempCByIndex(deviceIndex)); -} - -// reads scratchpad and returns the temperature in degrees C -float DallasTemperature::calculateTemperature(uint8_t* deviceAddress, uint8_t* scratchPad) -{ - int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB]; - - 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: - /* - - 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: - - COUNT_PER_C - COUNT_REMAIN - TEMPERATURE = TEMP_READ - 0.25 + -------------------------- - COUNT_PER_C - */ - - // 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; - } -} - -// returns temperature in degrees C or DEVICE_DISCONNECTED 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 -// operating range of the device -float DallasTemperature::getTempC(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; -} - -// returns temperature in degrees F -float DallasTemperature::getTempF(uint8_t* deviceAddress) -{ - return toFahrenheit(getTempC(deviceAddress)); -} - -// returns true if the bus requires parasite power -bool DallasTemperature::isParasitePowerMode(void) -{ - return parasite; -} - -#if REQUIRESALARMS - -/* - -ALARMS: - -TH and TL Register Format - -BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 - S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 - -Only bits 11 through 4 of the temperature register are used -in the TH and TL comparison since TH and TL are 8-bit -registers. If the measured temperature is lower than or equal -to TL or higher than or equal to TH, an alarm condition exists -and an alarm flag is set inside the DS18B20. This flag is -updated after every temperature measurement; therefore, if the -alarm condition goes away, the flag will be turned off after -the next temperature conversion. - -*/ - -// 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) -{ - // 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); - } -} - -// sets the low alarm temperature for a device in degreed 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) -{ - // 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); - } -} - -// returns a char with the current high alarm temperature or -// DEVICE_DISCONNECTED for an address -char DallasTemperature::getHighAlarmTemp(uint8_t* deviceAddress) -{ - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; - return DEVICE_DISCONNECTED; -} - -// returns a char with the current low alarm temperature or -// DEVICE_DISCONNECTED for an address -char DallasTemperature::getLowAlarmTemp(uint8_t* deviceAddress) -{ - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; - return DEVICE_DISCONNECTED; -} - -// 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; -} - -// This is a modified version of the OneWire::search method. -// -// Also added the OneWire search fix documented here: -// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 -// -// Perform an alarm search. If this function returns a '1' then it has -// enumerated the next device and you may retrieve the ROM from the -// OneWire::address variable. If there are no devices, no further -// devices, or something horrible happens in the middle of the -// enumeration then a 0 is returned. If a new device is found then -// its address is copied to newAddr. Use -// DallasTemperature::resetAlarmSearch() to start over. -bool DallasTemperature::alarmSearch(uint8_t* newAddr) -{ - uint8_t i; - char lastJunction = -1; - uint8_t done = 1; - - if (alarmSearchExhausted) return false; - if (!_wire->reset()) return false; - - // 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) - { - 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 exhasuted 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 - } - - 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; -} - -// returns true if device address has an alarm condition -bool DallasTemperature::hasAlarm(uint8_t* deviceAddress) -{ - ScratchPad scratchPad; - if (isConnected(deviceAddress, scratchPad)) - { - float temp = calculateTemperature(deviceAddress, scratchPad); - - // check low alarm - if ((char)temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; - - // check high alarm - if ((char)temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; - } - - // 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); -} - -// runs the alarm handler for all devices returned by alarmSearch() -void DallasTemperature::processAlarms(void) -{ - resetAlarmSearch(); - DeviceAddress alarmAddr; - - while (alarmSearch(alarmAddr)) - { - if (validAddress(alarmAddr)) - _AlarmHandler(alarmAddr); - } -} - -// sets the alarm handler -void DallasTemperature::setAlarmHandler(AlarmHandler *handler) -{ - _AlarmHandler = handler; -} - -// The default alarm handler -void DallasTemperature::defaultAlarmHandler(uint8_t* deviceAddress) -{ -} - -#endif - -// Convert float celsius to fahrenheit -float DallasTemperature::toFahrenheit(float celsius) -{ - return (celsius * 1.8) + 32; -} - -// Convert float fahrenheit to celsius -float DallasTemperature::toCelsius(float fahrenheit) -{ - return (fahrenheit - 32) / 1.8; -} - -#if REQUIRESNEW - -// 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 - - //!!! 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 -void DallasTemperature::operator delete(void* p) -{ - DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer - pNss->~DallasTemperature(); // Destruct the object - - free(p); // Free the memory -} - -#endif + devices = 0; // Reset the number of devices when we enumerate wire devices + + while (_wire->search(deviceAddress)) + { + if (validAddress(deviceAddress)) + { + if (!parasite && readPowerSupply(deviceAddress)) parasite = true; + + ScratchPad scratchPad; + + readScratchPad(deviceAddress, scratchPad); + + if (deviceAddress[0] == DS18S20MODEL) conversionDelay = TEMP_12_BIT; // 750 ms + else if (scratchPad[CONFIGURATION] > conversionDelay) conversionDelay = scratchPad[CONFIGURATION]; + + devices++; + } + } +} + +// returns the number of devices found on the bus +uint8_t DallasTemperature::getDeviceCount(void) +{ + return devices; +} + +// returns true if address is valid +bool DallasTemperature::validAddress(uint8_t* deviceAddress) +{ + 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; + + _wire->reset_search(); + + while (depth <= index && _wire->search(deviceAddress)) + { + if (depth == index && validAddress(deviceAddress)) return true; + depth++; + } + + return false; +} + +// attempt to determine if the device at the given address is connected to the bus +bool DallasTemperature::isConnected(uint8_t* deviceAddress) +{ + 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) +{ + 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) +{ + // send the command + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READSCRATCH); + + // read the response + + // byte 0: temperature LSB + scratchPad[TEMP_LSB] = _wire->read(); + + // byte 1: temperature MSB + scratchPad[TEMP_MSB] = _wire->read(); + + // byte 2: high alarm temp + scratchPad[HIGH_ALARM_TEMP] = _wire->read(); + + // byte 3: low alarm temp + scratchPad[LOW_ALARM_TEMP] = _wire->read(); + + // byte 4: + // DS18S20: store for crc + // DS18B20 & DS1822: configuration register + scratchPad[CONFIGURATION] = _wire->read(); + + // byte 5: + // internal use & crc + scratchPad[INTERNAL_BYTE] = _wire->read(); + + // byte 6: + // DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + scratchPad[COUNT_REMAIN] = _wire->read(); + + // 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) +{ + _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(); +} + +// reads the device's power requirements +bool DallasTemperature::readPowerSupply(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; +} + +// 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 a device to 9, 10, 11, or 12 bits +void DallasTemperature::setResolution(uint8_t* deviceAddress, uint8_t newResolution) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + // DS18S20 has a fixed 9-bit resolution + if (deviceAddress[0] != DS18S20MODEL) + { + switch (newResolution) + { + case 12: + scratchPad[CONFIGURATION] = TEMP_12_BIT; + break; + case 11: + scratchPad[CONFIGURATION] = TEMP_11_BIT; + break; + case 10: + scratchPad[CONFIGURATION] = TEMP_10_BIT; + break; + case 9: + default: + scratchPad[CONFIGURATION] = TEMP_9_BIT; + break; + } + writeScratchPad(deviceAddress, scratchPad); + } + } +} + +// sends command for all devices on the bus to perform a temperature +void DallasTemperature::requestTemperatures(void) +{ + _wire->reset(); + _wire->skip(); + _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: + default: + delay(750); + break; + } +} + +// sends command for one device to perform a temperature by address +void DallasTemperature::requestTemperaturesByAddress(uint8_t* deviceAddress) +{ + _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: + default: + delay(750); + break; + } +} + +// sends command for one device to perform a temp conversion by index +void DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + requestTemperaturesByAddress(deviceAddress); +} + + +// Fetch temperature for device index +float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + return getTempC((uint8_t*)deviceAddress); +} + +// Fetch temperature for device index +float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) +{ + return DallasTemperature::toFahrenheit(getTempCByIndex(deviceIndex)); +} + +// reads scratchpad and returns the temperature in degrees C +float DallasTemperature::calculateTemperature(uint8_t* deviceAddress, uint8_t* scratchPad) +{ + int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB]; + + 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: + /* + + 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: + + COUNT_PER_C - COUNT_REMAIN + TEMPERATURE = TEMP_READ - 0.25 + -------------------------- + COUNT_PER_C + */ + + // 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; + } +} + +// returns temperature in degrees C or DEVICE_DISCONNECTED 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 +// operating range of the device +float DallasTemperature::getTempC(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; +} + +// returns temperature in degrees F +float DallasTemperature::getTempF(uint8_t* deviceAddress) +{ + return toFahrenheit(getTempC(deviceAddress)); +} + +// returns true if the bus requires parasite power +bool DallasTemperature::isParasitePowerMode(void) +{ + return parasite; +} + +#if REQUIRESALARMS + +/* + +ALARMS: + +TH and TL Register Format + +BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 + S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 + +Only bits 11 through 4 of the temperature register are used +in the TH and TL comparison since TH and TL are 8-bit +registers. If the measured temperature is lower than or equal +to TL or higher than or equal to TH, an alarm condition exists +and an alarm flag is set inside the DS18B20. This flag is +updated after every temperature measurement; therefore, if the +alarm condition goes away, the flag will be turned off after +the next temperature conversion. + +*/ + +// 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) +{ + // 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); + } +} + +// sets the low alarm temperature for a device in degreed 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) +{ + // 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); + } +} + +// returns a char with the current high alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getHighAlarmTemp(uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; + return DEVICE_DISCONNECTED; +} + +// returns a char with the current low alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getLowAlarmTemp(uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; + return DEVICE_DISCONNECTED; +} + +// 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; +} + +// This is a modified version of the OneWire::search method. +// +// Also added the OneWire search fix documented here: +// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 +// +// Perform an alarm search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use +// DallasTemperature::resetAlarmSearch() to start over. +bool DallasTemperature::alarmSearch(uint8_t* newAddr) +{ + uint8_t i; + char lastJunction = -1; + uint8_t done = 1; + + if (alarmSearchExhausted) return false; + if (!_wire->reset()) return false; + + // 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) + { + 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 exhasuted 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 + } + + 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; +} + +// returns true if device address has an alarm condition +bool DallasTemperature::hasAlarm(uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + float temp = calculateTemperature(deviceAddress, scratchPad); + + // check low alarm + if ((char)temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; + + // check high alarm + if ((char)temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; + } + + // 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); +} + +// runs the alarm handler for all devices returned by alarmSearch() +void DallasTemperature::processAlarms(void) +{ + resetAlarmSearch(); + DeviceAddress alarmAddr; + + while (alarmSearch(alarmAddr)) + { + if (validAddress(alarmAddr)) + _AlarmHandler(alarmAddr); + } +} + +// sets the alarm handler +void DallasTemperature::setAlarmHandler(AlarmHandler *handler) +{ + _AlarmHandler = handler; +} + +// The default alarm handler +void DallasTemperature::defaultAlarmHandler(uint8_t* deviceAddress) +{ +} + +#endif + +// Convert float celsius to fahrenheit +float DallasTemperature::toFahrenheit(float celsius) +{ + return (celsius * 1.8) + 32; +} + +// Convert float fahrenheit to celsius +float DallasTemperature::toCelsius(float fahrenheit) +{ + return (fahrenheit - 32) / 1.8; +} + +#if REQUIRESNEW + +// 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 + + //!!! 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 +void DallasTemperature::operator delete(void* p) +{ + DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer + pNss->~DallasTemperature(); // Destruct the object + + free(p); // Free the memory +} + +#endif diff --git a/libraries/DallasTemperature/DallasTemperature.h b/libraries/DallasTemperature/DallasTemperature.h index 9e57fe2..daf4ad1 100644 --- a/libraries/DallasTemperature/DallasTemperature.h +++ b/libraries/DallasTemperature/DallasTemperature.h @@ -1,213 +1,213 @@ -#ifndef DallasTemperature_h -#define DallasTemperature_h - -// 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. - -// set to true to include code for new and delete operators -#ifndef REQUIRESNEW -#define REQUIRESNEW false -#endif - -// set to true to include code implementing alarm search functions -#ifndef REQUIRESALARMS -#define REQUIRESALARMS true -#endif - -#include -#include - -// Model IDs -#define DS18S20MODEL 0x10 -#define DS18B20MODEL 0x28 -#define DS1822MODEL 0x22 - -// OneWire commands -#define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad -#define COPYSCRATCH 0x48 // Copy EEPROM -#define READSCRATCH 0xBE // Read EEPROM -#define WRITESCRATCH 0x4E // Write to EEPROM -#define RECALLSCRATCH 0xB8 // Reload from last known -#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power -#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition - -// Scratchpad locations -#define TEMP_LSB 0 -#define TEMP_MSB 1 -#define HIGH_ALARM_TEMP 2 -#define LOW_ALARM_TEMP 3 -#define CONFIGURATION 4 -#define INTERNAL_BYTE 5 -#define COUNT_REMAIN 6 -#define COUNT_PER_C 7 -#define SCRATCHPAD_CRC 8 - -// Device resolution -#define TEMP_9_BIT 0x1F // 9 bit -#define TEMP_10_BIT 0x3F // 10 bit -#define TEMP_11_BIT 0x5F // 11 bit -#define TEMP_12_BIT 0x7F // 12 bit - -// Error Codes -#define DEVICE_DISCONNECTED -127 - -typedef uint8_t DeviceAddress[8]; - -class DallasTemperature -{ - public: - - DallasTemperature(OneWire*); - - // initalize 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*); - - // finds an address at a given index on the bus - bool getAddress(uint8_t*, const uint8_t); - - // attempt to determine if the device at the given address is connected to the bus - bool isConnected(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*); - - // read device's scratchpad - void readScratchPad(uint8_t*, uint8_t*); - - // write device's scratchpad - void writeScratchPad(uint8_t*, const uint8_t*); - - // read device's power requirements - bool readPowerSupply(uint8_t*); - - // returns the current resolution, 9-12 - uint8_t getResolution(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 - void requestTemperatures(void); - - // sends command for one device to perform a temperature conversion by address - void requestTemperaturesByAddress(uint8_t*); - - // sends command for one device to perform a temperature conversion by index - void requestTemperaturesByIndex(uint8_t); - - // returns temperature in degrees C - float getTempC(uint8_t*); - - // returns temperature in degrees F - float getTempF(uint8_t*); - - // Get temperature for device index (slow) - float getTempCByIndex(uint8_t); - - // Get temperature for device index (slow) - float getTempFByIndex(uint8_t); - - // returns true if the bus requires parasite power - bool isParasitePowerMode(void); - - #if REQUIRESALARMS - - typedef void AlarmHandler(uint8_t*); - - // sets the high alarm temperature for a device - // accepts a char. valid range is -55C - 125C - void setHighAlarmTemp(uint8_t*, const char); - - // sets the low alarm temperature for a device - // accepts a char. valid range is -55C - 125C - void setLowAlarmTemp(uint8_t*, const char); - - // returns a signed char with the current high alarm temperature for a device - // in the range -55C - 125C - char getHighAlarmTemp(uint8_t*); - - // returns a signed char with the current low alarm temperature for a device - // in the range -55C - 125C - char getLowAlarmTemp(uint8_t*); - - // resets internal variables used for the alarm search - void resetAlarmSearch(void); - - // search the wire for devices with active alarms - bool alarmSearch(uint8_t*); - - // returns true if ia specific device has an alarm - bool hasAlarm(uint8_t*); - - // returns true if any device is reporting an alarm on the bus - bool hasAlarm(void); - - // runs the alarm handler for all devices returned by alarmSearch() - void processAlarms(void); - - // sets the alarm handler - void setAlarmHandler(AlarmHandler *); - - // The default alarm handler - static void defaultAlarmHandler(uint8_t*); - - #endif - - // convert from celcius to farenheit - static float toFahrenheit(const float); - - // convert from farenheit to celsius - static float toCelsius(const float); - - #if REQUIRESNEW - - // initalize memory area - void* operator new (unsigned int); - - // delete memory reference - void operator delete(void*); - - #endif - - private: - typedef uint8_t ScratchPad[9]; - - // parasite power on or off - bool parasite; - - // used to determine the delay amount needed to allow for the - // temperature conversion to take place - int conversionDelay; - - // 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*); - - #if REQUIRESALARMS - - // required for alarmSearch - uint8_t alarmSearchAddress[8]; - char alarmSearchJunction; - uint8_t alarmSearchExhausted; - - // the alarm handler function pointer - AlarmHandler *_AlarmHandler; - - #endif - -}; -#endif +#ifndef DallasTemperature_h +#define DallasTemperature_h + +// 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. + +// set to true to include code for new and delete operators +#ifndef REQUIRESNEW +#define REQUIRESNEW false +#endif + +// set to true to include code implementing alarm search functions +#ifndef REQUIRESALARMS +#define REQUIRESALARMS true +#endif + +#include +#include + +// Model IDs +#define DS18S20MODEL 0x10 +#define DS18B20MODEL 0x28 +#define DS1822MODEL 0x22 + +// OneWire commands +#define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad +#define COPYSCRATCH 0x48 // Copy EEPROM +#define READSCRATCH 0xBE // Read EEPROM +#define WRITESCRATCH 0x4E // Write to EEPROM +#define RECALLSCRATCH 0xB8 // Reload from last known +#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power +#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition + +// Scratchpad locations +#define TEMP_LSB 0 +#define TEMP_MSB 1 +#define HIGH_ALARM_TEMP 2 +#define LOW_ALARM_TEMP 3 +#define CONFIGURATION 4 +#define INTERNAL_BYTE 5 +#define COUNT_REMAIN 6 +#define COUNT_PER_C 7 +#define SCRATCHPAD_CRC 8 + +// Device resolution +#define TEMP_9_BIT 0x1F // 9 bit +#define TEMP_10_BIT 0x3F // 10 bit +#define TEMP_11_BIT 0x5F // 11 bit +#define TEMP_12_BIT 0x7F // 12 bit + +// Error Codes +#define DEVICE_DISCONNECTED -127 + +typedef uint8_t DeviceAddress[8]; + +class DallasTemperature +{ + public: + + DallasTemperature(OneWire*); + + // initalize 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*); + + // finds an address at a given index on the bus + bool getAddress(uint8_t*, const uint8_t); + + // attempt to determine if the device at the given address is connected to the bus + bool isConnected(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*); + + // read device's scratchpad + void readScratchPad(uint8_t*, uint8_t*); + + // write device's scratchpad + void writeScratchPad(uint8_t*, const uint8_t*); + + // read device's power requirements + bool readPowerSupply(uint8_t*); + + // returns the current resolution, 9-12 + uint8_t getResolution(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 + void requestTemperatures(void); + + // sends command for one device to perform a temperature conversion by address + void requestTemperaturesByAddress(uint8_t*); + + // sends command for one device to perform a temperature conversion by index + void requestTemperaturesByIndex(uint8_t); + + // returns temperature in degrees C + float getTempC(uint8_t*); + + // returns temperature in degrees F + float getTempF(uint8_t*); + + // Get temperature for device index (slow) + float getTempCByIndex(uint8_t); + + // Get temperature for device index (slow) + float getTempFByIndex(uint8_t); + + // returns true if the bus requires parasite power + bool isParasitePowerMode(void); + + #if REQUIRESALARMS + + typedef void AlarmHandler(uint8_t*); + + // sets the high alarm temperature for a device + // accepts a char. valid range is -55C - 125C + void setHighAlarmTemp(uint8_t*, const char); + + // sets the low alarm temperature for a device + // accepts a char. valid range is -55C - 125C + void setLowAlarmTemp(uint8_t*, const char); + + // returns a signed char with the current high alarm temperature for a device + // in the range -55C - 125C + char getHighAlarmTemp(uint8_t*); + + // returns a signed char with the current low alarm temperature for a device + // in the range -55C - 125C + char getLowAlarmTemp(uint8_t*); + + // resets internal variables used for the alarm search + void resetAlarmSearch(void); + + // search the wire for devices with active alarms + bool alarmSearch(uint8_t*); + + // returns true if ia specific device has an alarm + bool hasAlarm(uint8_t*); + + // returns true if any device is reporting an alarm on the bus + bool hasAlarm(void); + + // runs the alarm handler for all devices returned by alarmSearch() + void processAlarms(void); + + // sets the alarm handler + void setAlarmHandler(AlarmHandler *); + + // The default alarm handler + static void defaultAlarmHandler(uint8_t*); + + #endif + + // convert from celcius to farenheit + static float toFahrenheit(const float); + + // convert from farenheit to celsius + static float toCelsius(const float); + + #if REQUIRESNEW + + // initalize memory area + void* operator new (unsigned int); + + // delete memory reference + void operator delete(void*); + + #endif + + private: + typedef uint8_t ScratchPad[9]; + + // parasite power on or off + bool parasite; + + // used to determine the delay amount needed to allow for the + // temperature conversion to take place + int conversionDelay; + + // 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*); + + #if REQUIRESALARMS + + // required for alarmSearch + uint8_t alarmSearchAddress[8]; + char alarmSearchJunction; + uint8_t alarmSearchExhausted; + + // the alarm handler function pointer + AlarmHandler *_AlarmHandler; + + #endif + +}; +#endif diff --git a/libraries/DallasTemperature/examples/Alarm/Alarm.pde b/libraries/DallasTemperature/examples/Alarm/Alarm.pde index e0884ea..bd8af00 100644 --- a/libraries/DallasTemperature/examples/Alarm/Alarm.pde +++ b/libraries/DallasTemperature/examples/Alarm/Alarm.pde @@ -159,4 +159,4 @@ void loop(void) */ } - + diff --git a/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde b/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde index d52e1f7..05b3a5f 100644 --- a/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde +++ b/libraries/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde @@ -142,4 +142,4 @@ void loop(void) delay(1000); } - + diff --git a/libraries/DallasTemperature/examples/Multiple/Multiple.pde b/libraries/DallasTemperature/examples/Multiple/Multiple.pde index 2694d07..86cc47d 100644 --- a/libraries/DallasTemperature/examples/Multiple/Multiple.pde +++ b/libraries/DallasTemperature/examples/Multiple/Multiple.pde @@ -137,4 +137,4 @@ void loop(void) printData(insideThermometer); printData(outsideThermometer); } - + diff --git a/libraries/DallasTemperature/examples/Simple/Simple.pde b/libraries/DallasTemperature/examples/Simple/Simple.pde index 5b2954d..e4383bf 100644 --- a/libraries/DallasTemperature/examples/Simple/Simple.pde +++ b/libraries/DallasTemperature/examples/Simple/Simple.pde @@ -30,4 +30,4 @@ void loop(void) Serial.print("Temperature for the device 1 (index 0) is: "); Serial.println(sensors.getTempCByIndex(0)); -} +} diff --git a/libraries/DallasTemperature/examples/Single/Single.pde b/libraries/DallasTemperature/examples/Single/Single.pde index 57994b6..61cfcd0 100644 --- a/libraries/DallasTemperature/examples/Single/Single.pde +++ b/libraries/DallasTemperature/examples/Single/Single.pde @@ -106,4 +106,4 @@ void printAddress(DeviceAddress deviceAddress) if (deviceAddress[i] < 16) Serial.print("0"); Serial.print(deviceAddress[i], HEX); } -} +} diff --git a/libraries/DallasTemperature/examples/Tester/Tester.pde b/libraries/DallasTemperature/examples/Tester/Tester.pde index 063d265..8da0722 100644 --- a/libraries/DallasTemperature/examples/Tester/Tester.pde +++ b/libraries/DallasTemperature/examples/Tester/Tester.pde @@ -121,4 +121,4 @@ void printAddress(DeviceAddress deviceAddress) if (deviceAddress[i] < 16) Serial.print("0"); Serial.print(deviceAddress[i], HEX); } -} +} diff --git a/libraries/InterruptChain/README.TXT b/libraries/InterruptChain/README.TXT index 53716fa..07e06dd 100644 --- a/libraries/InterruptChain/README.TXT +++ b/libraries/InterruptChain/README.TXT @@ -1,36 +1,36 @@ -InterruptChain library v1.3.0 (20130601) for Arduino 1.0 -Made by Randy Simons http://randysimons.nl/ - -This library allows for daisychaining the interrupts, i.e. you can attach -more than one interrupt handler to a single interrupt. - -See the examples for usage. See InterruptChainLib.h for details! - -License: GPLv3. See ./InterruptChain/license.txt - -Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino - - -Installation of library: - - Make sure Arduino is closed - - Copy the directory InterruptChain to the Arduino library directory (usually - /libraries/) - See http://arduino.cc/en/Guide/Libraries for detailed instructions. - -Examples are provided. - - -Changelog: -InterruptChain library v1.3.0 (20130601) for Arduino 1.0 - - Dropped support for Arduino pre-1.0 - - Doesn't use recursion internally, and fewer function calls. This should save - some extra bytes in RAM, at the cost of moderately increased Flash usage. - -InterruptChain library v1.2.0 (20120213) for Arduino 0022/1.0 - - Support for Arduino 1.0. - -InterruptChain library v1.1.0 (20110921) for Arduino 0022 - - Added enable, disable. Expanded setMode. - -InterruptChain library v1.0.0 (20110919) for Arduino 0022 +InterruptChain library v1.3.0 (20130601) for Arduino 1.0 +Made by Randy Simons http://randysimons.nl/ + +This library allows for daisychaining the interrupts, i.e. you can attach +more than one interrupt handler to a single interrupt. + +See the examples for usage. See InterruptChainLib.h for details! + +License: GPLv3. See ./InterruptChain/license.txt + +Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino + + +Installation of library: + - Make sure Arduino is closed + - Copy the directory InterruptChain to the Arduino library directory (usually + /libraries/) + See http://arduino.cc/en/Guide/Libraries for detailed instructions. + +Examples are provided. + + +Changelog: +InterruptChain library v1.3.0 (20130601) for Arduino 1.0 + - Dropped support for Arduino pre-1.0 + - Doesn't use recursion internally, and fewer function calls. This should save + some extra bytes in RAM, at the cost of moderately increased Flash usage. + +InterruptChain library v1.2.0 (20120213) for Arduino 0022/1.0 + - Support for Arduino 1.0. + +InterruptChain library v1.1.0 (20110921) for Arduino 0022 + - Added enable, disable. Expanded setMode. + +InterruptChain library v1.0.0 (20110919) for Arduino 0022 - First release \ No newline at end of file diff --git a/libraries/InterruptChain/keywords.txt b/libraries/InterruptChain/keywords.txt index 8a5ae9c..7b0c9cc 100644 --- a/libraries/InterruptChain/keywords.txt +++ b/libraries/InterruptChain/keywords.txt @@ -1,5 +1,5 @@ -InterruptChain KEYWORD1 -addInterruptCallback KEYWORD2 -setMode KEYWORD2 -enable KEYWORD2 +InterruptChain KEYWORD1 +addInterruptCallback KEYWORD2 +setMode KEYWORD2 +enable KEYWORD2 disable KEYWORD2 \ No newline at end of file diff --git a/libraries/NewPing/NewPing.cpp b/libraries/NewPing/NewPing.cpp index edf0135..b66bd6c 100644 --- a/libraries/NewPing/NewPing.cpp +++ b/libraries/NewPing/NewPing.cpp @@ -1,231 +1,231 @@ -// --------------------------------------------------------------------------- -// Created by Tim Eckel - teckel@leethost.com -// Copyright 2012 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html -// -// See "NewPing.h" for purpose, syntax, version history, links, and more. -// --------------------------------------------------------------------------- - -#include "NewPing.h" - - -// --------------------------------------------------------------------------- -// NewPing constructor -// --------------------------------------------------------------------------- - -NewPing::NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance) { - _triggerBit = digitalPinToBitMask(trigger_pin); // Get the port register bitmask for the trigger pin. - _echoBit = digitalPinToBitMask(echo_pin); // Get the port register bitmask for the echo pin. - - _triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin. - _echoInput = portInputRegister(digitalPinToPort(echo_pin)); // Get the input port register for the echo pin. - - _triggerMode = (uint8_t *) portModeRegister(digitalPinToPort(trigger_pin)); // Get the port mode register for the trigger pin. - - _maxEchoTime = min(max_cm_distance, MAX_SENSOR_DISTANCE) * US_ROUNDTRIP_CM + (US_ROUNDTRIP_CM / 2); // Calculate the maximum distance in uS. - -#if DISABLE_ONE_PIN == true - *_triggerMode |= _triggerBit; // Set trigger pin to output. -#endif -} - - -// --------------------------------------------------------------------------- -// Standard ping methods -// --------------------------------------------------------------------------- - -unsigned int NewPing::ping() { - if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function. - while (*_echoInput & _echoBit) // Wait for the ping echo. - if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance. - return (micros() - (_max_time - _maxEchoTime) - 5); // Calculate ping time, 5uS of overhead. -} - - -unsigned int NewPing::ping_in() { - unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS. - return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches. -} - - -unsigned int NewPing::ping_cm() { - unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS. - return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters. -} - - -unsigned int NewPing::ping_median(uint8_t it) { - unsigned int uS[it], last; - uint8_t j, i = 0; - uS[0] = NO_ECHO; - while (i < it) { - last = ping(); // Send ping. - if (last == NO_ECHO) { // Ping out of range. - it--; // Skip, don't include as part of median. - last = _maxEchoTime; // Adjust "last" variable so delay is correct length. - } else { // Ping in range, include as part of median. - if (i > 0) { // Don't start sort till second ping. - for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop. - uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion. - } else j = 0; // First ping is starting point for sort. - uS[j] = last; // Add last ping to array in sorted position. - i++; // Move to next ping. - } - if (i < it) delay(PING_MEDIAN_DELAY - (last >> 10)); // Millisecond delay between pings. - } - return (uS[it >> 1]); // Return the ping distance median. -} - - -// --------------------------------------------------------------------------- -// Standard ping method support functions (not called directly) -// --------------------------------------------------------------------------- - -boolean NewPing::ping_trigger() { -#if DISABLE_ONE_PIN != true - *_triggerMode |= _triggerBit; // Set trigger pin to output. -#endif - *_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is. - delayMicroseconds(4); // Wait for pin to go low, testing shows it needs 4uS to work every time. - *_triggerOutput |= _triggerBit; // Set trigger pin high, this tells the sensor to send out a ping. - delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS. - *_triggerOutput &= ~_triggerBit; // Set trigger pin back to low. -#if DISABLE_ONE_PIN != true - *_triggerMode &= ~_triggerBit; // Set trigger pin to input (when using one Arduino pin this is technically setting the echo pin to input as both are tied to the same Arduino pin). -#endif - - _max_time = micros() + MAX_SENSOR_DELAY; // Set a timeout for the ping to trigger. - while (*_echoInput & _echoBit && micros() <= _max_time) {} // Wait for echo pin to clear. - while (!(*_echoInput & _echoBit)) // Wait for ping to start. - if (micros() > _max_time) return false; // Something went wrong, abort. - - _max_time = micros() + _maxEchoTime; // Ping started, set the timeout. - return true; // Ping started successfully. -} - - -// --------------------------------------------------------------------------- -// Timer interrupt ping methods (won't work with ATmega8 and ATmega128) -// --------------------------------------------------------------------------- - -void NewPing::ping_timer(void (*userFunc)(void)) { - if (!ping_trigger()) return; // Trigger a ping, if it returns false, return without starting the echo timer. - timer_us(ECHO_TIMER_FREQ, userFunc); // Set ping echo timer check every ECHO_TIMER_FREQ uS. -} - - -boolean NewPing::check_timer() { - if (micros() > _max_time) { // Outside the timeout limit. - timer_stop(); // Disable timer interrupt - return false; // Cancel ping timer. - } - - if (!(*_echoInput & _echoBit)) { // Ping echo received. - timer_stop(); // Disable timer interrupt - ping_result = (micros() - (_max_time - _maxEchoTime) - 13); // Calculate ping time, 13uS of overhead. - return true; // Return ping echo true. - } - - return false; // Return false because there's no ping echo yet. -} - - -// --------------------------------------------------------------------------- -// Timer2/Timer4 interrupt methods (can be used for non-ultrasonic needs) -// --------------------------------------------------------------------------- - -// Variables used for timer functions -void (*intFunc)(); -void (*intFunc2)(); -unsigned long _ms_cnt_reset; -volatile unsigned long _ms_cnt; - - -void NewPing::timer_us(unsigned int frequency, void (*userFunc)(void)) { - timer_setup(); // Configure the timer interrupt. - intFunc = userFunc; // User's function to call when there's a timer event. - -#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo). - OCR4C = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit. - TIMSK4 = (1<>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit. - TIMSK2 |= (1< _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance. + return (micros() - (_max_time - _maxEchoTime) - 5); // Calculate ping time, 5uS of overhead. +} + + +unsigned int NewPing::ping_in() { + unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS. + return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches. +} + + +unsigned int NewPing::ping_cm() { + unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS. + return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters. +} + + +unsigned int NewPing::ping_median(uint8_t it) { + unsigned int uS[it], last; + uint8_t j, i = 0; + uS[0] = NO_ECHO; + while (i < it) { + last = ping(); // Send ping. + if (last == NO_ECHO) { // Ping out of range. + it--; // Skip, don't include as part of median. + last = _maxEchoTime; // Adjust "last" variable so delay is correct length. + } else { // Ping in range, include as part of median. + if (i > 0) { // Don't start sort till second ping. + for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop. + uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion. + } else j = 0; // First ping is starting point for sort. + uS[j] = last; // Add last ping to array in sorted position. + i++; // Move to next ping. + } + if (i < it) delay(PING_MEDIAN_DELAY - (last >> 10)); // Millisecond delay between pings. + } + return (uS[it >> 1]); // Return the ping distance median. +} + + +// --------------------------------------------------------------------------- +// Standard ping method support functions (not called directly) +// --------------------------------------------------------------------------- + +boolean NewPing::ping_trigger() { +#if DISABLE_ONE_PIN != true + *_triggerMode |= _triggerBit; // Set trigger pin to output. +#endif + *_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is. + delayMicroseconds(4); // Wait for pin to go low, testing shows it needs 4uS to work every time. + *_triggerOutput |= _triggerBit; // Set trigger pin high, this tells the sensor to send out a ping. + delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS. + *_triggerOutput &= ~_triggerBit; // Set trigger pin back to low. +#if DISABLE_ONE_PIN != true + *_triggerMode &= ~_triggerBit; // Set trigger pin to input (when using one Arduino pin this is technically setting the echo pin to input as both are tied to the same Arduino pin). +#endif + + _max_time = micros() + MAX_SENSOR_DELAY; // Set a timeout for the ping to trigger. + while (*_echoInput & _echoBit && micros() <= _max_time) {} // Wait for echo pin to clear. + while (!(*_echoInput & _echoBit)) // Wait for ping to start. + if (micros() > _max_time) return false; // Something went wrong, abort. + + _max_time = micros() + _maxEchoTime; // Ping started, set the timeout. + return true; // Ping started successfully. +} + + +// --------------------------------------------------------------------------- +// Timer interrupt ping methods (won't work with ATmega8 and ATmega128) +// --------------------------------------------------------------------------- + +void NewPing::ping_timer(void (*userFunc)(void)) { + if (!ping_trigger()) return; // Trigger a ping, if it returns false, return without starting the echo timer. + timer_us(ECHO_TIMER_FREQ, userFunc); // Set ping echo timer check every ECHO_TIMER_FREQ uS. +} + + +boolean NewPing::check_timer() { + if (micros() > _max_time) { // Outside the timeout limit. + timer_stop(); // Disable timer interrupt + return false; // Cancel ping timer. + } + + if (!(*_echoInput & _echoBit)) { // Ping echo received. + timer_stop(); // Disable timer interrupt + ping_result = (micros() - (_max_time - _maxEchoTime) - 13); // Calculate ping time, 13uS of overhead. + return true; // Return ping echo true. + } + + return false; // Return false because there's no ping echo yet. +} + + +// --------------------------------------------------------------------------- +// Timer2/Timer4 interrupt methods (can be used for non-ultrasonic needs) +// --------------------------------------------------------------------------- + +// Variables used for timer functions +void (*intFunc)(); +void (*intFunc2)(); +unsigned long _ms_cnt_reset; +volatile unsigned long _ms_cnt; + + +void NewPing::timer_us(unsigned int frequency, void (*userFunc)(void)) { + timer_setup(); // Configure the timer interrupt. + intFunc = userFunc; // User's function to call when there's a timer event. + +#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo). + OCR4C = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit. + TIMSK4 = (1<>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit. + TIMSK2 |= (1<= 100 - #include -#else - #include - #include -#endif - -#include -#include - -// Shoudln't need to changed these values unless you have a specific need to do so. -#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back. -#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space. -#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. -#define DISABLE_ONE_PIN false // Set to "true" to save up to 26 bytes of compiled code space if you're not using one pin sensor connections. - -// Probably shoudln't change these values unless you really know what you're doing. -#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance. -#define MAX_SENSOR_DELAY 18000 // Maximum uS it takes for sensor to start the ping (SRF06 is the highest measured, just under 18ms). -#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy). -#define PING_MEDIAN_DELAY 29 // Millisecond delay between pings in the ping_median method. - -// Conversion from uS to distance (round result to nearest cm or inch). -#define NewPingConvert(echoTime, conversionFactor) (max((echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0))) - - -class NewPing { - public: - NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance = MAX_SENSOR_DISTANCE); - unsigned int ping(); - unsigned int ping_in(); - unsigned int ping_cm(); - unsigned int ping_median(uint8_t it = 5); - unsigned int convert_in(unsigned int echoTime); - unsigned int convert_cm(unsigned int echoTime); - void ping_timer(void (*userFunc)(void)); - boolean check_timer(); - unsigned long ping_result; - static void timer_us(unsigned int frequency, void (*userFunc)(void)); - static void timer_ms(unsigned long frequency, void (*userFunc)(void)); - static void timer_stop(); - private: - boolean ping_trigger(); - boolean ping_wait_timer(); - uint8_t _triggerBit; - uint8_t _echoBit; - volatile uint8_t *_triggerOutput; - volatile uint8_t *_triggerMode; - volatile uint8_t *_echoInput; - unsigned int _maxEchoTime; - unsigned long _max_time; - static void timer_setup(); - static void timer_ms_cntdwn(); -}; - - +// --------------------------------------------------------------------------- +// NewPing Library - v1.5 - 08/15/2012 +// +// AUTHOR/LICENSE: +// Created by Tim Eckel - teckel@leethost.com +// Copyright 2012 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html +// +// LINKS: +// Project home: http://code.google.com/p/arduino-new-ping/ +// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html +// +// DISCLAIMER: +// This software is furnished "as is", without technical support, and with no +// warranty, express or implied, as to its usefulness for any purpose. +// +// BACKGROUND: +// When I first received an ultrasonic sensor I was not happy with how poorly +// it worked. Quickly I realized the problem wasn't the sensor, it was the +// available ping and ultrasonic libraries causing the problem. The NewPing +// library totally fixes these problems, adds many new features, and breaths +// new life into these very affordable distance sensors. +// +// FEATURES: +// * Works with many different ultrasonic sensor models: SR04, SRF05, SRF06, DYP-ME007 & Parallax PING)))™. +// * Interface with all but the SRF06 sensor using only one Arduino pin. +// * Doesn't lag for a full second if no ping/echo is received. +// * Ping sensors consistently and reliably at up to 30 times per second. +// * Timer interrupt method for event-driven sketches. +// * Built-in digital filter method ping_median() for easy error correction. +// * Uses port registers for a faster pin interface and smaller code size. +// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear". +// * Ease of using multiple sensors (example sketch with 15 sensors). +// * More accurate distance calculation (cm, inches & uS). +// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models. +// * Actively developed with features being added and bugs/issues addressed. +// +// CONSTRUCTOR: +// NewPing sonar(trigger_pin, echo_pin [, max_cm_distance]) +// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo. +// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values. +// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm. +// +// SYNTAX: +// sonar.ping() - Send a ping and get the echo time (in microseconds) as a result. +// sonar.ping_in() - Send a ping and get the distance in whole inches. +// sonar.ping_cm() - Send a ping and get the distance in whole centimeters. +// sonar.ping_median(iterations) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. +// sonar.convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch). +// sonar.convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm). +// sonar.ping_timer(function) - Send a ping and call function to test if ping is complete. +// sonar.check_timer() - Check if ping has returned within the set distance limit. +// NewPing::timer_us(frequency, function) - Call function every frequency microseconds. +// NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds. +// NewPing::timer_stop() - Stop the timer. +// +// HISTORY: +// 08/15/2012 v1.5 - Added ping_median() method which does a user specified +// number of pings (default=5) and returns the median ping in microseconds +// (out of range pings ignored). This is a very effective digital filter. +// Optimized for smaller compiled size (even smaller than skteches that +// don't use a library). +// +// 07/14/2012 v1.4 - Added support for the Parallax PING)))™ sensor. Interface +// with all but the SRF06 sensor using only one Arduino pin. You can also +// interface with the SRF06 using one pin if you install a 0.1uf capacitor +// on the trigger and echo pins of the sensor then tie the trigger pin to +// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin +// for trigger and echo, specify the same pin for both values. Various bug +// fixes. +// +// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2 +// interrupt, so be mindful of PWM or timing conflicts messing with Timer2 +// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on +// Mega, and Tone library). Simple to use timer interrupt functions you can +// use in your sketches totaly unrelated to ultrasonic sensors (don't use if +// you're also using NewPing's ping_timer because both use Timer2 interrupts). +// Loop counting ping method deleted in favor of timing ping method after +// inconsistant results kept surfacing with the loop timing ping method. +// Conversion to cm and inches now rounds to the nearest cm or inch. Code +// optimized to save program space and fixed a couple minor bugs here and +// there. Many new comments added as well as line spacing to group code +// sections for better source readability. +// +// 05/25/2012 v1.2 - Lots of code clean-up thanks to Adruino Forum members. +// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it +// doesn't give correct results (at least with ping sensors). The NewPing +// library is now VERY accurate and the code was simplified as a bonus. +// Smaller and faster code as well. Fixed some issues with very close ping +// results when converting to inches. All functions now return 0 only when +// there's no ping echo (out of range) and a positive value for a successful +// ping. This can effectively be used to detect if something is out of range +// or in-range and at what distance. Now compatible with Arduino 0023. +// +// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers +// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both +// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based +// platforms because it calls standard functions to retrieve port registers +// and bit masks. Also made a couple minor fixes to defines. +// +// 05/15/2012 v1.0 - Initial release. +// --------------------------------------------------------------------------- + +#ifndef NewPing_h +#define NewPing_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include + #include +#endif + +#include +#include + +// Shoudln't need to changed these values unless you have a specific need to do so. +#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back. +#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space. +#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. +#define DISABLE_ONE_PIN false // Set to "true" to save up to 26 bytes of compiled code space if you're not using one pin sensor connections. + +// Probably shoudln't change these values unless you really know what you're doing. +#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance. +#define MAX_SENSOR_DELAY 18000 // Maximum uS it takes for sensor to start the ping (SRF06 is the highest measured, just under 18ms). +#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy). +#define PING_MEDIAN_DELAY 29 // Millisecond delay between pings in the ping_median method. + +// Conversion from uS to distance (round result to nearest cm or inch). +#define NewPingConvert(echoTime, conversionFactor) (max((echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0))) + + +class NewPing { + public: + NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance = MAX_SENSOR_DISTANCE); + unsigned int ping(); + unsigned int ping_in(); + unsigned int ping_cm(); + unsigned int ping_median(uint8_t it = 5); + unsigned int convert_in(unsigned int echoTime); + unsigned int convert_cm(unsigned int echoTime); + void ping_timer(void (*userFunc)(void)); + boolean check_timer(); + unsigned long ping_result; + static void timer_us(unsigned int frequency, void (*userFunc)(void)); + static void timer_ms(unsigned long frequency, void (*userFunc)(void)); + static void timer_stop(); + private: + boolean ping_trigger(); + boolean ping_wait_timer(); + uint8_t _triggerBit; + uint8_t _echoBit; + volatile uint8_t *_triggerOutput; + volatile uint8_t *_triggerMode; + volatile uint8_t *_echoInput; + unsigned int _maxEchoTime; + unsigned long _max_time; + static void timer_setup(); + static void timer_ms_cntdwn(); +}; + + #endif \ No newline at end of file diff --git a/libraries/NewPing/examples/NewPing15Sensors/NewPing15Sensors.pde b/libraries/NewPing/examples/NewPing15Sensors/NewPing15Sensors.pde index 9af1f6c..8354059 100644 --- a/libraries/NewPing/examples/NewPing15Sensors/NewPing15Sensors.pde +++ b/libraries/NewPing/examples/NewPing15Sensors/NewPing15Sensors.pde @@ -1,74 +1,74 @@ -// --------------------------------------------------------------------------- -// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust -// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the -// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor -// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results -// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project -// would normally process the sensor results in this function (for example, decide if a robot needs to -// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs -// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other -// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind. -// --------------------------------------------------------------------------- -#include - -#define SONAR_NUM 15 // Number or sensors. -#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping. -#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo). - -unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor. -unsigned int cm[SONAR_NUM]; // Where the ping distances are stored. -uint8_t currentSensor = 0; // Keeps track of which sensor is active. - -NewPing sonar[SONAR_NUM] = { // Sensor object array. - NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping. - NewPing(43, 44, MAX_DISTANCE), - NewPing(45, 20, MAX_DISTANCE), - NewPing(21, 22, MAX_DISTANCE), - NewPing(23, 24, MAX_DISTANCE), - NewPing(25, 26, MAX_DISTANCE), - NewPing(27, 28, MAX_DISTANCE), - NewPing(29, 30, MAX_DISTANCE), - NewPing(31, 32, MAX_DISTANCE), - NewPing(34, 33, MAX_DISTANCE), - NewPing(35, 36, MAX_DISTANCE), - NewPing(37, 38, MAX_DISTANCE), - NewPing(39, 40, MAX_DISTANCE), - NewPing(50, 51, MAX_DISTANCE), - NewPing(52, 53, MAX_DISTANCE) -}; - -void setup() { - Serial.begin(115200); - pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting. - for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor. - pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL; -} - -void loop() { - for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors. - if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping? - pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged. - if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results. - sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance). - currentSensor = i; // Sensor being accessed. - cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor. - sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo). - } - } - // The rest of your code would go here. -} - -void echoCheck() { // If ping received, set the sensor distance to array. - if (sonar[currentSensor].check_timer()) - cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM; -} - -void oneSensorCycle() { // Sensor ping cycle complete, do something with the results. - for (uint8_t i = 0; i < SONAR_NUM; i++) { - Serial.print(i); - Serial.print("="); - Serial.print(cm[i]); - Serial.print("cm "); - } - Serial.println(); +// --------------------------------------------------------------------------- +// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust +// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the +// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor +// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results +// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project +// would normally process the sensor results in this function (for example, decide if a robot needs to +// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs +// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other +// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind. +// --------------------------------------------------------------------------- +#include + +#define SONAR_NUM 15 // Number or sensors. +#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping. +#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo). + +unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor. +unsigned int cm[SONAR_NUM]; // Where the ping distances are stored. +uint8_t currentSensor = 0; // Keeps track of which sensor is active. + +NewPing sonar[SONAR_NUM] = { // Sensor object array. + NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping. + NewPing(43, 44, MAX_DISTANCE), + NewPing(45, 20, MAX_DISTANCE), + NewPing(21, 22, MAX_DISTANCE), + NewPing(23, 24, MAX_DISTANCE), + NewPing(25, 26, MAX_DISTANCE), + NewPing(27, 28, MAX_DISTANCE), + NewPing(29, 30, MAX_DISTANCE), + NewPing(31, 32, MAX_DISTANCE), + NewPing(34, 33, MAX_DISTANCE), + NewPing(35, 36, MAX_DISTANCE), + NewPing(37, 38, MAX_DISTANCE), + NewPing(39, 40, MAX_DISTANCE), + NewPing(50, 51, MAX_DISTANCE), + NewPing(52, 53, MAX_DISTANCE) +}; + +void setup() { + Serial.begin(115200); + pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting. + for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor. + pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL; +} + +void loop() { + for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors. + if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping? + pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged. + if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results. + sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance). + currentSensor = i; // Sensor being accessed. + cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor. + sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo). + } + } + // The rest of your code would go here. +} + +void echoCheck() { // If ping received, set the sensor distance to array. + if (sonar[currentSensor].check_timer()) + cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM; +} + +void oneSensorCycle() { // Sensor ping cycle complete, do something with the results. + for (uint8_t i = 0; i < SONAR_NUM; i++) { + Serial.print(i); + Serial.print("="); + Serial.print(cm[i]); + Serial.print("cm "); + } + Serial.println(); } \ No newline at end of file diff --git a/libraries/NewPing/examples/NewPingExample/NewPingExample.ino b/libraries/NewPing/examples/NewPingExample/NewPingExample.ino index 42b2739..a37f5e9 100644 --- a/libraries/NewPing/examples/NewPingExample/NewPingExample.ino +++ b/libraries/NewPing/examples/NewPingExample/NewPingExample.ino @@ -20,4 +20,4 @@ void loop() { Serial.print("Ping: "); Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range) Serial.println("cm"); -} +} diff --git a/libraries/NewPing/examples/TimerExample/TimerExample.pde b/libraries/NewPing/examples/TimerExample/TimerExample.pde index ea66039..35e1db2 100644 --- a/libraries/NewPing/examples/TimerExample/TimerExample.pde +++ b/libraries/NewPing/examples/TimerExample/TimerExample.pde @@ -1,25 +1,25 @@ -// --------------------------------------------------------------------------- -// While the NewPing library's primary goal is to interface with ultrasonic sensors, interfacing with -// the Timer2 interrupt was a result of creating an interrupt-based ping method. Since these Timer2 -// interrupt methods were built, the library may as well provide the functionality to use these methods -// in your sketches. This shows how simple it is (no ultrasonic sensor required). Keep in mind that -// these methods use Timer2, as does NewPing's ping_timer method for using ultrasonic sensors. You -// can't use ping_timer at the same time you're using timer_ms or timer_us as all use the same timer. -// --------------------------------------------------------------------------- - -#include - -#define LED_PIN 13 // Pin with LED attached. - -void setup() { - pinMode(LED_PIN, OUTPUT); - NewPing::timer_ms(500, toggleLED); // Create a Timer2 interrupt that calls toggleLED in your sketch once every 500 milliseconds. -} - -void loop() { - // Do anything here, the Timer2 interrupt will take care of the flashing LED without your intervention. -} - -void toggleLED() { - digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED. +// --------------------------------------------------------------------------- +// While the NewPing library's primary goal is to interface with ultrasonic sensors, interfacing with +// the Timer2 interrupt was a result of creating an interrupt-based ping method. Since these Timer2 +// interrupt methods were built, the library may as well provide the functionality to use these methods +// in your sketches. This shows how simple it is (no ultrasonic sensor required). Keep in mind that +// these methods use Timer2, as does NewPing's ping_timer method for using ultrasonic sensors. You +// can't use ping_timer at the same time you're using timer_ms or timer_us as all use the same timer. +// --------------------------------------------------------------------------- + +#include + +#define LED_PIN 13 // Pin with LED attached. + +void setup() { + pinMode(LED_PIN, OUTPUT); + NewPing::timer_ms(500, toggleLED); // Create a Timer2 interrupt that calls toggleLED in your sketch once every 500 milliseconds. +} + +void loop() { + // Do anything here, the Timer2 interrupt will take care of the flashing LED without your intervention. +} + +void toggleLED() { + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED. } \ No newline at end of file diff --git a/libraries/NewPing/keywords.txt b/libraries/NewPing/keywords.txt index 9ef581a..ff7805b 100644 --- a/libraries/NewPing/keywords.txt +++ b/libraries/NewPing/keywords.txt @@ -1,29 +1,29 @@ -################################### -# Syntax Coloring Map For NewPing -################################### - -################################### -# Datatypes (KEYWORD1) -################################### - -NewPing KEYWORD1 - -################################### -# Methods and Functions (KEYWORD2) -################################### - -ping KEYWORD2 -ping_in KEYWORD2 -ping_cm KEYWORD2 -ping_median KEYWORD2 -ping_timer KEYWORD2 -check_timer KEYWORD2 -timer_us KEYWORD2 -timer_ms KEYWORD2 -timer_stop KEYWORD2 -convert_in KEYWORD2 -convert_cm KEYWORD2 - -################################### -# Constants (LITERAL1) -################################### +################################### +# Syntax Coloring Map For NewPing +################################### + +################################### +# Datatypes (KEYWORD1) +################################### + +NewPing KEYWORD1 + +################################### +# Methods and Functions (KEYWORD2) +################################### + +ping KEYWORD2 +ping_in KEYWORD2 +ping_cm KEYWORD2 +ping_median KEYWORD2 +ping_timer KEYWORD2 +check_timer KEYWORD2 +timer_us KEYWORD2 +timer_ms KEYWORD2 +timer_stop KEYWORD2 +convert_in KEYWORD2 +convert_cm KEYWORD2 + +################################### +# Constants (LITERAL1) +################################### diff --git a/libraries/NewRemoteSwitch/NewRemoteReceiver.cpp b/libraries/NewRemoteSwitch/NewRemoteReceiver.cpp index a2ebf40..b4e9ce6 100644 --- a/libraries/NewRemoteSwitch/NewRemoteReceiver.cpp +++ b/libraries/NewRemoteSwitch/NewRemoteReceiver.cpp @@ -1,318 +1,318 @@ -/* - * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ - * See NewRemoteReceiver.h for details. - * - * License: GPLv3. See license.txt - */ - -#include "NewRemoteReceiver.h" - - -/************ -* NewRemoteReceiver - -Protocol. (Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410, -but with slightly different timings, as measured on my device.) - _ _ -'0': | |_| |_____ (T,T,T,5T) - _ _ -'1': | |_____| |_ (T,5T,T,T) - _ _ -dim: | |_| |_ (T,T,T,T) - -T = short period of ~260µs. However, this code tries -to figure out the correct period - -A full frame looks like this: - -- start pulse: 1T high, 10.44T low -- 26 bit: Address -- 1 bit: group bit -- 1 bit: on/off/[dim] -- 4 bit: unit -- [4 bit: dim level. Only present of [dim] is chosen] -- stop pulse: 1T high, 40T low - -************/ - -int8_t NewRemoteReceiver::_interrupt; -volatile short NewRemoteReceiver::_state; -byte NewRemoteReceiver::_minRepeats; -NewRemoteReceiverCallBack NewRemoteReceiver::_callback; -boolean NewRemoteReceiver::_inCallback = false; -boolean NewRemoteReceiver::_enabled = false; - -void NewRemoteReceiver::init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback) { - _interrupt = interrupt; - _minRepeats = minRepeats; - _callback = callback; - - enable(); - if (_interrupt >= 0) { - attachInterrupt(_interrupt, interruptHandler, CHANGE); - } -} - -void NewRemoteReceiver::enable() { - _state = -1; - _enabled = true; -} - -void NewRemoteReceiver::disable() { - _enabled = false; -} - -void NewRemoteReceiver::deinit() { - _enabled = false; - if (_interrupt >= 0) { - detachInterrupt(_interrupt); - } -} - -void NewRemoteReceiver::interruptHandler() { - // This method is written as compact code to keep it fast. While breaking up this method into more - // methods would certainly increase the readability, it would also be much slower to execute. - // Making calls to other methods is quite expensive on AVR. As These interrupt handlers are called - // many times a second, calling other methods should be kept to a minimum. - - if (!_enabled) { - return; - } - - static byte receivedBit; // Contains "bit" currently receiving - static NewRemoteCode receivedCode; // Contains received code - static NewRemoteCode previousCode; // Contains previous received code - static byte repeats = 0; // The number of times the an identical code is received in a row. - static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges - static unsigned int min1Period, max1Period, min5Period, max5Period; - static bool skip; - - // Filter out too short pulses. This method works as a low pass filter. - edgeTimeStamp[1] = edgeTimeStamp[2]; - edgeTimeStamp[2] = micros(); - - if (skip) { - skip = false; - return; - } - - if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) { - // Last edge was too short. - // Skip this edge, and the next too. - skip = true; - return; - } - - unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0]; - edgeTimeStamp[0] = edgeTimeStamp[1]; - - // Note that if state>=0, duration is always >= 1 period. - - if (_state == -1) { - // wait for the long low part of a stop bit. - // Stopbit: 1T high, 40T low - // By default 1T is 260µs, but for maximum compatibility go as low as 120µs - if (duration > 4800) { // =40*120µs, minimal time between two edges before decoding starts. - // Sync signal received.. Preparing for decoding - repeats = 0; - - receivedCode.period = duration / 40; // Measured signal is 40T, so 1T (period) is measured signal / 40. - - // Allow for large error-margin. ElCheapo-hardware :( - min1Period = receivedCode.period * 3 / 10; // Lower limit for 1 period is 0.3 times measured period; high signals can "linger" a bit sometimes, making low signals quite short. - max1Period = receivedCode.period * 3; // Upper limit for 1 period is 3 times measured period - min5Period = receivedCode.period * 3; // Lower limit for 5 periods is 3 times measured period - max5Period = receivedCode.period * 8; // Upper limit for 5 periods is 8 times measured period - } - else { - return; - } - } else if (_state == 0) { // Verify start bit part 1 of 2 - // Duration must be ~1T - if (duration > max1Period) { - _state = -1; - return; - } - // Start-bit passed. Do some clean-up. - receivedCode.address = receivedCode.unit = receivedCode.dimLevel = 0; - } else if (_state == 1) { // Verify start bit part 2 of 2 - // Duration must be ~10.44T - if (duration < 7 * receivedCode.period || duration > 15 * receivedCode.period) { - _state = -1; - return; - } - } else if (_state < 148) { // state 146 is first edge of stop-sequence. All bits before that adhere to default protocol, with exception of dim-bit - receivedBit <<= 1; - - // One bit consists out of 4 bit parts. - // bit part durations can ONLY be 1 or 5 periods. - if (duration <= max1Period) { - receivedBit &= B1110; // Clear LSB of receivedBit - } else if (duration >= min5Period && duration <= max5Period) { - receivedBit |= B1; // Set LSB of receivedBit - } else if ( - // Check if duration matches the second part of stopbit (duration must be ~40T), and ... - (duration >= 20 * receivedCode.period && duration <= 80 * receivedCode.period) && - // if first part op stopbit was a short signal (short signal yielded a 0 as second bit in receivedBit), and ... - ((receivedBit & B10) == B00) && - // we are in a state in which a stopbit is actually valid, only then ... - (_state == 147 || _state == 131) ) { - // If a dim-level was present... - if (_state == 147) { - // ... test if it was an "on" signal ... - if (receivedCode.switchType == NewRemoteCode::on) { - // ... set the appropriate switch type - receivedCode.switchType = NewRemoteCode::on_with_dim; - } else { - // ... otherwise it was wrong (e.g. off-signal with dim) - _state = -1; - return; - } - } - - // a valid signal was found! - if ( - receivedCode.address != previousCode.address || - receivedCode.unit != previousCode.unit || - receivedCode.dimLevel != previousCode.dimLevel || - receivedCode.groupBit != previousCode.groupBit || - receivedCode.switchType != previousCode.switchType - ) { // memcmp isn't deemed safe - repeats=0; - previousCode = receivedCode; - } - - repeats++; - - if (repeats>=_minRepeats) { - if (!_inCallback) { - _inCallback = true; - (_callback)(receivedCode); - _inCallback = false; - } - // Reset after callback. - _state=-1; - return; - } - - // Reset for next round - _state=0; // no need to wait for another sync-bit! - return; - } - else { // Otherwise the entire sequence is invalid - _state = -1; - return; - } - - if (_state % 4 == 1) { // Last bit part? Note: this is the short version of "if ( (_state-2) % 4 == 3 )" - // There are 3 valid options for receivedBit: - // 0, indicated by short short short long == B0001. - // 1, short long shot short == B0100. - // dim, short shot short shot == B0000. - // Everything else: inconsistent data, trash the whole sequence. - - - if (_state < 106) { - // States 2 - 105 are address bit states - - receivedCode.address <<= 1; - - // Decode bit. Only 4 LSB's of receivedBit are used; trim the rest. - switch (receivedBit & B1111) { - case B0001: // Bit "0" received. - // receivedCode.address |= 0; But let's not do that, as it is wasteful. - break; - case B0100: // Bit "1" received. - receivedCode.address |= 1; - break; - default: // Bit was invalid. Abort. - _state = -1; - return; - } - } else if (_state < 110) { - // States 106 - 109 are group bit states. - switch (receivedBit & B1111) { - case B0001: // Bit "0" received. - receivedCode.groupBit = false; - break; - case B0100: // Bit "1" received. - receivedCode.groupBit = true; - break; - default: // Bit was invalid. Abort. - _state = -1; - return; - } - } else if (_state < 114) { - // States 110 - 113 are switch bit states. - switch (receivedBit & B1111) { - case B0001: // Bit "0" received. - receivedCode.switchType = NewRemoteCode::off; - break; - case B0100: // Bit "1" received. Note: this might turn out to be a on_with_dim signal. - receivedCode.switchType = NewRemoteCode::on; - break; - case B0000: // Bit "dim" received. - receivedCode.switchType = NewRemoteCode::dim; - break; - default: // Bit was invalid. Abort. - _state = -1; - return; - } - } else if (_state < 130){ - // States 114 - 129 are unit bit states. - receivedCode.unit <<= 1; - - // Decode bit. - switch (receivedBit & B1111) { - case B0001: // Bit "0" received. - // receivedCode.unit |= 0; But let's not do that, as it is wasteful. - break; - case B0100: // Bit "1" received. - receivedCode.unit |= 1; - break; - default: // Bit was invalid. Abort. - _state = -1; - return; - } - - } else if (_state < 146) { - // States 130 - 145 are dim bit states. - // If switchType == 0 these are never present. - // If switchType == 2 these are always present. - // If switchType == 1 these are or are not present, depending on the revision of the transmitter. - - receivedCode.dimLevel <<= 1; - - // Decode bit. - switch (receivedBit & B1111) { - case B0001: // Bit "0" received. - // receivedCode.dimLevel |= 0; But let's not do that, as it is wasteful. - break; - case B0100: // Bit "1" received. - receivedCode.dimLevel |= 1; - break; - default: // Bit was invalid. Abort. - _state = -1; - return; - } - } - } - } - - _state++; - return; -} - -boolean NewRemoteReceiver::isReceiving(int waitMillis) { - unsigned long startTime=millis(); - - int waited; // Signed int! - do { - if (_state >= 34) { // Abort if a significant part of a code (start pulse + 8 bits) has been received - return true; - } - waited = (millis()-startTime); - } while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time. - - return false; -} +/* + * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ + * See NewRemoteReceiver.h for details. + * + * License: GPLv3. See license.txt + */ + +#include "NewRemoteReceiver.h" + + +/************ +* NewRemoteReceiver + +Protocol. (Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410, +but with slightly different timings, as measured on my device.) + _ _ +'0': | |_| |_____ (T,T,T,5T) + _ _ +'1': | |_____| |_ (T,5T,T,T) + _ _ +dim: | |_| |_ (T,T,T,T) + +T = short period of ~260µs. However, this code tries +to figure out the correct period + +A full frame looks like this: + +- start pulse: 1T high, 10.44T low +- 26 bit: Address +- 1 bit: group bit +- 1 bit: on/off/[dim] +- 4 bit: unit +- [4 bit: dim level. Only present of [dim] is chosen] +- stop pulse: 1T high, 40T low + +************/ + +int8_t NewRemoteReceiver::_interrupt; +volatile short NewRemoteReceiver::_state; +byte NewRemoteReceiver::_minRepeats; +NewRemoteReceiverCallBack NewRemoteReceiver::_callback; +boolean NewRemoteReceiver::_inCallback = false; +boolean NewRemoteReceiver::_enabled = false; + +void NewRemoteReceiver::init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback) { + _interrupt = interrupt; + _minRepeats = minRepeats; + _callback = callback; + + enable(); + if (_interrupt >= 0) { + attachInterrupt(_interrupt, interruptHandler, CHANGE); + } +} + +void NewRemoteReceiver::enable() { + _state = -1; + _enabled = true; +} + +void NewRemoteReceiver::disable() { + _enabled = false; +} + +void NewRemoteReceiver::deinit() { + _enabled = false; + if (_interrupt >= 0) { + detachInterrupt(_interrupt); + } +} + +void NewRemoteReceiver::interruptHandler() { + // This method is written as compact code to keep it fast. While breaking up this method into more + // methods would certainly increase the readability, it would also be much slower to execute. + // Making calls to other methods is quite expensive on AVR. As These interrupt handlers are called + // many times a second, calling other methods should be kept to a minimum. + + if (!_enabled) { + return; + } + + static byte receivedBit; // Contains "bit" currently receiving + static NewRemoteCode receivedCode; // Contains received code + static NewRemoteCode previousCode; // Contains previous received code + static byte repeats = 0; // The number of times the an identical code is received in a row. + static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges + static unsigned int min1Period, max1Period, min5Period, max5Period; + static bool skip; + + // Filter out too short pulses. This method works as a low pass filter. + edgeTimeStamp[1] = edgeTimeStamp[2]; + edgeTimeStamp[2] = micros(); + + if (skip) { + skip = false; + return; + } + + if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) { + // Last edge was too short. + // Skip this edge, and the next too. + skip = true; + return; + } + + unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0]; + edgeTimeStamp[0] = edgeTimeStamp[1]; + + // Note that if state>=0, duration is always >= 1 period. + + if (_state == -1) { + // wait for the long low part of a stop bit. + // Stopbit: 1T high, 40T low + // By default 1T is 260µs, but for maximum compatibility go as low as 120µs + if (duration > 4800) { // =40*120µs, minimal time between two edges before decoding starts. + // Sync signal received.. Preparing for decoding + repeats = 0; + + receivedCode.period = duration / 40; // Measured signal is 40T, so 1T (period) is measured signal / 40. + + // Allow for large error-margin. ElCheapo-hardware :( + min1Period = receivedCode.period * 3 / 10; // Lower limit for 1 period is 0.3 times measured period; high signals can "linger" a bit sometimes, making low signals quite short. + max1Period = receivedCode.period * 3; // Upper limit for 1 period is 3 times measured period + min5Period = receivedCode.period * 3; // Lower limit for 5 periods is 3 times measured period + max5Period = receivedCode.period * 8; // Upper limit for 5 periods is 8 times measured period + } + else { + return; + } + } else if (_state == 0) { // Verify start bit part 1 of 2 + // Duration must be ~1T + if (duration > max1Period) { + _state = -1; + return; + } + // Start-bit passed. Do some clean-up. + receivedCode.address = receivedCode.unit = receivedCode.dimLevel = 0; + } else if (_state == 1) { // Verify start bit part 2 of 2 + // Duration must be ~10.44T + if (duration < 7 * receivedCode.period || duration > 15 * receivedCode.period) { + _state = -1; + return; + } + } else if (_state < 148) { // state 146 is first edge of stop-sequence. All bits before that adhere to default protocol, with exception of dim-bit + receivedBit <<= 1; + + // One bit consists out of 4 bit parts. + // bit part durations can ONLY be 1 or 5 periods. + if (duration <= max1Period) { + receivedBit &= B1110; // Clear LSB of receivedBit + } else if (duration >= min5Period && duration <= max5Period) { + receivedBit |= B1; // Set LSB of receivedBit + } else if ( + // Check if duration matches the second part of stopbit (duration must be ~40T), and ... + (duration >= 20 * receivedCode.period && duration <= 80 * receivedCode.period) && + // if first part op stopbit was a short signal (short signal yielded a 0 as second bit in receivedBit), and ... + ((receivedBit & B10) == B00) && + // we are in a state in which a stopbit is actually valid, only then ... + (_state == 147 || _state == 131) ) { + // If a dim-level was present... + if (_state == 147) { + // ... test if it was an "on" signal ... + if (receivedCode.switchType == NewRemoteCode::on) { + // ... set the appropriate switch type + receivedCode.switchType = NewRemoteCode::on_with_dim; + } else { + // ... otherwise it was wrong (e.g. off-signal with dim) + _state = -1; + return; + } + } + + // a valid signal was found! + if ( + receivedCode.address != previousCode.address || + receivedCode.unit != previousCode.unit || + receivedCode.dimLevel != previousCode.dimLevel || + receivedCode.groupBit != previousCode.groupBit || + receivedCode.switchType != previousCode.switchType + ) { // memcmp isn't deemed safe + repeats=0; + previousCode = receivedCode; + } + + repeats++; + + if (repeats>=_minRepeats) { + if (!_inCallback) { + _inCallback = true; + (_callback)(receivedCode); + _inCallback = false; + } + // Reset after callback. + _state=-1; + return; + } + + // Reset for next round + _state=0; // no need to wait for another sync-bit! + return; + } + else { // Otherwise the entire sequence is invalid + _state = -1; + return; + } + + if (_state % 4 == 1) { // Last bit part? Note: this is the short version of "if ( (_state-2) % 4 == 3 )" + // There are 3 valid options for receivedBit: + // 0, indicated by short short short long == B0001. + // 1, short long shot short == B0100. + // dim, short shot short shot == B0000. + // Everything else: inconsistent data, trash the whole sequence. + + + if (_state < 106) { + // States 2 - 105 are address bit states + + receivedCode.address <<= 1; + + // Decode bit. Only 4 LSB's of receivedBit are used; trim the rest. + switch (receivedBit & B1111) { + case B0001: // Bit "0" received. + // receivedCode.address |= 0; But let's not do that, as it is wasteful. + break; + case B0100: // Bit "1" received. + receivedCode.address |= 1; + break; + default: // Bit was invalid. Abort. + _state = -1; + return; + } + } else if (_state < 110) { + // States 106 - 109 are group bit states. + switch (receivedBit & B1111) { + case B0001: // Bit "0" received. + receivedCode.groupBit = false; + break; + case B0100: // Bit "1" received. + receivedCode.groupBit = true; + break; + default: // Bit was invalid. Abort. + _state = -1; + return; + } + } else if (_state < 114) { + // States 110 - 113 are switch bit states. + switch (receivedBit & B1111) { + case B0001: // Bit "0" received. + receivedCode.switchType = NewRemoteCode::off; + break; + case B0100: // Bit "1" received. Note: this might turn out to be a on_with_dim signal. + receivedCode.switchType = NewRemoteCode::on; + break; + case B0000: // Bit "dim" received. + receivedCode.switchType = NewRemoteCode::dim; + break; + default: // Bit was invalid. Abort. + _state = -1; + return; + } + } else if (_state < 130){ + // States 114 - 129 are unit bit states. + receivedCode.unit <<= 1; + + // Decode bit. + switch (receivedBit & B1111) { + case B0001: // Bit "0" received. + // receivedCode.unit |= 0; But let's not do that, as it is wasteful. + break; + case B0100: // Bit "1" received. + receivedCode.unit |= 1; + break; + default: // Bit was invalid. Abort. + _state = -1; + return; + } + + } else if (_state < 146) { + // States 130 - 145 are dim bit states. + // If switchType == 0 these are never present. + // If switchType == 2 these are always present. + // If switchType == 1 these are or are not present, depending on the revision of the transmitter. + + receivedCode.dimLevel <<= 1; + + // Decode bit. + switch (receivedBit & B1111) { + case B0001: // Bit "0" received. + // receivedCode.dimLevel |= 0; But let's not do that, as it is wasteful. + break; + case B0100: // Bit "1" received. + receivedCode.dimLevel |= 1; + break; + default: // Bit was invalid. Abort. + _state = -1; + return; + } + } + } + } + + _state++; + return; +} + +boolean NewRemoteReceiver::isReceiving(int waitMillis) { + unsigned long startTime=millis(); + + int waited; // Signed int! + do { + if (_state >= 34) { // Abort if a significant part of a code (start pulse + 8 bits) has been received + return true; + } + waited = (millis()-startTime); + } while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time. + + return false; +} diff --git a/libraries/NewRemoteSwitch/NewRemoteReceiver.h b/libraries/NewRemoteSwitch/NewRemoteReceiver.h index 6b78e7a..eaa5a45 100644 --- a/libraries/NewRemoteSwitch/NewRemoteReceiver.h +++ b/libraries/NewRemoteSwitch/NewRemoteReceiver.h @@ -1,107 +1,107 @@ -/* - * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ - * - * License: GPLv3. See license.txt - */ - -#ifndef NewRemoteReceiver_h -#define NewRemoteReceiver_h - -#include - -struct NewRemoteCode { - enum SwitchType { - off = 0, - on = 1, - dim = 2, - on_with_dim = 3 - }; - - unsigned int period; // Detected duration in microseconds of 1T in the received signal - unsigned long address; // Address of received code. [0..2^26-1] - boolean groupBit; // Group bit set or not - SwitchType switchType; // off, on, dim, on_with_dim. - byte unit; // Unit code of received code [0..15] - byte dimLevel; // Dim level [0..15] iff switchType == 2 -}; - -typedef void (*NewRemoteReceiverCallBack)(NewRemoteCode); - -/** -* See RemoteSwitch for introduction. -* -* NewRemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system -* as well as the signal sent by the RemoteSwtich class. When a correct signal is received, -* a user-defined callback function is called. -* -* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed. -* A call to the callback must be finished before NewRemoteReceiver will call the callback function again, thus -* there is no re-entrant problem. -* -* When sending your own code using NewRemoteSwich, disable() the receiver first. -* -* This is a pure static class, for simplicity and to limit memory-use. -*/ - -class NewRemoteReceiver { - public: - /** - * Initializes the decoder. - * - * If interrupt >= 0, init will register pin to this library. - * If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler() - * yourself whenever the output of the receiver changes, or you can use InterruptChain. - * - * @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details. - If < 0, you must call interruptHandler() yourself. - * @param minRepeats The number of times the same code must be received in a row before the callback is calles - * @param callback Pointer to a callback function, with signature void (*func)(NewRemoteCode) - */ - static void init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback); - - /** - * Enable decoding. No need to call enable() after init(). - */ - static void enable(); - - /** - * Disable decoding. You can re-enable decoding by calling enable(); - */ - static void disable(); - - /** - * Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to - * re-enable decoding, call init() again. - */ - static void deinit(); - - /** - * Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true. - * Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false. - * By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times. - * - * Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is - * the case in the callback), isReceiving() will not work properly. - * - * @param waitMillis number of milliseconds to monitor for signal. - * @return boolean If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true. - */ - static boolean isReceiving(int waitMillis = 150); - - /** - * Called every time the signal level changes (high to low or vice versa). Usually called by interrupt. - */ - static void interruptHandler(); - - private: - - static int8_t _interrupt; // Radio input interrupt - volatile static short _state; // State of decoding process. - static byte _minRepeats; - static NewRemoteReceiverCallBack _callback; - static boolean _inCallback; // When true, the callback function is being executed; prevents re-entrance. - static boolean _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately. - -}; - -#endif +/* + * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ + * + * License: GPLv3. See license.txt + */ + +#ifndef NewRemoteReceiver_h +#define NewRemoteReceiver_h + +#include + +struct NewRemoteCode { + enum SwitchType { + off = 0, + on = 1, + dim = 2, + on_with_dim = 3 + }; + + unsigned int period; // Detected duration in microseconds of 1T in the received signal + unsigned long address; // Address of received code. [0..2^26-1] + boolean groupBit; // Group bit set or not + SwitchType switchType; // off, on, dim, on_with_dim. + byte unit; // Unit code of received code [0..15] + byte dimLevel; // Dim level [0..15] iff switchType == 2 +}; + +typedef void (*NewRemoteReceiverCallBack)(NewRemoteCode); + +/** +* See RemoteSwitch for introduction. +* +* NewRemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system +* as well as the signal sent by the RemoteSwtich class. When a correct signal is received, +* a user-defined callback function is called. +* +* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed. +* A call to the callback must be finished before NewRemoteReceiver will call the callback function again, thus +* there is no re-entrant problem. +* +* When sending your own code using NewRemoteSwich, disable() the receiver first. +* +* This is a pure static class, for simplicity and to limit memory-use. +*/ + +class NewRemoteReceiver { + public: + /** + * Initializes the decoder. + * + * If interrupt >= 0, init will register pin to this library. + * If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler() + * yourself whenever the output of the receiver changes, or you can use InterruptChain. + * + * @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details. + If < 0, you must call interruptHandler() yourself. + * @param minRepeats The number of times the same code must be received in a row before the callback is calles + * @param callback Pointer to a callback function, with signature void (*func)(NewRemoteCode) + */ + static void init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback); + + /** + * Enable decoding. No need to call enable() after init(). + */ + static void enable(); + + /** + * Disable decoding. You can re-enable decoding by calling enable(); + */ + static void disable(); + + /** + * Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to + * re-enable decoding, call init() again. + */ + static void deinit(); + + /** + * Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true. + * Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false. + * By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times. + * + * Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is + * the case in the callback), isReceiving() will not work properly. + * + * @param waitMillis number of milliseconds to monitor for signal. + * @return boolean If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true. + */ + static boolean isReceiving(int waitMillis = 150); + + /** + * Called every time the signal level changes (high to low or vice versa). Usually called by interrupt. + */ + static void interruptHandler(); + + private: + + static int8_t _interrupt; // Radio input interrupt + volatile static short _state; // State of decoding process. + static byte _minRepeats; + static NewRemoteReceiverCallBack _callback; + static boolean _inCallback; // When true, the callback function is being executed; prevents re-entrance. + static boolean _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately. + +}; + +#endif diff --git a/libraries/NewRemoteSwitch/NewRemoteTransmitter.cpp b/libraries/NewRemoteSwitch/NewRemoteTransmitter.cpp index 4f8cb54..7220901 100644 --- a/libraries/NewRemoteSwitch/NewRemoteTransmitter.cpp +++ b/libraries/NewRemoteSwitch/NewRemoteTransmitter.cpp @@ -1,134 +1,134 @@ -/* - * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ - * See NewRemoteTransmitter.h for details. - * - * License: GPLv3. See license.txt - */ - -#include "NewRemoteTransmitter.h" - - -NewRemoteTransmitter::NewRemoteTransmitter(unsigned long address, byte pin, unsigned int periodusec, byte repeats) { - _address = address; - _pin = pin; - _periodusec = periodusec; - _repeats = (1 << repeats) - 1; // I.e. _repeats = 2^repeats - 1 - - pinMode(_pin, OUTPUT); -} - -void NewRemoteTransmitter::sendGroup(boolean switchOn) { - for (int8_t i = _repeats; i >= 0; i--) { - _sendStartPulse(); - - _sendAddress(); - - // Do send group bit - _sendBit(true); - - // Switch on | off - _sendBit(switchOn); - - // No unit. Is this actually ignored?.. - _sendUnit(0); - - _sendStopPulse(); - } -} - -void NewRemoteTransmitter::sendUnit(byte unit, boolean switchOn) { - for (int8_t i = _repeats; i >= 0; i--) { - _sendStartPulse(); - - _sendAddress(); - - // No group bit - _sendBit(false); - - // Switch on | off - _sendBit(switchOn); - - _sendUnit(unit); - - _sendStopPulse(); - } -} - -void NewRemoteTransmitter::sendDim(byte unit, byte dimLevel) { - for (int8_t i = _repeats; i >= 0; i--) { - _sendStartPulse(); - - _sendAddress(); - - // No group bit - _sendBit(false); - - // Switch type 'dim' - digitalWrite(_pin, HIGH); - delayMicroseconds(_periodusec); - digitalWrite(_pin, LOW); - delayMicroseconds(_periodusec); - digitalWrite(_pin, HIGH); - delayMicroseconds(_periodusec); - digitalWrite(_pin, LOW); - delayMicroseconds(_periodusec); - - _sendUnit(unit); - - for (int8_t j=3; j>=0; j--) { - _sendBit(dimLevel & 1<> 1)); // Actually 10.5T insteat of 10.44T. Close enough. -} - -void NewRemoteTransmitter::_sendAddress() { - for (int8_t i=25; i>=0; i--) { - _sendBit((_address >> i) & 1); - } -} - -void NewRemoteTransmitter::_sendUnit(byte unit) { - for (int8_t i=3; i>=0; i--) { - _sendBit(unit & 1<= 0; i--) { + _sendStartPulse(); + + _sendAddress(); + + // Do send group bit + _sendBit(true); + + // Switch on | off + _sendBit(switchOn); + + // No unit. Is this actually ignored?.. + _sendUnit(0); + + _sendStopPulse(); + } +} + +void NewRemoteTransmitter::sendUnit(byte unit, boolean switchOn) { + for (int8_t i = _repeats; i >= 0; i--) { + _sendStartPulse(); + + _sendAddress(); + + // No group bit + _sendBit(false); + + // Switch on | off + _sendBit(switchOn); + + _sendUnit(unit); + + _sendStopPulse(); + } +} + +void NewRemoteTransmitter::sendDim(byte unit, byte dimLevel) { + for (int8_t i = _repeats; i >= 0; i--) { + _sendStartPulse(); + + _sendAddress(); + + // No group bit + _sendBit(false); + + // Switch type 'dim' + digitalWrite(_pin, HIGH); + delayMicroseconds(_periodusec); + digitalWrite(_pin, LOW); + delayMicroseconds(_periodusec); + digitalWrite(_pin, HIGH); + delayMicroseconds(_periodusec); + digitalWrite(_pin, LOW); + delayMicroseconds(_periodusec); + + _sendUnit(unit); + + for (int8_t j=3; j>=0; j--) { + _sendBit(dimLevel & 1<> 1)); // Actually 10.5T insteat of 10.44T. Close enough. +} + +void NewRemoteTransmitter::_sendAddress() { + for (int8_t i=25; i>=0; i--) { + _sendBit((_address >> i) & 1); + } +} + +void NewRemoteTransmitter::_sendUnit(byte unit) { + for (int8_t i=3; i>=0; i--) { + _sendBit(unit & 1< - -/** -* NewRemoteTransmitter provides a generic class for simulation of common RF remote controls, like the A-series -* 'Klik aan Klik uit'-system (http://www.klikaanklikuit.nl/), used to remotely switch lights etc. -* -* This class is meant for new-style remotes, usually accompanied by receivers with "code learning" -* capabilities. For other remotes, use the RemoteTransmitter class. -* -* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. -* http://www.sparkfun.com/products/10534 -* http://www.conrad.nl/goto/?product=130428 -* -* Notes: -* - I measured the period length with an oscilloscope, using a A-series KAKU transmitter. Other devices -* or manufacturers may use other period length. Use the ShowReceivedCodeNewRemote example to find the -* period length for your devices. -* - You can copy the address of your "real" remotes, so you won't have to learn new codes into the receivers. -* In effect this duplicates a remote. But you can also pick a random number in the range 0..2^26-1. -*/ -class NewRemoteTransmitter { - public: - /** - * Constructor. - * - * To obtain the correct period length, use the ShowReceivedCodeNewRemote example, or you - * can use an oscilloscope. - * - * @param address Address of this transmitter [0..2^26-1] Duplicate the address of your hardware, or choose a random number. - * @param pin Output pin on Arduino to which the transmitter is connected - * @param periodusec Duration of one period, in microseconds. One bit takes 8 periods (but only 4 for 'dim' signal). - * @param repeats [0..8] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust, 8 is maximum (and overkill). - */ - NewRemoteTransmitter(unsigned long address, byte pin, unsigned int periodusec = 260, byte repeats = 4); - - /** - * Send on/off command to the address group. - * - * @param switchOn True to send "on" signal, false to send "off" signal. - */ - void sendGroup(boolean switchOn); - - /** - * Send on/off command to an unit on the current address. - * - * @param unit [0..15] target unit. - * @param switchOn True to send "on" signal, false to send "off" signal. - */ - void sendUnit(byte unit, boolean switchOn); - - /** - * Send dim value to an unit on the current address. - * - * @param unit [0..15] target unit. - * @param dimLevel [0..15] Dim level. 0 for off, 15 for brightest level. - */ - void sendDim(byte unit, byte dimLevel); - - protected: - unsigned long _address; // Address of this transmitter. - byte _pin; // Transmitter output pin - unsigned int _periodusec; // Oscillator period in microseconds - byte _repeats; // Number over repetitions of one telegram - - /** - * Transmits start-pulse - */ - void _sendStartPulse(); - - /** - * Transmits address part - */ - void _sendAddress(); - - /** - * Transmits unit part. - * - * @param unit [0-15] target unit. - */ - void _sendUnit(byte unit); - - /** - * Transmits stop pulse. - */ - void _sendStopPulse(); - - /** - * Transmits a single bit. - * - * @param isBitOne True, to send '1', false to send '0'. - */ - void _sendBit(boolean isBitOne); -}; -#endif +/* + * NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/ + * + * License: GPLv3. See license.txt + */ + +#ifndef NewRemoteTransmitter_h +#define NewRemoteTransmitter_h + +#include + +/** +* NewRemoteTransmitter provides a generic class for simulation of common RF remote controls, like the A-series +* 'Klik aan Klik uit'-system (http://www.klikaanklikuit.nl/), used to remotely switch lights etc. +* +* This class is meant for new-style remotes, usually accompanied by receivers with "code learning" +* capabilities. For other remotes, use the RemoteTransmitter class. +* +* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. +* http://www.sparkfun.com/products/10534 +* http://www.conrad.nl/goto/?product=130428 +* +* Notes: +* - I measured the period length with an oscilloscope, using a A-series KAKU transmitter. Other devices +* or manufacturers may use other period length. Use the ShowReceivedCodeNewRemote example to find the +* period length for your devices. +* - You can copy the address of your "real" remotes, so you won't have to learn new codes into the receivers. +* In effect this duplicates a remote. But you can also pick a random number in the range 0..2^26-1. +*/ +class NewRemoteTransmitter { + public: + /** + * Constructor. + * + * To obtain the correct period length, use the ShowReceivedCodeNewRemote example, or you + * can use an oscilloscope. + * + * @param address Address of this transmitter [0..2^26-1] Duplicate the address of your hardware, or choose a random number. + * @param pin Output pin on Arduino to which the transmitter is connected + * @param periodusec Duration of one period, in microseconds. One bit takes 8 periods (but only 4 for 'dim' signal). + * @param repeats [0..8] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust, 8 is maximum (and overkill). + */ + NewRemoteTransmitter(unsigned long address, byte pin, unsigned int periodusec = 260, byte repeats = 4); + + /** + * Send on/off command to the address group. + * + * @param switchOn True to send "on" signal, false to send "off" signal. + */ + void sendGroup(boolean switchOn); + + /** + * Send on/off command to an unit on the current address. + * + * @param unit [0..15] target unit. + * @param switchOn True to send "on" signal, false to send "off" signal. + */ + void sendUnit(byte unit, boolean switchOn); + + /** + * Send dim value to an unit on the current address. + * + * @param unit [0..15] target unit. + * @param dimLevel [0..15] Dim level. 0 for off, 15 for brightest level. + */ + void sendDim(byte unit, byte dimLevel); + + protected: + unsigned long _address; // Address of this transmitter. + byte _pin; // Transmitter output pin + unsigned int _periodusec; // Oscillator period in microseconds + byte _repeats; // Number over repetitions of one telegram + + /** + * Transmits start-pulse + */ + void _sendStartPulse(); + + /** + * Transmits address part + */ + void _sendAddress(); + + /** + * Transmits unit part. + * + * @param unit [0-15] target unit. + */ + void _sendUnit(byte unit); + + /** + * Transmits stop pulse. + */ + void _sendStopPulse(); + + /** + * Transmits a single bit. + * + * @param isBitOne True, to send '1', false to send '0'. + */ + void _sendBit(boolean isBitOne); +}; +#endif diff --git a/libraries/NewRemoteSwitch/README.TXT b/libraries/NewRemoteSwitch/README.TXT index c2e115b..a1b05f4 100644 --- a/libraries/NewRemoteSwitch/README.TXT +++ b/libraries/NewRemoteSwitch/README.TXT @@ -1,48 +1,48 @@ -NewRemoteSwitch library v1.1.0 (BETA) for Arduino 1.0 -Made by Randy Simons http://randysimons.nl/ - -This library provides an easy class for Arduino, to send and receive signals -used by some common "new style" 433MHz remote control switches. - -There are two styles of remote: - - "old style", which uses switches or a dial to set the house code. Use the - RemoteSwitch library instead. - - "new style", which use a button on the receivers to "learn" a signal. Use - this library. - -License: GPLv3. See ./NewRemoteSwitch/license.txt - -Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino - - -Installation of library: - - Make sure Arduino is closed - - Copy the directory NewRemoteSwitch to the Arduino library directory (usually - /libraries/) - See http://arduino.cc/en/Guide/Libraries for detailed instructions. - -Default installation demo: - - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. - (Note: your hardware may have a different pin configuration!) - - Start Arduino, and open the example: File -> Examples -> NewRemoteSwitch -> - ShowReceivedCode or ShowReceivedCodeNewRemote. - - Compile, upload and run - - Open serial monitor in Arduino (115200 baud) - - Press buttons on a 433MHz-remote, and watch the serial monitor - - -Changelog: -NewRemoteSwitch library v1.1.0 (20130601) for Arduino 1.0 - - BUGFIX: in many occasions, when receiving a dim-level, the code was rejected - even if the signal was correct. - - Support decoding A-series transmitters which transmit a dim-level in - combination with an on-signal, instead of a dim-signal. - - Uses NewRemodeCode::on, ::off, ::dim, ::on_with_dim instead of 0, 1, 2 and 3, - for better readability. This change is backwards compatible. - - Updated examples to use the new NewRemodeCode::on, ::off, ::dim and - ::on_with_dim notation. - - Reduced memory usage (Flash, RAM) - -NewRemoteSwitch library v1.0.0 (20121229) for Arduino 1.0 - - Support for receiving A-series Klik-aan-klik-uit remote. (NewRemoteReceiver) - - With examples to test and demonstrate. +NewRemoteSwitch library v1.1.0 (BETA) for Arduino 1.0 +Made by Randy Simons http://randysimons.nl/ + +This library provides an easy class for Arduino, to send and receive signals +used by some common "new style" 433MHz remote control switches. + +There are two styles of remote: + - "old style", which uses switches or a dial to set the house code. Use the + RemoteSwitch library instead. + - "new style", which use a button on the receivers to "learn" a signal. Use + this library. + +License: GPLv3. See ./NewRemoteSwitch/license.txt + +Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino + + +Installation of library: + - Make sure Arduino is closed + - Copy the directory NewRemoteSwitch to the Arduino library directory (usually + /libraries/) + See http://arduino.cc/en/Guide/Libraries for detailed instructions. + +Default installation demo: + - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. + (Note: your hardware may have a different pin configuration!) + - Start Arduino, and open the example: File -> Examples -> NewRemoteSwitch -> + ShowReceivedCode or ShowReceivedCodeNewRemote. + - Compile, upload and run + - Open serial monitor in Arduino (115200 baud) + - Press buttons on a 433MHz-remote, and watch the serial monitor + + +Changelog: +NewRemoteSwitch library v1.1.0 (20130601) for Arduino 1.0 + - BUGFIX: in many occasions, when receiving a dim-level, the code was rejected + even if the signal was correct. + - Support decoding A-series transmitters which transmit a dim-level in + combination with an on-signal, instead of a dim-signal. + - Uses NewRemodeCode::on, ::off, ::dim, ::on_with_dim instead of 0, 1, 2 and 3, + for better readability. This change is backwards compatible. + - Updated examples to use the new NewRemodeCode::on, ::off, ::dim and + ::on_with_dim notation. + - Reduced memory usage (Flash, RAM) + +NewRemoteSwitch library v1.0.0 (20121229) for Arduino 1.0 + - Support for receiving A-series Klik-aan-klik-uit remote. (NewRemoteReceiver) + - With examples to test and demonstrate. diff --git a/libraries/NewRemoteSwitch/docs/new kaku protocol.txt b/libraries/NewRemoteSwitch/docs/new kaku protocol.txt index 9535d9c..c84ca8c 100644 --- a/libraries/NewRemoteSwitch/docs/new kaku protocol.txt +++ b/libraries/NewRemoteSwitch/docs/new kaku protocol.txt @@ -1,23 +1,23 @@ -= Protocol of klikaanklikuit A-series devices = - -Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410, -but with slightly different timings, as measured on my device. - _ _ -'0': | |_| |_____ (T,T,T,5T) - _ _ -'1': | |_____| |_ (T,5T,T,T) - _ _ -'dim': | |_| |_ (T,T,T,T) - -T = short period of ~260µs. Use the ShowReceivedCodeNewRemote example to find the -actual period length for your devices. - -A full frame looks like this: - -- start pulse: 1T high, 10.44T low -- 26 bit: Address -- 1 bit: group bit -- 1 bit: on/off/[dim] -- 4 bit: unit -- [4 bit: dim level. Only present of [dim] is chosen] += Protocol of klikaanklikuit A-series devices = + +Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410, +but with slightly different timings, as measured on my device. + _ _ +'0': | |_| |_____ (T,T,T,5T) + _ _ +'1': | |_____| |_ (T,5T,T,T) + _ _ +'dim': | |_| |_ (T,T,T,T) + +T = short period of ~260µs. Use the ShowReceivedCodeNewRemote example to find the +actual period length for your devices. + +A full frame looks like this: + +- start pulse: 1T high, 10.44T low +- 26 bit: Address +- 1 bit: group bit +- 1 bit: on/off/[dim] +- 4 bit: unit +- [4 bit: dim level. Only present of [dim] is chosen] - stop pulse: 1T high, 40T low \ No newline at end of file diff --git a/libraries/NewRemoteSwitch/examples/LightShow/LightShow.ino b/libraries/NewRemoteSwitch/examples/LightShow/LightShow.ino index a2a8823..14f8639 100644 --- a/libraries/NewRemoteSwitch/examples/LightShow/LightShow.ino +++ b/libraries/NewRemoteSwitch/examples/LightShow/LightShow.ino @@ -1,55 +1,55 @@ -/** - * Demo for RF remote switch receiver. - * For details, see NewRemoteReceiver.h! - * - * Connect the transmitter to digital pin 11. - * - * This sketch demonstrates the use of the NewRemoteTransmitter class. - * - * When run, this sketch switches some pre-defined devices on and off in a loop. - * - * NOTE: the actual receivers have the address and group numbers in this example - * are only for demonstration! If you want to duplicate an existing remote, please - * try the "retransmitter"-example instead. - * - * To use this actual example, you'd need to "learn" the used code in the receivers - * This sketch is unsuited for that. - * - */ - -#include - -// Create a transmitter on address 123, using digital pin 11 to transmit, -// with a period duration of 260ms (default), repeating the transmitted -// code 2^3=8 times. -NewRemoteTransmitter transmitter(123, 11, 260, 3); - -void setup() { -} - -void loop() { - // Switch unit 2 off - transmitter.sendUnit(2, false); - - // Switch all devices in the group off - transmitter.sendGroup(false); - - // Set unit 1 to dim-level 3 (range 0-15) - transmitter.sendDim(1, 3); - - // Wait 5 seconds - delay(5000); - - - // Switch unit 2 on - transmitter.sendUnit(2, true); - - // Switch all devices in the group on - transmitter.sendGroup(true); - - // Set unit 1 to dim-level 15, full brightness. - transmitter.sendDim(1, 15); - - // Wait 5 seconds - delay(5000); -} +/** + * Demo for RF remote switch receiver. + * For details, see NewRemoteReceiver.h! + * + * Connect the transmitter to digital pin 11. + * + * This sketch demonstrates the use of the NewRemoteTransmitter class. + * + * When run, this sketch switches some pre-defined devices on and off in a loop. + * + * NOTE: the actual receivers have the address and group numbers in this example + * are only for demonstration! If you want to duplicate an existing remote, please + * try the "retransmitter"-example instead. + * + * To use this actual example, you'd need to "learn" the used code in the receivers + * This sketch is unsuited for that. + * + */ + +#include + +// Create a transmitter on address 123, using digital pin 11 to transmit, +// with a period duration of 260ms (default), repeating the transmitted +// code 2^3=8 times. +NewRemoteTransmitter transmitter(123, 11, 260, 3); + +void setup() { +} + +void loop() { + // Switch unit 2 off + transmitter.sendUnit(2, false); + + // Switch all devices in the group off + transmitter.sendGroup(false); + + // Set unit 1 to dim-level 3 (range 0-15) + transmitter.sendDim(1, 3); + + // Wait 5 seconds + delay(5000); + + + // Switch unit 2 on + transmitter.sendUnit(2, true); + + // Switch all devices in the group on + transmitter.sendGroup(true); + + // Set unit 1 to dim-level 15, full brightness. + transmitter.sendDim(1, 15); + + // Wait 5 seconds + delay(5000); +} diff --git a/libraries/NewRemoteSwitch/keywords.txt b/libraries/NewRemoteSwitch/keywords.txt index 80a7ec0..876ece8 100644 --- a/libraries/NewRemoteSwitch/keywords.txt +++ b/libraries/NewRemoteSwitch/keywords.txt @@ -1,11 +1,11 @@ -NewRemoteReceiver KEYWORD1 -NewRemoteCode KEYWORD1 -isReceiving KEYWORD2 -init KEYWORD2 -enable KEYWORD2 -disable KEYWORD2 -deinit KEYWORD2 -NewRemoteTransmitter KEYWORD1 -sendGroup KEYWORD2 -sendUnit KEYWORD2 +NewRemoteReceiver KEYWORD1 +NewRemoteCode KEYWORD1 +isReceiving KEYWORD2 +init KEYWORD2 +enable KEYWORD2 +disable KEYWORD2 +deinit KEYWORD2 +NewRemoteTransmitter KEYWORD1 +sendGroup KEYWORD2 +sendUnit KEYWORD2 sendDim KEYWORD2 \ No newline at end of file diff --git a/libraries/OneWire/examples/DS250x_PROM/DS250x_PROM.pde b/libraries/OneWire/examples/DS250x_PROM/DS250x_PROM.pde index baa51c8..a85b1c2 100644 --- a/libraries/OneWire/examples/DS250x_PROM/DS250x_PROM.pde +++ b/libraries/OneWire/examples/DS250x_PROM/DS250x_PROM.pde @@ -87,4 +87,4 @@ void loop() { - + diff --git a/libraries/RemoteSensor/README.TXT b/libraries/RemoteSensor/README.TXT index 17d7007..38444a5 100644 --- a/libraries/RemoteSensor/README.TXT +++ b/libraries/RemoteSensor/README.TXT @@ -1,62 +1,62 @@ -RemoteSensor library v1.0.1 (20120213) for Arduino 1.0 -Made by Randy Simons http://randysimons.nl/ - -This library provides an easy class for Arduino, to send and receive signals -used by some common weather stations using remote 433MHz sensors, like those -made by Cresta. -E.g. http://www.cresta.nl/index.php?Itemid=2&option=com_zoo&view=item&category_id=32&item_id=281&lang=en - -Cresta is just a brandname. The original OEM seems to be Hideki Electronics. -There are other brands which use the same hardware and / or protocol. As far -as I know these include Mebus, Irox, Honeywell, Cresta and RST. - -This software is based on the work of Oopsje. See docs/CrestaProtocol.pdf - -See SensorTransmitter.h and SensorReciver.h for details! - -License: GPLv3. See ./RemoteSensor/license.txt - -Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino - - -Installation of library: - - Make sure Arduino is closed - - Copy the directory RemoteSensor to the Arduino library directory (usually - /libraries/) - See http://arduino.cc/en/Guide/Libraries for detailed instructions. - -Default installation sender & demo: - - Connect tha data-in-pin of a 433MHz transmitter to digital pin 11. See - docs/hardware setup.jpg. - (Note: your hardware may have a different pin configuration!) - - Start Arduino, and open the example: File -> Examples -> RemoteSensor -> - ThermoHygroTransmitter - - Alter addresses/devices to reflect your own setup. Otherwise nothing will - happen. - - Compile, upload and run! - -Default installation receiver & demo: - - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. - (Note: your hardware may have a different pin configuration!) - - Start Arduino, and open the example: File -> Examples -> RemoteSensor -> - ThermoHygroReceiver - - Compile, upload and run - - Open serial monitor in Arduino (115200 baud) - - Wait for your 433MHz-sensor to transmit (less than 1 minute), and watch the - serial monitor - - -Changelog: -RemoteSensor library v1.0.2 (20130601) for Arduino 1.0 - - Reduced memory usage (Flash, RAM). Because of this, a small backwards - incompatibility is introduced: The last parameter of - SensorReceiver::decodeThermoHygro now is a byte instead of short. - - Dropped support for Arduino pre-1.0 - -RemoteSensor library v1.0.1 (20120213) for Arduino 0022/1.0 - - Ignore obviously too short or too long signals in SensorReceiver, for better - recognition rate. - - Support for Arduino 1.0. - -RemoteSensor library v1.0.0 (20110919) for Arduino 0022 +RemoteSensor library v1.0.1 (20120213) for Arduino 1.0 +Made by Randy Simons http://randysimons.nl/ + +This library provides an easy class for Arduino, to send and receive signals +used by some common weather stations using remote 433MHz sensors, like those +made by Cresta. +E.g. http://www.cresta.nl/index.php?Itemid=2&option=com_zoo&view=item&category_id=32&item_id=281&lang=en + +Cresta is just a brandname. The original OEM seems to be Hideki Electronics. +There are other brands which use the same hardware and / or protocol. As far +as I know these include Mebus, Irox, Honeywell, Cresta and RST. + +This software is based on the work of Oopsje. See docs/CrestaProtocol.pdf + +See SensorTransmitter.h and SensorReciver.h for details! + +License: GPLv3. See ./RemoteSensor/license.txt + +Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino + + +Installation of library: + - Make sure Arduino is closed + - Copy the directory RemoteSensor to the Arduino library directory (usually + /libraries/) + See http://arduino.cc/en/Guide/Libraries for detailed instructions. + +Default installation sender & demo: + - Connect tha data-in-pin of a 433MHz transmitter to digital pin 11. See + docs/hardware setup.jpg. + (Note: your hardware may have a different pin configuration!) + - Start Arduino, and open the example: File -> Examples -> RemoteSensor -> + ThermoHygroTransmitter + - Alter addresses/devices to reflect your own setup. Otherwise nothing will + happen. + - Compile, upload and run! + +Default installation receiver & demo: + - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. + (Note: your hardware may have a different pin configuration!) + - Start Arduino, and open the example: File -> Examples -> RemoteSensor -> + ThermoHygroReceiver + - Compile, upload and run + - Open serial monitor in Arduino (115200 baud) + - Wait for your 433MHz-sensor to transmit (less than 1 minute), and watch the + serial monitor + + +Changelog: +RemoteSensor library v1.0.2 (20130601) for Arduino 1.0 + - Reduced memory usage (Flash, RAM). Because of this, a small backwards + incompatibility is introduced: The last parameter of + SensorReceiver::decodeThermoHygro now is a byte instead of short. + - Dropped support for Arduino pre-1.0 + +RemoteSensor library v1.0.1 (20120213) for Arduino 0022/1.0 + - Ignore obviously too short or too long signals in SensorReceiver, for better + recognition rate. + - Support for Arduino 1.0. + +RemoteSensor library v1.0.0 (20110919) for Arduino 0022 - Initial version \ No newline at end of file diff --git a/libraries/RemoteSensor/SensorTransmitter.h b/libraries/RemoteSensor/SensorTransmitter.h index 7176ce1..6a5141a 100644 --- a/libraries/RemoteSensor/SensorTransmitter.h +++ b/libraries/RemoteSensor/SensorTransmitter.h @@ -1,111 +1,111 @@ -/* - * RemoteSensor library v1.0.2 (20130601) for Arduino 1.0 - * - * This library encodes, encrypts en transmits data to - * remote weather stations made by Hideki Electronics.. - * - * Copyright 2011-2013 by Randy Simons http://randysimons.nl/ - * - * Parts of this code based on Oopsje's CrestaProtocol.pdf, for which - * I thank him very much! - * - * License: GPLv3. See license.txt - */ - -#ifndef SensorTransmitter_h -#define SensorTransmitter_h - -#include - -/** - * SensorTransmitter provides a generic class to simulate Cresta weather sensors, for use - * with Cresta weather stations. - * E.g. http://www.cresta.nl/index.php?Itemid=2&option=com_zoo&view=item&category_id=32&item_id=281&lang=en - * - * Cresta is just a brand name. The original OEM seems to be Hideki Electronics. There are - * other brands which use the same hardware and / or protocol. As far as I know these include - * Mebus, Irox, Honeywell, Cresta and RST. - * - * Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. - * http://www.sparkfun.com/products/10534 - * http://www.conrad.nl/goto/?product=130428 - */ -class SensorTransmitter { - public: - /** - * Initializes the transmitter. About the random id: "A sensor selects a random value - * in the range of column 1 when it is reset. It keeps the same ID until it is reset again." - * You can leave it at 0 for most purposes - * The transmitter pin is set in OUTPUT mode; you don't have to do this yourself. - * - * @param transmitterPin Arduino-pin connected to the 433MHz transmitter - * @param randomId A "random" value in the range [0..31] - */ - SensorTransmitter(byte transmitterPin, byte randomId); - - /** - * Sends a raw sensor package. Before transmitting, the data is encrypted and checksums are - * added. The buffer of the data doesn't need to have room for the checksums, as the data is - * copied internally to a new buffer which is always large enough. - * However, the data must be valid! - * - * The data is transmitted 3 times. - * - * Note that this is a static method. - * - * @param transmitterPin Arduino-pin connected to the 433MHz transmitter - * @param data Pointer to data to transmit - */ - static void sendPackage(byte transmitterPin, byte *data); - - protected: - byte _transmitterPin; - byte _randomId; - - private: - /** - * Sends data as manchester encoded stream - */ - static void sendManchesterPackage(byte transmitterPin, byte *data, byte cnt); - - /** - * Sends a single byte as manchester encoded stream - */ - static void sendManchesterByte(byte transmitterPin, byte b); - - /** - * Encryption and checksum - */ - static byte encryptAndAddCheck(byte *buffer); - static byte secondCheck(byte b); - static byte encryptByte(byte b); -}; - -class ThermoHygroTransmitter : public SensorTransmitter { - public: - /** - * Mimics a Thermo / Hygro sensor. The channel of this device can be 1..5, but note - * that only the more expensive receivers can use channels 4 and 5. However, for use - * in conjunction with SensorReceiver this is of no concern. - * - * @param transmitterPin Arduino-pin connected to the 433MHz transmitter - * @param randomId A "random" value in the range [0..31] - * @channel The channel of this sensor, range [1..5] - * @see SensorTransmitter::SensorTransmitter (constructor) - */ - ThermoHygroTransmitter(byte transmitterPin, byte randomId, byte channel); - - /** - * Sends temperature and humidity. - * - * @param temperature 10x the actual temperature. You want to send 23,5 degrees, then temperature should be 235. - * @param humidty Humidity in percentage-points REL. Thus, for 34% REH humidity should be 34. - */ - void sendTempHumi(int temperature, byte humidity); - - private: - byte _channel; // Note: internally, the channels for the thermo/hygro-sensor are mapped as follow: - // 1=>1, 2=>2, 3=>3, 4=>5, 5=>6. - // This because interally the rain sensor, UV sensor and anemometer are on channel 4. -}; +/* + * RemoteSensor library v1.0.2 (20130601) for Arduino 1.0 + * + * This library encodes, encrypts en transmits data to + * remote weather stations made by Hideki Electronics.. + * + * Copyright 2011-2013 by Randy Simons http://randysimons.nl/ + * + * Parts of this code based on Oopsje's CrestaProtocol.pdf, for which + * I thank him very much! + * + * License: GPLv3. See license.txt + */ + +#ifndef SensorTransmitter_h +#define SensorTransmitter_h + +#include + +/** + * SensorTransmitter provides a generic class to simulate Cresta weather sensors, for use + * with Cresta weather stations. + * E.g. http://www.cresta.nl/index.php?Itemid=2&option=com_zoo&view=item&category_id=32&item_id=281&lang=en + * + * Cresta is just a brand name. The original OEM seems to be Hideki Electronics. There are + * other brands which use the same hardware and / or protocol. As far as I know these include + * Mebus, Irox, Honeywell, Cresta and RST. + * + * Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. + * http://www.sparkfun.com/products/10534 + * http://www.conrad.nl/goto/?product=130428 + */ +class SensorTransmitter { + public: + /** + * Initializes the transmitter. About the random id: "A sensor selects a random value + * in the range of column 1 when it is reset. It keeps the same ID until it is reset again." + * You can leave it at 0 for most purposes + * The transmitter pin is set in OUTPUT mode; you don't have to do this yourself. + * + * @param transmitterPin Arduino-pin connected to the 433MHz transmitter + * @param randomId A "random" value in the range [0..31] + */ + SensorTransmitter(byte transmitterPin, byte randomId); + + /** + * Sends a raw sensor package. Before transmitting, the data is encrypted and checksums are + * added. The buffer of the data doesn't need to have room for the checksums, as the data is + * copied internally to a new buffer which is always large enough. + * However, the data must be valid! + * + * The data is transmitted 3 times. + * + * Note that this is a static method. + * + * @param transmitterPin Arduino-pin connected to the 433MHz transmitter + * @param data Pointer to data to transmit + */ + static void sendPackage(byte transmitterPin, byte *data); + + protected: + byte _transmitterPin; + byte _randomId; + + private: + /** + * Sends data as manchester encoded stream + */ + static void sendManchesterPackage(byte transmitterPin, byte *data, byte cnt); + + /** + * Sends a single byte as manchester encoded stream + */ + static void sendManchesterByte(byte transmitterPin, byte b); + + /** + * Encryption and checksum + */ + static byte encryptAndAddCheck(byte *buffer); + static byte secondCheck(byte b); + static byte encryptByte(byte b); +}; + +class ThermoHygroTransmitter : public SensorTransmitter { + public: + /** + * Mimics a Thermo / Hygro sensor. The channel of this device can be 1..5, but note + * that only the more expensive receivers can use channels 4 and 5. However, for use + * in conjunction with SensorReceiver this is of no concern. + * + * @param transmitterPin Arduino-pin connected to the 433MHz transmitter + * @param randomId A "random" value in the range [0..31] + * @channel The channel of this sensor, range [1..5] + * @see SensorTransmitter::SensorTransmitter (constructor) + */ + ThermoHygroTransmitter(byte transmitterPin, byte randomId, byte channel); + + /** + * Sends temperature and humidity. + * + * @param temperature 10x the actual temperature. You want to send 23,5 degrees, then temperature should be 235. + * @param humidty Humidity in percentage-points REL. Thus, for 34% REH humidity should be 34. + */ + void sendTempHumi(int temperature, byte humidity); + + private: + byte _channel; // Note: internally, the channels for the thermo/hygro-sensor are mapped as follow: + // 1=>1, 2=>2, 3=>3, 4=>5, 5=>6. + // This because interally the rain sensor, UV sensor and anemometer are on channel 4. +}; #endif \ No newline at end of file diff --git a/libraries/RemoteSensor/examples/Repeater/Repeater.ino b/libraries/RemoteSensor/examples/Repeater/Repeater.ino index f4c5264..1c38105 100644 --- a/libraries/RemoteSensor/examples/Repeater/Repeater.ino +++ b/libraries/RemoteSensor/examples/Repeater/Repeater.ino @@ -51,4 +51,4 @@ void retransmit(byte *data) { noInterrupts(); SensorReceiver::enable(); } - + diff --git a/libraries/RemoteSensor/examples/ThermoHygroTransmitter/ThermoHygroTransmitter.ino b/libraries/RemoteSensor/examples/ThermoHygroTransmitter/ThermoHygroTransmitter.ino index c5ce497..f0505a0 100644 --- a/libraries/RemoteSensor/examples/ThermoHygroTransmitter/ThermoHygroTransmitter.ino +++ b/libraries/RemoteSensor/examples/ThermoHygroTransmitter/ThermoHygroTransmitter.ino @@ -25,4 +25,4 @@ // Wait two seconds before sending next. delay(2000); } - } + } diff --git a/libraries/RemoteSensor/keywords.txt b/libraries/RemoteSensor/keywords.txt index 2935b35..a2cbaf4 100644 --- a/libraries/RemoteSensor/keywords.txt +++ b/libraries/RemoteSensor/keywords.txt @@ -1,9 +1,9 @@ -SensorReceiver KEYWORD1 -init KEYWORD2 -decodeThermoHygro KEYWORD2 -enable KEYWORD2 -disable KEYWORD2 -interruptHandler KEYWORD2 -SensorTransmitter KEYWORD1 -sendPackage KEYWORD2 +SensorReceiver KEYWORD1 +init KEYWORD2 +decodeThermoHygro KEYWORD2 +enable KEYWORD2 +disable KEYWORD2 +interruptHandler KEYWORD2 +SensorTransmitter KEYWORD1 +sendPackage KEYWORD2 ThermoHygroTransmitter KEYWORD1 \ No newline at end of file diff --git a/libraries/RemoteSwitch/README.TXT b/libraries/RemoteSwitch/README.TXT index e6af2f4..02aaccf 100644 --- a/libraries/RemoteSwitch/README.TXT +++ b/libraries/RemoteSwitch/README.TXT @@ -1,81 +1,81 @@ -RemoteSwitch library v2.3.0 (20121229) for Arduino 1.0 -Made by Randy Simons http://randysimons.nl/ - -This library provides an easy class for Arduino, to send and receive signals -used by some common "old style" 433MHz remote control switches. - -There are two styles of remote: - - "old style", which uses switches or a dial to set the house code. Use this - library. - - "new style", which use a button on the receivers to "learn" a signal. Use - the NewRemoteSwitch library instead. - -See RemoteTransmitter.h and RemoteReceiver.h for details! - -License: GPLv3. See ./RemoteSwitch/license.txt - -Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino - - -Installation of library: - - Make sure Arduino is closed - - Copy the directory RemoteSwitch to the Arduino library directory (usually - /libraries/) - See http://arduino.cc/en/Guide/Libraries for detailed instructions. - -Default installation sender & demo: - - Connect tha data-in-pin of a 433MHz transmitter to digital pin 11. See - docs/hardware setup.jpg. - (Note: your hardware may have a different pin configuration!) - - Start Arduino, and open the example: File -> Examples -> RemoteSwitch -> - LightShow - - Alter addresses/devices to reflect your own setup. Otherwise nothing will - happen. - - Compile, upload and run! - -Default installation receiver & demo: - - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. - (Note: your hardware may have a different pin configuration!) - - Start Arduino, and open the example: File -> Examples -> RemoteSwitch -> - ShowReceivedCode or ShowReceivedCodeNewKaku, depending on your remote. - - Compile, upload and run - - Open serial monitor in Arduino (115200 baud) - - Press buttons on a 433MHz-remote, and watch the serial monitor - -Notes: - - These transmitters often use the PT2262 IC, or equivalent. For details about - the waveforms used by these remotes, the datasheet of the PT2262 is provided. - Page 4 and 5 will be of most interest. - - -Changelog: -RemoteSwitch library v2.3.0 (20121229) for Arduino 1.0 - - Improved reception quality by filtering too short pulses. - - Dropped pre-v1.0 Arduino support. - - Added RemoteReceiver::deinit() - -RemoteSwitch library v2.2.1 (20120314) for Arduino 0022/1.0 - - Fixed Elro code, it caused memory corruption. - - Renamed old-style .pde files to new-style .ino - -RemoteSwitch library v2.2.0 (20120213) for Arduino 0022/1.0 - - Added support for Elro switches (http://www.elro.eu/en/m/products/category/home_automation/home_control) - (untested; I don't have these kind of devices) - - Allowed the number of repeated signals transmitted by RemoteTransmitter to be - changed. - - By default, 16 instead of 8 repeats are sent. - - Support for Arduino 1.0. - - Added Datasheet PT2262, which (or equivalent) is often used in the transmitters. - - RemoteReceiver::isReceiving timeout changed to 150ms; 100ms was too short. - -RemoteSwitch library v2.1.1 (20110920) for Arduino 0022 - - Improved RemoteReceiver::isReceiving - -RemoteSwitch library v2.1.0 (20110919) for Arduino 0022 - - Changed classnames from *Switch to *Transmitter - - Added RemoteTransmitter::sendCode. See example "retransmitter". - - RemoteReceiver::interruptHandler() is now public, for use with InterruptChain - -RemoteSwitch library v2.0.0 (20100130) for Arduino 0017 - - Complete rewrite; can now receive and decode signals directly from +RemoteSwitch library v2.3.0 (20121229) for Arduino 1.0 +Made by Randy Simons http://randysimons.nl/ + +This library provides an easy class for Arduino, to send and receive signals +used by some common "old style" 433MHz remote control switches. + +There are two styles of remote: + - "old style", which uses switches or a dial to set the house code. Use this + library. + - "new style", which use a button on the receivers to "learn" a signal. Use + the NewRemoteSwitch library instead. + +See RemoteTransmitter.h and RemoteReceiver.h for details! + +License: GPLv3. See ./RemoteSwitch/license.txt + +Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino + + +Installation of library: + - Make sure Arduino is closed + - Copy the directory RemoteSwitch to the Arduino library directory (usually + /libraries/) + See http://arduino.cc/en/Guide/Libraries for detailed instructions. + +Default installation sender & demo: + - Connect tha data-in-pin of a 433MHz transmitter to digital pin 11. See + docs/hardware setup.jpg. + (Note: your hardware may have a different pin configuration!) + - Start Arduino, and open the example: File -> Examples -> RemoteSwitch -> + LightShow + - Alter addresses/devices to reflect your own setup. Otherwise nothing will + happen. + - Compile, upload and run! + +Default installation receiver & demo: + - Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo. + (Note: your hardware may have a different pin configuration!) + - Start Arduino, and open the example: File -> Examples -> RemoteSwitch -> + ShowReceivedCode or ShowReceivedCodeNewKaku, depending on your remote. + - Compile, upload and run + - Open serial monitor in Arduino (115200 baud) + - Press buttons on a 433MHz-remote, and watch the serial monitor + +Notes: + - These transmitters often use the PT2262 IC, or equivalent. For details about + the waveforms used by these remotes, the datasheet of the PT2262 is provided. + Page 4 and 5 will be of most interest. + + +Changelog: +RemoteSwitch library v2.3.0 (20121229) for Arduino 1.0 + - Improved reception quality by filtering too short pulses. + - Dropped pre-v1.0 Arduino support. + - Added RemoteReceiver::deinit() + +RemoteSwitch library v2.2.1 (20120314) for Arduino 0022/1.0 + - Fixed Elro code, it caused memory corruption. + - Renamed old-style .pde files to new-style .ino + +RemoteSwitch library v2.2.0 (20120213) for Arduino 0022/1.0 + - Added support for Elro switches (http://www.elro.eu/en/m/products/category/home_automation/home_control) + (untested; I don't have these kind of devices) + - Allowed the number of repeated signals transmitted by RemoteTransmitter to be + changed. + - By default, 16 instead of 8 repeats are sent. + - Support for Arduino 1.0. + - Added Datasheet PT2262, which (or equivalent) is often used in the transmitters. + - RemoteReceiver::isReceiving timeout changed to 150ms; 100ms was too short. + +RemoteSwitch library v2.1.1 (20110920) for Arduino 0022 + - Improved RemoteReceiver::isReceiving + +RemoteSwitch library v2.1.0 (20110919) for Arduino 0022 + - Changed classnames from *Switch to *Transmitter + - Added RemoteTransmitter::sendCode. See example "retransmitter". + - RemoteReceiver::interruptHandler() is now public, for use with InterruptChain + +RemoteSwitch library v2.0.0 (20100130) for Arduino 0017 + - Complete rewrite; can now receive and decode signals directly from the receiver's digital out. \ No newline at end of file diff --git a/libraries/RemoteSwitch/RemoteReceiver.cpp b/libraries/RemoteSwitch/RemoteReceiver.cpp index 41a60f5..fe5421f 100644 --- a/libraries/RemoteSwitch/RemoteReceiver.cpp +++ b/libraries/RemoteSwitch/RemoteReceiver.cpp @@ -1,193 +1,193 @@ -/* - * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ - * See RemoteReceiver.h for details. - * - * License: GPLv3. See license.txt - */ - -#include "RemoteReceiver.h" - - -/************ -* RemoteReceiver -************/ - -int8_t RemoteReceiver::_interrupt; -volatile int8_t RemoteReceiver::_state; -byte RemoteReceiver::_minRepeats; -RemoteReceiverCallBack RemoteReceiver::_callback; -boolean RemoteReceiver::_inCallback = false; -boolean RemoteReceiver::_enabled = false; - -void RemoteReceiver::init(int8_t interrupt, byte minRepeats, RemoteReceiverCallBack callback) { - _interrupt = interrupt; - _minRepeats = minRepeats; - _callback = callback; - - enable(); - if (_interrupt >= 0) { - attachInterrupt(_interrupt, interruptHandler, CHANGE); - } -} - -void RemoteReceiver::enable() { - _state = -1; - _enabled = true; -} - -void RemoteReceiver::disable() { - _enabled = false; -} - -void RemoteReceiver::deinit() { - _enabled = false; - if (_interrupt >= 0) { - detachInterrupt(_interrupt); - } -} - -void RemoteReceiver::interruptHandler() { - if (!_enabled) { - return; - } - - static unsigned int period; // Calculated duration of 1 period - static byte receivedBit; // Contains "bit" currently receiving - static unsigned long receivedCode; // Contains received code - static unsigned long previousCode; // Contains previous received code - static byte repeats = 0; // The number of times the an identical code is received in a row. - static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges - static unsigned int min1Period, max1Period, min3Period, max3Period; - static bool skip; - - // Filter out too short pulses. This method works as a low pass filter. - edgeTimeStamp[1] = edgeTimeStamp[2]; - edgeTimeStamp[2] = micros(); - - if (skip) { - skip = false; - return; - } - - if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) { - // Last edge was too short. - // Skip this edge, and the next too. - skip = true; - return; - } - - unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0]; - edgeTimeStamp[0] = edgeTimeStamp[1]; - - // Note that if state>=0, duration is always >= 1 period. - - if (_state==-1) { // Waiting for sync-signal - if (duration>3720) { // =31*120 minimal time between two edges before decoding starts. - // Sync signal received.. Preparing for decoding - period=duration/31; - receivedCode=previousCode=repeats=0; - - // Allow for large error-margin. ElCheapo-hardware :( - min1Period=period*4/10; // Avoid floating point math; saves memory. - max1Period=period*16/10; - min3Period=period*23/10; - max3Period=period*37/10; - } - else { - return; - } - } else if (_state<48) { // Decoding message - receivedBit <<= 1; - - // bit part durations can ONLY be 1 or 3 periods. - if (duration<=max1Period) { - receivedBit &= B1110; // Clear LSB of receivedBit - } - else if (duration>=min3Period && duration<=max3Period) { - receivedBit |= B1; // Set LSB of receivedBit - } - else { // Otherwise the entire sequence is invalid - _state=-1; - return; - } - - if ((_state%4)==3) { // Last bit part? - // Shift - receivedCode*=3; - - // Only 4 LSB's are used; trim the rest. - switch (receivedBit & B1111) { - case B0101: // short long short long == B0101 - // bit "0" received - receivedCode+=0; // I hope the optimizer handles this ;) - break; - case B1010: // long short long short == B1010 - // bit "1" received - receivedCode+=1; - break; - case B0110: // short long long short - // bit "f" received - receivedCode+=2; - break; - default: - // Bit was rubbish. Abort. - _state=-1; - return; - } - } - } else if (_state==48) { // Waiting for sync bit part 1 - // Must be 1 period. - if (duration>max1Period) { - _state=-1; - return; - } - } else { // Waiting for sync bit part 2 - // Must be 31 periods. - if (durationperiod*36) { - _state=-1; - return; - } - - // receivedCode is a valid code! - - if (receivedCode!=previousCode) { - repeats=0; - previousCode=receivedCode; - } - - repeats++; - - if (repeats>=_minRepeats) { - if (!_inCallback) { - _inCallback = true; - (_callback)(receivedCode, period); - _inCallback = false; - } - // Reset after callback. - _state=-1; - return; - } - - // Reset for next round - receivedCode = 0; - _state=0; // no need to wait for another sync-bit! - return; - } - - _state++; - return; -} - -boolean RemoteReceiver::isReceiving(int waitMillis) { - unsigned long startTime=millis(); - - int waited; // Signed int! - do { - if (_state == 48) { // Abort if a valid code has been received in the mean time - return true; - } - waited = (millis()-startTime); - } while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time. - - return false; -} +/* + * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ + * See RemoteReceiver.h for details. + * + * License: GPLv3. See license.txt + */ + +#include "RemoteReceiver.h" + + +/************ +* RemoteReceiver +************/ + +int8_t RemoteReceiver::_interrupt; +volatile int8_t RemoteReceiver::_state; +byte RemoteReceiver::_minRepeats; +RemoteReceiverCallBack RemoteReceiver::_callback; +boolean RemoteReceiver::_inCallback = false; +boolean RemoteReceiver::_enabled = false; + +void RemoteReceiver::init(int8_t interrupt, byte minRepeats, RemoteReceiverCallBack callback) { + _interrupt = interrupt; + _minRepeats = minRepeats; + _callback = callback; + + enable(); + if (_interrupt >= 0) { + attachInterrupt(_interrupt, interruptHandler, CHANGE); + } +} + +void RemoteReceiver::enable() { + _state = -1; + _enabled = true; +} + +void RemoteReceiver::disable() { + _enabled = false; +} + +void RemoteReceiver::deinit() { + _enabled = false; + if (_interrupt >= 0) { + detachInterrupt(_interrupt); + } +} + +void RemoteReceiver::interruptHandler() { + if (!_enabled) { + return; + } + + static unsigned int period; // Calculated duration of 1 period + static byte receivedBit; // Contains "bit" currently receiving + static unsigned long receivedCode; // Contains received code + static unsigned long previousCode; // Contains previous received code + static byte repeats = 0; // The number of times the an identical code is received in a row. + static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges + static unsigned int min1Period, max1Period, min3Period, max3Period; + static bool skip; + + // Filter out too short pulses. This method works as a low pass filter. + edgeTimeStamp[1] = edgeTimeStamp[2]; + edgeTimeStamp[2] = micros(); + + if (skip) { + skip = false; + return; + } + + if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) { + // Last edge was too short. + // Skip this edge, and the next too. + skip = true; + return; + } + + unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0]; + edgeTimeStamp[0] = edgeTimeStamp[1]; + + // Note that if state>=0, duration is always >= 1 period. + + if (_state==-1) { // Waiting for sync-signal + if (duration>3720) { // =31*120 minimal time between two edges before decoding starts. + // Sync signal received.. Preparing for decoding + period=duration/31; + receivedCode=previousCode=repeats=0; + + // Allow for large error-margin. ElCheapo-hardware :( + min1Period=period*4/10; // Avoid floating point math; saves memory. + max1Period=period*16/10; + min3Period=period*23/10; + max3Period=period*37/10; + } + else { + return; + } + } else if (_state<48) { // Decoding message + receivedBit <<= 1; + + // bit part durations can ONLY be 1 or 3 periods. + if (duration<=max1Period) { + receivedBit &= B1110; // Clear LSB of receivedBit + } + else if (duration>=min3Period && duration<=max3Period) { + receivedBit |= B1; // Set LSB of receivedBit + } + else { // Otherwise the entire sequence is invalid + _state=-1; + return; + } + + if ((_state%4)==3) { // Last bit part? + // Shift + receivedCode*=3; + + // Only 4 LSB's are used; trim the rest. + switch (receivedBit & B1111) { + case B0101: // short long short long == B0101 + // bit "0" received + receivedCode+=0; // I hope the optimizer handles this ;) + break; + case B1010: // long short long short == B1010 + // bit "1" received + receivedCode+=1; + break; + case B0110: // short long long short + // bit "f" received + receivedCode+=2; + break; + default: + // Bit was rubbish. Abort. + _state=-1; + return; + } + } + } else if (_state==48) { // Waiting for sync bit part 1 + // Must be 1 period. + if (duration>max1Period) { + _state=-1; + return; + } + } else { // Waiting for sync bit part 2 + // Must be 31 periods. + if (durationperiod*36) { + _state=-1; + return; + } + + // receivedCode is a valid code! + + if (receivedCode!=previousCode) { + repeats=0; + previousCode=receivedCode; + } + + repeats++; + + if (repeats>=_minRepeats) { + if (!_inCallback) { + _inCallback = true; + (_callback)(receivedCode, period); + _inCallback = false; + } + // Reset after callback. + _state=-1; + return; + } + + // Reset for next round + receivedCode = 0; + _state=0; // no need to wait for another sync-bit! + return; + } + + _state++; + return; +} + +boolean RemoteReceiver::isReceiving(int waitMillis) { + unsigned long startTime=millis(); + + int waited; // Signed int! + do { + if (_state == 48) { // Abort if a valid code has been received in the mean time + return true; + } + waited = (millis()-startTime); + } while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time. + + return false; +} diff --git a/libraries/RemoteSwitch/RemoteReceiver.h b/libraries/RemoteSwitch/RemoteReceiver.h index 8f0b35d..f965d9e 100644 --- a/libraries/RemoteSwitch/RemoteReceiver.h +++ b/libraries/RemoteSwitch/RemoteReceiver.h @@ -1,88 +1,88 @@ -/* - * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ - * - * License: GPLv3. See license.txt - */ - -#ifndef RemoteReceiver_h -#define RemoteReceiver_h - -#include - -typedef void (*RemoteReceiverCallBack)(unsigned long, unsigned int); - -/** -* See RemoteSwitch for introduction. -* -* RemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system -* as well as the signal sent by the RemoteSwtich class. When a correct signal is received, -* a user-defined callback function is called. -* -* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed. -* A call to the callback must b finished before RemoteReceiver will call the callback function again, thus -* there is no re-entrant problem. -* -* When sending your own code using RemoteSwich, disable() the receiver first. -* -* This is a pure static class, for simplicity and to limit memory-use. -*/ - -class RemoteReceiver { - public: - /** - * Initializes the decoder. - * - * If interrupt >= 0, init will register pin to this library. - * If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler() - * yourself whenever the output of the receiver changes, or you can use InterruptChain. - * - * @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details. - If < 0, you must call interruptHandler() yourself. - * @param minRepeats The number of times the same code must be received in a row before the callback is calles - * @param callback Pointer to a callback function, with signature void (*func)(unsigned long, unsigned int). First parameter is the decoded data, the second the period of the timing. - */ - static void init(int8_t interrupt, byte minRepeats, RemoteReceiverCallBack callback); - - /** - * Enable decoding. No need to call enable() after init(). - */ - static void enable(); - - /** - * Disable decoding. You can re-enable decoding by calling enable(); - */ - static void disable(); - - /** - * Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to - * re-enable decoding, call init() again. - */ - static void deinit(); - - /** - * Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true. - * Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false. - * By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times. - * - * Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is - * the case in the callback), isReceiving() will not work properly. - * - * @param waitMillis number of milliseconds to monitor for signal. - * @return boolean If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true. - */ - static boolean isReceiving(int waitMillis = 150); - - static void interruptHandler(); - - private: - - static int8_t _interrupt; // Radio input interrupt - volatile static int8_t _state; // State of decoding process. There are 49 states, 1 for "waiting for signal" and 48 for decoding the 48 edges in a valid code. - static byte _minRepeats; - static RemoteReceiverCallBack _callback; - static boolean _inCallback; // When true, the callback function is being executed; prevents re-entrance. - static boolean _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately. - -}; - -#endif +/* + * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ + * + * License: GPLv3. See license.txt + */ + +#ifndef RemoteReceiver_h +#define RemoteReceiver_h + +#include + +typedef void (*RemoteReceiverCallBack)(unsigned long, unsigned int); + +/** +* See RemoteSwitch for introduction. +* +* RemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system +* as well as the signal sent by the RemoteSwtich class. When a correct signal is received, +* a user-defined callback function is called. +* +* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed. +* A call to the callback must b finished before RemoteReceiver will call the callback function again, thus +* there is no re-entrant problem. +* +* When sending your own code using RemoteSwich, disable() the receiver first. +* +* This is a pure static class, for simplicity and to limit memory-use. +*/ + +class RemoteReceiver { + public: + /** + * Initializes the decoder. + * + * If interrupt >= 0, init will register pin to this library. + * If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler() + * yourself whenever the output of the receiver changes, or you can use InterruptChain. + * + * @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details. + If < 0, you must call interruptHandler() yourself. + * @param minRepeats The number of times the same code must be received in a row before the callback is calles + * @param callback Pointer to a callback function, with signature void (*func)(unsigned long, unsigned int). First parameter is the decoded data, the second the period of the timing. + */ + static void init(int8_t interrupt, byte minRepeats, RemoteReceiverCallBack callback); + + /** + * Enable decoding. No need to call enable() after init(). + */ + static void enable(); + + /** + * Disable decoding. You can re-enable decoding by calling enable(); + */ + static void disable(); + + /** + * Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to + * re-enable decoding, call init() again. + */ + static void deinit(); + + /** + * Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true. + * Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false. + * By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times. + * + * Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is + * the case in the callback), isReceiving() will not work properly. + * + * @param waitMillis number of milliseconds to monitor for signal. + * @return boolean If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true. + */ + static boolean isReceiving(int waitMillis = 150); + + static void interruptHandler(); + + private: + + static int8_t _interrupt; // Radio input interrupt + volatile static int8_t _state; // State of decoding process. There are 49 states, 1 for "waiting for signal" and 48 for decoding the 48 edges in a valid code. + static byte _minRepeats; + static RemoteReceiverCallBack _callback; + static boolean _inCallback; // When true, the callback function is being executed; prevents re-entrance. + static boolean _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately. + +}; + +#endif diff --git a/libraries/RemoteSwitch/RemoteTransmitter.cpp b/libraries/RemoteSwitch/RemoteTransmitter.cpp index f2a1cbd..d4df6e6 100644 --- a/libraries/RemoteSwitch/RemoteTransmitter.cpp +++ b/libraries/RemoteSwitch/RemoteTransmitter.cpp @@ -1,305 +1,305 @@ -/* - * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ - * See RemoteTransmitter.h for details. - * - * License: GPLv3. See license.txt - */ - -#include "RemoteTransmitter.h" - - -/************ -* RemoteTransmitter -************/ - -RemoteTransmitter::RemoteTransmitter(byte pin, unsigned int periodusec, byte repeats) { - _pin=pin; - _periodusec=periodusec; - _repeats=repeats; - - pinMode(_pin, OUTPUT); -} - -unsigned long RemoteTransmitter::encodeTelegram(byte trits[]) { - unsigned long data = 0; - - // Encode data - for (byte i=0;i<12;i++) { - data*=3; - data+=trits[i]; - } - - // Encode period duration - data |= (unsigned long)_periodusec << 23; - - // Encode repeats - data |= (unsigned long)_repeats << 20; - - return data; -} - -void RemoteTransmitter::sendTelegram(byte trits[]) { - sendTelegram(encodeTelegram(trits),_pin); -} - -/** -* Format data: -* pppppppp|prrrdddd|dddddddd|dddddddd (32 bit) -* p = perioud (9 bit unsigned int -* r = repeats as 2log. Thus, if r = 3, then signal is sent 2^3=8 times -* d = data -*/ -void RemoteTransmitter::sendTelegram(unsigned long data, byte pin) { - unsigned int periodusec = (unsigned long)data >> 23; - byte repeats = ((unsigned long)data >> 20) & B111; - - sendCode(pin, data, periodusec, repeats); -} - -void RemoteTransmitter::sendCode(byte pin, unsigned long code, unsigned int periodusec, byte repeats) { - code &= 0xfffff; // Truncate to 20 bit ; - // Convert the base3-code to base4, to avoid lengthy calculations when transmitting.. Messes op timings. - // Also note this swaps endianess in the process. The MSB must be transmitted first, but is converted to - // LSB here. This is easier when actually transmitting later on. - unsigned long dataBase4 = 0; - - for (byte i=0; i<12; i++) { - dataBase4<<=2; - dataBase4|=(code%3); - code/=3; - } - - repeats = 1 << (repeats & B111); // repeats := 2^repeats; - - for (byte j=0;j>=2; - } - - // Send termination/synchronization-signal. Total length: 32 periods - digitalWrite(pin, HIGH); - delayMicroseconds(periodusec); - digitalWrite(pin, LOW); - delayMicroseconds(periodusec*31); - } -} - -boolean RemoteTransmitter::isSameCode(unsigned long encodedTelegram, unsigned long receivedData) { - return (receivedData==(encodedTelegram & 0xFFFFF)); // compare the 20 LSB's -} - - -/************ -* ActionTransmitter -************/ - -ActionTransmitter::ActionTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { - // Call constructor -} - - -void ActionTransmitter::sendSignal(byte systemCode, char device, boolean on) { - sendTelegram(getTelegram(systemCode,device,on), _pin); -} - -unsigned long ActionTransmitter::getTelegram(byte systemCode, char device, boolean on) { - byte trits[12]; - - device-=65; - - for (byte i=0; i<5; i++) { - // Trits 0-4 contain address (2^5=32 addresses) - trits[i]=(systemCode & 1)?1:2; - systemCode>>=1; - - // Trits 5-9 contain device. Only one trit has value 0, others have 2 (float)! - trits[i+5]=(i==device?0:2); - } - - // Switch on or off - trits[10]=(!on?0:2); - trits[11]=(on?0:2); - - return encodeTelegram(trits); -} - -/************ -* BlokkerTransmitter -************/ - -BlokkerTransmitter::BlokkerTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { - // Call constructor -} - - -void BlokkerTransmitter::sendSignal(byte device, boolean on) { - sendTelegram(getTelegram(device,on), _pin); -} - -unsigned long BlokkerTransmitter::getTelegram(byte device, boolean on) { - byte trits[12]={0}; - - device--; - - for (byte i=1; i<4; i++) { - // Trits 1-3 contain device - trits[i]=(device & 1)?0:1; - device>>=1; - } - - // Switch on or off - trits[8]=(on?1:0); - - return encodeTelegram(trits); -} - -/************ -* KaKuTransmitter -************/ - -KaKuTransmitter::KaKuTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { - // Call constructor -} - -void KaKuTransmitter::sendSignal(char address, byte device, boolean on) { - sendTelegram(getTelegram(address, device, on), _pin); -} - -unsigned long KaKuTransmitter::getTelegram(char address, byte device, boolean on) { - byte trits[12]; - - address-=65; - device-=1; - - for (byte i=0; i<4; i++) { - // Trits 0-3 contain address (2^4 = 16 addresses) - trits[i]=(address & 1)?2:0; - address>>=1; - - // Trits 4-8 contain device (2^4 = 16 addresses) - trits[i+4]=(device & 1)?2:0; - device>>=1; - } - - // Trits 8-10 seem to be fixed - trits[8]=0; - trits[9]=2; - trits[10]=2; - - // Switch on or off - trits[11]=(on?2:0); - - return encodeTelegram(trits); -} - -void KaKuTransmitter::sendSignal(char address, byte group, byte device, boolean on) { - sendTelegram(getTelegram(address, group, on), _pin); -} - -unsigned long KaKuTransmitter::getTelegram(char address, byte group, byte device, boolean on) { - byte trits[12], i; - - address-=65; - group-=1; - device-=1; - - // Address. M3E Pin A0-A3 - for (i=0; i<4; i++) { - // Trits 0-3 contain address (2^4 = 16 addresses) - trits[i]=(address & 1)?2:0; - address>>=1; - } - - // Device. M3E Pin A4-A5 - for (; i<6; i++) { - trits[i]=(device & 1)?2:0; - device>>=1; - } - - // Group. M3E Pin A6-A7 - for (; i<8; i++) { - trits[i]=(group & 1)?2:0; - group>>=1; - } - - // Trits 8-10 are be fixed. M3E Pin A8/D0-A10/D2 - trits[8]=0; - trits[9]=2; - trits[10]=2; - - // Switch on or off, M3E Pin A11/D3 - trits[11]=(on?2:0); - - return encodeTelegram(trits); -} - - -/************ -* ElroTransmitter -************/ - -ElroTransmitter::ElroTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin, periodusec, repeats) { - //Call constructor -} - -void ElroTransmitter::sendSignal(byte systemCode, char device, boolean on) { - sendTelegram(getTelegram(systemCode, device, on), _pin); -} - -unsigned long ElroTransmitter::getTelegram(byte systemCode, char device, boolean on) { - byte trits[12]; - - device-=65; - - for (byte i=0; i<5; i++) { - //trits 0-4 contain address (2^5=32 addresses) - trits[i]=(systemCode & 1)?0:2; - systemCode>>=1; - - //trits 5-9 contain device. Only one trit has value 0, others have 2 (float)! - trits[i+5]=(i==device?0:2); - } - - //switch on or off - trits[10]=(on?0:2); - trits[11]=(!on?0:2); - - return encodeTelegram(trits); -} +/* + * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ + * See RemoteTransmitter.h for details. + * + * License: GPLv3. See license.txt + */ + +#include "RemoteTransmitter.h" + + +/************ +* RemoteTransmitter +************/ + +RemoteTransmitter::RemoteTransmitter(byte pin, unsigned int periodusec, byte repeats) { + _pin=pin; + _periodusec=periodusec; + _repeats=repeats; + + pinMode(_pin, OUTPUT); +} + +unsigned long RemoteTransmitter::encodeTelegram(byte trits[]) { + unsigned long data = 0; + + // Encode data + for (byte i=0;i<12;i++) { + data*=3; + data+=trits[i]; + } + + // Encode period duration + data |= (unsigned long)_periodusec << 23; + + // Encode repeats + data |= (unsigned long)_repeats << 20; + + return data; +} + +void RemoteTransmitter::sendTelegram(byte trits[]) { + sendTelegram(encodeTelegram(trits),_pin); +} + +/** +* Format data: +* pppppppp|prrrdddd|dddddddd|dddddddd (32 bit) +* p = perioud (9 bit unsigned int +* r = repeats as 2log. Thus, if r = 3, then signal is sent 2^3=8 times +* d = data +*/ +void RemoteTransmitter::sendTelegram(unsigned long data, byte pin) { + unsigned int periodusec = (unsigned long)data >> 23; + byte repeats = ((unsigned long)data >> 20) & B111; + + sendCode(pin, data, periodusec, repeats); +} + +void RemoteTransmitter::sendCode(byte pin, unsigned long code, unsigned int periodusec, byte repeats) { + code &= 0xfffff; // Truncate to 20 bit ; + // Convert the base3-code to base4, to avoid lengthy calculations when transmitting.. Messes op timings. + // Also note this swaps endianess in the process. The MSB must be transmitted first, but is converted to + // LSB here. This is easier when actually transmitting later on. + unsigned long dataBase4 = 0; + + for (byte i=0; i<12; i++) { + dataBase4<<=2; + dataBase4|=(code%3); + code/=3; + } + + repeats = 1 << (repeats & B111); // repeats := 2^repeats; + + for (byte j=0;j>=2; + } + + // Send termination/synchronization-signal. Total length: 32 periods + digitalWrite(pin, HIGH); + delayMicroseconds(periodusec); + digitalWrite(pin, LOW); + delayMicroseconds(periodusec*31); + } +} + +boolean RemoteTransmitter::isSameCode(unsigned long encodedTelegram, unsigned long receivedData) { + return (receivedData==(encodedTelegram & 0xFFFFF)); // compare the 20 LSB's +} + + +/************ +* ActionTransmitter +************/ + +ActionTransmitter::ActionTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { + // Call constructor +} + + +void ActionTransmitter::sendSignal(byte systemCode, char device, boolean on) { + sendTelegram(getTelegram(systemCode,device,on), _pin); +} + +unsigned long ActionTransmitter::getTelegram(byte systemCode, char device, boolean on) { + byte trits[12]; + + device-=65; + + for (byte i=0; i<5; i++) { + // Trits 0-4 contain address (2^5=32 addresses) + trits[i]=(systemCode & 1)?1:2; + systemCode>>=1; + + // Trits 5-9 contain device. Only one trit has value 0, others have 2 (float)! + trits[i+5]=(i==device?0:2); + } + + // Switch on or off + trits[10]=(!on?0:2); + trits[11]=(on?0:2); + + return encodeTelegram(trits); +} + +/************ +* BlokkerTransmitter +************/ + +BlokkerTransmitter::BlokkerTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { + // Call constructor +} + + +void BlokkerTransmitter::sendSignal(byte device, boolean on) { + sendTelegram(getTelegram(device,on), _pin); +} + +unsigned long BlokkerTransmitter::getTelegram(byte device, boolean on) { + byte trits[12]={0}; + + device--; + + for (byte i=1; i<4; i++) { + // Trits 1-3 contain device + trits[i]=(device & 1)?0:1; + device>>=1; + } + + // Switch on or off + trits[8]=(on?1:0); + + return encodeTelegram(trits); +} + +/************ +* KaKuTransmitter +************/ + +KaKuTransmitter::KaKuTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin,periodusec,repeats) { + // Call constructor +} + +void KaKuTransmitter::sendSignal(char address, byte device, boolean on) { + sendTelegram(getTelegram(address, device, on), _pin); +} + +unsigned long KaKuTransmitter::getTelegram(char address, byte device, boolean on) { + byte trits[12]; + + address-=65; + device-=1; + + for (byte i=0; i<4; i++) { + // Trits 0-3 contain address (2^4 = 16 addresses) + trits[i]=(address & 1)?2:0; + address>>=1; + + // Trits 4-8 contain device (2^4 = 16 addresses) + trits[i+4]=(device & 1)?2:0; + device>>=1; + } + + // Trits 8-10 seem to be fixed + trits[8]=0; + trits[9]=2; + trits[10]=2; + + // Switch on or off + trits[11]=(on?2:0); + + return encodeTelegram(trits); +} + +void KaKuTransmitter::sendSignal(char address, byte group, byte device, boolean on) { + sendTelegram(getTelegram(address, group, on), _pin); +} + +unsigned long KaKuTransmitter::getTelegram(char address, byte group, byte device, boolean on) { + byte trits[12], i; + + address-=65; + group-=1; + device-=1; + + // Address. M3E Pin A0-A3 + for (i=0; i<4; i++) { + // Trits 0-3 contain address (2^4 = 16 addresses) + trits[i]=(address & 1)?2:0; + address>>=1; + } + + // Device. M3E Pin A4-A5 + for (; i<6; i++) { + trits[i]=(device & 1)?2:0; + device>>=1; + } + + // Group. M3E Pin A6-A7 + for (; i<8; i++) { + trits[i]=(group & 1)?2:0; + group>>=1; + } + + // Trits 8-10 are be fixed. M3E Pin A8/D0-A10/D2 + trits[8]=0; + trits[9]=2; + trits[10]=2; + + // Switch on or off, M3E Pin A11/D3 + trits[11]=(on?2:0); + + return encodeTelegram(trits); +} + + +/************ +* ElroTransmitter +************/ + +ElroTransmitter::ElroTransmitter(byte pin, unsigned int periodusec, byte repeats) : RemoteTransmitter(pin, periodusec, repeats) { + //Call constructor +} + +void ElroTransmitter::sendSignal(byte systemCode, char device, boolean on) { + sendTelegram(getTelegram(systemCode, device, on), _pin); +} + +unsigned long ElroTransmitter::getTelegram(byte systemCode, char device, boolean on) { + byte trits[12]; + + device-=65; + + for (byte i=0; i<5; i++) { + //trits 0-4 contain address (2^5=32 addresses) + trits[i]=(systemCode & 1)?0:2; + systemCode>>=1; + + //trits 5-9 contain device. Only one trit has value 0, others have 2 (float)! + trits[i+5]=(i==device?0:2); + } + + //switch on or off + trits[10]=(on?0:2); + trits[11]=(!on?0:2); + + return encodeTelegram(trits); +} diff --git a/libraries/RemoteSwitch/RemoteTransmitter.h b/libraries/RemoteSwitch/RemoteTransmitter.h index 56ed7d4..4916e6c 100644 --- a/libraries/RemoteSwitch/RemoteTransmitter.h +++ b/libraries/RemoteSwitch/RemoteTransmitter.h @@ -1,249 +1,249 @@ -/* - * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ - * - * License: GPLv3. See license.txt - */ - -#ifndef RemoteTransmitter_h -#define RemoteTransmitter_h - -#include - -/** -* RemoteTransmitter provides a generic class for simulation of common RF remote controls, like the 'Klik aan Klik uit'-system -* (http://www.klikaanklikuit.nl/), used to remotely switch lights etc. -* -* Many of these remotes seem to use a 433MHz SAW resonator and one of these chips: LP801B, HX2262, PT2262, M3E. -* Datasheet for the HX2262/PT2262 ICs: -* http://www.princeton.com.tw/downloadprocess/downloadfile.asp?mydownload=PT2262_1.pdf -* -* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. -* http://www.sparkfun.com/products/10534 -* http://www.conrad.nl/goto/?product=130428 -* -* Notes: -* - Since these chips use (and send!) tri-state inputs (low, high and floating) I use 'trits' instead of 'bits', -* when appropriate. -* - I measured the period lengths with a scope. Thus: they work for my remotes, but may fail for yours... -* A better way would be to calculate the 'target'-timings using the datasheets and the resistor-values on the remotes. -*/ -class RemoteTransmitter { - public: - /** - * Constructor. - * - * To obtain the correct period length, an oscilloscope is convenient, but you can also read the - * datasheet of the transmitter, measure the resistor for the oscillator and calculate the frequency. - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodusec [0..511] Duration of one period, in microseconds. A trit is 6 periods. - * @param repeats [0..7] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust. - */ - RemoteTransmitter(byte pin, unsigned int periodusec, byte repeats); - - /** - * Encodes the data base on the current object and the given trits. The data can be reused, e.g. - * for use with the static version of sendTelegram, so you won't need to instantiate costly objects! - * - * @return The data suited for use with RemoteTransmitter::sendTelegram. - */ - unsigned long encodeTelegram(byte trits[]); - - /** - * Send a telegram, including synchronization-part. - * - * @param trits Array of size 12. "trits" should be either 0, 1 or 2, where 2 indicates "float" - */ - void sendTelegram(byte trits[]); - - /** - * Send a telegram, including synchronization-part. The data-param encodes the period duration, number of repeats and the actual data. - * Note: static method, which allows for use in low-mem situations. - * - * Format data: - * pppppppp|prrrdddd|dddddddd|dddddddd (32 bit) - * p = period (9 bit unsigned integer) - * r = repeats as 2log. Thus, if r = 3, then signal is sent 2^3=8 times - * d = data - * - * @param data data, period and repeats. - * @param pin Pin number of the transmitter. - */ - static void sendTelegram(unsigned long data, byte pin); - - /** - * The complement of RemoteReceiver. Send a telegram with specified code as data. - * - * Note: static method, which allows for use in low-mem situations. - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodusec [0..511] Duration of one period, in microseconds. A trit is 6 periods. - * @param repeats [0..7] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust. - * @param code The code to transmit. Note: only the first 20 bits are used, the rest is ignored. Also see sendTelegram. - */ - static void sendCode(byte pin, unsigned long code, unsigned int periodusec, byte repeats); - - /** - * Compares the data received with RemoteReceive with the data obtained by one of the getTelegram-functions. - * Period duration and repetitions are ignored by this function; only the data-payload is compared. - * - * @return true, if the codes are identical (the 20 least significant bits match) - */ - static boolean isSameCode(unsigned long encodedTelegram, unsigned long receivedData); - - protected: - byte _pin; // Transmitter output pin - unsigned int _periodusec; // Oscillator period in microseconds - byte _repeats; // Number over repetitions of one telegram -}; - -/** -* ActionTransmitter simulates a remote, as sold in the Dutch 'Action' stores. But there are many similar systems on the market. -* If your remote has setting for 5 address bits, and can control 5 devices on or off, then you can try to use the ActionTransmitter. -* Otherwise you may have luck with the ElroTransmitter, which is similar. -*/ -class ActionTransmitter: RemoteTransmitter { - public: - /** - * Constructor - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodsec Duration of one period, in microseconds. Default is 190usec - * @param repeats [0..7] The 2log-Number of times the signal is repeated. - * @see RemoteTransmitter - */ - ActionTransmitter(byte pin, unsigned int periodusec=190, byte repeats=4); - - /** - * Send a on or off signal to a device. - * - * @param systemCode 5-bit address (dip switches in remote). Range [0..31] - * @param device Device to switch. Range: [A..E] (case sensitive!) - * @param on True, to switch on. False to switch off, - */ - void sendSignal(byte systemCode, char device, boolean on); - - /** - * Generates the telegram (data) which can be used for RemoteTransmitter::sendTelegram. - * See sendSignal for details on the parameters - * - * @return Encoded data, including repeats and period duration. - */ - unsigned long getTelegram(byte systemCode, char device, boolean on); -}; - -/** -* BlokkerTransmitter simulates a remote, as sold in the Dutch 'Blokker' stores. But there are many similar systems on the market. -* These remotes have 4 on, 4 off buttons and a switch to switch between device 1-4 and 5-8. No further configuration -* possible. -*/ -class BlokkerTransmitter: RemoteTransmitter { - public: - /** - * Constructor - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodsec Duration of one period, in microseconds. Default is 307usec - * @param repeats [0..7] The 2log-Number of times the signal is repeated. - * @see RemoteTransmitter - */ - BlokkerTransmitter(byte pin, unsigned int periodusec=230, byte repeats=4); - - /** - * Send a on or off signal to a device. - * - * @param device Device to switch. Range: [1..8] - * @param on True, to switch on. False to switch off, - */ - void sendSignal(byte device, boolean on); - - /** - * @see RemoteTransmitter::getTelegram - */ - unsigned long getTelegram(byte device, boolean on); -}; - -/** -* KaKuTransmitter simulates a KlikAanKlikUit-remote, but there are many clones. -* If your transmitter has a address dial with the characters A till P, you can try this class. -*/ -class KaKuTransmitter: RemoteTransmitter { - public: - /** - * Constructor - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodsec Duration of one period, in microseconds. Default is 375usec - * @param repeats [0..7] The 2log-Number of times the signal is repeated. - * @see RemoteTransmitter - */ - KaKuTransmitter(byte pin, unsigned int periodusec=375, byte repeats=4); - - /** - * Send a on or off signal to a device. - * - * @param address address (dial switches in remote). Range [A..P] (case sensitive!) - * @param group Group to switch. Range: [1..4] - * @param device Device to switch. Range: [1..4] - * @param on True, to switch on. False to switch off, - */ - void sendSignal(char address, byte group, byte device, boolean on); - - /** - * Send a on or off signal to a device. - * - * @param address address (dip switches in remote). Range [A..P] (case sensitive!) - * @param device device (dial switches in remote). Range [1..16] - * @param on True, to switch on. False to switch off, - */ - void sendSignal(char address, byte device, boolean on); - - /** - * @see RemoteTransmitter::getTelegram - */ - unsigned long getTelegram(char address, byte group, byte device, boolean on); - - /** - * @see RemoteTransmitter::getTelegram - */ - unsigned long getTelegram(char address, byte device, boolean on); -}; - -/** -* ElroTransmitter simulates remotes of the Elro "Home Control" series -* see http://www.elro.eu/en/m/products/category/home_automation/home_control -* There are are many similar systems on the market. If your remote has setting for 5 address bits, and can control -* 4 devices on or off, then you can try to use the ElroTransmitter. Otherwise you may have luck with the -* ActionTransmitter, which is similar. -*/ -class ElroTransmitter: RemoteTransmitter { - public: - /** - * Constructor - * - * @param pin output pin on Arduino to which the transmitter is connected - * @param periodsec Duration of one period, in microseconds. Default is 320usec - * @param repeats [0..7] The 2log-Number of times the signal is repeated. - * @see RemoteSwitch - */ - ElroTransmitter(byte pin, unsigned int periodusec=320, byte repeats=4); - - /** - * Send a on or off signal to a device. - * - * @param systemCode 5-bit address (dip switches in remote). Range [0..31] - * @param device Device to switch. Range: [A..D] (case sensitive!) - * @param on True, to switch on. False to switch off, - */ - void sendSignal(byte systemCode, char device, boolean on); - - /** - * Generates the telegram (data) which can be used for RemoteSwitch::sendTelegram. - * See sendSignal for details on the parameters - * - * @return Encoded data, including repeats and period duration. - */ - unsigned long getTelegram(byte systemCode, char device, boolean on); -}; - -#endif +/* + * RemoteSwitch library v2.3.0 (20121229) made by Randy Simons http://randysimons.nl/ + * + * License: GPLv3. See license.txt + */ + +#ifndef RemoteTransmitter_h +#define RemoteTransmitter_h + +#include + +/** +* RemoteTransmitter provides a generic class for simulation of common RF remote controls, like the 'Klik aan Klik uit'-system +* (http://www.klikaanklikuit.nl/), used to remotely switch lights etc. +* +* Many of these remotes seem to use a 433MHz SAW resonator and one of these chips: LP801B, HX2262, PT2262, M3E. +* Datasheet for the HX2262/PT2262 ICs: +* http://www.princeton.com.tw/downloadprocess/downloadfile.asp?mydownload=PT2262_1.pdf +* +* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g. +* http://www.sparkfun.com/products/10534 +* http://www.conrad.nl/goto/?product=130428 +* +* Notes: +* - Since these chips use (and send!) tri-state inputs (low, high and floating) I use 'trits' instead of 'bits', +* when appropriate. +* - I measured the period lengths with a scope. Thus: they work for my remotes, but may fail for yours... +* A better way would be to calculate the 'target'-timings using the datasheets and the resistor-values on the remotes. +*/ +class RemoteTransmitter { + public: + /** + * Constructor. + * + * To obtain the correct period length, an oscilloscope is convenient, but you can also read the + * datasheet of the transmitter, measure the resistor for the oscillator and calculate the frequency. + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodusec [0..511] Duration of one period, in microseconds. A trit is 6 periods. + * @param repeats [0..7] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust. + */ + RemoteTransmitter(byte pin, unsigned int periodusec, byte repeats); + + /** + * Encodes the data base on the current object and the given trits. The data can be reused, e.g. + * for use with the static version of sendTelegram, so you won't need to instantiate costly objects! + * + * @return The data suited for use with RemoteTransmitter::sendTelegram. + */ + unsigned long encodeTelegram(byte trits[]); + + /** + * Send a telegram, including synchronization-part. + * + * @param trits Array of size 12. "trits" should be either 0, 1 or 2, where 2 indicates "float" + */ + void sendTelegram(byte trits[]); + + /** + * Send a telegram, including synchronization-part. The data-param encodes the period duration, number of repeats and the actual data. + * Note: static method, which allows for use in low-mem situations. + * + * Format data: + * pppppppp|prrrdddd|dddddddd|dddddddd (32 bit) + * p = period (9 bit unsigned integer) + * r = repeats as 2log. Thus, if r = 3, then signal is sent 2^3=8 times + * d = data + * + * @param data data, period and repeats. + * @param pin Pin number of the transmitter. + */ + static void sendTelegram(unsigned long data, byte pin); + + /** + * The complement of RemoteReceiver. Send a telegram with specified code as data. + * + * Note: static method, which allows for use in low-mem situations. + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodusec [0..511] Duration of one period, in microseconds. A trit is 6 periods. + * @param repeats [0..7] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust. + * @param code The code to transmit. Note: only the first 20 bits are used, the rest is ignored. Also see sendTelegram. + */ + static void sendCode(byte pin, unsigned long code, unsigned int periodusec, byte repeats); + + /** + * Compares the data received with RemoteReceive with the data obtained by one of the getTelegram-functions. + * Period duration and repetitions are ignored by this function; only the data-payload is compared. + * + * @return true, if the codes are identical (the 20 least significant bits match) + */ + static boolean isSameCode(unsigned long encodedTelegram, unsigned long receivedData); + + protected: + byte _pin; // Transmitter output pin + unsigned int _periodusec; // Oscillator period in microseconds + byte _repeats; // Number over repetitions of one telegram +}; + +/** +* ActionTransmitter simulates a remote, as sold in the Dutch 'Action' stores. But there are many similar systems on the market. +* If your remote has setting for 5 address bits, and can control 5 devices on or off, then you can try to use the ActionTransmitter. +* Otherwise you may have luck with the ElroTransmitter, which is similar. +*/ +class ActionTransmitter: RemoteTransmitter { + public: + /** + * Constructor + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodsec Duration of one period, in microseconds. Default is 190usec + * @param repeats [0..7] The 2log-Number of times the signal is repeated. + * @see RemoteTransmitter + */ + ActionTransmitter(byte pin, unsigned int periodusec=190, byte repeats=4); + + /** + * Send a on or off signal to a device. + * + * @param systemCode 5-bit address (dip switches in remote). Range [0..31] + * @param device Device to switch. Range: [A..E] (case sensitive!) + * @param on True, to switch on. False to switch off, + */ + void sendSignal(byte systemCode, char device, boolean on); + + /** + * Generates the telegram (data) which can be used for RemoteTransmitter::sendTelegram. + * See sendSignal for details on the parameters + * + * @return Encoded data, including repeats and period duration. + */ + unsigned long getTelegram(byte systemCode, char device, boolean on); +}; + +/** +* BlokkerTransmitter simulates a remote, as sold in the Dutch 'Blokker' stores. But there are many similar systems on the market. +* These remotes have 4 on, 4 off buttons and a switch to switch between device 1-4 and 5-8. No further configuration +* possible. +*/ +class BlokkerTransmitter: RemoteTransmitter { + public: + /** + * Constructor + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodsec Duration of one period, in microseconds. Default is 307usec + * @param repeats [0..7] The 2log-Number of times the signal is repeated. + * @see RemoteTransmitter + */ + BlokkerTransmitter(byte pin, unsigned int periodusec=230, byte repeats=4); + + /** + * Send a on or off signal to a device. + * + * @param device Device to switch. Range: [1..8] + * @param on True, to switch on. False to switch off, + */ + void sendSignal(byte device, boolean on); + + /** + * @see RemoteTransmitter::getTelegram + */ + unsigned long getTelegram(byte device, boolean on); +}; + +/** +* KaKuTransmitter simulates a KlikAanKlikUit-remote, but there are many clones. +* If your transmitter has a address dial with the characters A till P, you can try this class. +*/ +class KaKuTransmitter: RemoteTransmitter { + public: + /** + * Constructor + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodsec Duration of one period, in microseconds. Default is 375usec + * @param repeats [0..7] The 2log-Number of times the signal is repeated. + * @see RemoteTransmitter + */ + KaKuTransmitter(byte pin, unsigned int periodusec=375, byte repeats=4); + + /** + * Send a on or off signal to a device. + * + * @param address address (dial switches in remote). Range [A..P] (case sensitive!) + * @param group Group to switch. Range: [1..4] + * @param device Device to switch. Range: [1..4] + * @param on True, to switch on. False to switch off, + */ + void sendSignal(char address, byte group, byte device, boolean on); + + /** + * Send a on or off signal to a device. + * + * @param address address (dip switches in remote). Range [A..P] (case sensitive!) + * @param device device (dial switches in remote). Range [1..16] + * @param on True, to switch on. False to switch off, + */ + void sendSignal(char address, byte device, boolean on); + + /** + * @see RemoteTransmitter::getTelegram + */ + unsigned long getTelegram(char address, byte group, byte device, boolean on); + + /** + * @see RemoteTransmitter::getTelegram + */ + unsigned long getTelegram(char address, byte device, boolean on); +}; + +/** +* ElroTransmitter simulates remotes of the Elro "Home Control" series +* see http://www.elro.eu/en/m/products/category/home_automation/home_control +* There are are many similar systems on the market. If your remote has setting for 5 address bits, and can control +* 4 devices on or off, then you can try to use the ElroTransmitter. Otherwise you may have luck with the +* ActionTransmitter, which is similar. +*/ +class ElroTransmitter: RemoteTransmitter { + public: + /** + * Constructor + * + * @param pin output pin on Arduino to which the transmitter is connected + * @param periodsec Duration of one period, in microseconds. Default is 320usec + * @param repeats [0..7] The 2log-Number of times the signal is repeated. + * @see RemoteSwitch + */ + ElroTransmitter(byte pin, unsigned int periodusec=320, byte repeats=4); + + /** + * Send a on or off signal to a device. + * + * @param systemCode 5-bit address (dip switches in remote). Range [0..31] + * @param device Device to switch. Range: [A..D] (case sensitive!) + * @param on True, to switch on. False to switch off, + */ + void sendSignal(byte systemCode, char device, boolean on); + + /** + * Generates the telegram (data) which can be used for RemoteSwitch::sendTelegram. + * See sendSignal for details on the parameters + * + * @return Encoded data, including repeats and period duration. + */ + unsigned long getTelegram(byte systemCode, char device, boolean on); +}; + +#endif diff --git a/libraries/RemoteSwitch/examples/LightShow/LightShow.ino b/libraries/RemoteSwitch/examples/LightShow/LightShow.ino index 2400ae0..f52f969 100644 --- a/libraries/RemoteSwitch/examples/LightShow/LightShow.ino +++ b/libraries/RemoteSwitch/examples/LightShow/LightShow.ino @@ -1,63 +1,63 @@ -/* -* Demo for RF remote switch transmitter. -* For details, see RemoteTransmitter.h! -* -* This sketch switches some devices on and off in a loop. -* -* Setup: -* - Connect a 433MHz transmitter to digital pin 11. -*/ - -#include - -// Intantiate a new ActionTransmitter remote, use pin 11 -ActionTransmitter actionTransmitter(11); - -// Intantiate a new KaKuTransmitter remote, also use pin 11 (same transmitter!) -KaKuTransmitter kaKuTransmitter(11); - -// Intantiate a new Blokker remote, also use pin 11 (same transmitter!) -BlokkerTransmitter blokkerTransmitter(11); - -// Intantiate a new Elro remote, also use pin 11 (same transmitter!) -ElroTransmitter elroTransmitter(11); - - -void setup() { -} - -void loop() { - // Switch off KaKu-device 10 on address M - kaKuTransmitter.sendSignal('M',10,false); - - // Switch on Action-device B on system code 1. - actionTransmitter.sendSignal(1,'B',true); - - // Switch on Blokker-device 7. - blokkerTransmitter.sendSignal(7,true); - - // Switch on Elro-device C on system code 1. - elroTransmitter.sendSignal(1,'C',true); - - - // Wait 2 seconds - delay(2000); - - - - // Switch on KaKu-device 2 of group 3 on address M (which is the same as device 10 on address M!) - kaKuTransmitter.sendSignal('M',3,2,true); - - // Switch off Action-device B on system code 1. - actionTransmitter.sendSignal(1,'B',false); - - // Switch off Blokker-device 7. - blokkerTransmitter.sendSignal(7,false); - - // Switch off Elro-device C on system code 1. - elroTransmitter.sendSignal(1,'C',false); - - - // Wait 4 seconds - delay(4000); -} +/* +* Demo for RF remote switch transmitter. +* For details, see RemoteTransmitter.h! +* +* This sketch switches some devices on and off in a loop. +* +* Setup: +* - Connect a 433MHz transmitter to digital pin 11. +*/ + +#include + +// Intantiate a new ActionTransmitter remote, use pin 11 +ActionTransmitter actionTransmitter(11); + +// Intantiate a new KaKuTransmitter remote, also use pin 11 (same transmitter!) +KaKuTransmitter kaKuTransmitter(11); + +// Intantiate a new Blokker remote, also use pin 11 (same transmitter!) +BlokkerTransmitter blokkerTransmitter(11); + +// Intantiate a new Elro remote, also use pin 11 (same transmitter!) +ElroTransmitter elroTransmitter(11); + + +void setup() { +} + +void loop() { + // Switch off KaKu-device 10 on address M + kaKuTransmitter.sendSignal('M',10,false); + + // Switch on Action-device B on system code 1. + actionTransmitter.sendSignal(1,'B',true); + + // Switch on Blokker-device 7. + blokkerTransmitter.sendSignal(7,true); + + // Switch on Elro-device C on system code 1. + elroTransmitter.sendSignal(1,'C',true); + + + // Wait 2 seconds + delay(2000); + + + + // Switch on KaKu-device 2 of group 3 on address M (which is the same as device 10 on address M!) + kaKuTransmitter.sendSignal('M',3,2,true); + + // Switch off Action-device B on system code 1. + actionTransmitter.sendSignal(1,'B',false); + + // Switch off Blokker-device 7. + blokkerTransmitter.sendSignal(7,false); + + // Switch off Elro-device C on system code 1. + elroTransmitter.sendSignal(1,'C',false); + + + // Wait 4 seconds + delay(4000); +} diff --git a/libraries/RemoteSwitch/keywords.txt b/libraries/RemoteSwitch/keywords.txt index 69eafe2..ece29b0 100644 --- a/libraries/RemoteSwitch/keywords.txt +++ b/libraries/RemoteSwitch/keywords.txt @@ -1,15 +1,15 @@ -RemoteTransmitter KEYWORD1 -ActionTransmitter KEYWORD1 -BlokkerTransmitter KEYWORD1 -KaKuTransmitter KEYWORD1 -ElroTransmitter KEYWORD1 -sendTelegram KEYWORD2 -sendCode KEYWORD2 -sendSignal KEYWORD2 -isSameCode KEYWORD2 -RemoteReceiver KEYWORD1 -init KEYWORD2 -enable KEYWORD2 -disable KEYWORD2 -deinit KEYWORD2 +RemoteTransmitter KEYWORD1 +ActionTransmitter KEYWORD1 +BlokkerTransmitter KEYWORD1 +KaKuTransmitter KEYWORD1 +ElroTransmitter KEYWORD1 +sendTelegram KEYWORD2 +sendCode KEYWORD2 +sendSignal KEYWORD2 +isSameCode KEYWORD2 +RemoteReceiver KEYWORD1 +init KEYWORD2 +enable KEYWORD2 +disable KEYWORD2 +deinit KEYWORD2 isReceiving KEYWORD2 \ No newline at end of file diff --git a/libraries/SimpleFIFO/SimpleFIFO.h b/libraries/SimpleFIFO/SimpleFIFO.h index 880ac95..3cf0c7a 100644 --- a/libraries/SimpleFIFO/SimpleFIFO.h +++ b/libraries/SimpleFIFO/SimpleFIFO.h @@ -1,89 +1,89 @@ -#ifndef SimpleFIFO_h -#define SimpleFIFO_h -/* -|| -|| @file SimpleFIFO.h -|| @version 1.2 -|| @author Alexander Brevig -|| @contact alexanderbrevig@gmail.com -|| -|| @description -|| | A simple FIFO class, mostly for primitive types but can be used with classes if assignment to int is allowed -|| | This FIFO is not dynamic, so be sure to choose an appropriate size for it -|| # -|| -|| @license -|| | Copyright (c) 2010 Alexander Brevig -|| | 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; version -|| | 2.1 of the License. -|| | -|| | 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 -|| # -|| -*/ -template -class SimpleFIFO { -public: - const char size; //speculative feature, in case it's needed - - SimpleFIFO(); - - T dequeue(); //get next element - bool enqueue( T element ); //add an element - T peek() const; //get the next element without releasing it from the FIFO - void flush(); //[1.1] reset to default state - - //how many elements are currently in the FIFO? - char count() { return numberOfElements; } - -private: -#ifndef SimpleFIFO_NONVOLATILE - volatile char numberOfElements; - volatile char nextIn; - volatile char nextOut; - volatile T raw[rawSize]; -#else - char numberOfElements; - char nextIn; - char nextOut; - T raw[rawSize]; -#endif -}; - -template -SimpleFIFO::SimpleFIFO() : size(rawSize) { - flush(); -} -template -bool SimpleFIFO::enqueue( T element ) { - if ( count() >= rawSize ) { return false; } - numberOfElements++; - nextIn %= size; - raw[nextIn] = element; - nextIn++; //advance to next index - return true; -} -template -T SimpleFIFO::dequeue() { - numberOfElements--; - nextOut %= size; - return raw[ nextOut++]; -} -template -T SimpleFIFO::peek() const { - return raw[ nextOut % size]; -} -template -void SimpleFIFO::flush() { - nextIn = nextOut = numberOfElements = 0; -} +#ifndef SimpleFIFO_h +#define SimpleFIFO_h +/* +|| +|| @file SimpleFIFO.h +|| @version 1.2 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | A simple FIFO class, mostly for primitive types but can be used with classes if assignment to int is allowed +|| | This FIFO is not dynamic, so be sure to choose an appropriate size for it +|| # +|| +|| @license +|| | Copyright (c) 2010 Alexander Brevig +|| | 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; version +|| | 2.1 of the License. +|| | +|| | 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 +|| # +|| +*/ +template +class SimpleFIFO { +public: + const char size; //speculative feature, in case it's needed + + SimpleFIFO(); + + T dequeue(); //get next element + bool enqueue( T element ); //add an element + T peek() const; //get the next element without releasing it from the FIFO + void flush(); //[1.1] reset to default state + + //how many elements are currently in the FIFO? + char count() { return numberOfElements; } + +private: +#ifndef SimpleFIFO_NONVOLATILE + volatile char numberOfElements; + volatile char nextIn; + volatile char nextOut; + volatile T raw[rawSize]; +#else + char numberOfElements; + char nextIn; + char nextOut; + T raw[rawSize]; +#endif +}; + +template +SimpleFIFO::SimpleFIFO() : size(rawSize) { + flush(); +} +template +bool SimpleFIFO::enqueue( T element ) { + if ( count() >= rawSize ) { return false; } + numberOfElements++; + nextIn %= size; + raw[nextIn] = element; + nextIn++; //advance to next index + return true; +} +template +T SimpleFIFO::dequeue() { + numberOfElements--; + nextOut %= size; + return raw[ nextOut++]; +} +template +T SimpleFIFO::peek() const { + return raw[ nextOut % size]; +} +template +void SimpleFIFO::flush() { + nextIn = nextOut = numberOfElements = 0; +} #endif diff --git a/libraries/SimpleFIFO/examples/HelloSimpleFIFO/HelloSimpleFIFO.ino b/libraries/SimpleFIFO/examples/HelloSimpleFIFO/HelloSimpleFIFO.ino index e68a1d1..3e7bfae 100644 --- a/libraries/SimpleFIFO/examples/HelloSimpleFIFO/HelloSimpleFIFO.ino +++ b/libraries/SimpleFIFO/examples/HelloSimpleFIFO/HelloSimpleFIFO.ino @@ -1,27 +1,27 @@ -#include - -void setup() { - Serial.begin(9600); - - SimpleFIFO sFIFO; //store 10 ints - - sFIFO.enqueue(1); - sFIFO.enqueue(2); - sFIFO.enqueue(3); - sFIFO.enqueue(4); - sFIFO.enqueue(5); - - Serial.print(F("Peek: ")); - Serial.println(sFIFO.peek()); - - for (int i=0; i + +void setup() { + Serial.begin(9600); + + SimpleFIFO sFIFO; //store 10 ints + + sFIFO.enqueue(1); + sFIFO.enqueue(2); + sFIFO.enqueue(3); + sFIFO.enqueue(4); + sFIFO.enqueue(5); + + Serial.print(F("Peek: ")); + Serial.println(sFIFO.peek()); + + for (int i=0; i -#include "Time.h" - -// the short strings for each day or month must be exactly dt_SHORT_STR_LEN -#define dt_SHORT_STR_LEN 3 // the length of short strings - -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"; - -PGM_P monthNames_P[] PROGMEM = -{ - "",monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6, - monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12 -}; - -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"; - -PGM_P dayNames_P[] PROGMEM = { dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7}; -char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat"; - -/* functions to return date strings */ - -char* monthStr(uint8_t month) -{ - strcpy_P(buffer, (PGM_P)pgm_read_word(&(monthNames_P[month]))); - return buffer; -} - -char* monthShortStr(uint8_t month) -{ - for (int i=0; i < dt_SHORT_STR_LEN; i++) - buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)])); - buffer[dt_SHORT_STR_LEN] = 0; - return buffer; -} - -char* dayStr(uint8_t day) -{ - strcpy_P(buffer, (PGM_P)pgm_read_word(&(dayNames_P[day]))); - return buffer; -} - -char* dayShortStr(uint8_t day) -{ - uint8_t index = day*dt_SHORT_STR_LEN; - for (int i=0; i < dt_SHORT_STR_LEN; i++) - buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i])); - buffer[dt_SHORT_STR_LEN] = 0; - return buffer; -} +/* DateStrings.cpp + * Definitions for date strings for use with the Time library + * + * No memory is consumed in the sketch if your code does not call any of the string methods + * You can change the text of the strings, make sure the short strings are each exactly 3 characters + * the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in Time.h + * + */ + +#include +#include "Time.h" + +// the short strings for each day or month must be exactly dt_SHORT_STR_LEN +#define dt_SHORT_STR_LEN 3 // the length of short strings + +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"; + +PGM_P monthNames_P[] PROGMEM = +{ + "",monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6, + monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12 +}; + +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"; + +PGM_P dayNames_P[] PROGMEM = { dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7}; +char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat"; + +/* functions to return date strings */ + +char* monthStr(uint8_t month) +{ + strcpy_P(buffer, (PGM_P)pgm_read_word(&(monthNames_P[month]))); + return buffer; +} + +char* monthShortStr(uint8_t month) +{ + for (int i=0; i < dt_SHORT_STR_LEN; i++) + buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)])); + buffer[dt_SHORT_STR_LEN] = 0; + return buffer; +} + +char* dayStr(uint8_t day) +{ + strcpy_P(buffer, (PGM_P)pgm_read_word(&(dayNames_P[day]))); + return buffer; +} + +char* dayShortStr(uint8_t day) +{ + uint8_t index = day*dt_SHORT_STR_LEN; + for (int i=0; i < dt_SHORT_STR_LEN; i++) + buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i])); + buffer[dt_SHORT_STR_LEN] = 0; + return buffer; +} diff --git a/libraries/Time/Examples/TimeNTP/TimeNTP.pde b/libraries/Time/Examples/TimeNTP/TimeNTP.pde index 11927c6..ff9311a 100644 --- a/libraries/Time/Examples/TimeNTP/TimeNTP.pde +++ b/libraries/Time/Examples/TimeNTP/TimeNTP.pde @@ -117,4 +117,4 @@ void write_n(int what, int how_many) { for( int i = 0; i < how_many; i++ ) UdpBytewise.write(what); -} +} diff --git a/libraries/Time/Examples/TimeRTC/TimeRTC.pde b/libraries/Time/Examples/TimeRTC/TimeRTC.pde index 1a1ed80..0e37c51 100644 --- a/libraries/Time/Examples/TimeRTC/TimeRTC.pde +++ b/libraries/Time/Examples/TimeRTC/TimeRTC.pde @@ -44,4 +44,4 @@ void printDigits(int digits){ Serial.print('0'); Serial.print(digits); } - + diff --git a/libraries/Time/Examples/TimeRTCLog/TimeRTCLog.pde b/libraries/Time/Examples/TimeRTCLog/TimeRTCLog.pde index 76ed17d..b8297b6 100644 --- a/libraries/Time/Examples/TimeRTCLog/TimeRTCLog.pde +++ b/libraries/Time/Examples/TimeRTCLog/TimeRTCLog.pde @@ -103,4 +103,4 @@ void showDuration(time_t duration){ Serial.print(duration); Serial.print(" second(s) "); } - + diff --git a/libraries/Time/Examples/TimeRTCSet/TimeRTCSet.pde b/libraries/Time/Examples/TimeRTCSet/TimeRTCSet.pde index 48b696c..e798164 100644 --- a/libraries/Time/Examples/TimeRTCSet/TimeRTCSet.pde +++ b/libraries/Time/Examples/TimeRTCSet/TimeRTCSet.pde @@ -79,4 +79,4 @@ time_t processSyncMessage() { } return 0; } - + diff --git a/libraries/Time/Examples/TimeSerial/TimeSerial.pde b/libraries/Time/Examples/TimeSerial/TimeSerial.pde index 55c67a6..382c598 100644 --- a/libraries/Time/Examples/TimeSerial/TimeSerial.pde +++ b/libraries/Time/Examples/TimeSerial/TimeSerial.pde @@ -79,4 +79,4 @@ time_t requestSync() Serial.print(TIME_REQUEST,BYTE); return 0; // the time will be sent later in response to serial mesg } - + diff --git a/libraries/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde b/libraries/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde index dcff97e..62eac10 100644 --- a/libraries/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde +++ b/libraries/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde @@ -77,4 +77,4 @@ time_t requestSync() Serial.print(TIME_REQUEST,BYTE); return 0; // the time will be sent later in response to serial mesg } - + diff --git a/libraries/Time/Readme.txt b/libraries/Time/Readme.txt index 22bc4aa..06d82f1 100644 --- a/libraries/Time/Readme.txt +++ b/libraries/Time/Readme.txt @@ -1,131 +1,131 @@ -Readme file for Arduino Time Library - -Time is a library that provides timekeeping functionality for Arduino. - -The code is derived from the Playground DateTime library but is updated -to provide an API that is more flexable and easier to use. - -A primary goal was to enable date and time functionality that can be used with -a variety of external time sources with minimum differences required in sketch logic. - -Example sketches illustrate how similar sketch code can be used with: a Real Time Clock, -internet NTP time service, GPS time data, and Serial time messages from a computer -for time synchronization. - -The functions available in the library include: - -hour(); // the hour now (0-23) -minute(); // the minute now (0-59) -second(); // the second now (0-59) -day(); // the day now (1-31) -weekday(); // day of the week, Sunday is day 0 -month(); // the month now (1-12) -year(); // the full four digit year: (2009, 2010 etc) - -there are also functions to return the hour in 12 hour format -hourFormat12(); // the hour now in 12 hour format -isAM(); // returns true if time now is AM -isPM(); // returns true if time now is PM - -now(); // returns the current time as seconds since Jan 1 1970 - -The time and date functions can take an optional parameter for the time. This prevents -errors if the time rolls over between elements. For example, if a new minute begins -between getting the minute and second, the values will be inconsistent. Using the -following functions eliminates this probglem - time_t t = now(); // store the current time in time variable t - hour(t); // returns the hour for the given time t - minute(t); // returns the minute for the given time t - second(t); // returns the second for the given time t - day(t); // the day for the given time t - weekday(t); // day of the week for the given time t - month(t); // the month for the given time t - year(t); // the year for the given time t - - -Functions for managing the timer services are: -setTime(t); // set the system time to the give time t -setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr (2010 or 10 sets year to 2010) -adjustTime(adjustment); // adjust system time by adding the adjustment value - -timeStatus(); // indicates if time has been set and recently synchronized - // returns one of the following enumerations: - timeNotSet // the time has never been set, the clock started at Jan 1 1970 - timeNeedsSync // the time had been set but a sync attempt did not succeed - timeSet // the time is set and is synced -Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but -the returned time may have drifted if the status is timeNeedsSync. - -setSyncProvider(getTimeFunction); // set the external time provider -setSyncInterval(interval); // set the number of seconds between re-sync - - -There are many convenience macros in the time.h file for time constants and conversion of time units. - -To use the library, copy the download to the Library directory. - -The Time directory contains the Time library and some example sketches -illustrating how the library can be used with various time sources: - -- TimeSerial.pde shows Arduino as a clock without external hardware. - It is synchronized by time messages sent over the serial port. - A companion Processing sketch will automatically provide these messages - if it is running and connected to the Arduino serial port. - -- TimeSerialDateStrings.pde adds day and month name strings to the sketch above - Short (3 character) and long strings are available to print the days of - the week and names of the months. - -- TimeRTC uses a DS1307 real time clock to provide time synchronization. - A basic RTC library named DS1307RTC is included in the download. - To run this sketch the DS1307RTC library must be installed. - -- TimeRTCSet is similar to the above and adds the ability to set the Real Time Clock - -- TimeRTCLog demonstrates how to calculate the difference between times. - It is a vary simple logger application that monitors events on digtial pins - and prints (to the serial port) the time of an event and the time period since the previous event. - -- TimeNTP uses the Arduino Ethernet shield to access time using the internet NTP time service. - The NTP protocol uses UDP and the UdpBytewise library is required, see: - http://bitbucket.org/bjoern/arduino_osc/src/14667490521f/libraries/Ethernet/ - --TimeGPS gets time from a GPS - This requires the TinyGPS and NewSoftSerial libraries from Mikal Hart: - http://arduiniana.org/libraries/TinyGPS and http://arduiniana.org/libraries/newsoftserial/ - -Differences between this code and the playground DateTime library -although the Time library is based on the DateTime codebase, the API has changed. -Changes in the Time library API: -- time elements are functions returning int (they are variables in DateTime) -- Years start from 1970 -- days of the week and months start from 1 (they start from 0 in DateTime) -- DateStrings do not require a seperate library -- time elements can be accessed non-atomically (in DateTime they are always atomic) -- function added to automatically sync time with extrnal source -- localTime and maketime parameters changed, localTime renamed to breakTime - -Technical notes: - -Internal system time is based on the standard Unix time_t. -The value is the number of seconds since Jan 1 1970. -System time begins at zero when the sketch starts. - -The internal time can be automatically synchronized at regular intervals to an external time source. -This is enabled by calling the setSyncProvider(provider) function - the provider argument is -the address of a function that returns the current time as a time_t. -See the sketches in the examples directory for usage. - -The default interval for re-syncing the time is 5 minutes but can be changed by calling the -setSyncInterval( interval) method to set the number of seconds between re-sync attempts. - -The Time library defines a structure for holding time elements that is a compact version of the C tm structure. -All the members of the Arduino tm structure are bytes and the year is offset from 1970. -Convenience macros provide conversion to and from the Arduino format. - -Low level functions to convert between system time and individual time elements are provided: - breakTime( time, &tm); // break time_t into elements stored in tm struct - makeTime( &tm); // return time_t from elements stored in tm struct - -The DS1307RTC library included in the download provides an example of how a time provider +Readme file for Arduino Time Library + +Time is a library that provides timekeeping functionality for Arduino. + +The code is derived from the Playground DateTime library but is updated +to provide an API that is more flexable and easier to use. + +A primary goal was to enable date and time functionality that can be used with +a variety of external time sources with minimum differences required in sketch logic. + +Example sketches illustrate how similar sketch code can be used with: a Real Time Clock, +internet NTP time service, GPS time data, and Serial time messages from a computer +for time synchronization. + +The functions available in the library include: + +hour(); // the hour now (0-23) +minute(); // the minute now (0-59) +second(); // the second now (0-59) +day(); // the day now (1-31) +weekday(); // day of the week, Sunday is day 0 +month(); // the month now (1-12) +year(); // the full four digit year: (2009, 2010 etc) + +there are also functions to return the hour in 12 hour format +hourFormat12(); // the hour now in 12 hour format +isAM(); // returns true if time now is AM +isPM(); // returns true if time now is PM + +now(); // returns the current time as seconds since Jan 1 1970 + +The time and date functions can take an optional parameter for the time. This prevents +errors if the time rolls over between elements. For example, if a new minute begins +between getting the minute and second, the values will be inconsistent. Using the +following functions eliminates this probglem + time_t t = now(); // store the current time in time variable t + hour(t); // returns the hour for the given time t + minute(t); // returns the minute for the given time t + second(t); // returns the second for the given time t + day(t); // the day for the given time t + weekday(t); // day of the week for the given time t + month(t); // the month for the given time t + year(t); // the year for the given time t + + +Functions for managing the timer services are: +setTime(t); // set the system time to the give time t +setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr (2010 or 10 sets year to 2010) +adjustTime(adjustment); // adjust system time by adding the adjustment value + +timeStatus(); // indicates if time has been set and recently synchronized + // returns one of the following enumerations: + timeNotSet // the time has never been set, the clock started at Jan 1 1970 + timeNeedsSync // the time had been set but a sync attempt did not succeed + timeSet // the time is set and is synced +Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but +the returned time may have drifted if the status is timeNeedsSync. + +setSyncProvider(getTimeFunction); // set the external time provider +setSyncInterval(interval); // set the number of seconds between re-sync + + +There are many convenience macros in the time.h file for time constants and conversion of time units. + +To use the library, copy the download to the Library directory. + +The Time directory contains the Time library and some example sketches +illustrating how the library can be used with various time sources: + +- TimeSerial.pde shows Arduino as a clock without external hardware. + It is synchronized by time messages sent over the serial port. + A companion Processing sketch will automatically provide these messages + if it is running and connected to the Arduino serial port. + +- TimeSerialDateStrings.pde adds day and month name strings to the sketch above + Short (3 character) and long strings are available to print the days of + the week and names of the months. + +- TimeRTC uses a DS1307 real time clock to provide time synchronization. + A basic RTC library named DS1307RTC is included in the download. + To run this sketch the DS1307RTC library must be installed. + +- TimeRTCSet is similar to the above and adds the ability to set the Real Time Clock + +- TimeRTCLog demonstrates how to calculate the difference between times. + It is a vary simple logger application that monitors events on digtial pins + and prints (to the serial port) the time of an event and the time period since the previous event. + +- TimeNTP uses the Arduino Ethernet shield to access time using the internet NTP time service. + The NTP protocol uses UDP and the UdpBytewise library is required, see: + http://bitbucket.org/bjoern/arduino_osc/src/14667490521f/libraries/Ethernet/ + +-TimeGPS gets time from a GPS + This requires the TinyGPS and NewSoftSerial libraries from Mikal Hart: + http://arduiniana.org/libraries/TinyGPS and http://arduiniana.org/libraries/newsoftserial/ + +Differences between this code and the playground DateTime library +although the Time library is based on the DateTime codebase, the API has changed. +Changes in the Time library API: +- time elements are functions returning int (they are variables in DateTime) +- Years start from 1970 +- days of the week and months start from 1 (they start from 0 in DateTime) +- DateStrings do not require a seperate library +- time elements can be accessed non-atomically (in DateTime they are always atomic) +- function added to automatically sync time with extrnal source +- localTime and maketime parameters changed, localTime renamed to breakTime + +Technical notes: + +Internal system time is based on the standard Unix time_t. +The value is the number of seconds since Jan 1 1970. +System time begins at zero when the sketch starts. + +The internal time can be automatically synchronized at regular intervals to an external time source. +This is enabled by calling the setSyncProvider(provider) function - the provider argument is +the address of a function that returns the current time as a time_t. +See the sketches in the examples directory for usage. + +The default interval for re-syncing the time is 5 minutes but can be changed by calling the +setSyncInterval( interval) method to set the number of seconds between re-sync attempts. + +The Time library defines a structure for holding time elements that is a compact version of the C tm structure. +All the members of the Arduino tm structure are bytes and the year is offset from 1970. +Convenience macros provide conversion to and from the Arduino format. + +Low level functions to convert between system time and individual time elements are provided: + breakTime( time, &tm); // break time_t into elements stored in tm struct + makeTime( &tm); // return time_t from elements stored in tm struct + +The DS1307RTC library included in the download provides an example of how a time provider can use the low level functions to interface with the Time library. \ No newline at end of file diff --git a/libraries/UIPEthernet/Dhcp.cpp b/libraries/UIPEthernet/Dhcp.cpp index c15fe83..d34e8e2 100644 --- a/libraries/UIPEthernet/Dhcp.cpp +++ b/libraries/UIPEthernet/Dhcp.cpp @@ -1,478 +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); -} +// 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/UIPEthernet/Dhcp.h b/libraries/UIPEthernet/Dhcp.h index cc3cd35..01405d7 100644 --- a/libraries/UIPEthernet/Dhcp.h +++ b/libraries/UIPEthernet/Dhcp.h @@ -1,178 +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 +// 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/UIPEthernet/Dns.h b/libraries/UIPEthernet/Dns.h index 4ccb1e1..4913ca8 100644 --- a/libraries/UIPEthernet/Dns.h +++ b/libraries/UIPEthernet/Dns.h @@ -1,41 +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 +// 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/UIPEthernet/src/Dhcp.cpp b/libraries/UIPEthernet/src/Dhcp.cpp index c15fe83..d34e8e2 100644 --- a/libraries/UIPEthernet/src/Dhcp.cpp +++ b/libraries/UIPEthernet/src/Dhcp.cpp @@ -1,478 +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); -} +// 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/UIPEthernet/src/Dhcp.h b/libraries/UIPEthernet/src/Dhcp.h index cc3cd35..01405d7 100644 --- a/libraries/UIPEthernet/src/Dhcp.h +++ b/libraries/UIPEthernet/src/Dhcp.h @@ -1,178 +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 +// 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/UIPEthernet/src/Dns.h b/libraries/UIPEthernet/src/Dns.h index 4ccb1e1..4913ca8 100644 --- a/libraries/UIPEthernet/src/Dns.h +++ b/libraries/UIPEthernet/src/Dns.h @@ -1,41 +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 +// 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