fixed crlf for project

This commit is contained in:
Henrik Ekblad
2014-03-07 21:17:56 +01:00
parent 586a4d6239
commit c1441dca4a
62 changed files with 6964 additions and 6964 deletions
+325 -325
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+194 -194
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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(&current);
// 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(&current);
// 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
View File
@@ -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
+213 -213
View File
@@ -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);
}
}
}
+35 -35
View File
@@ -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
+4 -4
View File
@@ -1,5 +1,5 @@
InterruptChain KEYWORD1
addInterruptCallback KEYWORD2
setMode KEYWORD2
enable KEYWORD2
InterruptChain KEYWORD1
addInterruptCallback KEYWORD2
setMode KEYWORD2
enable KEYWORD2
disable KEYWORD2
+231 -231
View File
@@ -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
View File
@@ -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.
}
+29 -29
View File
@@ -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)
###################################
+318 -318
View File
@@ -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;
}
+107 -107
View File
@@ -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
+134 -134
View File
@@ -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);
}
}
+103 -103
View File
@@ -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
+48 -48
View File
@@ -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);
}
+10 -10
View File
@@ -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() {
+61 -61
View File
@@ -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
+110 -110
View File
@@ -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);
}
}
}
+8 -8
View File
@@ -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
+80 -80
View File
@@ -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.
+193 -193
View File
@@ -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;
}
+88 -88
View File
@@ -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
+305 -305
View File
@@ -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);
}
+249 -249
View File
@@ -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);
}
+14 -14
View File
@@ -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
+88 -88
View File
@@ -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
}
+80 -80
View File
@@ -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;
}
+1 -1
View File
@@ -117,4 +117,4 @@ void write_n(int what, int how_many)
{
for( int i = 0; i < how_many; i++ )
UdpBytewise.write(what);
}
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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