fixed crlf for project
This commit is contained in:
@@ -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
|
||||
|
||||
+651
-651
File diff suppressed because it is too large
Load Diff
+194
-194
@@ -1,194 +1,194 @@
|
||||
#ifndef UART_H
|
||||
#define UART_H
|
||||
/************************************************************************
|
||||
Title: Interrupt UART library with receive/transmit circular buffers
|
||||
Author: Peter Fleury <pfleury@gmx.ch> 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 <uart.h> @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
|
||||
* <br>no receive data available
|
||||
* - \b UART_BUFFER_OVERFLOW
|
||||
* <br>Receive ringbuffer overflow.
|
||||
* We are not reading the receive buffer fast enough,
|
||||
* one or more received character have been dropped
|
||||
* - \b UART_OVERRUN_ERROR
|
||||
* <br>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
|
||||
* <br>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 <pfleury@gmx.ch> 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 <uart.h> @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
|
||||
* <br>no receive data available
|
||||
* - \b UART_BUFFER_OVERFLOW
|
||||
* <br>Receive ringbuffer overflow.
|
||||
* We are not reading the receive buffer fast enough,
|
||||
* one or more received character have been dropped
|
||||
* - \b UART_OVERRUN_ERROR
|
||||
* <br>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
|
||||
* <br>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
|
||||
|
||||
|
||||
+252
-252
@@ -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 <henrik.ekblad@gmail.com>
|
||||
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 <avr/eeprom.h>
|
||||
#include <util/delay.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 <henrik.ekblad@gmail.com>
|
||||
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 <avr/eeprom.h>
|
||||
#include <util/delay.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
+157
-157
@@ -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 <henrik.ekblad@gmail.com>
|
||||
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 <RF24/nRF24L01.h>
|
||||
#include <RF24/RF24.h>
|
||||
#include <RF24/RF24_config.h>
|
||||
#include <crc8/crc8.h>
|
||||
|
||||
#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 <henrik.ekblad@gmail.com>
|
||||
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 <RF24/nRF24L01.h>
|
||||
#include <RF24/RF24.h>
|
||||
#include <RF24/RF24_config.h>
|
||||
#include <crc8/crc8.h>
|
||||
|
||||
#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
|
||||
|
||||
+63
-63
@@ -1,63 +1,63 @@
|
||||
/* please read copyright-notice at EOF */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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 <stdint.h>
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
+42
-42
@@ -1,42 +1,42 @@
|
||||
#ifndef CRC8_H_
|
||||
#define CRC8_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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 <stdint.h>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,79 +1,79 @@
|
||||
#include <spi.h>
|
||||
#include <ds1305.h>
|
||||
|
||||
#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<<ISC01) | (0<<ISC00);
|
||||
// enable interrupts
|
||||
EIMSK = (1<<INT0);
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// do nothing - all action happens in interrupt
|
||||
}
|
||||
#include <spi.h>
|
||||
#include <ds1305.h>
|
||||
|
||||
#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<<ISC01) | (0<<ISC00);
|
||||
// enable interrupts
|
||||
EIMSK = (1<<INT0);
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// do nothing - all action happens in interrupt
|
||||
}
|
||||
|
||||
+111
-111
@@ -1,111 +1,111 @@
|
||||
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 <andrew@rocketnumbernine.com>
|
||||
|
||||
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 <andrew@rocketnumbernine.com>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <inttypes.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
// 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 <inttypes.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -159,4 +159,4 @@ void loop(void)
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -142,4 +142,4 @@ void loop(void)
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -137,4 +137,4 @@ void loop(void)
|
||||
printData(insideThermometer);
|
||||
printData(outsideThermometer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,4 +30,4 @@ void loop(void)
|
||||
|
||||
Serial.print("Temperature for the device 1 (index 0) is: ");
|
||||
Serial.println(sensors.getTempCByIndex(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,4 +106,4 @@ void printAddress(DeviceAddress deviceAddress)
|
||||
if (deviceAddress[i] < 16) Serial.print("0");
|
||||
Serial.print(deviceAddress[i], HEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,4 +121,4 @@ void printAddress(DeviceAddress deviceAddress)
|
||||
if (deviceAddress[i] < 16) Serial.print("0");
|
||||
Serial.print(deviceAddress[i], HEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
<Sketchbook directory>/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
|
||||
<Sketchbook directory>/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
|
||||
@@ -1,5 +1,5 @@
|
||||
InterruptChain KEYWORD1
|
||||
addInterruptCallback KEYWORD2
|
||||
setMode KEYWORD2
|
||||
enable KEYWORD2
|
||||
InterruptChain KEYWORD1
|
||||
addInterruptCallback KEYWORD2
|
||||
setMode KEYWORD2
|
||||
enable KEYWORD2
|
||||
disable KEYWORD2
|
||||
+231
-231
@@ -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<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = 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.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms(unsigned long frequency, void (*userFunc)(void)) {
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
intFunc = NewPing::timer_ms_cntdwn; // Timer events are sent here once every ms till user's frequency is reached.
|
||||
intFunc2 = userFunc; // User's function to call when user's frequency is reached.
|
||||
_ms_cnt = _ms_cnt_reset = frequency; // Current ms counter and reset value.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_stop() { // Disable timer interrupt.
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
TIMSK4 = 0;
|
||||
#else
|
||||
TIMSK2 &= ~(1<<OCIE2A);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::timer_setup() {
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
timer_stop(); // Disable Timer4 interrupt.
|
||||
TCCR4A = TCCR4C = TCCR4D = TCCR4E = 0;
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4); // Set Timer4 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TIFR4 = (1<<TOV4);
|
||||
TCNT4 = 0; // Reset Timer4 counter.
|
||||
#else
|
||||
timer_stop(); // Disable Timer2 interrupt.
|
||||
ASSR &= ~(1<<AS2); // Set clock, not pin.
|
||||
TCCR2A = (1<<WGM21); // Set Timer2 to CTC mode.
|
||||
TCCR2B = (1<<CS22); // Set Timer2 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TCNT2 = 0; // Reset Timer2 counter.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms_cntdwn() {
|
||||
if (!_ms_cnt--) { // Count down till we reach zero.
|
||||
intFunc2(); // Scheduled time reached, run the main timer event function.
|
||||
_ms_cnt = _ms_cnt_reset; // Reset the ms timer.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
ISR(TIMER4_OVF_vect) {
|
||||
#else
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
#endif
|
||||
if(intFunc) intFunc(); // If wrapped function is set, call it.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversion methods (rounds result to nearest inch or cm).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::convert_in(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::convert_cm(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = 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.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms(unsigned long frequency, void (*userFunc)(void)) {
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
intFunc = NewPing::timer_ms_cntdwn; // Timer events are sent here once every ms till user's frequency is reached.
|
||||
intFunc2 = userFunc; // User's function to call when user's frequency is reached.
|
||||
_ms_cnt = _ms_cnt_reset = frequency; // Current ms counter and reset value.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_stop() { // Disable timer interrupt.
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
TIMSK4 = 0;
|
||||
#else
|
||||
TIMSK2 &= ~(1<<OCIE2A);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::timer_setup() {
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
timer_stop(); // Disable Timer4 interrupt.
|
||||
TCCR4A = TCCR4C = TCCR4D = TCCR4E = 0;
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4); // Set Timer4 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TIFR4 = (1<<TOV4);
|
||||
TCNT4 = 0; // Reset Timer4 counter.
|
||||
#else
|
||||
timer_stop(); // Disable Timer2 interrupt.
|
||||
ASSR &= ~(1<<AS2); // Set clock, not pin.
|
||||
TCCR2A = (1<<WGM21); // Set Timer2 to CTC mode.
|
||||
TCCR2B = (1<<CS22); // Set Timer2 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TCNT2 = 0; // Reset Timer2 counter.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms_cntdwn() {
|
||||
if (!_ms_cnt--) { // Count down till we reach zero.
|
||||
intFunc2(); // Scheduled time reached, run the main timer event function.
|
||||
_ms_cnt = _ms_cnt_reset; // Reset the ms timer.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
ISR(TIMER4_OVF_vect) {
|
||||
#else
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
#endif
|
||||
if(intFunc) intFunc(); // If wrapped function is set, call it.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversion methods (rounds result to nearest inch or cm).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::convert_in(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::convert_cm(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
}
|
||||
|
||||
+161
-161
@@ -1,162 +1,162 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
// 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 <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
// 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
|
||||
@@ -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 <NewPing.h>
|
||||
|
||||
#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 <NewPing.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <NewPing.h>
|
||||
|
||||
#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 <NewPing.h>
|
||||
|
||||
#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.
|
||||
}
|
||||
@@ -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)
|
||||
###################################
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
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 <interrupt> 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 <Arduino.h>
|
||||
|
||||
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 <interrupt> 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
|
||||
|
||||
@@ -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<<j);
|
||||
}
|
||||
|
||||
_sendStopPulse();
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStartPulse(){
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 10 + (_periodusec >> 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<<i);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStopPulse() {
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 40);
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendBit(boolean isBitOne) {
|
||||
if (isBitOne) {
|
||||
// Send '1'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
} else {
|
||||
// Send '0'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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<<j);
|
||||
}
|
||||
|
||||
_sendStopPulse();
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStartPulse(){
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 10 + (_periodusec >> 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<<i);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStopPulse() {
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 40);
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendBit(boolean isBitOne) {
|
||||
if (isBitOne) {
|
||||
// Send '1'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
} else {
|
||||
// Send '0'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
/*
|
||||
* 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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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
|
||||
<Sketchbook directory>/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
|
||||
<Sketchbook directory>/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.
|
||||
|
||||
@@ -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
|
||||
@@ -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 <NewRemoteTransmitter.h>
|
||||
|
||||
// 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 <NewRemoteTransmitter.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -87,4 +87,4 @@ void loop() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
<Sketchbook directory>/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
|
||||
<Sketchbook directory>/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
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -51,4 +51,4 @@ void retransmit(byte *data) {
|
||||
noInterrupts();
|
||||
SensorReceiver::enable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,4 +25,4 @@
|
||||
// Wait two seconds before sending next.
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
<Sketchbook directory>/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
|
||||
<Sketchbook directory>/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.
|
||||
@@ -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 (duration<period*25 || duration>period*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 (duration<period*25 || duration>period*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;
|
||||
}
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
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 <interrupt> 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 <Arduino.h>
|
||||
|
||||
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 <interrupt> 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
|
||||
|
||||
@@ -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<repeats;j++) {
|
||||
// Sent one telegram
|
||||
|
||||
// Recycle code as working var to save memory
|
||||
code=dataBase4;
|
||||
for (byte i=0; i<12; i++) {
|
||||
switch (code & B11) {
|
||||
case 0:
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
break;
|
||||
case 1:
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
break;
|
||||
case 2: // KA: X or float
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
break;
|
||||
}
|
||||
// Next trit
|
||||
code>>=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<repeats;j++) {
|
||||
// Sent one telegram
|
||||
|
||||
// Recycle code as working var to save memory
|
||||
code=dataBase4;
|
||||
for (byte i=0; i<12; i++) {
|
||||
switch (code & B11) {
|
||||
case 0:
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
break;
|
||||
case 1:
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
break;
|
||||
case 2: // KA: X or float
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, HIGH);
|
||||
delayMicroseconds(periodusec*3);
|
||||
digitalWrite(pin, LOW);
|
||||
delayMicroseconds(periodusec);
|
||||
break;
|
||||
}
|
||||
// Next trit
|
||||
code>>=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);
|
||||
}
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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 <Arduino.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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 <RemoteTransmitter.h>
|
||||
|
||||
// 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 <RemoteTransmitter.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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<typename T, int rawSize>
|
||||
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<typename T, int rawSize>
|
||||
SimpleFIFO<T,rawSize>::SimpleFIFO() : size(rawSize) {
|
||||
flush();
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
bool SimpleFIFO<T,rawSize>::enqueue( T element ) {
|
||||
if ( count() >= rawSize ) { return false; }
|
||||
numberOfElements++;
|
||||
nextIn %= size;
|
||||
raw[nextIn] = element;
|
||||
nextIn++; //advance to next index
|
||||
return true;
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
T SimpleFIFO<T,rawSize>::dequeue() {
|
||||
numberOfElements--;
|
||||
nextOut %= size;
|
||||
return raw[ nextOut++];
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
T SimpleFIFO<T,rawSize>::peek() const {
|
||||
return raw[ nextOut % size];
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
void SimpleFIFO<T,rawSize>::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<typename T, int rawSize>
|
||||
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<typename T, int rawSize>
|
||||
SimpleFIFO<T,rawSize>::SimpleFIFO() : size(rawSize) {
|
||||
flush();
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
bool SimpleFIFO<T,rawSize>::enqueue( T element ) {
|
||||
if ( count() >= rawSize ) { return false; }
|
||||
numberOfElements++;
|
||||
nextIn %= size;
|
||||
raw[nextIn] = element;
|
||||
nextIn++; //advance to next index
|
||||
return true;
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
T SimpleFIFO<T,rawSize>::dequeue() {
|
||||
numberOfElements--;
|
||||
nextOut %= size;
|
||||
return raw[ nextOut++];
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
T SimpleFIFO<T,rawSize>::peek() const {
|
||||
return raw[ nextOut % size];
|
||||
}
|
||||
template<typename T, int rawSize>
|
||||
void SimpleFIFO<T,rawSize>::flush() {
|
||||
nextIn = nextOut = numberOfElements = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
#include <SimpleFIFO.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
SimpleFIFO<int,10> 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<sFIFO.count(); i++) {
|
||||
Serial.print(F("Dequeue "));
|
||||
Serial.println(sFIFO.dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
|
||||
#include <SimpleFIFO.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
SimpleFIFO<int,10> 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<sFIFO.count(); i++) {
|
||||
Serial.print(F("Dequeue "));
|
||||
Serial.println(sFIFO.dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
/* 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 <avr/pgmspace.h>
|
||||
#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 <avr/pgmspace.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -117,4 +117,4 @@ void write_n(int what, int how_many)
|
||||
{
|
||||
for( int i = 0; i < how_many; i++ )
|
||||
UdpBytewise.write(what);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,4 @@ void printDigits(int digits){
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -103,4 +103,4 @@ void showDuration(time_t duration){
|
||||
Serial.print(duration);
|
||||
Serial.print(" second(s) ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -79,4 +79,4 @@ time_t processSyncMessage() {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
+130
-130
@@ -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.
|
||||
+478
-478
@@ -1,478 +1,478 @@
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
+178
-178
@@ -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
|
||||
|
||||
+41
-41
@@ -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 <UIPUdp.h>
|
||||
|
||||
class DNSClient
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
void begin(const IPAddress& aDNSServer);
|
||||
|
||||
/** Convert a numeric IP address string into a four-byte IP address.
|
||||
@param aIPAddrString IP address to convert
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int inet_aton(const char *aIPAddrString, IPAddress& aResult);
|
||||
|
||||
/** Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
protected:
|
||||
uint16_t BuildRequest(const char* aName);
|
||||
uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress);
|
||||
|
||||
IPAddress iDNSServer;
|
||||
uint16_t iRequestId;
|
||||
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 <UIPUdp.h>
|
||||
|
||||
class DNSClient
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
void begin(const IPAddress& aDNSServer);
|
||||
|
||||
/** Convert a numeric IP address string into a four-byte IP address.
|
||||
@param aIPAddrString IP address to convert
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int inet_aton(const char *aIPAddrString, IPAddress& aResult);
|
||||
|
||||
/** Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
protected:
|
||||
uint16_t BuildRequest(const char* aName);
|
||||
uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress);
|
||||
|
||||
IPAddress iDNSServer;
|
||||
uint16_t iRequestId;
|
||||
UIPUDP iUdp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+478
-478
@@ -1,478 +1,478 @@
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
+178
-178
@@ -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
|
||||
|
||||
@@ -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 <UIPUdp.h>
|
||||
|
||||
class DNSClient
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
void begin(const IPAddress& aDNSServer);
|
||||
|
||||
/** Convert a numeric IP address string into a four-byte IP address.
|
||||
@param aIPAddrString IP address to convert
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int inet_aton(const char *aIPAddrString, IPAddress& aResult);
|
||||
|
||||
/** Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
protected:
|
||||
uint16_t BuildRequest(const char* aName);
|
||||
uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress);
|
||||
|
||||
IPAddress iDNSServer;
|
||||
uint16_t iRequestId;
|
||||
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 <UIPUdp.h>
|
||||
|
||||
class DNSClient
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
void begin(const IPAddress& aDNSServer);
|
||||
|
||||
/** Convert a numeric IP address string into a four-byte IP address.
|
||||
@param aIPAddrString IP address to convert
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int inet_aton(const char *aIPAddrString, IPAddress& aResult);
|
||||
|
||||
/** Resolve the given hostname to an IP address.
|
||||
@param aHostname Name to be resolved
|
||||
@param aResult IPAddress structure to store the returned IP address
|
||||
@result 1 if aIPAddrString was successfully converted to an IP address,
|
||||
else error code
|
||||
*/
|
||||
int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
protected:
|
||||
uint16_t BuildRequest(const char* aName);
|
||||
uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress);
|
||||
|
||||
IPAddress iDNSServer;
|
||||
uint16_t iRequestId;
|
||||
UIPUDP iUdp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user