From 2d73cc884553bf2fa24215a7bc644e3bdbee70b0 Mon Sep 17 00:00:00 2001 From: Willem Date: Sun, 13 Nov 2022 01:46:38 +0100 Subject: [PATCH] Added project --- .gitignore | 51 + .project | 11 + Makefile | 52 + build.txt | 38 + .../node_lib/device/xdevice-connector-a.js | 291 +++ .../node_lib/device/xdevice-encryption.js | 120 + .../node_lib/lib/build-backend-mongoose.js | 123 ++ .../debug-server/node_lib/lib/build-config.js | 16 + .../debug-server/node_lib/lib/build-view.js | 95 + .../node_lib/lib/factory-express-api.js | 338 +++ .../node_lib/lib/factory-express.js | 138 ++ .../node_lib/lib/node-ff-tcrud.js | 54 + .../debug-server/node_lib/lib/tcrud-field.js | 110 + .../debug-server/node_lib/lib/tcrud-view.js | 204 ++ lib-build/debug-server/node_lib/lib/tcrud.js | 230 ++ .../angular/controller-action-none.ejs | 8 + .../angular/controller-route.ejs | 5 + .../node-ff-tcrud/angular/controller.ejs | 99 + .../angular/thtml/crud/create.ejs | 20 + .../angular/thtml/crud/delete.ejs | 6 + .../node-ff-tcrud/angular/thtml/crud/edit.ejs | 16 + .../node-ff-tcrud/angular/thtml/crud/list.ejs | 50 + .../node-ff-tcrud/angular/thtml/crud/read.ejs | 19 + .../node-ff-tcrud/csv/list-footer.ejs | 1 + .../node-ff-tcrud/csv/list-header.ejs | 1 + .../node-ff-tcrud/csv/list-record.ejs | 1 + .../node-ff-tcrud/csv/read-record.ejs | 1 + .../node-ff-tcrud/rss/list-footer.ejs | 1 + .../node-ff-tcrud/rss/list-header.ejs | 2 + .../node-ff-tcrud/rss/list-record.ejs | 5 + .../node-ff-tcrud/xml/list-footer.ejs | 2 + .../node-ff-tcrud/xml/list-header.ejs | 3 + .../node-ff-tcrud/xml/list-record.ejs | 5 + .../node-ff-tcrud/xml/read-record.ejs | 8 + .../node_lib/model/xnode-base-command.js | 75 + .../debug-server/node_lib/model/xnode-base.js | 98 + .../node_lib/model/xnode-data-value.js | 59 + .../debug-server/node_lib/model/xnode-data.js | 53 + .../debug-server/node_lib/model/xnode.js | 98 + .../node_lib/model/xsystem-session.js | 35 + .../node_lib/model/xsystem-state.js | 146 ++ .../node_lib/model/xsystem-user.js | 46 + .../debug-server/node_lib/server-build.js | 38 + lib-build/debug-server/package.json | 44 + lib-build/debug-server/server-assets.json | 27 + lib-build/debug-server/server-config.js | 71 + lib-build/debug-server/server-init.js | 102 + lib-build/debug-server/server.js | 115 + .../debug-server/www_static/css/boot.css | 149 ++ .../debug-server/www_static/css/flot.css | 11 + .../debug-server/www_static/css/panel.css | 56 + .../debug-server/www_static/css/style.css | 54 + .../debug-server/www_static/img/xensit-sm.png | Bin 0 -> 7425 bytes .../www_static/js/controller/server-about.js | 13 + .../www_static/js/controller/server-dash.js | 14 + .../www_static/js/controller/server-index.js | 13 + .../www_static/js/controller/server-routes.js | 26 + .../www_static/js/xds-directives.js | 9 + .../debug-server/www_static/js/xds-filters.js | 9 + .../www_static/js/xds-services.js | 5 + lib-build/debug-server/www_static/js/xds.js | 27 + lib-build/debug-server/www_views/index.ejs | 23 + .../www_views/thtml/error/http-404.ejs | 7 + .../www_views/thtml/error/http-500.ejs | 7 + .../www_views/thtml/layout/footer.ejs | 7 + .../www_views/thtml/layout/header.ejs | 16 + .../www_views/thtml/server/about.ejs | 5 + .../www_views/thtml/server/dash.ejs | 96 + .../www_views/thtml/server/index.ejs | 5 + .../www_views/thtml/server/routes-group.ejs | 17 + .../www_views/thtml/server/routes.ejs | 28 + lib-build/make/Makefile.inc.debug | 40 + lib-build/make/Makefile.inc.libs | 36 + lib-build/make/Makefile.inc.local-template | 20 + lib-build/make/Makefile.inc.root | 284 +++ lib-build/make/Makefile.master | 50 + lib-build/make/Makefile.master-flash | 45 + lib-build/tools/mega-hex2c.tcl | 86 + lib-build/tools/xxtea.c | 171 ++ lib-ext/dht.git/DHT.cpp | 179 ++ lib-ext/dht.git/DHT.h | 41 + lib-ext/dht.git/README.txt | 3 + .../dht.git/examples/DHTtester/DHTtester.ino | 71 + lib-ext/ethercard.git/.gitignore | 3 + lib-ext/ethercard.git/CONTRIBUTING.md | 22 + lib-ext/ethercard.git/Doxyfile | 1923 +++++++++++++++++ lib-ext/ethercard.git/Doxylogo.png | Bin 0 -> 6626 bytes lib-ext/ethercard.git/Doxymods.css | 73 + lib-ext/ethercard.git/EtherCard.cpp | 416 ++++ lib-ext/ethercard.git/EtherCard.h | 587 +++++ lib-ext/ethercard.git/README.md | 46 + lib-ext/ethercard.git/dhcp.cpp | 432 ++++ lib-ext/ethercard.git/dns.cpp | 117 + lib-ext/ethercard.git/docu.dox | 96 + lib-ext/ethercard.git/enc28j60.cpp | 611 ++++++ lib-ext/ethercard.git/enc28j60.h | 114 + .../ethercard.git/examples/JeeUdp/JeeUdp.ino | 320 +++ lib-ext/ethercard.git/examples/SSDP/SSDP.ino | 144 ++ .../examples/backSoon/backSoon.ino | 63 + .../examples/etherNode/etherNode.ino | 276 +++ .../examples/getDHCPandDNS/getDHCPandDNS.ino | 55 + .../examples/getStaticIP/getStaticIP.ino | 57 + .../examples/getViaDNS/getViaDNS.ino | 52 + .../examples/multipacket/multipacket.ino | 77 + .../examples/multipacketSD/multipacketSD.ino | 129 ++ .../examples/nanether/nanether.ino | 58 + .../examples/noipClient/noipClient.ino | 279 +++ .../ethercard.git/examples/pings/pings.ino | 62 + .../examples/rbbb_server/rbbb_server.ino | 43 + .../examples/stashTest/stashTest.ino | 118 + .../examples/testDHCP/testDHCP.ino | 40 + .../examples/twitter/twitter.ino | 84 + .../examples/udpListener/udpListener.ino | 95 + .../examples/webClient/webClient.ino | 50 + .../ethercard.git/examples/xively/xively.ino | 139 ++ lib-ext/ethercard.git/net.h | 123 ++ lib-ext/ethercard.git/tcpip.cpp | 810 +++++++ lib-ext/ethercard.git/udpserver.cpp | 72 + lib-ext/ethercard.git/webutil.cpp | 202 ++ lib-ext/narcoleptic/Narcoleptic.cpp | 57 + lib-ext/narcoleptic/Narcoleptic.h | 34 + .../Examples/GarageMote/GarageMote.ino | 418 ++++ .../GarageMote_base/GarageMote_base.ino | 132 ++ .../rfm-69.git/Examples/Gateway/Gateway.ino | 173 ++ .../MailboxNotifier4_sender.ino | 176 ++ .../MightyBoostControl/MightyBoostControl.ino | 221 ++ .../Examples/MotionMote/MotionMote.ino | 150 ++ .../Examples/MotionMote/OLD/MotionMote.ino | 68 + .../Examples/MotionMote/OLD/MotionMote.jpg | Bin 0 -> 20602 bytes .../MotionMote/OLD/MotionMote_CC-BY-SA.svg | 26 + lib-ext/rfm-69.git/Examples/Node/Node.ino | 172 ++ .../rfm-69.git/Examples/OLEDMote/OLEDMote.ino | 242 +++ .../Examples/PiGateway/PiGateway.ino | 146 ++ .../Examples/PiGateway/PiGateway_withLCD.ino | 186 ++ .../Struct_receive/Struct_receive.ino | 139 ++ .../Examples/Struct_send/Struct_send.ino | 135 ++ .../Examples/TxRxBlinky/TxRxBlinky.ino | 191 ++ .../WirelessProgramming_gateway.ino | 138 ++ .../WirelessProgramming_node.ino | 167 ++ lib-ext/rfm-69.git/License.txt | 674 ++++++ lib-ext/rfm-69.git/README.md | 60 + lib-ext/rfm-69.git/RFM69.cpp | 498 +++++ lib-ext/rfm-69.git/RFM69.h | 143 ++ lib-ext/rfm-69.git/RFM69registers.h | 1109 ++++++++++ lib-ext/rfm-69.git/keywords.txt | 54 + lib-ext/rfm-69.git/library.json | 12 + lib/isp-repair/MegaIspRepair.cpp | 248 +++ lib/isp-repair/MegaIspRepair.h | 39 + lib/isp-repair/MegaIspRepairConfig.h | 49 + lib/isp-repair/readme.txt | 44 + lib/xnode-shared/XnodeConstants.h | 77 + lib/xnode-shared/XnodeProtocol.h | 38 + lib/xnode-shared/XnodeSatelliteConfig.h | 14 + lib/xnode-shared/XnodeSerial.cpp | 104 + lib/xnode-shared/XnodeSerial.h | 32 + lib/xnode-shared/XnodeSystem.cpp | 323 +++ lib/xnode-shared/XnodeSystem.h | 49 + lib/xnode-shared/XnodeSystemHardware.h | 15 + lib/xnode-shared/XnodeSystemModule.h | 11 + lib/xnode-shared/XnodeUtil.cpp | 85 + lib/xnode-shared/XnodeUtil.h | 27 + protocol-a.txt | 59 + readme.txt | 7 + todo.txt | 64 + xnode-base/Makefile | 5 + xnode-base/XnodeBase.cpp | 34 + xnode-base/XnodeBaseConfig.h | 32 + xnode-base/XnodeBaseHardware.cpp | 172 ++ xnode-base/XnodeBaseHardware.h | 56 + xnode-base/XnodeBaseNetwork.cpp | 625 ++++++ xnode-base/XnodeBaseNetwork.h | 53 + xnode-base/XnodeBaseRadio.cpp | 243 +++ xnode-base/XnodeBaseRadio.h | 33 + xnode-mega-flash/Makefile | 22 + xnode-mega-flash/XnodeMegaFlash.cpp | 17 + xnode-satellite-boot/XnodeSatelliteBoot.c | 2 + xnode-satellite/Makefile | 4 + xnode-satellite/XnodeSatellite.cpp | 31 + xnode-satellite/XnodeSatelliteHardware.cpp | 42 + xnode-satellite/XnodeSatelliteHardware.h | 26 + xnode-satellite/XnodeSatelliteRadio.cpp | 204 ++ xnode-satellite/XnodeSatelliteRadio.h | 34 + xnode-satellite/XnodeSatelliteSensor.cpp | 117 + xnode-satellite/XnodeSatelliteSensor.h | 28 + xnode-test-blink/Makefile | 3 + xnode-test-blink/XnodeTestBlink.cpp | 43 + 186 files changed, 21174 insertions(+) create mode 100644 .gitignore create mode 100644 .project create mode 100644 Makefile create mode 100644 build.txt create mode 100644 lib-build/debug-server/node_lib/device/xdevice-connector-a.js create mode 100644 lib-build/debug-server/node_lib/device/xdevice-encryption.js create mode 100644 lib-build/debug-server/node_lib/lib/build-backend-mongoose.js create mode 100644 lib-build/debug-server/node_lib/lib/build-config.js create mode 100644 lib-build/debug-server/node_lib/lib/build-view.js create mode 100644 lib-build/debug-server/node_lib/lib/factory-express-api.js create mode 100644 lib-build/debug-server/node_lib/lib/factory-express.js create mode 100644 lib-build/debug-server/node_lib/lib/node-ff-tcrud.js create mode 100644 lib-build/debug-server/node_lib/lib/tcrud-field.js create mode 100644 lib-build/debug-server/node_lib/lib/tcrud-view.js create mode 100644 lib-build/debug-server/node_lib/lib/tcrud.js create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-action-none.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-route.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/delete.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/read.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-footer.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-header.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-record.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/read-record.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-footer.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-header.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-record.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-footer.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-header.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-record.ejs create mode 100644 lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/read-record.ejs create mode 100644 lib-build/debug-server/node_lib/model/xnode-base-command.js create mode 100644 lib-build/debug-server/node_lib/model/xnode-base.js create mode 100644 lib-build/debug-server/node_lib/model/xnode-data-value.js create mode 100644 lib-build/debug-server/node_lib/model/xnode-data.js create mode 100644 lib-build/debug-server/node_lib/model/xnode.js create mode 100644 lib-build/debug-server/node_lib/model/xsystem-session.js create mode 100644 lib-build/debug-server/node_lib/model/xsystem-state.js create mode 100644 lib-build/debug-server/node_lib/model/xsystem-user.js create mode 100644 lib-build/debug-server/node_lib/server-build.js create mode 100644 lib-build/debug-server/package.json create mode 100644 lib-build/debug-server/server-assets.json create mode 100644 lib-build/debug-server/server-config.js create mode 100644 lib-build/debug-server/server-init.js create mode 100644 lib-build/debug-server/server.js create mode 100644 lib-build/debug-server/www_static/css/boot.css create mode 100644 lib-build/debug-server/www_static/css/flot.css create mode 100644 lib-build/debug-server/www_static/css/panel.css create mode 100644 lib-build/debug-server/www_static/css/style.css create mode 100644 lib-build/debug-server/www_static/img/xensit-sm.png create mode 100644 lib-build/debug-server/www_static/js/controller/server-about.js create mode 100644 lib-build/debug-server/www_static/js/controller/server-dash.js create mode 100644 lib-build/debug-server/www_static/js/controller/server-index.js create mode 100644 lib-build/debug-server/www_static/js/controller/server-routes.js create mode 100644 lib-build/debug-server/www_static/js/xds-directives.js create mode 100644 lib-build/debug-server/www_static/js/xds-filters.js create mode 100644 lib-build/debug-server/www_static/js/xds-services.js create mode 100644 lib-build/debug-server/www_static/js/xds.js create mode 100644 lib-build/debug-server/www_views/index.ejs create mode 100644 lib-build/debug-server/www_views/thtml/error/http-404.ejs create mode 100644 lib-build/debug-server/www_views/thtml/error/http-500.ejs create mode 100644 lib-build/debug-server/www_views/thtml/layout/footer.ejs create mode 100644 lib-build/debug-server/www_views/thtml/layout/header.ejs create mode 100644 lib-build/debug-server/www_views/thtml/server/about.ejs create mode 100644 lib-build/debug-server/www_views/thtml/server/dash.ejs create mode 100644 lib-build/debug-server/www_views/thtml/server/index.ejs create mode 100644 lib-build/debug-server/www_views/thtml/server/routes-group.ejs create mode 100644 lib-build/debug-server/www_views/thtml/server/routes.ejs create mode 100644 lib-build/make/Makefile.inc.debug create mode 100644 lib-build/make/Makefile.inc.libs create mode 100644 lib-build/make/Makefile.inc.local-template create mode 100644 lib-build/make/Makefile.inc.root create mode 100644 lib-build/make/Makefile.master create mode 100644 lib-build/make/Makefile.master-flash create mode 100644 lib-build/tools/mega-hex2c.tcl create mode 100644 lib-build/tools/xxtea.c create mode 100644 lib-ext/dht.git/DHT.cpp create mode 100644 lib-ext/dht.git/DHT.h create mode 100644 lib-ext/dht.git/README.txt create mode 100644 lib-ext/dht.git/examples/DHTtester/DHTtester.ino create mode 100644 lib-ext/ethercard.git/.gitignore create mode 100644 lib-ext/ethercard.git/CONTRIBUTING.md create mode 100644 lib-ext/ethercard.git/Doxyfile create mode 100644 lib-ext/ethercard.git/Doxylogo.png create mode 100644 lib-ext/ethercard.git/Doxymods.css create mode 100644 lib-ext/ethercard.git/EtherCard.cpp create mode 100644 lib-ext/ethercard.git/EtherCard.h create mode 100644 lib-ext/ethercard.git/README.md create mode 100644 lib-ext/ethercard.git/dhcp.cpp create mode 100644 lib-ext/ethercard.git/dns.cpp create mode 100644 lib-ext/ethercard.git/docu.dox create mode 100644 lib-ext/ethercard.git/enc28j60.cpp create mode 100644 lib-ext/ethercard.git/enc28j60.h create mode 100644 lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino create mode 100644 lib-ext/ethercard.git/examples/SSDP/SSDP.ino create mode 100644 lib-ext/ethercard.git/examples/backSoon/backSoon.ino create mode 100644 lib-ext/ethercard.git/examples/etherNode/etherNode.ino create mode 100644 lib-ext/ethercard.git/examples/getDHCPandDNS/getDHCPandDNS.ino create mode 100644 lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino create mode 100644 lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino create mode 100644 lib-ext/ethercard.git/examples/multipacket/multipacket.ino create mode 100644 lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino create mode 100644 lib-ext/ethercard.git/examples/nanether/nanether.ino create mode 100644 lib-ext/ethercard.git/examples/noipClient/noipClient.ino create mode 100644 lib-ext/ethercard.git/examples/pings/pings.ino create mode 100644 lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino create mode 100644 lib-ext/ethercard.git/examples/stashTest/stashTest.ino create mode 100644 lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino create mode 100644 lib-ext/ethercard.git/examples/twitter/twitter.ino create mode 100644 lib-ext/ethercard.git/examples/udpListener/udpListener.ino create mode 100644 lib-ext/ethercard.git/examples/webClient/webClient.ino create mode 100644 lib-ext/ethercard.git/examples/xively/xively.ino create mode 100755 lib-ext/ethercard.git/net.h create mode 100644 lib-ext/ethercard.git/tcpip.cpp create mode 100644 lib-ext/ethercard.git/udpserver.cpp create mode 100644 lib-ext/ethercard.git/webutil.cpp create mode 100644 lib-ext/narcoleptic/Narcoleptic.cpp create mode 100644 lib-ext/narcoleptic/Narcoleptic.h create mode 100644 lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino create mode 100644 lib-ext/rfm-69.git/Examples/GarageMote_base/GarageMote_base.ino create mode 100644 lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino create mode 100644 lib-ext/rfm-69.git/Examples/MailboxNotifier/MailboxNotifier4_sender.ino create mode 100644 lib-ext/rfm-69.git/Examples/MightyBoostControl/MightyBoostControl.ino create mode 100644 lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino create mode 100644 lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino create mode 100644 lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.jpg create mode 100644 lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote_CC-BY-SA.svg create mode 100644 lib-ext/rfm-69.git/Examples/Node/Node.ino create mode 100644 lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino create mode 100644 lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino create mode 100644 lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino create mode 100644 lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino create mode 100644 lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino create mode 100644 lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino create mode 100644 lib-ext/rfm-69.git/Examples/WirelessProgramming_gateway/WirelessProgramming_gateway.ino create mode 100644 lib-ext/rfm-69.git/Examples/WirelessProgramming_node/WirelessProgramming_node.ino create mode 100644 lib-ext/rfm-69.git/License.txt create mode 100644 lib-ext/rfm-69.git/README.md create mode 100644 lib-ext/rfm-69.git/RFM69.cpp create mode 100644 lib-ext/rfm-69.git/RFM69.h create mode 100644 lib-ext/rfm-69.git/RFM69registers.h create mode 100644 lib-ext/rfm-69.git/keywords.txt create mode 100644 lib-ext/rfm-69.git/library.json create mode 100644 lib/isp-repair/MegaIspRepair.cpp create mode 100644 lib/isp-repair/MegaIspRepair.h create mode 100644 lib/isp-repair/MegaIspRepairConfig.h create mode 100644 lib/isp-repair/readme.txt create mode 100644 lib/xnode-shared/XnodeConstants.h create mode 100644 lib/xnode-shared/XnodeProtocol.h create mode 100644 lib/xnode-shared/XnodeSatelliteConfig.h create mode 100644 lib/xnode-shared/XnodeSerial.cpp create mode 100644 lib/xnode-shared/XnodeSerial.h create mode 100644 lib/xnode-shared/XnodeSystem.cpp create mode 100644 lib/xnode-shared/XnodeSystem.h create mode 100644 lib/xnode-shared/XnodeSystemHardware.h create mode 100644 lib/xnode-shared/XnodeSystemModule.h create mode 100644 lib/xnode-shared/XnodeUtil.cpp create mode 100644 lib/xnode-shared/XnodeUtil.h create mode 100644 protocol-a.txt create mode 100644 readme.txt create mode 100644 todo.txt create mode 100644 xnode-base/Makefile create mode 100644 xnode-base/XnodeBase.cpp create mode 100644 xnode-base/XnodeBaseConfig.h create mode 100644 xnode-base/XnodeBaseHardware.cpp create mode 100644 xnode-base/XnodeBaseHardware.h create mode 100644 xnode-base/XnodeBaseNetwork.cpp create mode 100644 xnode-base/XnodeBaseNetwork.h create mode 100644 xnode-base/XnodeBaseRadio.cpp create mode 100644 xnode-base/XnodeBaseRadio.h create mode 100644 xnode-mega-flash/Makefile create mode 100644 xnode-mega-flash/XnodeMegaFlash.cpp create mode 100644 xnode-satellite-boot/XnodeSatelliteBoot.c create mode 100644 xnode-satellite/Makefile create mode 100644 xnode-satellite/XnodeSatellite.cpp create mode 100644 xnode-satellite/XnodeSatelliteHardware.cpp create mode 100644 xnode-satellite/XnodeSatelliteHardware.h create mode 100644 xnode-satellite/XnodeSatelliteRadio.cpp create mode 100644 xnode-satellite/XnodeSatelliteRadio.h create mode 100644 xnode-satellite/XnodeSatelliteSensor.cpp create mode 100644 xnode-satellite/XnodeSatelliteSensor.h create mode 100644 xnode-test-blink/Makefile create mode 100644 xnode-test-blink/XnodeTestBlink.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c080079 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# +# Xensit Xnode Ignore list +# + +# Ignore all build folders +build + +# Ignore all generated source +*.generated + +# Ignore local include makefile +lib-build/make/Makefile.inc.local + +# Ignore nodejs deps + www logs +lib-build/debug-server/www_logs +lib-build/debug-server/node_modules +lib-build/debug-server/npm-debug.log +lib-build/debug-server/www_static/js/lib +lib-build/debug-server/www_static/css/lib + +# Ignore binary files +*.o +*.class +*.old +*.bak +*.backup +*.dat +*.data +*.gif +*.pdf +*.doc + +# Ignore ~ backup files. +*~ + +# Ignore some eclipse files +.settings +.classpath + +# Ignore netbeans directory +nbproject + +# Ignore mac finder files +.DS_Store + +# Ignore windows files. +Thumbs.db +Desktop.ini + +# Ignore kde dolphin files +.directory diff --git a/.project b/.project new file mode 100644 index 0000000..6444775 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + xnode + + + + + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..94995fd --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +# +# Call ordered depency make commands +# + +# Save command line option for child +ARD_HOME_ARGU = ${ARD_HOME} + +# Optional include an local override for arduino home +-include lib-build/make/Makefile.inc.local + +# Safety check +ifndef ARD_HOME + $(error $$(ARD_HOME) not defined) +endif + +# Only pass to child if defined from command line. +ifndef ARD_HOME_ARGU + ARD_HOME_ARGU_CHILD = ARD_HOME=${ARD_HOME} +endif + +# Locate and check for avr-size +AVR_SIZE ?= $(ARD_HOME)/hardware/tools/avr/bin/avr-size +ifeq ("$(wildcard $(AVR_SIZE))","") + $(error $$(AVR_SIZE) not found) +endif + +# Define all projects to build +PROJECTS = \ +xnode-base \ +xnode-mega-flash \ +xnode-satellite \ +xnode-test-blink + +# Hook all to projects +all: projects + +# Declare subprojects targets +.PHONY: $(PROJECTS) +projects: $(PROJECTS) projects-result +$(PROJECTS): + $(MAKE) -s -C $@ clean all ${ARD_HOME_ARGU_CHILD} +projects-result: + @echo + @echo "Full xnode build is ready to burn." + @echo + @echo "Binary program sizes;" + ${AVR_SIZE} xnode*/build/*.hex + @echo + @echo "Done." + +# Declare subprojects depencies +xnode-mega-flash: xnode-satellite xnode-base xnode-test-blink diff --git a/build.txt b/build.txt new file mode 100644 index 0000000..f2d40fd --- /dev/null +++ b/build.txt @@ -0,0 +1,38 @@ + +Minimal build setup: + +1) Download+unzip arduino ide version 1.6.0 is tested ! + Get it from http://www.arduino.cc/ + +2) Install make and tcl; + apt-get install tcl make + +3) Build all project in one go; + make ARD_HOME=/path/to/arduino-ide-1.6.0 + +Optional: + +To override multiple flags and parameters for every +build there is a local makefile include template. + +1) cp lib-build/make/Makefile.inc.local-template lib-build/make/Makefile.inc.local +2) Edit lib-build/make/Makefile.inc.local +3) make or cd xnode-base;make/etc + +Now the make command of the sub projects and this parent build +will use the local make settings. + +Build commands; + + Build all hex files; + cd project-root/ + make + + Build clean satellite only + cd project-root/xnode-satellite + make clean all + + Build and upload clean base only + cd project-root/xnode-base + make clean upload + make clean upload ISP_PORT=/dev/ttyACM1 diff --git a/lib-build/debug-server/node_lib/device/xdevice-connector-a.js b/lib-build/debug-server/node_lib/device/xdevice-connector-a.js new file mode 100644 index 0000000..8f1306e --- /dev/null +++ b/lib-build/debug-server/node_lib/device/xdevice-connector-a.js @@ -0,0 +1,291 @@ +var XDeviceEncryption = require('./xdevice-encryption'); +var Mongoose = require('mongoose'); +var XSystemState = Mongoose.model( 'xsystem-state' ); +var XNode = Mongoose.model( 'xnode' ); +var XNodeBase = Mongoose.model( 'xnode-base' ); +var XNodeBaseCommand = Mongoose.model( 'xnode-base-command' ); +var XNodeData = Mongoose.model( 'xnode-data' ); +var XNodeDataValue = Mongoose.model( 'xnode-data-value' ); +var Async = require('async'); +var Winston = require('winston'); +var Log = Winston.loggers.get('main'); + +var createXnodeBase = function(created_ip,callbackResult) { + Async.series({ + cnt_base_net_id: function(callback) { + XSystemState.incHexByName('_a_seq_base_net_id', function(err, xprop) { + callback(err,xprop.value); + }); + }, + cnt_base_net_key: function(callback){ + XSystemState.incHexByName('_a_seq_base_net_key', function(err, xprop) { + callback(err,xprop.value); + }); + }, + cnt_base_net_mac: function(callback){ + XSystemState.incHexByName('_a_seq_base_net_mac', function(err, xprop) { + callback(err,xprop.value); + }); + }, + cnt_base_rf_key: function(callback){ + XSystemState.incHexByName('_a_seq_base_rf_key', function(err, xprop) { + callback(err,xprop.value); + }); + } + }, + function(err, result) { + if (err) { + callbackResult(err); + return; + } + var xnodeBase = new XNodeBase(); + xnodeBase.created_ip = created_ip; + xnodeBase.net_id = result.cnt_base_net_id; + xnodeBase.net_key = result.cnt_base_net_key; + xnodeBase.net_mac = result.cnt_base_net_mac; + xnodeBase.rf_key = result.cnt_base_rf_key; + xnodeBase.init_index = 0; + xnodeBase.save(function(err,xnodeBase) { + Log.debug("XDeviceConnectorA.createXnodeBase _id="+xnodeBase._id+" net_id="+xnodeBase.net_id); + callbackResult(err,xnodeBase); + }); + }); +} + +var handleInit = function(req,res,next) { + Log.debug('XDeviceConnectorA.handleInit'); + var net_id = req.body.ni; + if (net_id == 0) { + createXnodeBase(req.ip,function(err,xnodeBase) { + if (err) { return next(err); } + Log.info('XDeviceConnectorA.handleInit response: Xinet_id '+xnodeBase.net_id); + res.send('Xinet_id '+xnodeBase.net_id+'\n'); + }); + } else { + XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) { + if (err) { return next(err); } + if (xnodeBase == null) { + Log.warn('XDeviceConnectorA.handleInit illegal net_id='+req.body.ni); + res.send('X'); + return; + } + if (xnodeBase.init_index > 4) { + Log.error('initXnode stateError, device was already init-ited.'); + res.send('XXreboot'); + return; + } + xnodeBase.init_index++; + xnodeBase.save(function(err) { + var result; + if (xnodeBase.init_index == 1) { + result = 'Xinet_key '+xnodeBase.net_key; + } else if (xnodeBase.init_index == 2) { + result = 'Xinet_mac '+xnodeBase.net_mac; + } else if (xnodeBase.init_index == 3) { + result = 'Xirf_key '+xnodeBase.rf_key; + } else if (xnodeBase.init_index == 4) { + result = 'Xireboot'; + XNodeBaseCommand.insert(net_id,'help',req.ip,next); // trigger node data on next ping :) + } else { + result = 'X'; // code error + } + Log.info('XDeviceConnectorA.initXnode response net_id='+xnodeBase.net_id+' step='+xnodeBase.init_index+' reply='+result); + res.send(result); + }); + }); + } +}; + +var replyCommand = function(req,res,next) { + XNodeBaseCommand.findOpenByNetId(req.body.ni, function ( err, data ) { + if (err) { return next(err); } + if (data.length > 0) { + Log.debug('XDeviceConnectorA.replyCommand send cmd: '+data[0].command); + data[0].send_date = new Date(); + data[0].save(function(err) { + if (err) { return next(err); } + res.send('XX'+data[0].command); + }); + } else { + res.send('X'); + } + }); +} + +var logData = function(xnode,data_raw,data_text,req) { + var xdata = new XNodeData(); + xdata.remote_ip = req.ip; + xdata.node_id = xnode.node_id; + xdata.net_id = req.body.ni; + xdata.data_raw = data_raw; + xdata.data_text = data_text; + xdata.save(function(err,xdata) { + if (err) { return next(err); } + Log.debug("XDeviceConnectorA.logData _id="+xdata._id+" net_id="+xdata.net_id+" node_id="+xdata.node_id+" data_text.length="+xdata.data_text.length); + }); +} + +var logDataValue = function(xnode,data_text,req, next) { + if (data_text.indexOf('help') > 0) { + return; // done't save help cmds as values. + } + if (data_text.indexOf('#ERR') > 0) { + return; // done't save errors. + } + var data_lines = data_text.split('\n'); + for(var i = 0; i < data_lines.length; i ++) { + var data_line = data_lines[i]; + var data_rows = data_line.split('='); + var data_name = data_rows[0]; + var data_value = data_rows[1]; + if (data_name.length == 0) { + continue; + } + xval = new XNodeDataValue(); + xval.net_id = xnode.net_id; + xval.node_id = xnode.node_id; + xval.name = data_name; + xval.value = data_value; + xval.save(function(err,xval) { + if (err) { return next(err); } + Log.debug("XDeviceConnectorA.logDataValue _id="+xval._id+" net_id="+xval.net_id+" node_id="+xval.node_id+" name="+xval.name+" value="+xval.value); + }); + } +} + +var logRxCount = function(xnode,data_text,next) { + xnode.rx_date=new Date(); + xnode.rx_requests++; + xnode.rx_bytes=data_text.length + xnode.rx_bytes; + xnode.save(function(err,xnode) { + if (err) { return next(err); } + Log.debug("XDeviceConnectorA.logRxCount _id="+xnode._id+" rx_requests="+xnode.rx_requests); + }); +} + +var updateMetaInfo = function(xnode,req, next) { + if (xnode.info_date == null) { + xnode.info_date = new Date(new Date().getTime() - 60*60*1000 - 1000); // triggers update + } + var dateLastHour = new Date(new Date().getTime() - 60*60*1000); + if (dateLastHour.getTime() > xnode.info_date.getTime() ) { + + if (xnode.node_id == 1) { + XNodeBaseCommand.insert(xnode.net_id,'sys_info',req.ip, next); + XNodeBaseCommand.insert(xnode.net_id,'rf_info',req.ip, next); + XNodeBaseCommand.insert(xnode.net_id,'net_info',req.ip, next); + XNodeBaseCommand.insert(xnode.net_id,'net_info_eth0',req.ip, next); + } else { + Log.debug("todo"); + //XNodeBaseCommand.insert(xnode.net_id,'@2 sys_info',req.ip, next); + //XNodeBaseCommand.insert(xnode.net_id,'@2 rf_info',req.ip, next); + } + + xnode.info_date = new Date(); + xnode.save(function(err,xsat) { + if (err) { return next(err); } + Log.debug("XDeviceConnectorA.updateMetaInfo _id="+xnode._id); + }); + } +} + +var handleDataNode = function(xnode,req,res,next) { + var net_id = req.body.ni; + var node_id = req.body.nn; + var data_raw = req.body.nd; + + Log.debug('XDeviceConnectorA.handleDataNode ni='+xnode.net_id); + +// log.debug('XDeviceConnectorA.handleData TODO FIX XXTEA'); +// var result = XDeviceEncryption.xxteaDecrypt(req.body.nd,xnode.hw_net_key); +// log.debug('XDeviceConnectorA.handleData xxteaDecrypt='+result+' hw_net_key='+xnode.hw_net_key); + + var data_text = data_raw; + + logRxCount (xnode,data_text,next); + logData (xnode,data_raw,data_text,req); + logDataValue (xnode,data_text, req, next); + updateMetaInfo (xnode,req, next); + replyCommand (req,res,next); +} + +var handleData = function(req,res,next) { + var net_id = req.body.ni; + var node_id = req.body.nn; + if (net_id == '000000000000') { + Log.warn('XDeviceConnectorA.handleData zero net_id='+net_id); + res.send('X'); + return; + } + if (node_id == 0) { + Log.warn('XDeviceConnectorA.handleData zero node_id='+node_id); + res.send('X'); + return; + } + Log.debug('XDeviceConnectorA.handleData ni='+net_id+' nn='+node_id); + XNode.findByNetIdAndNodeId(net_id,node_id,function(err,xnode) { + if (err) { return next(err); } + if (xnode == null) { + Log.debug('XDeviceConnectorA.handleData creating new XNode.'); + xnode = new XNode(); + xnode.net_id = net_id; + xnode.node_id = node_id; + xnode.save(function(err) { + if (err) { return next(err); } + handleDataNode(xnode,req,res,next); + }); + } else { + handleDataNode(xnode,req,res,next); + } + }); +} + +var handlePing = function(req,res,next) { + var net_id = req.body.ni; + if (net_id == '000000000000') { + Log.debug('XDeviceConnectorA.handlePing zero net_id='+net_id); + res.send('X'); + return; + } + Log.debug('XDeviceConnectorA.handlePing net_id='+net_id); + XNodeBase.findOneByNetId(net_id,function(err,xnodeBase) { + if (err) { return next(err); } + if (xnodeBase == null) { + Log.warn('XDeviceConnectorA.handlePing illegal net_id='+net_id); + res.send('X'); + return; + } + xnodeBase.ping_counter++; + xnodeBase.ping_last_date=new Date(); + xnodeBase.save(function(err) { + if (err) { return next(err); } + if (req.body.rc == 0) { + res.send('X'); // no cmd on first ping. + } else { + replyCommand(req,res,next); + } + }); + }); +} + +exports.deviceControl = function(req, res, next) { + var postType = req.body.pt; + var url = req.originalUrl || req.url; + var ip = req.ip; + Log.debug('POST '+url+' ip='+ip+' pt='+postType+' rc='+req.body.rc+' ni='+req.body.ni); + if (postType == 'i') { + handleInit(req,res,next); + return; + } + if (postType == 'p') { + handlePing(req,res,next); + return; + } + if (postType == 'd') { + handleData(req,res,next); + return; + } + Log.warn('XDeviceConnectorA.deviceControl unknown postType='+postType); + res.send('X'); +} + diff --git a/lib-build/debug-server/node_lib/device/xdevice-encryption.js b/lib-build/debug-server/node_lib/device/xdevice-encryption.js new file mode 100644 index 0000000..275b9cd --- /dev/null +++ b/lib-build/debug-server/node_lib/device/xdevice-encryption.js @@ -0,0 +1,120 @@ +var winston = require('winston'); +var log = winston.loggers.get('main'); + +var delta = 0x9E3779B9; +var XXTEA_NUM_ROUNDS = 32; + +//var xxxteaEncrypt = function(unsigned long v[2]) { +// unsigned int i; +// unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9; +// for (i=0; i < XXTEA_NUM_ROUNDS; i++) { +// v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]); +// sum += delta; +// v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]); +// } +// v[0]=v0; v[1]=v1; +//} + +var xxxteaDecrypt = function(vArray,keyBuff) { + log.debug('XDeviceEncryption.xxxteaDecrypt vArray='+JSON.stringify(vArray)+' keyBuff='+JSON.stringify(keyBuff)); + var v0=vArray.v0; + var v1=vArray.v1; + + log.debug('XDeviceEncryption.xxxteaDecrypt start v0='+v0.toString(16)+' v1='+v1.toString(16)); + + var delta=0x9E3779B9 + var sum=delta*XXTEA_NUM_ROUNDS; + for (var i=0; i < XXTEA_NUM_ROUNDS; i++) { + v1 -= (((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + keyBuff.readUInt32BE((sum>>>11) & 3)); + var v1Org = v1; + + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + keyBuff.readUInt32BE(sum & 3)); + + //log.debug('XDeviceEncryption.xxxteaDecrypt v0='+v0.toString(16)+' v1='+v1.toString(16)); + + if (v0 < 0) { v0 = Math.pow(2,32) + v0; } + if (v0 > Math.pow(2,32)) { v0 = v0 - Math.pow(2,32); } + + if (v1 < 0) { v1 = Math.pow(2,32) + v1; } + if (v1 > Math.pow(2,32)) { v1 = v1 - Math.pow(2,32); } + } + + //v0 = v0 & 0xFFFFFFFF; + //v1 = v1 & 0xFFFFFFFF; + + + + var result = {v0: v0,v1: v1}; + log.debug('XDeviceEncryption.xxxteaDecrypt result='+JSON.stringify(result)); + return result; +} + +// public static method encrypt +exports.xxteaEncrypt = function(string, key) { + log.debug('XDeviceEncryption.xxteaEncrypt key='+key+' data='+string); + if (string.length == 0) { + return(''); + } + + //var v = strToLongs(Utf8.encode(string)); + //var k = strToLongs(Utf8.encode(key).slice(0,16)); + var v = buffToLongs(new Buffer(string, 'hex')); + var k = buffToLongs(new Buffer(key, 'hex')); + + //if (v.length <= 1) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding a null + var n = v.length; + + // ---- ---- + + var z = v[n-1], y = v[0], delta = 0x9E3779B9; + var mx, e, q = Math.floor(6 + 52/n), sum = 0; + + while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word + sum += delta; + e = sum>>>2 & 3; + for (var p = 0; p < n; p++) { + y = v[(p+1)%n]; + mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z); + z = v[p] += mx; + } + } + + // ---- ---- + + var buff = longsToBuff(v); + return buff.toString('ascii'); +} + +exports.xxteaDecrypt = function(data, key) { + log.debug('XDeviceEncryption.xxteaDecrypt key='+key+' data='+data); + if (data.length == 0) { + return(''); + } + var d = new Buffer(data, 'hex'); + var k = new Buffer(key, 'hex'); + var n = d.length; + var r = new Buffer(n); + + log.debug('XDeviceEncryption.xxteaDecrypt dataBuffer='+d.toString('hex')); + + // ---- ---- + + for (var i=0;i= 0) { + if (req.url.indexOf('xml') > 0) { + req.query['export'] = 'xml'; + } else if (req.url.indexOf('csv') > 0) { + req.query['export'] = 'csv'; + } else if (req.url.indexOf('rss') > 0) { + req.query['export'] = 'rss'; + } + if (req.url.indexOf('json') == 0) { + console.log('inject export type: '+req.query['export']); + } + } + next(); + }; +} + +var _ = require('underscore'); + +var filterQueryList = function (model) { + return mcrud.parseQuery() + .defaults({ limit: '10' }) + .overrides({}) + .maxes({ limit: 1000 }); + //.removes() +} + +var filterDataUpdate = function (model) { + return mcrud.parseData() + overrides({}); + //.removes('auth') + //.overrides({ updated: Date.now }) + //.defaults({ 'info.gender': 'M' })) +} + +function allowCrudType(tview,tcrudType) { + return tview[tcrudType].tenable; // todo add roles +} + +//var rssXNodeMap = function(link,feed,data) { +// feed.addNewItem(data.net_id, link+'/ui/XNode/read/'+data._id, data.changed_data, data.net_id+' id', {}); +//} + +var sendRedirect = function (location) { + if (!location) { + throw new Error('no location'); + } + return function(req, res) { + res.redirect(location); + }; +}; + +var renderCrudView = function (tview) { + return function (req, res, next) { + var result = { + tview: tview, + } + res.json({ + data: result + }); + }; +} + +var renderCrudController = function (tview, thtmlPrefix, tapiPrefix) { + return function (req, res, next) { + res.set('Content-Type', 'text/javascript'); + res.render('node-ff-tcrud/angular/controller',{ + tview: tview, + thtmlPrefix: thtmlPrefix, + tapiPrefix: tapiPrefix, + }); + }; +} + +var renderCrudTemplate = function (tview,paction) { + return function (req, res, next) { + res.render('node-ff-tcrud/angular/'+paction+'/'+req.params.action,{ + tview: tview, + }); + }; +} + +var buildCrud = function (server,tcrud) { + + if (!tcrud.tenable || !tcrud.tmodel) { + logger.info('disabled server: '+tcrud.tid); + return; + } + + var tview = buildView.createTCrudView(tcrud /*, fetchCrudRoles()*/); + var model = mongoose.model( tcrud.tmodel ); + + // Export tdebug + var uriDebug = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json') + '/_debug/'; + var tcrudClone = clone(tcrud); + tcrudClone.tparent = null; // rm loop: tparent.tchilds[] = this + server.get(uriDebug + 'tview', renderCrudView(tview)); + server.get(uriDebug + 'tcrud', renderCrudView(tcrudClone)); + + if (_.contains(tview.tmeta.tserver.texports,'json')) { + + if (allowCrudType(tview,'tlist')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tlist')).Read() + .pipe(filterQueryList(model)) + .pipe(mcrud.findAll(model).stream()); + } + if (allowCrudType(tview,'tcreate')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tcreate')).Create() + .pipe(mcrud.createNew(model)); + } + if (allowCrudType(tview,'tread')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tread') + '/:_id').Read() + .pipe(mcrud.findOne(model)); + } + if (allowCrudType(tview,'tedit')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tedit') + '/:_id').Update() + .pipe(filterDataUpdate(model)) + .pipe(mcrud.updateOne (model)); + } + if (allowCrudType(tview,'tdelete')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tdelete') +'/:_id').Delete() + .pipe(mcrud.removeOne(model)); + } + if (allowCrudType(tview,'tcount')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tcount')).Read() + .pipe(filterQueryList(model)) + .pipe(mcrud.findAll(model).stream()); + } + if (allowCrudType(tview,'tverify')) { + ncrud.entity(buildView.createBaseApiUri(tview,'json','tverify') + '/:_id').Update() + .pipe(mcrud.findOne(model)); + } + } + + if (_.contains(tview.tmeta.tserver.texports,'xml')) { + if (allowCrudType(tview,'tlist')) { + ncrud.entity(buildView.createBaseApiUri(tview,'xml','tlist')).Read() + .pipe(filterQueryList(model)) + .pipe(mcrud.findAll(model).stream().exports({ xml: renderTemplateDataList(tview,'xml','text/xml') })); + } + if (allowCrudType(tview,'tcreate')) { + ncrud.entity(buildView.createBaseApiUri(tview,'xml','tcreate')).Create() + .pipe(mcrud.createNew(model)); + } + if (allowCrudType(tview,'tread')) { + ncrud.entity(buildView.createBaseApiUri(tview,'xml','tread') +'/:_id').Read() + .pipe(renderTemplateDataRead(tview,'xml','text/xml',model)); + } + if (allowCrudType(tview,'tedit')) { + ncrud.entity(buildView.createBaseApiUri(tview,'xml','tedit')+'/:_id').Update() + .pipe(filterDataUpdate(model)) + .pipe(mcrud.updateOne (model)); + } + if (allowCrudType(tview,'tdelete')) { + ncrud.entity(buildView.createBaseApiUri(tview,'xml','tdelete')+'/:_id').Delete() + .pipe(mcrud.removeOne (model)); + } + } + + if (_.contains(tview.tmeta.tserver.texports,'csv')) { + if (allowCrudType(tview,'tlist')) { + ncrud.entity(buildView.createBaseApiUri(tview,'csv','tlist')).Read() + .pipe(filterQueryList(model)) + .pipe(mcrud.findAll(model).stream().exports({ csv: renderTemplateDataList(tview,'csv','text/csv') })); + } + if (allowCrudType(tview,'tread')) { + ncrud.entity(buildView.createBaseApiUri(tview,'csv','tread') +'/:_id').Read() + .pipe(renderTemplateDataRead(tview,'csv','text/csv',model)); + } + } + + if (_.contains(tview.tmeta.tserver.texports,'rss')) { + if (allowCrudType(tview,'tlist')) { + ncrud.entity(buildView.createBaseApiUri(tview,'rss','tlist')).Read() + .pipe(mcrud.parseQuery() + .defaults({ limit: '10' }) + .maxes({ limit: 50 }) + ) + .pipe(mcrud.findAll(model) + .stream() + .exports({ rss: renderTemplateDataList(tview,'rss','text/xml') }) + ); + } + //.exports({ rss: exports.exportRss('todo',tview.xid,rssXNodeMap) }) + } + if (_.contains(tview.tmeta.tserver.texports,'angular')) { + + var uriPrefix = tcrud.tmeta.tserver.tslug + '/' + buildView.createBaseApiUri(tview,'angular'); + var thtmlPrefix = uriPrefix + '/' + tview.tmeta.texport.angular.thtml; + var tapiPrefix = tcrud.tmeta.tserver.tslug + '/' +buildView.createBaseApiUri(tview,'json'); + + //server.get('/ui/include/crud/:name/:action', XViewInclude.renderTemplateCrud); + //server.get('/ui/include/js/controller/:name', XViewInclude.renderCrudController); + + server.get(uriPrefix + '/thtml/crud/:action', renderCrudTemplate(tview,'thtml/crud/')); + server.get(uriPrefix + '/controller.js', renderCrudController(tview,thtmlPrefix,tapiPrefix)); + //server.get(uriPrefix + '/service.js', renderCrudService(tview)) + } +} + +function walkViews(server,tcrud) { + //logger.debug('walk views: '+tcrud.tid); + if (tcrud.tparent) { + buildCrud(server,tcrud); + } + for (var i = 0; i < tcrud.tchilds.length; i++) { + walkViews(server,tcrud.tchilds[i]); + } +} + +function buildCrudApi(server) { // todo add return function + + troot = server.get('ff_root_tcrud_view'); + walkViews(server,troot); + + server.use(exports.injectExportFormat(troot.tmeta.tserver.tslug)); + server.use(exports.bodyParserXml()); + ncrud.launch(server,{ + base: troot.tmeta.tserver.tslug, + cors: false, + timeoute: 10e3 + }); +} + +module.exports = buildCrudApi; diff --git a/lib-build/debug-server/node_lib/lib/factory-express.js b/lib-build/debug-server/node_lib/lib/factory-express.js new file mode 100644 index 0000000..24409e9 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/factory-express.js @@ -0,0 +1,138 @@ +var logger = require('winston').loggers.get('main'); +var clone = require('clone'); + +/* +var createRouter = function(server,path) { + var router = express.Router(); + router.path = path; + server.use(router.path,router); + return router; +} +*/ + +var walkRouteTree = function(result,stack,parent_path) { + if (parent_path == null) { + parent_path = ''; + } + stack.forEach(function(middleware) { + if (middleware.route){ + var path = parent_path + middleware.route.path; + for (var httpMethod in middleware.route.methods) { + var data = { + "uriPath": path, + "httpMethod": httpMethod + }; + result.push(data); + } + } else if (middleware.name === 'router') { + var pp = parent_path + middleware.handle.path; + walkRouteTree(result,middleware.handle.stack,pp); + } else { + //log.info('route err: '+JSON.stringify(middleware)); + } + }); + return result; +} + +exports.renderServerUptime = function(options) { + if (!options) { + options: {}; + } + var timeBoot = new Date().getTime(); + return function (req, res, next) { + var timeNow = new Date().getTime(); + var result = { + time_boot: timeBoot, + time_now: timeNow, + uptime: timeNow-timeBoot + } + res.json({ + data: result + }); + }; +}; + +exports.renderServerRoutes = function(server) { + if (!server) { + throw new Error('no server'); + } + return function (req, res, next) { + var routeList = server.get('ff_tcrud_route_list'); + if (!routeList) { + console.log('no routeList'); + routeList = []; + } + var reqGroups = req.query.groups; + var groupList = []; + if (reqGroups) { + groupList = reqGroups.split(','); + } + //console.log('groups: '+reqGroups); + var result = { + all: [], + }; + for (var i = 0; i < groupList.length; i++) { + var groupName = groupList[i].split('/').join('_'); + result[groupName] = []; + } + groupList.sort(function(a, b) { + return a.length < b.length; // longest first as we break on first hit + }); + + for (i = 0; i < routeList.length; i++) { + var route = routeList[i]; + var added = false; + for (var ii = 0; ii < groupList.length; ii++) { + if (route.uriPath.indexOf(groupList[ii]) > 0) { + var groupName = groupList[ii].split('/').join('_'); + result[groupName].push(route); + added = true; + break; + } + } + if (!added) { + result.all.push(route); + } + } + res.json({ + data: result + }); + }; +}; + +exports.buildServerRoutes = function(server) { // todo add return function + if (!server) { + throw new Error('no server'); + } + var result = walkRouteTree([],server._router.stack); + result.sort(function(a, b) { + return a.uriPath.localeCompare(b.uriPath); + }); + server.set('ff_tcrud_route_list',result); +}; + +exports.sendRedirect = function (location) { + if (!location) { + throw new Error('no location'); + } + return function(req, res) { + res.redirect(location); + }; +}; + +exports.renderTemplatePath = function (viewPath) { + if (!viewPath) { + viewPath = ''; + } + return function (req, res) { + res.locals.query = req.query; + //console.log('template query keys: '+Object.keys(req.query)); + var qi = req.url.indexOf('?'); + if (qi === -1) { + qi = req.url.length; + } + res.render(viewPath + req.url.substring(req.route.path.length-1, qi)); + }; +}; + +exports.buildCrudApi = require('./factory-express-api'); diff --git a/lib-build/debug-server/node_lib/lib/node-ff-tcrud.js b/lib-build/debug-server/node_lib/lib/node-ff-tcrud.js new file mode 100644 index 0000000..b7dfcb4 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/node-ff-tcrud.js @@ -0,0 +1,54 @@ +'use strict'; + +var tcrud = { + factory: { + express: require('./factory-express'), + }, + build: { + config: require('./build-config'), + view: require('./build-view'), + backend: { + mongoose: require('./build-backend-mongoose'), + }, + } +}; + +module.exports = tcrud; + +/* + + //app.use(function (req, res, next) {res.locals.c_var='test';next();}); + + +var http = require('http'); +var ejs = require('ejs'); +var fs = require('fs'); +http.createServer(function (req, res) { +res.writeHead(200, {'Content-Type': 'text/xml'}); +fs.readFile('placemark.ejs', 'utf8', function (err, template) { + +var content = ejs.render(template,{ + name:"test name", + description:"this is the description", + coordinates:"-122.0822035425683,37.42228990140251,0", + filename: __dirname + '/placemark.ejs' +}); + +res.write(content); +res.end() +}); +}).listen(8000); + + + var scripts = document.getElementsByTagName("script"); + var currentScriptPath = scripts[scripts.length-1].src; + console.log("currentScriptPath:"+currentScriptPath); + var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1); + console.log("baseUrl:"+baseUrl); + var bu2 = document.querySelector("script[src$='routes.js']"); + currentScriptPath = bu2.src; + console.log("bu2:"+bu2); + console.log("src:"+bu2.src); + baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1); + console.log("baseUrl:"+baseUrl); +*/ \ No newline at end of file diff --git a/lib-build/debug-server/node_lib/lib/tcrud-field.js b/lib-build/debug-server/node_lib/lib/tcrud-field.js new file mode 100644 index 0000000..13c4756 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/tcrud-field.js @@ -0,0 +1,110 @@ +var clone = require('clone'); + +var template = { + tid: null, + tname: null, + ttype: null, + tslug: null, + tvalidate: { + io: null, + }, + tlist: { + tenable: true, + ttext: null, + troles: [], + }, + tread: { + tenable: true, + ttext: null, + troles: [], + }, + tedit: { + tenable: true, + ttext: null, + troles: [], + }, + tcreate: { + tenable: true, + ttext: null, + troles: [], + }, +}; + +exports.autoFieldName = function (fieldKey,fieldName) { + if (fieldKey === undefined) { + throw new Error('no fieldKey'); + } + if (fieldName && fieldName.length !== 0) { + return fieldName; + } + var result = ''; + var names = fieldKey.split('_'); + for (var i in names) { + var name = names[i]; + if (name.length > 1) { + name = name.substring(0,1).toUpperCase() + name.substring(1); + } + result = result + name + ' '; + } + return result; +} + +var autoFieldEnable = function(tfield,type) { + if (type === undefined) { + throw new Error('no type'); + } + if (tfield[type] === undefined) { + tfield[type] = {}; + } + if (tfield[type].tenable !== undefined) { + return; + } + var fieldKey = tfield.tid; + var result = true; + if ('tlist' === type) { + var name = fieldKey.toLowerCase(); + if (fieldKey.indexOf('description') >= 0) { + result = false; + } else if (fieldKey.indexOf('comment') >= 0) { + result = false; + } + } + tfield[type].tenable = result; +} + + +exports.newInstance = function (id) { + var tfield = clone(template); + tfield.tid = id; + return tfield; +} + +exports.fillDefaults = function (tfield) { + if (tfield === undefined) { + throw new Error('no tfield'); + } + var tid = tfield.tid; + if (tid === undefined) { + throw new Error('no tfield.tid'); + } + if (tfield.tname === undefined) { + tfield.tname = exports.autoFieldName(tid); + } + if (tfield.tname === undefined) { + tfield.tname = exports.autoFieldName(tid); + } + if (tfield.tslug === undefined) { + tfield.tslug = tid; + } + if (tfield.ttype === undefined) { + tfield.ttype = 'text'; + } + if (tfield.tlist === undefined) { + tfield.tlist = {}; + } + autoFieldEnable(tfield,'tlist'); + autoFieldEnable(tfield,'tread'); + autoFieldEnable(tfield,'tedit'); + autoFieldEnable(tfield,'tcreate'); +} + diff --git a/lib-build/debug-server/node_lib/lib/tcrud-view.js b/lib-build/debug-server/node_lib/lib/tcrud-view.js new file mode 100644 index 0000000..2ad2b27 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/tcrud-view.js @@ -0,0 +1,204 @@ +var clone = require('clone'); +var tsurgeon = require('tree-surgeon'); + +var template = { + tid: null, + tname: null, + tplural: null, + tslug: null, + tcode: null, + tmodel: null, + tcount: { + ttext: null, + tenable: null, + texport: null, + }, + tlist: { + tfields: [], + ttext: null, + tlinks: null, + tenable: null, + texport: null, + }, + tread: { + tfields: [], + ttext: null, + tenable: null, + texport: null, + }, + tedit: { + tfields: [], + ttext: null, + tenable: null, + texport: null, + }, + tcreate: { + tfields: [], + ttext: null, + tenable: null, + texport: null, + }, + tdelete: { + ttext: null, + tenable: null, + texport: null, + }, + tverify: { + ttext: null, + tenable: null, + texport: null, + }, + tmeta: { + tfields: null, + tvalidate: null, + tserver: null, + texport: null, + }, +}; + +function copyByTemplate(prefix,objectDest,objectSrc,copyTemplate) { + var keys = Object.keys(copyTemplate); + var result = []; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var value = objectSrc[key]; + if (!value) { + //console.log(prefix+'.'+key+' src object has no value.'); + continue; // no src value + } + var templateValue = copyTemplate[key]; + if (templateValue === null) { + if (objectDest[key] !== null) { + //console.log(prefix+'.'+key+' has own value: '+objectDest[key]); + continue; + } else { + //console.log(prefix+'.'+key+' copy value: '+value); + objectDest[key] = clone(value); + } + } else { + //console.log(prefix+'.'+key+' going deeper'); + copyByTemplate(prefix+'.'+key,objectDest[key],value,templateValue) + } + } +} + +function addFilteredFields(tview,type,tcrud) { + result = []; + var keys = Object.keys(tcrud.tmeta.tfields); + var result = []; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var tfield = tcrud.tmeta.tfields[key]; + if (tfield[type]) { + if (!tfield[type].tenable) { + //console.log('------------- type: ' + type + ' key: ' + key + ' res: ' + tfield[type].tenable) + continue; + } + } + result.push(key); // default is true.. + } + tview[type].tfields = result; +} + +function forceLookupKeySimple() { + var low = 100000; + var high = 999999; + return Math.floor(Math.random() * (high - low + 1) + low).toString(16).toUpperCase(); +} + +function forceLookupTFields(tview) { + var keys = Object.keys(tview.tmeta.tfields); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var keyNew = 'FTL_' +forceLookupKeySimple() + '_' + key.substring(key.length/3,key.length/3*2); // no....its; Force template lookup + var tfield = tview.tmeta.tfields[key]; + tview.tmeta.tfields[key] = undefined; + tview.tmeta.tfields[keyNew] = tfield; + + var ckeys = Object.keys(tview); + for (var ii = 0; ii < ckeys.length; ii++) { + var ckey = ckeys[ii]; + if (ckey === 'tmeta') { + continue; + } + var obj = tview[ckey]; + if (obj && obj.tfields) { + var tfieldsNew = []; + for (var iii = 0; iii < obj.tfields.length; iii++) { + var tkey = obj.tfields[iii]; + if (tkey === key) { + tfieldsNew.push(keyNew); + } else { + tfieldsNew.push(tkey); + } + } + obj.tfields = tfieldsNew; + } + } + } +} + +function formatValuePart(value,replaceChar,splitChar,partFn) { + var result = ''; + var parts = value.split(splitChar); + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + if (part.length > 1) { + result += partFn(part); + } else { + result += part; + } + if (i < parts.length - 1) { + result += replaceChar; + } + } + return result; +} + +function formatValue(value,removeChars,replaceChar,partFn) { + for (var i = 0; i < removeChars.length; i++) { + value = formatValuePart(value,replaceChar,removeChars[i],partFn); + } + return value; +} + +exports.newInstance = function (tcrud) { + var tview = clone(template); + var tid = tcrud.tid; + tview.tid = tid; + + copyByTemplate('tview',tview,tcrud,template); + + //console.info('TCrudView.tslug: '+tview.tslug); + + if (!tview.tslug) { + tview.tslug = formatValue(tid,['.',',','/','=','&','?',' '],'', function (part) { + return part; // todo use fully correct uri removeal and escaping. + }) + //console.info('TCrudView.tslug auto: '+tview.tslug); + } + if (!tview.tname) { + tview.tname = formatValue(tid,['_','-','.',','],' ', function (part) { + return part.substring(0,1).toUpperCase()+part.substring(1).toLowerCase(); + }); + } + if (!tview.tcode) { + tview.tcode = formatValue(tid,[' ','_','-','.',','],'',function (part) { + return part.toLowerCase(); + }); + } + + if (!tview.tplural) { + tview.tplural = tview.tname + 's'; + } + + addFilteredFields(tview,'tlist',tcrud); + addFilteredFields(tview,'tread',tcrud); + addFilteredFields(tview,'tedit',tcrud); + addFilteredFields(tview,'tcreate',tcrud); + + forceLookupTFields(tview); + + return tview; +} + diff --git a/lib-build/debug-server/node_lib/lib/tcrud.js b/lib-build/debug-server/node_lib/lib/tcrud.js new file mode 100644 index 0000000..80d1488 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/tcrud.js @@ -0,0 +1,230 @@ +var clone = require('clone'); + +var template = { + tid: null, + tname: null, + tplural: null, + tslug: null, + tmodel: null, + tenable: true, + tparam: null, + troles: [], + tparent: null, + tchilds: [], + tlist: { + tenable: true, + ttext: 'Listing of ..', + troles: [], + tserver: { + tpipe: { + query: { + defaults: { limit: '10' }, + maxes: { limit: 50 }, + }, + }, + }, + texport: { + json: { + tslug: 'list', + }, + xml: { + tslug: 'list', + }, + rss: { + tslug: 'list', + }, + csv: { + tslug: 'list', + }, + angular: { + tslug: 'list', + thtml: 'crud/list', + tcontroller: { + prefix: 'tcrudAuto', + postfix: 'ListCntr', + argu: '$scope, $http, $location, $routeParams', + }, + tlinks: { + 'DataTODO':'/ui/XNodeData/list/XNode/{{row.net_id}}/{{row.net_id}}', + }, + }, + }, + }, + tcreate: { + tenable: true, + ttext: null, + troles: [], + texport: { + json: { + tslug: 'create', + }, + xml: { + tslug: 'create', + }, + angular: { + tslug: 'create', + thtml: 'crud/create', + tcontroller: { + prefix: 'tcrudAuto', + postfix: 'CreateCntr', + argu: '$scope, $http, $location, $routeParams', + }, + }, + }, + }, + tedit: { + tenable: true, + ttext: null, + troles: [], + texport: { + json: { + tslug: 'edit', + }, + xml: { + tslug: 'edit', + }, + angular: { + tslug: 'edit', + thtml: 'crud/edit', + tcontroller: { + prefix: 'tcrudAuto', + postfix: 'EditCntr', + argu: '$scope, $http, $location, $routeParams', + }, + }, + }, + }, + tread: { + tenable: true, + ttext: null, + troles: [], + tslug: '', + texport: { + json: { + tslug: 'read', + }, + xml: { + tslug: 'read', + }, + csv: { + tslug: 'read', + }, + angular: { + tslug: 'read', + thtml: 'crud/read', + troute: { + + }, + tcontroller: { + prefix: 'tcrudAuto', + postfix: 'ReadCntr', + argu: '$scope, $http, $location, $routeParams', + }, + }, + }, + }, + tdelete: { + tenable: true, + ttext: null, + troles: [], + texport: { + json: { + tslug: 'delete', + }, + xml: { + tslug: 'delete', + }, + angular: { + tslug: 'delete', + thtml: 'crud/delete', + tcontroller: { + prefix: 'tcrudAuto', + postfix: 'DeleteCntr', + argu: '$scope, $http, $location, $routeParams', + }, + }, + }, + }, + tcount: { + tenable: true, + ttext: 'Count records', + troles: [], + texport: { + json: { + tslug: 'list-count', + }, + xml: { + tslug: 'list-count', + }, + csv: { + tslug: 'list-count', + }, + }, + }, + tverify: { + tenable: true, + ttext: 'Verify data', + troles: [], + texport: { + json: { + tslug: 'verify', + }, + xml: { + tslug: 'verify', + }, + csv: { + tslug: 'verify', + }, + }, + }, + ttemplate: { + tid: '_id', + tname: '_id', + tdescription: '_id', + }, + tmeta: { + troles: [], + tfields: {}, + tvalidate: { + io: { 'admin_role': 'object|properties[test]' }, + }, + tserver: { + thost: 'http://localhost:8080/', + tslug: '/api', + tpopfix: true, + texports: ['json','xml','csv','rss','angular'], + }, + texport: { + json: { + tslug: 'json', + }, + xml: { + tslug: 'xml', + }, + csv: { + tslug: 'csv', + }, + rss: { + tslug: 'rss', + itemTitle: '$data._id', + itemLink: '$siteLink/ui/$modelUri/read/$[\'data._id\']', + itemDate: '', + itemDescription: '', + //itemFields: '', + }, + angular: { + tslug: 'angular', + tbase: '/ui', + thtml: 'thtml', + }, + }, + }, +}; + +exports.newInstance = function (tid) { + var tcrud = clone(template); + tcrud.tid = tid; + tcrud.tslug = tid; // view fills more defaults. + return tcrud; +} + diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-action-none.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-action-none.ejs new file mode 100644 index 0000000..983c257 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-action-none.ejs @@ -0,0 +1,8 @@ + + $scope.<%= taction %>None = function () { + <% if (tview.tlist) { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>'); + <% } else { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/'); + <% } %> + } diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-route.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-route.ejs new file mode 100644 index 0000000..865dda3 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller-route.ejs @@ -0,0 +1,5 @@ + + $routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview[taction].texport.angular.tslug %><%= routeEnd %>', { + templateUrl: '<%= thtmlPrefix %>/<%= tview[taction].texport.angular.thtml %>', + controller: <%= tview[taction].texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview[taction].texport.angular.tcontroller.postfix %> + }); \ No newline at end of file diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller.ejs new file mode 100644 index 0000000..c0745f8 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/controller.ejs @@ -0,0 +1,99 @@ +'use strict'; + +// Auto generated controller mapping for: <%= tview.tid %> + + +crudRouteInit.push(<%= tview.tcode %>Init); + +function <%= tview.tcode %>Init($routeProvider, $locationProvider) { +<% if (tview.tlist) { %> + $routeProvider.when('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/', { + redirectTo: '<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>' + }); + <%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tlist', routeEnd: ''}); %> +<% } %> +<% if (tview.tcreate) { %> + <%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tcreate', routeEnd: ''}); %> +<% } %> +<% if (tview.tedit) { %> + <%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tedit', routeEnd: '/:id'}); %> +<% } %> +<% if (tview.tread) { %> + <%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tread', routeEnd: '/:id'}); %> +<% } %> +<% if (tview.tdelete) { %> + <%- include('controller-route', {tview: tview,thtmlPrefix:thtmlPrefix,taction: 'tdelete', routeEnd: '/:id'}); %> +<% } %> +} + +<% if (tview.tlist) { %> +function <%= tview.tlist.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tlist.texport.angular.tcontroller.postfix %>(<%= tview.tlist.texport.angular.tcontroller.argu %>) { + $http.get('<%= tapiPrefix %>/<%= tview.tlist.texport.json.tslug %>').success(function(data, status, headers, config) { + $scope.data = data.data; + }); +} +<% } %> + +<% if (tview.tcreate) { %> +function <%= tview.tcreate.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tcreate.texport.angular.tcontroller.postfix %>(<%= tview.tcreate.texport.angular.tcontroller.argu %>) { + $scope.data = {}; + $scope.tcreateData = function () { + $http.post('<%= tapiPrefix %>/<%= tview.tcreate.texport.json.tslug %>', $scope.data).success(function(data) { + <% if (tview.tlist) { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>'); + <% } else { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/'); + <% } %> + }); + } + <%- include('controller-action-none', {tview: tview,taction: 'tcreate'}); %> +} +<% } %> + +<% if (tview.tread) { %> +function <%= tview.tread.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tread.texport.angular.tcontroller.postfix %>(<%= tview.tread.texport.angular.tcontroller.argu %>) { + $scope.data = {}; + $http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) { + $scope.data = data.data; + }); + <%- include('controller-action-none', {tview: tview,taction: 'tread'}); %> +} +<% } %> + +<% if (tview.tedit) { %> +function <%= tview.tedit.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tedit.texport.angular.tcontroller.postfix %>(<%= tview.tedit.texport.angular.tcontroller.argu %>) { + $scope.data = {}; + $http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) { + $scope.data = data.data; + }); + $scope.teditData = function () { + $http.put('<%= tapiPrefix %>/<%= tview.tedit.texport.json.tslug %>/' + $routeParams.id, $scope.data ).success(function(data) { + <% if (tview.tread) { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tread.texport.angular.tslug %>/' + $routeParams.id); + <% } else { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/'); + <% } %> + }); + } + <%- include('controller-action-none', {tview: tview,taction: 'tedit'}); %> +} +<% } %> + +<% if (tview.tdelete) { %> +function <%= tview.tdelete.texport.angular.tcontroller.prefix %><%= tview.tcode %><%= tview.tdelete.texport.angular.tcontroller.postfix %>(<%= tview.tdelete.texport.angular.tcontroller.argu %>) { + $scope.data = {}; + $http.get('<%= tapiPrefix %>/<%= tview.tread.texport.json.tslug %>/' + $routeParams.id).success(function(data) { + $scope.data = data.data; + }); + $scope.tdeleteData = function () { + $http.delete('<%= tapiPrefix %>/<%= tview.tdelete.texport.json.tslug %>/'+ $routeParams.id, $scope.data).success(function(data) { + <% if (tview.tlist) { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/<%= tview.tslug %>/<%= tview.tlist.texport.angular.tslug %>'); + <% } else { %> + $location.url('<%= tview.tmeta.texport.angular.tbase %>/'); + <% } %> + }); + } + <%- include('controller-action-none', {tview: tview,taction: 'tdelete'}); %> +} +<% } %> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs new file mode 100644 index 0000000..e620b29 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/create.ejs @@ -0,0 +1,20 @@ +

Create <%= tview.tname %>

+
+
+
+ <% tview.tedit.tfields.forEach(function (fieldKey) { %> +
+ + +
+ <% }) %> + + +
+
+
+
+ + diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/delete.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/delete.ejs new file mode 100644 index 0000000..8e7bdc6 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/delete.ejs @@ -0,0 +1,6 @@ +

Delete <%= tview.tname %>

+
+

Are you sure you want to delete this <%= tview.tname %> {{data._id}} ?

+ | - + +
diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs new file mode 100644 index 0000000..c9a6731 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/edit.ejs @@ -0,0 +1,16 @@ + +

Edit <%= tview.tname %>

+
+
+
+ <% tview.tedit.tfields.forEach(function (fieldKey) { %> +
+ + +
+ <% }) %> + + +
+
+
diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs new file mode 100644 index 0000000..b220897 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/list.ejs @@ -0,0 +1,50 @@ + +

There are {{data.length}} <%= tview.tplural %>

+ +<% if (tview.tcreate) { %> +

+ Create New +

+<% } %> +
+ + + + <% if (tview.tread) { %><% } %> + <% if (tview.tedit) { %><% } %> + <% if (tview.tdelete) { %><% } %> + <% tview.tlist.tfields.forEach(function (fieldKey) { %> + + <% }) %> + + + + + <% if (tview.tread) { %> + + <% } %> + <% if (tview.tedit) { %> + + <% } %> + <% if (tview.tdelete) { %> + + <% } %> + <% tview.tlist.tfields.forEach(function (fieldKey) { %> + + <% }) %> + + +
OpenEditDelete<%= tview.tmeta.tfields[fieldKey].tname %>
+ Read + + Edit + + Delete + {{row.<%= tview.tmeta.tfields[fieldKey].tid %>}}
+
+<% if (tview.tcreate) { %> +

+ Create New +

+<% } %> + diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/read.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/read.ejs new file mode 100644 index 0000000..0155dc5 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/angular/thtml/crud/read.ejs @@ -0,0 +1,19 @@ +
+

{{data._id}}

+ <% if (tview.tedit) { %> +

+ Edit +

+ <% } %> + <% if (tview.tdelete) { %> +

+ Delete +

+ <% } %> + <% tview.tread.tfields.forEach(function (fieldKey) { %> +

<%= tview.tmeta.tfields[fieldKey].tname %>: {{data.<%= tview.tmeta.tfields[fieldKey].tid %>}}

+ <% }) %> +

+ +

+ \ No newline at end of file diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-footer.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-footer.ejs new file mode 100644 index 0000000..cdea42d --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-footer.ejs @@ -0,0 +1 @@ +# END diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-header.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-header.ejs new file mode 100644 index 0000000..cbabfe7 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-header.ejs @@ -0,0 +1 @@ +# CSV: <%= tview.tid %> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-record.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-record.ejs new file mode 100644 index 0000000..39a2ca8 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/list-record.ejs @@ -0,0 +1 @@ +<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/read-record.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/read-record.ejs new file mode 100644 index 0000000..39a2ca8 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/csv/read-record.ejs @@ -0,0 +1 @@ +<% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %><%= record[tfield.tid] %>,<% }) %> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-footer.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-footer.ejs new file mode 100644 index 0000000..29f01a4 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-footer.ejs @@ -0,0 +1 @@ +List> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-header.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-header.ejs new file mode 100644 index 0000000..21e1b5d --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-header.ejs @@ -0,0 +1,2 @@ + +<<%= tview.tid %>List> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-record.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-record.ejs new file mode 100644 index 0000000..5f59b36 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/rss/list-record.ejs @@ -0,0 +1,5 @@ + <<%= tview.tid %>> + <% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %> + <<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %>> + <% }) %> + > \ No newline at end of file diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-footer.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-footer.ejs new file mode 100644 index 0000000..1a598fc --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-footer.ejs @@ -0,0 +1,2 @@ + List> + diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-header.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-header.ejs new file mode 100644 index 0000000..e6b4381 --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-header.ejs @@ -0,0 +1,3 @@ + + + <<%= tview.tid %>List> diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-record.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-record.ejs new file mode 100644 index 0000000..49683de --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/list-record.ejs @@ -0,0 +1,5 @@ + <<%= tview.tid %>> + <% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %> + <<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %>> + <% }) %> + > \ No newline at end of file diff --git a/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/read-record.ejs b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/read-record.ejs new file mode 100644 index 0000000..5b1fc6d --- /dev/null +++ b/lib-build/debug-server/node_lib/lib/www_views/node-ff-tcrud/xml/read-record.ejs @@ -0,0 +1,8 @@ + + + <<%= tview.tid %>> + <% Object.keys(tview.tlist.tfields).forEach(function (tfieldKey) {var tfield = tview.tlist.tfields[tfieldKey]; %> + <<%= tfieldKey %> type="<%= tfield.type %>"><%= record[tfield.tid] %>> + <% }) %> + > + diff --git a/lib-build/debug-server/node_lib/model/xnode-base-command.js b/lib-build/debug-server/node_lib/model/xnode-base-command.js new file mode 100644 index 0000000..f24e76a --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xnode-base-command.js @@ -0,0 +1,75 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + net_id: { + type: String, + index: { unique: false }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + command: { + type: String, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + insert_ip: { + type: String, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + insert_date: { + type: Date, + default: Date.now, + tfield: { + tlist: { tenable: false }, + }, + }, + send_date: { + type: Date + }, + done_date: { + type: Date + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findByNetIdLimit10: function (net_id, callback) { + logger.debug(modelBackend+'.findByNetId net_id='+net_id); + this.find({net_id:net_id}).sort('-insert_date').limit(10).exec(callback); + }, + findOpenByNetId: function (net_id, callback) { + logger.debug(modelBackend+'.findOpenByNetId net_id='+net_id); + this.find({net_id:net_id}).where('send_date',null).sort('insert_date').limit(1).exec(callback); + }, + findOpenCommandLimit5: function (callback) { + logger.debug(modelBackend+'.findOpenCommands'); + var dateLastHour = new Date(new Date().getTime() - 30*60*1000); // soft limit on long open errors. + this.find({insert_date: { $gt: dateLastHour}}).where('send_date',null).sort('insert_date').limit(5).exec(callback); + }, + findSendCommandLimit5: function (callback) { + logger.debug(modelBackend+'.findSendCommands'); + var dateLastHour = new Date(new Date().getTime() - 60*60*1000); + this.find({send_date: { $gt: dateLastHour}}).sort('-insert_date').limit(5).exec(callback); + }, + insert: function (net_id,command,insert_ip, next) { + var xcmd = new this(); + xcmd.net_id = net_id; + xcmd.command = command; + xcmd.insert_ip = insert_ip; + xcmd.save(function(err,xcmd) { + if (err) { return next(err); } + logger.debug(modelBackend+'.insert _id='+xcmd._id+' net_id='+xcmd.net_id); + }); + } +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xnode-base.js b/lib-build/debug-server/node_lib/model/xnode-base.js new file mode 100644 index 0000000..5cea92f --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xnode-base.js @@ -0,0 +1,98 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + net_id: { + type: String, + index: { unique: true }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + net_key: { + type: String, + tfield: { + tvalidate: { io: 'string' }, + tlist: { tenable: false }, + }, + }, + net_mac: { + type: String, + tcrud: { + tname: 'Net MAC', + tlist: { tenable: false }, + } + }, + rf_key: { + type: String, + tfield: { + tname: 'RF Key', + tlist: { tenable: false }, + } + }, + init_index: { + type: Number, + tfield: { + tlist: { tenable: false }, + } + }, + + ping_counter: { + type: Number, + default: 0, + tfield: { + tname: 'Ping #' + } + }, + ping_last_date: { + type: Date, + index: { unique: true, sparse: true } + }, + ping_rtt: { + type: Number, + default: 0, + tfield: { + tname: 'Ping RTT' + } + }, + + changed_date: { + type: Date, + default: Date.now, + tfield: { + tlist: { tenable: false }, + } + }, + created_date: { + type: Date, + default: Date.now, + tfield: { + tlist: { tenable: false }, + } + }, + created_ip: { + type: String, + tfield: { + tvalidate: { io: 'string' }, + }, + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findOneByNetId: function (net_id, callback) { + logger.debug(modelBackend+'.findByNetId net_id='+net_id); + this.findOne({net_id:net_id}).exec(callback); + }, + findLastPingLimit5: function (callback) { + var dateLastHour = new Date(new Date().getTime() - 60*60*1000); + logger.debug(modelBackend+'.findLastPinged lastDate: '+dateLastHour); + this.find({}).where('ping_last_date').gt(dateLastHour).sort('-ping_last_date').limit(5).exec(callback); + } +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xnode-data-value.js b/lib-build/debug-server/node_lib/model/xnode-data-value.js new file mode 100644 index 0000000..9bf7354 --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xnode-data-value.js @@ -0,0 +1,59 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + /* + uuid: { + type: String, + index: { unique: true }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + */ + node_id: { + type: Number, + index: { unique: false }, + tfield: { + tvalidate: { io: 'number' }, + }, + }, + insert_date: { + type: Date, + index: { unique: false }, + default: Date.now, + }, + name: { + type: String, + index: { unique: false }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + value: { + type: String, + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findLastAddedLimit5: function (callback) { + logger.debug(modelBackend+'.findLastAddedLimit5'); + this.find({}).sort('-insert_date').limit(5).exec(callback); + }, + findByNetIdAndNodeId: function (net_id,node_id, callback) { + logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id); + this + .aggregate({ $match: { net_id:net_id ,node_id:node_id }}) + .group({ _id: "$name", value: { $min : "$value" } }) + .sort("_id") + .exec(callback); + //this.find({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback); + } +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xnode-data.js b/lib-build/debug-server/node_lib/model/xnode-data.js new file mode 100644 index 0000000..f3b72c9 --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xnode-data.js @@ -0,0 +1,53 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + //node : {type : Schema.ObjectId, ref : 'XNode'} + node_id: { + type: Number, + index: { unique: false }, + tfield: { + tvalidate: { io: 'number' }, + }, + }, + data_raw: { + type: String, + tfield: { + ttype: 'textarea', + tvalidate: { io: 'string' }, + tlist: { tenable: false }, + } + }, + data_text: { + type: String, + tfield: { + tvalidate: { io: 'number' }, + ttype: 'textarea', + } + }, + remote_ip: { + type: String, + tfield: { + tname: 'Remote IP', + tvalidate: { io: 'ip_address' }, + tlist: { tenable: false }, + } + }, + insert_date: { + type: Date, default: Date.now, + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findLastLimit5: function (callback) { + logger.debug(modelBackend+'.findLastLimit5'); + this.find({}).sort('-insert_date').limit(5).exec(callback); + } +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xnode.js b/lib-build/debug-server/node_lib/model/xnode.js new file mode 100644 index 0000000..7845d7c --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xnode.js @@ -0,0 +1,98 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + net_id: { + type: String, + index: { unique: false }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + node_id: { + type: Number, + index: { unique: false }, + tfield: { + tvalidate: { io: 'number' }, + }, + }, + insert_date: { + type: Date, + index: { unique: false }, + default: Date.now, + tfield: { + tlist: { tenable: false }, + } + }, + info_date: { + type: Date, + tfield: { + tlist: { tenable: false }, + } + }, + + name: { + type: String, + }, + description: { + type: String, + tfield: { + tlist: { tenable: false }, + } + }, + gps_latitude: { + type: Number, + tfield: { + tname: 'Latitude', + tlist: { tenable: false }, + } + }, + gps_longitude: { + type: Number, + tfield: { + tname: 'Longitude', + tlist: { tenable: false }, + } + }, + + rx_bytes: { + type: Number, + default: 0, + tfield: { + tname: 'RX bytes' + } + }, + rx_requests: { + type: Number, + default: 0, + tfield: { + tname: 'RX req#' + } + }, + rx_date: { + type: Date, + index: { unique: false }, + default: Date.now, + tfield: { + tname: 'RX Date' + } + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findByNetId: function (net_id, callback) { + logger.debug(modelBackend+'.findByNetId net_id='+net_id+""); + this.find({net_id:net_id}).sort('insert_date').exec(callback); + }, + findByNetIdAndNodeId: function (net_id,node_id, callback) { + logger.debug(modelBackend+'.findByNetIdAndNodeId net_id='+net_id+' node_id='+node_id); + this.findOne({net_id:net_id,node_id:node_id}).sort('insert_date').exec(callback); + } +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xsystem-session.js b/lib-build/debug-server/node_lib/model/xsystem-session.js new file mode 100644 index 0000000..57b203b --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xsystem-session.js @@ -0,0 +1,35 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + _id: { + type: String, + tfield: { + tname: 'SID', + ttype: 'textarea' + } + }, + session: { + type: String, + tfield: { + ttype: 'textarea' + } + }, + expires: { + type: Date, + }, +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findLastChangedLimit5: function (callback) { + logger.debug(modelBackend+'.findLastChangedLimit5'); + this.find({}).sort('-changed_date').limit(5).exec(callback); + }, +}); + +module.exports = mongoose.model(modelName, modelSchema, modelBackend); diff --git a/lib-build/debug-server/node_lib/model/xsystem-state.js b/lib-build/debug-server/node_lib/model/xsystem-state.js new file mode 100644 index 0000000..75b882a --- /dev/null +++ b/lib-build/debug-server/node_lib/model/xsystem-state.js @@ -0,0 +1,146 @@ +var logger = require('winston').loggers.get('main'); +var mongoose = require('mongoose'); +var tmongoose = require('../lib/node-ff-tcrud').build.backend.mongoose; +var modelName = __filename.split('/').pop().split('.')[0]; +var modelBackend = modelName.split('-').join('_'); + +var modelMeta = { + name: { + type: String, + trim: true, + index: { unique: true }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + type: { + type: String, + trim: true, + index: { unique: false }, + tfield: { + tvalidate: { io: 'string' }, + }, + }, + value: { + type: String, + trim: true, + tfield: { + xtype: 'textarea', + tvalidate: { io: 'string' }, + }, + }, + description: { + type: String, + trim: true, + tfield: { + ttype: 'textarea', + tvalidate: { io: 'string' }, + }, + }, + changed_date: { + type: Date, + default: Date.now, + tfield: { + tlist: { tenable: false }, + }, + }, + created_date: { + type: Date, + default: Date.now, + tfield: { + tlist: { tenable: false }, + }, + } +}; + +var modelSchema = new mongoose.Schema(modelMeta); + +modelSchema.statics = tmongoose.buildStaticsModelValidated(modelMeta,modelSchema, { + findLastChangedLimit5: function (callback) { + logger.debug(modelBackend+'.findLastChangedLimit5'); + this.find({}).sort('-changed_date').limit(5).exec(callback); + }, + findOneByName: function (name, callback) { + logger.debug(modelBackend+'.findByName name='+name); + this.findOne({name:name}).exec(callback); + }, + ensureExcists: function (name, type, defaultValue, description, callback) { + this.findOneByName(name, function(err, xprop) { + if (err) { + callback(err); + return; + } + if (xprop == null) { + logger.debug(modelBackend+'.getByName create name='+name+' defaultValue='+defaultValue); + var model = mongoose.model(modelName); + xprop = new model(); + xprop.name = name; + xprop.type = type; + xprop.value = defaultValue; + xprop.description = description; + xprop.save(function(err,xprop) { + if (callback) { + callback(err, xprop); + } + }); + } else { + logger.debug(modelBackend+'.getByName fetched name='+name); + if (callback) { + callback(null, xprop); + } + } + }); + }, + setByName: function (name, value, callback) { + this.findOneByName(name, function(err, xprop) { + if (err) { throw err } + logger.debug(modelBackend+'.setByName name='+name+' valueNew='+value+' valueOld='+xprop.value); + xprop.value = value; + xprop.save(function(err) { + callback(err, xprop); + }); + }); + }, + incByName: function (name, callback) { + this.findOneByName(name, function(err, xprop) { + if (err) { throw err } + xprop.value++; + logger.debug(modelBackend+'.incByName name='+name+' value='+xprop.value); + xprop.save(function(err) { + callback(err, xprop); + }); + }); + }, + incHexByName: function (name, callback) { + this.findOneByName(name, function(err, xprop) { + // DIY inc per 8 chars as JS goes to ~14chars before zering the rest. + var v = xprop.value; + var r = ''; + var inc = true; + for (var i=0;ili { + display: inline-block; + float: left; +} + +.top-nav>li>a { + padding-top: 15px; + padding-bottom: 15px; + line-height: 20px; + color: #999; +} + +.top-nav>li>a:hover, +.top-nav>li>a:focus, +.top-nav>.open>a, +.top-nav>.open>a:hover, +.top-nav>.open>a:focus { + color: #fff; + background-color: #000; +} + +.top-nav>.open>.dropdown-menu { + float: left; + position: absolute; + margin-top: 0; + border: 1px solid rgba(0,0,0,.15); + border-top-left-radius: 0; + border-top-right-radius: 0; + background-color: #fff; + -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175); + box-shadow: 0 6px 12px rgba(0,0,0,.175); +} + +.top-nav>.open>.dropdown-menu>li>a { + white-space: normal; +} + +ul.message-dropdown { + padding: 0; + max-height: 250px; + overflow-x: hidden; + overflow-y: auto; +} + +li.message-preview { + width: 275px; + border-bottom: 1px solid rgba(0,0,0,.15); +} + +li.message-preview>a { + padding-top: 15px; + padding-bottom: 15px; +} + +li.message-footer { + margin: 5px 0; +} + +ul.alert-dropdown { + width: 200px; +} + +/* Side Navigation */ + +@media(min-width:768px) { + .side-nav { + position: fixed; + top: 51px; + left: 225px; + width: 225px; + margin-left: -225px; + border: none; + border-radius: 0; + overflow-y: auto; + background-color: #222; + } + + .side-nav>li>a { + width: 225px; + } + + .side-nav li a:hover, + .side-nav li a:focus { + outline: none; + background-color: #000 !important; + } +} + +.side-nav>li>ul { + padding: 0; +} + +.side-nav>li>ul>li>a { + display: block; + padding: 10px 15px 10px 38px; + text-decoration: none; + color: #999; +} + +.side-nav>li>ul>li>a:hover { + color: #fff; +} + +.huge { + font-size: 40px; +} diff --git a/lib-build/debug-server/www_static/css/flot.css b/lib-build/debug-server/www_static/css/flot.css new file mode 100644 index 0000000..6ecdaeb --- /dev/null +++ b/lib-build/debug-server/www_static/css/flot.css @@ -0,0 +1,11 @@ + +.flot-chart { + display: block; + height: 400px; +} + +.flot-chart-content { + width: 100%; + height: 100%; +} + diff --git a/lib-build/debug-server/www_static/css/panel.css b/lib-build/debug-server/www_static/css/panel.css new file mode 100644 index 0000000..7e97652 --- /dev/null +++ b/lib-build/debug-server/www_static/css/panel.css @@ -0,0 +1,56 @@ + +.panel-green { + border-color: #5cb85c; +} + +.panel-green .panel-heading { + border-color: #5cb85c; + color: #fff; + background-color: #5cb85c; +} + +.panel-green a { + color: #5cb85c; +} + +.panel-green a:hover { + color: #3d8b3d; +} + +.panel-red { + border-color: #d9534f; +} + +.panel-red .panel-heading { + border-color: #d9534f; + color: #fff; + background-color: #d9534f; +} + +.panel-red a { + color: #d9534f; +} + +.panel-red a:hover { + color: #b52b27; +} + +.panel-yellow { + border-color: #f0ad4e; +} + +.panel-yellow .panel-heading { + border-color: #f0ad4e; + color: #fff; + background-color: #f0ad4e; +} + +.panel-yellow a { + color: #f0ad4e; +} + +.panel-yellow a:hover { + color: #df8a13; +} + + diff --git a/lib-build/debug-server/www_static/css/style.css b/lib-build/debug-server/www_static/css/style.css new file mode 100644 index 0000000..d610696 --- /dev/null +++ b/lib-build/debug-server/www_static/css/style.css @@ -0,0 +1,54 @@ + +#wrapper { + padding-right: 0px; + padding-left: 0px; +} + +.side-nav { + right: 0px; + left: 0px; +} + +.btn { + margin-right: 10px; +} + +.navbar-footer { + margin-left: 45%; +} + +.navbar-toggle { + display: none; +} + +.navbar-brand { + background-color: #2CABE1; +} + +.navbar-inverse .navbar-brand { + color: #FFFFFF; +} + +.navbar-inverse .navbar-brand:focus { + outline: none; +} + +.navbar-inverse .navbar-brand:hover { + background-color: #FF9A28; + outline: none; +} + +.navbar-inverse { + background-color: #2CABE1; +} + +#menuLogo { + position: absolute; + top: 47px; + right: 0px; + background: url("../img/xensit-sm.png") 50% 0px no-repeat transparent !important; + height: 77px; + width: 212px; +} + + diff --git a/lib-build/debug-server/www_static/img/xensit-sm.png b/lib-build/debug-server/www_static/img/xensit-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..7fafc38f794db23ea97ca8002e4c69da67bfdb3f GIT binary patch literal 7425 zcmZu$byQT(`(8jmlZ;(odg`ud-6y(xFSlr< z-&I7muYsz7+y9=TuJZqSNIca|z3;x5{jcCD^W^&9brSo4wA6@~NGWLf$#zI4LIHqB z$spC22L21!{GedE>9(_;MnCGW@lAZO9Q^n1bEJod`(0LUJqijEq)*HAeAji{Ib>FI zy6GZ3)G}~dGu`6ctl*55*`w0aJ>@`OLvTjsRnu#PX_=%^{AfZd_0#3;E78XE z`Sh;z{Dg=+ztBP*#d+~YN5`LL+ood<3S*7zsmDSxY~-R=a0hu8;k?x!FfkaeN*5DHHgN`0{Fy*fK)-`F^QjxUsj z(ylON|L86MtK;~I_M7S{CtO=kO{$&4X&?IpU0Vn&W^asKJR#>aoT z&)&3rWHfQ79rG-;PPYxi>pv!qNf61v2NKwYk1wxKEgy_S>$%MLwb0X#rTe8^fi3gN zH}o$~{z)m5)7jo7=UoksAcs^e0SALP|0k$&OaV70#GMUk*zS?^-!=&}Hi zG3(n+0+eZwr|poJVIP#*u0$U|B7iM3V@VtNvy+s-#b#3xQEH^F`-D8q;Q8Ae7eWNA zmM|1rKKC6-kxAR*Cu4%odHHoq6C!z3mY1^{a};6jRr8_Evp8*SS%X_UL4bmUum6*X zyZ~Wn+WG`N8q7Ix%kn{1V6gd$HD9G8r`G-=s`zfnJd`vV@ukRQ*GqtsAy^Z^E-acU zjGD__mkIQ5h5-%a+7nE>CP05`hK8x!_%msT0Di6B*E&(Ef4r;+@~T#fj@OPOSMD_(UgdaF*`JO$+pVn-I@-&Up6z9sIifS+5ooR~D%d@1dg zkjYwk93T7yH=4RjSZ5cC5l0{qaTJcO0RxM-d zftKtOiXoMAt+r@s^dmG7d5#n(N1IW4{OlBVva}^3M_`4SC0)<8$2>*Zs);Y{+(=3I zRKsK@{dLMm67wCay6laP*48HiMn4DO#*UGtY-V-UrtvL!oAM1&#@!N6_JW)w+~27D zB*}Iv09cR*3+wKTA>}y-g4zo7>YcasQq}FFQrJ;_HX!frwAtq#o z#^d3YtR1R+)4Mk3O zNLq^Io4Pct=khVrz+8bTjjSP^Sd5(;Fa=Y>GM(A(;l5RrRzfaKV^Ry3eojVwM1I;7 zKy1P&ZRsY3NzZj58pLP3JFmbGCXK1%BUE+*{z^OuUS4+$V|EhiU1fHbir-&mqt(fp z_y{oC44o!#_?9@7Y|%C`puF^}yn|G~Uh{@bVYb_c*vZA_MKSc#+qR5iY3I}*+Jzg3A?k!H?(!jF--hK(f;XM!p*(_yrfNXsDt=`72O;d%3b9*}wCLpqu(_rb$#RJYGGhD*Hwj3WtXM)D=k#_I*9On$OUirfsUnmztT*JH47%^Ar>Ij zn2x(W=O8*=n}Jx(HI@6@I4Y}5FsCn`Zcvq7DxzfRp9bNVj~ReFKgkTMt}P^oqMjk% zUC`^h0Sn3Gi4sRK4n*57^ksB&6eE(H+`0dz&1($!z_z{WQNA(JZN%qIeq$ZTzZ&sU z-bwY4g@gp&WrEIPxO7F}1xmtFdf9rDAK8UhKf^2$dC2Fbk8DUY0MlLyiY&ds{lmIi zh)|)%-CA8pm;|&+TZNc6c+rg^*I7OsVr9)`$114t9{g@>zP2hVA({#DsVoN+9lXwj zJnH7EG;F9A)tM(kyS~RIVdqBJ)hRIy5aWYj9-D4QlI89zhKTUhx@}nO19Cq ze)n_EO)C)qwy_b+27IL8WfHkI7){JoS`TcHlC=Up+UswzC zzo$1zCc4VI-g6=V0xl%)?vYA=`Y^R|+1~pz!t@;f_JGuhe_GoXo{}Z9-{&2=F#Y~? zr;Q%Dd_RMiw;SNP{V1_*D@!L^`|pp21u0(MN_B5Ocn6E{%Aw&oFKT?iut2!5QV`aB z<4+LG={ZIg<+z~_)}7A^w;#7h3WpWg%Hf#94?Db_;4)iG=}fUJ#EzFjtoQh;Sk{k? znRX)9Z(e7@xR1|PYlGk6BVawmS1!UHHTaUEhjvx%EL*?&v^|{FbvH2j!;(RE>io9{ zL^5#_o42^YRUAF9q~hiJFU1;HP5Y!$E?&h`zd21O@3;tN)VQDjGVMT>{jRZOnby667xw-H zN?^nn$mv;L*uZax+l9)ePBIv0U*_7IcKNw$ zg|oaGDY&>LlHX$S)?3uQPar=>=0u{nMYibrGFATi7P1U#LXe`yA4V=}jDWDAOC#SB z`#h2nt=*&J5`Okl6Euce^QRVjZ=sQVKw(gCh?Tkfy&L?ULCbK3hpkhPV;%u*{pV|? zd9ISoycO?{zc_m6weZmowL&}dty1OqZ4WvU;?sz8={1W>tpLFokfyinV4Op@s#!_`De1W;&NKN>b!o(BE{#f6tZ}l? zYtKo&pxM2L8ecI6FV20=%@wAdOYVN|iBsbo_$$+IR|;?KnizL7-%m{8`4=AOLG+XP z%V}i|EKc+BU_wO}A1ZeD<*j*I8EuZw1VLtc;R=HYiUiaCYS+ zD3D-+KDOcyc4>($6avto=X1}{D26><~3`4m4Dk+{Pd8l!^%8-<#@qS zO;f0A!&ve9C^;GOh5sY1vEwdla~OPNpx6xl_KZefE$Xo`-DG1G%dv@d?(!s`TDwe( zgq=KS(*!kMXq=$4PnGCfUu*GsWQwthlb!H{zgRO&f%C>3-8utVD<>rSy%JD*CCSMj1l^NcBbSsxrs+qz}M zUIWj%m`zCjD{b0!g$>4D+4S!R*qOp6Vgga)6dQa}TdS-$l9H*~2Z7nveo|c6vu(L) z2!b_L4e)M~p8d<)Xc#wn&M*U`fQuXOmK`N)dp!U-7A0y#ePgD$H-GM+5f4?7)=oyS zc4>mVyoC2y=%ho-8D_>ARY(oV^Vzt2` zLI_yc1jmr|=kl7X^gZu_z*L8(%C~cxxFSP)Ib3cTM}SLHO)M8LBFM#N-3>Sf23H>m z#NR;?zb64>#PQ<0Gwy=$Gkx_lcJ48w4>79>Tk9`sZ zq-0{>b)~Hd$qBH##YN+ws6nAHY+xj(1NwyUiX zckV-BXiZ*+%p9tAaa!uhH11ZE@(!rLV!R)?RiQ6t7Al%1Ay4+#p%1wxIS8$+9ha4a z_hV7PJx)%syf#;d>+tx@5N{}!;bnzcZ(>Z1$zTpk^(QPwtCu`Z6Llqj_ z$2snTu4n7+Q)O^}NqwG`_pd24$;?BD_!~(X%{MS@?zb5izHoAPeY!~=-Wi-gCHI#9 zv3G>sczde{%^STi^I#P$M|jsA2;Z0A?Vvq=CfiZ5`N2wX@fB=j1OZbLs`H;WB(^tmZo*=mGHADq1`!ir>K6_&RA49(Q>IV6Fy^@tn?P zLJi{DCyLc|?XIx7WAg-mkxb5wRNnr?h)*vWW76R}o1lmR1_G8OwGJ#M>@8EE1t0TowV(;ZYZZPw zEjdaaV`V2wbbafSeZoq{Qb5g%L5o&#-J#&T3G1HfbG|~WEvdf@Z1ndW?xNAZIYj@Y zQS)X2CMI8*pKHY5l1UH>UAO&qs30!<;-NugIKKk`&2{{;$Jk#-wx0 z9mFi|-#kMi!W6zfd_H@h&&X{ka*SB$XG4B}WF&Atf~Qj3^*sY*@>#?PvZB?BvIkJ` z!+ZNKrwp5RkENiCl+{JPcrMe*qyfe5li|?fI_}U?beYplU~%R_>xgpHNsiw?0h{&c zTnOPwA;FR-%I~57^i8*OB6IRcB}vWBswtcl+O=aNG~BXQ+M60WdjgvdB| zHnSIYP;Kb3K$Z%9-KvqxwQ6`i0`?ieAG}^N?mjg{w-!`G54|Az1;0kp%R%Q#{*B%| z$hUfefH?trID$^Dw<;0AUj%kTbpbEC{xWgJY_#=s+RZrs<{;zuQt0(~oVtK&sy&ZY z+wk+?3Rz0a0IFCNAFrmg`7a-mA;*rio4}}#BhxO z&-QkmBU5sQi8u!?3Kk1{b;0oEpOO+73oltFchR*@CBFlKKysct<6DILx@%6Rgo9Dz zjk7{cS}sZcwUoB+QLT?Q96$}MmQlIQm^a}Mfco@>{?W$AI{7qKG6)#=rSufPrGo-L zrtQc`>$~^In4-?`S~&t`WPk>=E2gDxt1raLtU@I|=^+<*zBNfb=rS*yG~~hl?pC`m8wk^LAV%Fa>HsflT*{wp3q|)r1rRRFO2{7)amPF%OhAW z+VA;uqfkdrl2Lce`8k@%5?R$7)(HlPniGT?vS+{l)8 zZ)A0o++%am%z-Oxz#>Tnt=^6fyLzWjhqlsWFf3DA5M4MYm)wZ4erPOI^FngB0U@I3U8NkJO;y^OSh(*Ix2U&oC!PxdF%C23mu-re`^rpeklVlHJnPVpP$ zcy#CTz4$x31D>xdOU+361k9oQ^~}NLVsnRjX|>~?NYE8l>+y!Z!WvU*J;AeA(0gtq zKbN`YqF(88%X+y2t<~A-(j82JRXEVd4n^UVdm^1gl9hv8U^jM0{#Gb(gd`g^=v;8R#P!d2=y&`F+Z- z-1lGfM}E&K#bAaiV`fETRvd|{2wnK>+8JMQm^-Hs`qxg3Z<)D^ILdy0G6FgNiAX;e z!f;unq&o@D*;&-a9EBgHi!4EoqcxyQxl#LfH`)-M-OBmDR4!Nw(}Z1cAf1f@>yHTs zDiWfkQx|=NA}3irYgejk;TJB>fgi!V--1D8<`GPx0Y)IvA>&=D!ZnvbbESvgnvDW0 zbi=>w!^cOzzxmzgSA#rp-&gXDNON%EV@4cg=0J=jRafpEI+O;m%m&L#j-9OV@P0j9 z&P>=3!fkr+@`f(;N!@z}30sUsdsA2IiLW@ zc1Uvv$2$xTf?Buzt;rK>ddOgEpWM?2yUX z><##wb_VTh&m(4^mo9F+{46E(Y6hEPU4e`%WTMx~ATL9Tf@y`2qatQ;gD!SpXm8qT zs*kZ;OQr*_xzPqjN6Qc4Q!RswtEikTQmgm!KB+26s=eE45j<;mLvidX9}Yin6NU2g zv7~<&fvRchvl-24m*9tOKKn6!{szFcz z3@hF(Q5f*&>rJIp`W$<>0*4F=SV^SD8u8Z01cH*%Hi*SnWwQk=?y-84tuPHo%nDZK z*Q83MPTODlT{jDZbX9V}GuH*&C8Ap6Lpoz@MTaV|??LOTaZD z4kz5{N+#{>iEp^U&>CE@iuS%40beFP$O)B8tC9s|FqH5Ll`EH%&82`u&!QarB@ zH}U%j9E>_#OciDVg5g<~TGsR+@;h6{U0g? zQOq1=^A!D!Hw0fehnjhLwFf*iHq6$<&Juf*juqHuFP^JtdI<44m zZ7p<2YnP$NT^Y=z}dLR4(%E_r@=~(`>7;9E`DD5S7RW<0!mfu6ev{ zHh6KhVLZiAMq%9c-d0M68&UUOsTR_znapsdk>-ZvtlH_jns~i&e*#avv)82UCBv^3 zJndgQo8y@(fBz1iaAHZtHN2}U89In6LzG$hRC}}DuQ+DVj!pjEzk1>s3}tY(91izqzq42jzGyN0{BfII+-9m{3l@_rI$!^WAX-Q2zl-VpVs%$r>|brp0RqTy zu`(&EiptZ*XiO$j@DGJm2=zHr)_=f3kVPk6z3njk;Vu&LWUcln5+~=6O$nFf9H4=~ zUQNgTXEKm`G#2BF{P8&6LxjG?WKbS|25(Vf6vS_s!KcA3IzW{MFR`H`=p#*Ruvj1P z^OAZxOiXZP1v)Ubw(5TQ@=gm<1g*(ZNj*oF6CX6^s(a782vqtYYY?lF%$wrz3Um-C zo3BVD)iujsxX;fQv+K*k`pchiK%GySWDil<+H_o@u3l-)sR+Q;Nr<;VwK zZ|kOzV87w{q(IVl+9#wB%7bu5exWMno&*%u0IMW;Kz)VPqx&q+Rqs>W*b7D+af-7l qjE0(QEf%o@l?(rWxsQ?kiW{9Ftay-iz + + + <%= pageTitle %> + + + + + <% if (pageCssFiles.length) { %><% pageCssFiles.forEach(function (cssFile) { %><% }) %><% } %> + + +
+
+
+
+
+
+
+
+
+ <% if (pageJsFiles.length) { %><% pageJsFiles.forEach(function (jsFile) { %><% }) %><% } %> + + diff --git a/lib-build/debug-server/www_views/thtml/error/http-404.ejs b/lib-build/debug-server/www_views/thtml/error/http-404.ejs new file mode 100644 index 0000000..d0bd0a8 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/error/http-404.ejs @@ -0,0 +1,7 @@ +
+

400

+

Page Not Found

+
+		Please check you url.
+	
+
diff --git a/lib-build/debug-server/www_views/thtml/error/http-500.ejs b/lib-build/debug-server/www_views/thtml/error/http-500.ejs new file mode 100644 index 0000000..1847be4 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/error/http-500.ejs @@ -0,0 +1,7 @@ +
+

500

+

Server Error

+
+		Sorry server at fault.
+	
+
diff --git a/lib-build/debug-server/www_views/thtml/layout/footer.ejs b/lib-build/debug-server/www_views/thtml/layout/footer.ejs new file mode 100644 index 0000000..6c4e9b2 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/layout/footer.ejs @@ -0,0 +1,7 @@ + diff --git a/lib-build/debug-server/www_views/thtml/layout/header.ejs b/lib-build/debug-server/www_views/thtml/layout/header.ejs new file mode 100644 index 0000000..739cbf1 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/layout/header.ejs @@ -0,0 +1,16 @@ + diff --git a/lib-build/debug-server/www_views/thtml/server/about.ejs b/lib-build/debug-server/www_views/thtml/server/about.ejs new file mode 100644 index 0000000..0686d33 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/server/about.ejs @@ -0,0 +1,5 @@ +
+

About

+

Testing debug server for xensit xnodes.

+

Internal use only.

+
diff --git a/lib-build/debug-server/www_views/thtml/server/dash.ejs b/lib-build/debug-server/www_views/thtml/server/dash.ejs new file mode 100644 index 0000000..f973da4 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/server/dash.ejs @@ -0,0 +1,96 @@ +extends layout + +block content + h1= title + div + h2 Last five node data. + table + thead + tr + th Net id + th Node Id + th Value + tbody + each row in lastData + tr + td #{row.net_id} + td #{row.node_id} + td + p #{row.insert_date} + p #{row.data_text} + + div(id='split') + div(id='splitLeft') + div + h2 Last five node values. + table + thead + tr + th Net id + th Name + th Value + th insert_date + tbody + each row in lastValues + tr + td #{row.net_id} + td #{row.name} + td #{row.value} + td #{row.insert_date} + div + h2 Last five changed settings + table + thead + tr + th Name + th Value + tbody + each row in lastSettings + tr + td #{row.name} + td #{row.value} + + div(id='splitRight') + div + h2 Last five pings + table + thead + tr + th Net id + th Ping Count + th Ping Last + tbody + each xnode in lastPinged + tr + td #{xnode.hw_net_id} + td #{xnode.ping_counter} + td #{xnode.ping_last_date} + div + h2 Last five open Cmds + table + thead + tr + th Net id + th Command + th Insert date + tbody + each xnode in openCommands + tr + td #{xnode.net_id} + td #{xnode.command} + td #{xnode.insert_date} + div + h2 Last five send Cmds + table + thead + tr + th Net id + th Command + th Send date + tbody + each xnode in sendCommands + tr + td #{xnode.net_id} + td #{xnode.command} + td #{xnode.send_date} + \ No newline at end of file diff --git a/lib-build/debug-server/www_views/thtml/server/index.ejs b/lib-build/debug-server/www_views/thtml/server/index.ejs new file mode 100644 index 0000000..3edf235 --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/server/index.ejs @@ -0,0 +1,5 @@ +
+

XNode Debug Server Home

+

Welcome

+

Make your self at home.

+
diff --git a/lib-build/debug-server/www_views/thtml/server/routes-group.ejs b/lib-build/debug-server/www_views/thtml/server/routes-group.ejs new file mode 100644 index 0000000..408cf7b --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/server/routes-group.ejs @@ -0,0 +1,17 @@ +
+

<%= routeGroup.toUpperCase() %>

+ + + + + + + + + + + + + +
PathMethod
{{route.uriPath}}{{route.httpMethod}}
+
diff --git a/lib-build/debug-server/www_views/thtml/server/routes.ejs b/lib-build/debug-server/www_views/thtml/server/routes.ejs new file mode 100644 index 0000000..667deaf --- /dev/null +++ b/lib-build/debug-server/www_views/thtml/server/routes.ejs @@ -0,0 +1,28 @@ +
+

Server Routes

+

This page show all the nodejs express routes.

+
+ <% if (query.group1 && query.group2) { %> +
+ <% query.group1.split(',').forEach(function (routeGroup) { %> + <%- include('routes-group', {routeGroup: routeGroup}); %> + <% }) %> +
+
+ <% query.group2.split(',').forEach(function (routeGroup) { %> + <%- include('routes-group', {routeGroup: routeGroup}); %> + <% }) %> +
+ <% } else if (query.group1) { %> +
+ <% query.group1.split(',').forEach(function (routeGroup) { %> + <%- include('routes-group', {routeGroup: routeGroup}); %> + <% }) %> +
+ <% } else { %> +
+ <%- include('routes-group', {routeGroup: 'all'}); %> +
+ <% } %> +
+
diff --git a/lib-build/make/Makefile.inc.debug b/lib-build/make/Makefile.inc.debug new file mode 100644 index 0000000..f174001 --- /dev/null +++ b/lib-build/make/Makefile.inc.debug @@ -0,0 +1,40 @@ +# +# Managed debug logging +# +# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR + +# Replace keywords with debug flags. +ifneq (,$(findstring NETWORK,$(DEBUG_LOGGING))) + DEBUG_NETWORK ?= -DDEBUG_NETWORK +endif +ifneq (,$(findstring RADIO,$(DEBUG_LOGGING))) + DEBUG_RADIO ?= -DDEBUG_RADIO +endif +ifneq (,$(findstring SYSTEM,$(DEBUG_LOGGING))) + DEBUG_SYSTEM ?= -DDEBUG_SYSTEM +endif +ifneq (,$(findstring SERIAL,$(DEBUG_LOGGING))) + DEBUG_SERIAL ?= -DDEBUG_SERIAL +endif +ifneq (,$(findstring SENSOR,$(DEBUG_LOGGING))) + DEBUG_SENSOR ?= -DDEBUG_SENSOR +endif +ifneq (,$(findstring ALL,$(DEBUG_LOGGING))) + DEBUG_NETWORK ?= -DDEBUG_NETWORK + DEBUG_RADIO ?= -DDEBUG_RADIO + DEBUG_SYSTEM ?= -DDEBUG_SYSTEM + DEBUG_SERIAL ?= -DDEBUG_SERIAL + DEBUG_SENSOR ?= -DDEBUG_SENSOR +endif + +# Let NONE keyword override to disable. +ifeq (,$(findstring NONE,$(DEBUG_LOGGING))) + # Argragate debug flags to build. + DEBUG_FLAGS ?= \ + $(DEBUG_NETWORK) \ + $(DEBUG_RADIO) \ + $(DEBUG_SYSTEM) \ + $(DEBUG_SERIAL) \ + $(DEBUG_SENSOR) +endif + diff --git a/lib-build/make/Makefile.inc.libs b/lib-build/make/Makefile.inc.libs new file mode 100644 index 0000000..bf990aa --- /dev/null +++ b/lib-build/make/Makefile.inc.libs @@ -0,0 +1,36 @@ +# +# Managed libraries versions +# + +# Replace libraries with versioned libraries paths. +ifneq (,$(findstring spi,$(MASTER_LIBS))) + II_SPI = $(ARD_HOME)/hardware/arduino/avr/libraries/SPI +endif +ifneq (,$(findstring rfm,$(MASTER_LIBS))) + II_RFM = ../lib-ext/rfm-69.git +endif +ifneq (,$(findstring dht,$(MASTER_LIBS))) + II_DHT = ../lib-ext/dht.git +endif +ifneq (,$(findstring ethercard,$(MASTER_LIBS))) + II_ETHERCARD = ../lib-ext/ethercard.git +endif +ifneq (,$(findstring isp-repair,$(MASTER_LIBS))) + II_ISP_REPAIR = ../lib/isp-repair +endif +ifneq (,$(findstring xnode-shared,$(MASTER_LIBS))) + II_XNODE_SHARED = ../lib/xnode-shared +endif +ifneq (,$(findstring xnode-shared-satellite,$(MASTER_LIBS))) + II_XNODE_SHARED_SATELLITE = ../lib/xnode-shared-satellite +endif + +# Argragate Internal Includes to ROOT_LIBS +ROOT_LIBS = \ + $(II_SPI) \ + $(II_RFM) \ + $(II_DHT) \ + $(II_ETHERCARD) \ + $(II_ISP_REPAIR) \ + $(II_XNODE_SHARED) \ + $(II_XNODE_SHARED_SATELLITE) diff --git a/lib-build/make/Makefile.inc.local-template b/lib-build/make/Makefile.inc.local-template new file mode 100644 index 0000000..8034a0e --- /dev/null +++ b/lib-build/make/Makefile.inc.local-template @@ -0,0 +1,20 @@ +# Local env included makefile +# This file should be ignored in version control +# note: the ?= is so you can override those again in cmdline. +# +# Change to local arduino installation. +ARD_HOME ?= /home/willemc/devv/avr/ide/arduino-1.6.0 + +# Default port to isp +# PORT ?= /dev/ttyACM0 + +# Uncomment to have serial debug printing +# Supported arguments are: NONE,ALL,NETWORK,RADIO,SYSTEM,SERIAL,SENSOR +# DEBUG_LOGGING ?= ALL + +# Uncomment to disable lookup and this this address. +# DEBUG_NET_HISIP ?= {10,11,12,177} + +# Only needed in some extreme cases where there is +# transparant http proxy filtering in the network... +# DEBUG_NET_GATE ?= {10,11,12,177} diff --git a/lib-build/make/Makefile.inc.root b/lib-build/make/Makefile.inc.root new file mode 100644 index 0000000..5dda8dd --- /dev/null +++ b/lib-build/make/Makefile.inc.root @@ -0,0 +1,284 @@ +# +# Copyright 2011 Alan Burlison, alan@bleaklow.com. All rights reserved. +# Subsequently modified by Matthieu Weber, matthieu.weber@jyu.fi. +# Use is subject to license terms. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY ALAN BURLISON "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL ALAN BURLISON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Changed some code for working without pde/ino files. +# Added extra build flag and libary support. +# wc, 2014-01-13 +# +# Minor adjustments for Mac OS X and for educational purposes by Maik Schmidt, +# contact@maik-schmidt.de. +# +# Makefile for building Arduino projects outside of the Arduino environment +# +# This makefile should be included into a per-project Makefile of the following +# form: +# +# ---------- +# BOARD = mega +# PORT = /dev/term/0 +# INC_DIRS = ../common +# LIB_DIRS = ../libraries/Task ../../libraries/VirtualWire +# include ../../Makefile.master +# ---------- +# +# Where: +# BOARD : Arduino board type, from $(ARD_HOME)/hardware/boards.txt +# PORT : USB port +# INC_DIRS : List pf directories containing header files +# LIB_DIRS : List of directories containing library source +# +# Before using this Makefile you can adjust the following macros to suit +# your environment, either by editing this file directly or by defining them in +# the Makefile that includes this one, in which case they will override the +# definitions below: +# ARD_REV : arduino software revision, e.g. 0017, 0018 +# ARD_HOME : installation directory of the Arduino software. +# ARD_BIN : location of compiler binaries +# AVRDUDE : location of avrdude executable +# AVRDUDE_CONF : location of avrdude configuration file +# PROGRAMMER : avrdude programmer type +# MON_CMD : serial monitor command +# MON_SPEED : serial monitor speed +# + +# Global configuration. +ARD_REV ?= 0022 +ARD_HOME ?= /Applications/Arduino.app/Contents/Resources/Java +ARD_BIN ?= /usr/local/CrossPack-AVR/bin +AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude +AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf +PROGRAMMER ?= stk500v1 +MON_SPEED ?= 57600 +MON_CMD ?= picocom +PORT ?= /dev/tty.usbserial-A60061a3 +BOARD ?= atmega328 + +### Nothing below here should require editing. ### + +# Check for the required definitions. + +ifndef BOARD + $(error $$(BOARD) not defined) +endif +ifndef PORT + $(error $$(PORT) not defined) +endif + +# Version-specific settings +ARD_BOARDS = $(ARD_HOME)/hardware/arduino/avr/boards.txt +ARD_SRC_DIR = $(ARD_HOME)/hardware/arduino/avr/cores/arduino +ARD_MAIN = $(ARD_SRC_DIR)/main.cpp + +# Standard macros. +SKETCH = $(notdir $(CURDIR)) +BUILD_DIR = build +VPATH = $(LIB_DIRS) + +# Macros derived from boards.txt +MCU := $(shell sed -n 's/$(BOARD)\.build\.mcu=\(.*\)/\1/p' < $(ARD_BOARDS)) +F_CPU := $(shell sed -n 's/$(BOARD)\.build\.f_cpu=\(.*\)/\1/p' < $(ARD_BOARDS)) +UPLOAD_SPEED := \ + $(shell sed -n 's/$(BOARD)\.upload\.speed=\(.*\)/\1/p' < $(ARD_BOARDS)) + +# Build tools. +CC = $(ARD_BIN)/avr-gcc +CXX = $(ARD_BIN)/avr-g++ +CXXFILT = $(ARD_BIN)/avr-c++filt +OBJCOPY = $(ARD_BIN)/avr-objcopy +OBJDUMP = $(ARD_BIN)/avr-objdump +AR = $(ARD_BIN)/avr-ar +SIZE = $(ARD_BIN)/avr-size +NM = $(ARD_BIN)/avr-nm +MKDIR = mkdir -p +RM = rm -rf +MV = mv -f +LN = ln -f + +# Compiler flags. +INC_FLAGS = \ + $(addprefix -I,$(INC_DIRS)) $(addprefix -I,$(LIB_DIRS)) -I$(ARD_SRC_DIR) +ARD_FLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -DARDUINO=$(ARD_REV) $(SKETCH_FLAGS) +C_CXX_FLAGS = \ + -Wall -Wextra -Wundef -Wno-unused-parameter \ + -fdiagnostics-show-option -g -Wa,-adhlns=$(BUILD_DIR)/$*.lst +C_FLAGS = \ + $(C_CXX_FLAGS) -std=gnu99 -Wstrict-prototypes -Wno-old-style-declaration +CXX_FLAGS = $(C_CXX_FLAGS) + +# Optimiser flags. +# optimise for size, unsigned by default, pack data. +# separate sections, drop unused ones, shorten branches, jumps. +# don't inline, vectorise loops. no exceptions. +# no os preamble, use function calls in prologues. +# http://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/ +# http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html +OPT_FLAGS = \ + -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \ + -ffunction-sections -fdata-sections -Wl,--gc-sections,--relax \ + -fno-inline-small-functions -fno-tree-scev-cprop -fno-exceptions \ + -ffreestanding -mcall-prologues + +# Build parameters. +IMAGE = $(BUILD_DIR)/$(SKETCH) +ARD_C_SRC = $(wildcard $(ARD_SRC_DIR)/*.c) +ARD_CXX_SRC = $(wildcard $(ARD_SRC_DIR)/*.cpp) +ARD_C_OBJ = $(patsubst %.c,%.o,$(notdir $(ARD_C_SRC))) +ARD_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(ARD_CXX_SRC))) +ARD_LIB = arduino +ARD_AR = $(BUILD_DIR)/lib$(ARD_LIB).a +ARD_AR_OBJ = $(ARD_AR)($(ARD_C_OBJ) $(ARD_CXX_OBJ)) +ARD_LD_FLAG = -l$(ARD_LIB) + +# Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734 +$(ARD_AR)(Tone.o) : CXX_FLAGS += -w + +# Sketch libraries. +LIB_C_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.c)) +LIB_CXX_SRC = $(foreach ld,$(LIB_DIRS),$(wildcard $(ld)/*.cpp)) +LIB_SRC = $(LIB_C_SRC) $(LIB_CXX_SRC) +ifneq "$(strip $(LIB4_C_SRC) $(LIB_CXX_SRC))" "" + LIB_C_OBJ = $(patsubst %.c,%.o,$(notdir $(LIB_C_SRC))) + LIB_CXX_OBJ = $(patsubst %.cpp,%.o,$(notdir $(LIB_CXX_SRC))) + LIB_LIB = library + LIB_AR = $(BUILD_DIR)/lib$(LIB_LIB).a + LIB_AR_OBJ = $(LIB_AR)($(LIB_C_OBJ)$(LIB_CXX_OBJ)) + LIB_LD_FLAG = -l$(LIB_LIB) +endif + +# Sketch PDE source. +# SKT_PDE_SRC = $(wildcard *.pde) +#ifneq "$(strip $(SKT_PDE_SRC))" "" +# SKT_PDE_OBJ = $(BUILD_DIR)/$(SKETCH)_pde.o +#endif +SKT_PDE_OBJ = $(patsubst %.cpp,%.o,$(notdir $(SKT_PDE_SRC))) + +# C and C++ source. +SKT_C_SRC = $(wildcard *.c) +SKT_CXX_SRC = $(wildcard *.cpp) +ifneq "$(strip $(SKT_C_SRC) $(SKT_CXX_SRC))" "" + SKT_C_OBJ = $(patsubst %.c,%.o,$(SKT_C_SRC)) + SKT_CXX_OBJ = $(patsubst %.cpp,%.o,$(SKT_CXX_SRC)) + SKT_LIB = sketch + SKT_AR = $(BUILD_DIR)/lib$(SKT_LIB).a + SKT_AR_OBJ = $(SKT_AR)($(SKT_C_OBJ) $(SKT_CXX_OBJ)) + #SKT_AR_OBJ = $(SKT_AR)/($(SKT_C_OBJ) $(SKT_CXX_OBJ)) // mmm: '/' rmed after make 4.0 to work + SKT_LD_FLAG = -l$(SKT_LIB) +endif + +# Definitions. +define run-cc + @ $(CC) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $< + $(CC) -c $(C_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \ + $< -o $(BUILD_DIR)/$% + @ $(AR) rc $@ $(BUILD_DIR)/$% + @ $(RM) $(BUILD_DIR)/$% + @ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp + @ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst +endef + +define run-cxx + @ $(CXX) $(ARD_FLAGS) $(INC_FLAGS) -M -MT '$@($%)' -MF $@_$*.dep $< + $(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \ + $< -o $(BUILD_DIR)/$% + @ $(AR) rc $@ $(BUILD_DIR)/$% + @ $(RM) $(BUILD_DIR)/$% + @ $(CXXFILT) < $(BUILD_DIR)/$*.lst > $(BUILD_DIR)/$*.lst.tmp + @ $(MV) $(BUILD_DIR)/$*.lst.tmp $(BUILD_DIR)/$*.lst +endef + +# Rules. +.PHONY : all clean upload monitor upload_monitor + +all : $(BUILD_DIR) $(IMAGE).hex + +clean : + $(RM) $(BUILD_DIR) + +$(BUILD_DIR) : + $(MKDIR) $@ + +$(SKT_PDE_OBJ) : $(SKT_PDE_SRC) + $(CXX) -c $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) $(INC_FLAGS) \ + $< -o $(BUILD_DIR)/$(SKT_PDE_OBJ) + +# echo '#include ' > $(BUILD_DIR)/$(SKETCH)_pde.cpp +# echo '#include "$(SKT_PDE_SRC)"' >> $(BUILD_DIR)/$(SKETCH)_pde.cpp +# $(LN) $(SKT_PDE_SRC) $(BUILD_DIR)/$(SKT_PDE_SRC) +# cd $(BUILD_DIR) && ../$(CXX) -c $(subst build/,,$(CXX_FLAGS)) \ +# $(OPT_FLAGS) $(ARD_FLAGS) -I.. \ +# $(patsubst -I..%,-I../..%,$(INC_FLAGS)) \ +# $(SKETCH)_pde.cpp -o $(@F) + + +(%.o) : $(ARD_SRC_DIR)/%.c + $(run-cc) + +(%.o) : $(ARD_SRC_DIR)/%.cpp + $(run-cxx) + +(%.o) : %.c + $(run-cc) + +(%.o) : %.cpp + $(run-cxx) + +# not used +#$(BUILD_DIR)/%.d %.c +# $(run-cc-d) +# +#$(BUILD_DIR)/%.d %.cpp +# $(run-cxx-d) + +#build/libsketch.a build/libarduino.a +$(IMAGE).hex : $(ARD_AR_OBJ) $(LIB_AR_OBJ) $(SKT_AR_OBJ) $(SKT_PDE_OBJ) + $(CC) $(CXX_FLAGS) $(OPT_FLAGS) $(ARD_FLAGS) -L$(BUILD_DIR) \ + $(BUILD_DIR)/$(SKT_PDE_OBJ) $(SKT_LD_FLAG) $(LIB_LD_FLAG) $(ARD_LD_FLAG) -lm \ + -o $(IMAGE).elf + $(OBJCOPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load \ + --no-change-warnings --change-section-lma .eeprom=0 $(IMAGE).elf \ + $(IMAGE).eep + $(OBJCOPY) -O ihex -R .eeprom $(IMAGE).elf $(IMAGE).hex + $(OBJDUMP) -h -S $(IMAGE).elf | $(CXXFILT) -t > $(IMAGE).lst + $(SIZE) $(IMAGE).hex + +# START:makemods +upload : all + - pkill -f '$(MON_CMD).*$(PORT)' + - sleep 1 + - stty -f $(PORT) hupcl + - $(AVRDUDE) -V -C$(AVRDUDE_CONF) -p$(MCU) -c$(PROGRAMMER) \ + -P$(PORT) -b$(UPLOAD_SPEED) -D -Uflash:w:$(IMAGE).hex:i + +monitor : + $(MON_CMD) $(PORT) $(MON_SPEED) +# END:makemods + +upload_monitor : upload monitor + +-include $(wildcard $(BUILD_DIR)/*.dep)) + +# vim:ft=make diff --git a/lib-build/make/Makefile.master b/lib-build/make/Makefile.master new file mode 100644 index 0000000..642100e --- /dev/null +++ b/lib-build/make/Makefile.master @@ -0,0 +1,50 @@ +# Include this makefile per project +# +# Optional parameters; +# MASTER_LIBS = Simple library name list. +# MASTER_INC_DIRS = hook to include extra header files. +# MASTER_LIB_DIRS = hook to include extra libraries. +# MASTER_FLAGS = hook for extra build flags +# + +ifndef SKT_PDE_SRC + $(error $$(SKT_PDE_SRC) not defined) +endif + +THIS_PATH = ../lib-build/make/ +INC_LOCAL = . + +# Optional include an local override +-include $(THIS_PATH)/Makefile.inc.local + +# Copy debug ips +ifdef DEBUG_NET_HISIP + DEBUG_NET_FLAG_HISIP = -DDEBUG_NET_HISIP=$(DEBUG_NET_HISIP) +endif +ifdef DEBUG_NET_GATE + DEBUG_NET_FLAG_GATE = -DDEBUG_NET_GATE=$(DEBUG_NET_GATE) +endif + +# Add some normal defaults for root makefile +ARD_REV ?= 105 +ARD_BIN ?= $(ARD_HOME)/hardware/tools/avr/bin +AVRDUDE ?= $(ARD_HOME)/hardware/tools/avr/bin/avrdude +AVRDUDE_CONF ?= $(ARD_HOME)/hardware/tools/avr/etc/avrdude.conf +BOARD ?= uno +PORT ?= /dev/ttyACM0 +PROGRAMMER ?= arduino +MON_SPEED ?= 115200 +MON_CMD ?= picocom +ROOT_INCS = $(ARD_HOME)/hardware/arduino/avr/variants/standard/ + +# Include managed build parameters +include $(THIS_PATH)/Makefile.inc.debug +include $(THIS_PATH)/Makefile.inc.libs + +# Create build dirs for root makefile +INC_DIRS = $(MASTER_INC_DIRS) $(ROOT_INCS) $(INC_LOCAL) +LIB_DIRS = $(MASTER_LIB_DIRS) $(ROOT_LIBS) +SKETCH_FLAGS = $(MASTER_FLAGS) $(DEBUG_NET_FLAG_HISIP) $(DEBUG_NET_FLAG_GATE) $(DEBUG_FLAGS) + +# Include the root parent makefile +include $(THIS_PATH)/Makefile.inc.root diff --git a/lib-build/make/Makefile.master-flash b/lib-build/make/Makefile.master-flash new file mode 100644 index 0000000..20b66d0 --- /dev/null +++ b/lib-build/make/Makefile.master-flash @@ -0,0 +1,45 @@ +# Master makefile to flash tool projects +# +# Parameter; +# MASTER_FLASH_PROG = The hex file to flash +# +# Option Parameter; +# MASTER_FLASH_BOOT = The bootloader to flash +# MASTER_FLASH_PAIR_EXTRA = extra pair list of hex files to flash, +# note where the keyword optiboot get replaced by the optiboot hex file. +# + +ifndef MASTER_FLASH_PROG + $(error $$(MASTER_FLASH_PROG) not defined) +endif + +# Define libary includes +MASTER_LIBS = isp-repair + +# Include our master +include ../lib-build/make/Makefile.master + +HEX_FILE_BOOT_OPTI = $(ARD_HOME)/hardware/arduino/avr/bootloaders/optiboot/optiboot_atmega328.hex +HEX_FILE_BLINK_TEST = ../xnode-test-blink/build/xnode-test-blink.hex + +# Define local variables +HEX2C = tclsh ../lib-build/tools/mega-hex2c.tcl +HEX_DATA = xnode-flashdata.generated +HEX_PAIR_BLINK = $(HEX_FILE_BOOT_OPTI) $(HEX_FILE_BLINK_TEST) +MASTER_FLASH_BOOT ?= $(HEX_FILE_BOOT_OPTI) +HEX_PAIR_MASTER = $(MASTER_FLASH_BOOT) $(MASTER_FLASH_PROG) +HEX_PAIR_EXTRA = $(subst optiboot,$(HEX_FILE_BOOT_OPTI),$(MASTER_FLASH_PAIR_EXTRA)) +HEX_PAIR_LIST = $(HEX_PAIR_BLINK) $(HEX_PAIR_MASTER) $(HEX_PAIR_EXTRA) + +# Hook in our local extra build targets +clean : clean-hex +$(BUILD_DIR) : $(HEX_DATA) + +# Generate flashdata before compiling +$(HEX_DATA) : + $(HEX2C) $(HEX_PAIR_LIST) > $(HEX_DATA) + +clean-hex : + $(RM) $(HEX_DATA) + + diff --git a/lib-build/tools/mega-hex2c.tcl b/lib-build/tools/mega-hex2c.tcl new file mode 100644 index 0000000..66534ff --- /dev/null +++ b/lib-build/tools/mega-hex2c.tcl @@ -0,0 +1,86 @@ +#!/usr/bin/env tclsh + +# Changed to byte array per file with index struct for mega version +# wc, 2014-01-13 + +# Generate a C include file from one or more Intel HEX files (avr-gcc output) +# jcw, 2010-04-18 + +# Examples: +# ./hex2c.tcl Blink.cpp.hex ATmegaBOOT_168_atmega328.hex >data_blink.h +# ./hex2c.tcl RF12demo.cpp.hex ATmegaBOOT_168_atmega328.hex >data_rf12demo.h +# ./hex2c.tcl Blink.cpp.hex optiboot_atmega328.hex >opti_blink.h +# ./hex2c.tcl RF12demo.cpp.hex optiboot_atmega328.hex >opti_rf12demo.h + +if {$argv eq ""} { + puts stderr "Usage: [info script] infile.hex ?...? >outfile.h" + exit 1 +} + +set bytes {} +set psi 0 +foreach a $argv { + set start [llength $bytes] + set mtime [clock format [file mtime $a] -format "%Y-%m-%d"] + puts stderr $a: + set fd [open $a] + while {[gets $fd line] > 0} { + if {[scan $line {:%2x%4x%2x%s} count addr type data]} { + if {$type == 0} { + if {![info exists next]} { + set first [format 0x%04X $addr] + set next $addr + } + while {$next < $addr} { + lappend bytes 255 ;# pad with unset bytes if there is a gap + incr next + } + if {$next != $addr} { + puts stderr "non-contiguous data ($next vs $addr)" + } + incr next $count + foreach {x y} [split [string range $data 0 end-2] ""] { + lappend bytes [scan $x$y %x] + } + } + } + } + incr next -$first + set f [format %-30s [file tail $a]] + lappend sections "\"$f\",\"$mtime\",progdata_$psi,$first,$start,$next" + #lappend sections "\"$mtime $f ${next}b @ $first\",$first,$start,$next" + unset next + close $fd + + lappend byte_sections $bytes + set bytes {} + incr psi +} + +puts "// This file was generated by hex2c.tcl on [clock format [clock seconds]]" +puts "" +puts "" + +set pgi 0 +foreach bs $byte_sections { + puts "const unsigned char progdata_$pgi\[] PROGMEM = {" + set out " " + foreach x $bs { + if {[string length $out$x,] > 80} { + puts $out + set out " " + } + append out $x , + } + puts $out + puts "};" + incr pgi +} + +puts "" +puts "mega_flash_data_struct sections\[] = {" +foreach x $sections { + puts " {$x}," +} +puts "};" +puts "" diff --git a/lib-build/tools/xxtea.c b/lib-build/tools/xxtea.c new file mode 100644 index 0000000..1701035 --- /dev/null +++ b/lib-build/tools/xxtea.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +#define DELTA 0x9e3779b9 +#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) + +void btea(uint32_t *v, int n, uint32_t const key[4]) { + uint32_t y, z, sum; + unsigned p, rounds, e; + if (n > 1) { /* Coding Part */ + rounds = 6 + 52/n; + sum = 0; + z = v[n-1]; + do { + sum += DELTA; + e = (sum >> 2) & 3; + for (p=0; p> 2) & 3; + for (p=n-1; p>0; p--) { + z = v[p-1]; + y = v[p] -= MX; + } + z = v[n-1]; + y = v[0] -= MX; + sum -= DELTA; + } while (--rounds); + } +} + +void convToQU32(uint32_t *v/*, int n*/,int *data,int dataOffset) { + for (int i=0;i<4;i++) { + int idx = dataOffset + i*4; + //uint32_t value = (data[idx]) + (data[idx+1] << 8) + (data[idx+2] << 16) + (data[idx+3] << 24); + uint32_t value = (data[idx+3]) + (data[idx+2] << 8) + (data[idx+1] << 16) + (data[idx+0] << 24); + printf("convToQU32 %08x \n", value); + v[i] = value; + } +} + +#define XXTEA_NUM_ROUNDS 32 +void xxteaDecrypt(unsigned long v[2],unsigned long net_key[4]) +{ + unsigned int i; + uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS; + for (i=0; i < XXTEA_NUM_ROUNDS; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + net_key[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + net_key[sum & 3]); + } + v[0]=v0; v[1]=v1; +} + +int main (int argc, char *argv[] ) { + // Arguments parsing + if ( argc != 4 ) { + printf( "usage: %s encrypt|decrypt key message\n", argv[0] ); // prog name + printf( "note: parameters are pure hex and key should be 32 chars. \n"); + return 1; + } + int operation = 0; + if (strcmp("encrypt", argv[1]) == 0) { + operation = 1; + } + if (strcmp("decrypt", argv[1]) == 0) { + operation = -1; + } + if (operation == 0) { + printf( "Could not parse first argument.\n"); + return 1; + } + printf( "operation: %d.\n",operation); + char* keyBuffer = argv[2]; + int keyBufferLength = strlen(keyBuffer); + if (keyBufferLength != 32) { + printf( "key should by 32 chars.\n"); + return 1; + } + char* messageBuffer = argv[3]; + int messageBufferLength = strlen(messageBuffer); + if (messageBufferLength < 16) { + printf( "message should be minimal 16 chars.\n"); + return 1; + } + // Done arguments + + // Convert data + int keyData[16]; + int keyDataIndex = 0; + for (int i=0;i> 8 & 255); + //printf("%02x ", data[i] >> 16 & 255); + //printf("%02x ", data[i] >> 24 & 255); + + printf("%c ", data[i] & 255); + printf("%c ", data[i] >> 8 & 255); + printf("%c ", data[i] >> 16 & 255); + printf("%c ", data[i] >> 24 & 255); + } + printf("\n"); + return 0; +} diff --git a/lib-ext/dht.git/DHT.cpp b/lib-ext/dht.git/DHT.cpp new file mode 100644 index 0000000..2ef244c --- /dev/null +++ b/lib-ext/dht.git/DHT.cpp @@ -0,0 +1,179 @@ +/* DHT library + +MIT license +written by Adafruit Industries +*/ + +#include "DHT.h" + +DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) { + _pin = pin; + _type = type; + _count = count; + firstreading = true; +} + +void DHT::begin(void) { + // set up the pins! + pinMode(_pin, INPUT); + digitalWrite(_pin, HIGH); + _lastreadtime = 0; +} + +//boolean S == Scale. True == Farenheit; False == Celcius +float DHT::readTemperature(bool S) { + float f; + + if (read()) { + switch (_type) { + case DHT11: + f = data[2]; + if(S) + f = convertCtoF(f); + + return f; + case DHT22: + case DHT21: + f = data[2] & 0x7F; + f *= 256; + f += data[3]; + f /= 10; + if (data[2] & 0x80) + f *= -1; + if(S) + f = convertCtoF(f); + + return f; + } + } + return NAN; +} + +float DHT::convertCtoF(float c) { + return c * 9 / 5 + 32; +} + +float DHT::convertFtoC(float f) { + return (f - 32) * 5 / 9; +} + +float DHT::readHumidity(void) { + float f; + if (read()) { + switch (_type) { + case DHT11: + f = data[0]; + return f; + case DHT22: + case DHT21: + f = data[0]; + f *= 256; + f += data[1]; + f /= 10; + return f; + } + } + return NAN; +} + +float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) { + // Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and + // Wikipedia: http://en.wikipedia.org/wiki/Heat_index + return -42.379 + + 2.04901523 * tempFahrenheit + + 10.14333127 * percentHumidity + + -0.22475541 * tempFahrenheit*percentHumidity + + -0.00683783 * pow(tempFahrenheit, 2) + + -0.05481717 * pow(percentHumidity, 2) + + 0.00122874 * pow(tempFahrenheit, 2) * percentHumidity + + 0.00085282 * tempFahrenheit*pow(percentHumidity, 2) + + -0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2); +} + + +boolean DHT::read(void) { + uint8_t laststate = HIGH; + uint8_t counter = 0; + uint8_t j = 0, i; + unsigned long currenttime; + + // Check if sensor was read less than two seconds ago and return early + // to use last reading. + currenttime = millis(); + if (currenttime < _lastreadtime) { + // ie there was a rollover + _lastreadtime = 0; + } + if (!firstreading && ((currenttime - _lastreadtime) < 2000)) { + return true; // return last correct measurement + //delay(2000 - (currenttime - _lastreadtime)); + } + firstreading = false; + /* + Serial.print("Currtime: "); Serial.print(currenttime); + Serial.print(" Lasttime: "); Serial.print(_lastreadtime); + */ + _lastreadtime = millis(); + + data[0] = data[1] = data[2] = data[3] = data[4] = 0; + + // pull the pin high and wait 250 milliseconds + digitalWrite(_pin, HIGH); + delay(250); + + // now pull it low for ~20 milliseconds + pinMode(_pin, OUTPUT); + digitalWrite(_pin, LOW); + delay(20); + noInterrupts(); + digitalWrite(_pin, HIGH); + delayMicroseconds(40); + pinMode(_pin, INPUT); + + // read in timings + for ( i=0; i< MAXTIMINGS; i++) { + counter = 0; + while (digitalRead(_pin) == laststate) { + counter++; + delayMicroseconds(1); + if (counter == 255) { + break; + } + } + laststate = digitalRead(_pin); + + if (counter == 255) break; + + // ignore first 3 transitions + if ((i >= 4) && (i%2 == 0)) { + // shove each bit into the storage bytes + data[j/8] <<= 1; + if (counter > _count) + data[j/8] |= 1; + j++; + } + + } + + interrupts(); + + /* + Serial.println(j, DEC); + Serial.print(data[0], HEX); Serial.print(", "); + Serial.print(data[1], HEX); Serial.print(", "); + Serial.print(data[2], HEX); Serial.print(", "); + Serial.print(data[3], HEX); Serial.print(", "); + Serial.print(data[4], HEX); Serial.print(" =? "); + Serial.println(data[0] + data[1] + data[2] + data[3], HEX); + */ + + // check we read 40 bits and that the checksum matches + if ((j >= 40) && + (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) { + return true; + } + + + return false; + +} diff --git a/lib-ext/dht.git/DHT.h b/lib-ext/dht.git/DHT.h new file mode 100644 index 0000000..5280f9c --- /dev/null +++ b/lib-ext/dht.git/DHT.h @@ -0,0 +1,41 @@ +#ifndef DHT_H +#define DHT_H +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +/* DHT library + +MIT license +written by Adafruit Industries +*/ + +// how many timing transitions we need to keep track of. 2 * number bits + extra +#define MAXTIMINGS 85 + +#define DHT11 11 +#define DHT22 22 +#define DHT21 21 +#define AM2301 21 + +class DHT { + private: + uint8_t data[6]; + uint8_t _pin, _type, _count; + unsigned long _lastreadtime; + boolean firstreading; + + public: + DHT(uint8_t pin, uint8_t type, uint8_t count=6); + void begin(void); + float readTemperature(bool S=false); + float convertCtoF(float); + float convertFtoC(float); + float computeHeatIndex(float tempFahrenheit, float percentHumidity); + float readHumidity(void); + boolean read(void); + +}; +#endif diff --git a/lib-ext/dht.git/README.txt b/lib-ext/dht.git/README.txt new file mode 100644 index 0000000..4dfcbab --- /dev/null +++ b/lib-ext/dht.git/README.txt @@ -0,0 +1,3 @@ +This is an Arduino library for the DHT series of low cost temperature/humidity sensors. + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder DHT. Check that the DHT folder contains DHT.cpp and DHT.h. Place the DHT library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. \ No newline at end of file diff --git a/lib-ext/dht.git/examples/DHTtester/DHTtester.ino b/lib-ext/dht.git/examples/DHTtester/DHTtester.ino new file mode 100644 index 0000000..021107f --- /dev/null +++ b/lib-ext/dht.git/examples/DHTtester/DHTtester.ino @@ -0,0 +1,71 @@ +// Example testing sketch for various DHT humidity/temperature sensors +// Written by ladyada, public domain + +#include "DHT.h" + +#define DHTPIN 2 // what pin we're connected to + +// Uncomment whatever type you're using! +//#define DHTTYPE DHT11 // DHT 11 +#define DHTTYPE DHT22 // DHT 22 (AM2302) +//#define DHTTYPE DHT21 // DHT 21 (AM2301) + +// Connect pin 1 (on the left) of the sensor to +5V +// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1 +// to 3.3V instead of 5V! +// Connect pin 2 of the sensor to whatever your DHTPIN is +// Connect pin 4 (on the right) of the sensor to GROUND +// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor + +// Initialize DHT sensor for normal 16mhz Arduino +DHT dht(DHTPIN, DHTTYPE); +// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you +// might need to increase the threshold for cycle counts considered a 1 or 0. +// You can do this by passing a 3rd parameter for this threshold. It's a bit +// of fiddling to find the right value, but in general the faster the CPU the +// higher the value. The default for a 16mhz AVR is a value of 6. For an +// Arduino Due that runs at 84mhz a value of 30 works. +// Example to initialize DHT sensor for Arduino Due: +//DHT dht(DHTPIN, DHTTYPE, 30); + +void setup() { + Serial.begin(9600); + Serial.println("DHTxx test!"); + + dht.begin(); +} + +void loop() { + // Wait a few seconds between measurements. + delay(2000); + + // Reading temperature or humidity takes about 250 milliseconds! + // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + float h = dht.readHumidity(); + // Read temperature as Celsius + float t = dht.readTemperature(); + // Read temperature as Fahrenheit + float f = dht.readTemperature(true); + + // Check if any reads failed and exit early (to try again). + if (isnan(h) || isnan(t) || isnan(f)) { + Serial.println("Failed to read from DHT sensor!"); + return; + } + + // Compute heat index + // Must send in temp in Fahrenheit! + float hi = dht.computeHeatIndex(f, h); + + Serial.print("Humidity: "); + Serial.print(h); + Serial.print(" %\t"); + Serial.print("Temperature: "); + Serial.print(t); + Serial.print(" *C "); + Serial.print(f); + Serial.print(" *F\t"); + Serial.print("Heat index: "); + Serial.print(hi); + Serial.println(" *F"); +} diff --git a/lib-ext/ethercard.git/.gitignore b/lib-ext/ethercard.git/.gitignore new file mode 100644 index 0000000..a0c1726 --- /dev/null +++ b/lib-ext/ethercard.git/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.esproj +/html diff --git a/lib-ext/ethercard.git/CONTRIBUTING.md b/lib-ext/ethercard.git/CONTRIBUTING.md new file mode 100644 index 0000000..1f12897 --- /dev/null +++ b/lib-ext/ethercard.git/CONTRIBUTING.md @@ -0,0 +1,22 @@ +Contributing to EtherCard +========================= + +Contributions to the EtherCard codebase are welcome using the usual Github pull request workflow. + +Please remember that memory, particularly RAM, is often limited on Arduino, so try and be efficient when adding new features. + + +Code Style +---------- + +When making contributions, please use the following code style to keep the codebase consistent: + +* Indent using *4 spaces* not tabs +* When placing an opening brace on the same line, there should be one space before it +* Closing braces should be broken from the preceding line + +If in doubt, this is the same as the default [astyle] settings, so use the astyle tool to check your code. + + + +[astyle]: http://astyle.sourceforge.net/ diff --git a/lib-ext/ethercard.git/Doxyfile b/lib-ext/ethercard.git/Doxyfile new file mode 100644 index 0000000..9dc52f4 --- /dev/null +++ b/lib-ext/ethercard.git/Doxyfile @@ -0,0 +1,1923 @@ +# Doxyfile 1.8.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "EtherCard" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Ardino interface library for the ENC28J60 Ethernet controller chip (GPL)." + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = Doxylogo.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = Markdown=md + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ino + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = examples/* + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = Doxymods.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 200 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4 will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = YES + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/lib-ext/ethercard.git/Doxylogo.png b/lib-ext/ethercard.git/Doxylogo.png new file mode 100644 index 0000000000000000000000000000000000000000..695ed9126955b9301430651d9b05f5a124a54320 GIT binary patch literal 6626 zcmV<886D<{P)4Tx05}naRo`#hR1`jmZ&IWdKOk5~hl<6oRa0BJ8yc;~21%2p?MfD<>DVeH z9(p*dx19w`~g7O0}n_%Aq@s%d)fBDv`JHkDym6Hd+5XuAtvnwRpGmK zVkc9?T=n|PIo~X-eVh__(Z?q}P9Z-Dj?gOW6|D%o20XmjW-qs4UjrD(li^iv8@eK9k+ZFm zVRFymFOPAzG5-%Pn|1W;U4vNroTa&AxDScmEA~{ri9gr1^c?U@uwSpaNnw8l_>cP1 zd;)kMQS_;jeRSUEM_*s96y65j1$)tOrwdK{YIQMt92l|D^(E_=$Rjw{b!QT@q!)ni zR`|5oW9X5n$Wv+HVc@|^eX5yXnsHX8PF3UX~a6)MwxDE0HaPjyrlI!;jX{6Kvuh*8ej?;85ekN$?5uuCiS zBTvvVG+XTxAO{m@bvM#Jr)z6J><&E22D|vq?Y?Vkbo_DijopiF$2PET#mZ8eu=y$(ArYkv7@Ex`GL?QCc!_*KFrd&;n1r7 zqW-CFs9&fT)ZaU5gc&=gBz-DaCw(vdOp0__x+47~U6sC(E(JNe@4cTT*n6*E zVH4eoU1-&7pEV~_PRe`a7v+@vy!^5}8?Y3)UmlaER00009a7bBm000XU000XU0RWnu7ytkjWJyFpRA>dQ zS_yPj)w%xfx%Y<5BoJiEKuA!OQ3M=72!o1ZK?4b-idBoE?NeV}Z?)CufL*>-wc6L! z!MYStQQMFR$fOpP86h&s5R@T-fC+&NB#@Bgj_>>advD;p61y=EizOGF`!7TEO8*vTz0c{^+2?fk#ITW~~*! z|2X;_96We%#q-ZUA29tnW^r+`qoAO`Z{A(b-Eq0#&L;o_JF>I0ueV&TNx?wiMi4*D zA=1SP6~Rr=L}?5J0%9)A--MTkaBW5HI*-Tmucb?uo-km*BF)q4$?Nq(7(oKEK&(Xo&CShn=FAy^ib-5toW#V$NOW|xbn4VerPJ8hC{1W{`t)h> zp+DQO9^OgG5{|Z11qVP|KA*P{YX0~~AAK~Rbp+X#nzku9W6(J{ITK(j3o%hwNQ<5k zzQbiva#hvUl9HS(x88cI48QI=$;il%$jC_2(5?c8$;p!^Wp8n@tX{oZwrtrVZrCmv zqD%|~d{AQu&naG?Z{DK9!iPApq3vRmToRm-7=X=$g#Jl;!DOuyRaI3jR`VAXY@>FLy8rozK4$JBFcveHT z@A%}CPg*Vo@S@-huxU9tv%#{rI4OwngL_VLlhV3->Qu?g%aiWiyDM!l7J5Q~H<1t= zL-M8X1ZfyxTKX~8x^?Sh-n@BIQ&S^}iHQWrYA>Yf_IW((0Pr>fyqJn!5S#%9iRFOM z0#1%AK!?%P)TEy7@y8#R@#DrREd);D&L_|i+Sc6z)n5AX$1-u^LbhL#`Nz$h_`Uam9j z;FVWiQDAnRg1riuU_iGEay30&3NbB4X~P$5;?YE zlLVlCYL6h=)HOCV$c`O5WaRbNYhMG*3`Brz%QAE3Ou6UYd!@3nQrASh!V&>H31w{q)n4nv$Zxj6ImXZQXbLD{}xB;x{+7aWR!4Zw$H&sN*4hC}001j+hfe$lA^3p+zS zTL)~jA!(wDQnlth{IK-s(L-8VT4&m_Bok5IjEup*sWVPc^Cj0>4Y;Is`eZ9F@jQX zCc+2j9wWzD2!zqc&+fZVOr+lta3qjwc4+yE&=vqZZ#jEH(z2&WRM###$5)6%23&KE zBp^Iv`F6z$dB1apY<=TRIS%Rinp^aJ_zwZH+&p@;j2}N<>JY*Kpc4WK!10WP^i&d* zo@GRc`&g%CQEEXpCRc93x-($F03FN>st;}aP_0;M4jh#7ci)zXq*MvODN$F_CyduR zw%N34lZ*zDEdCac9Qd328CUpGv4yfrV>_B>mp^jLDHPp9)U_826M5X}Ru z1Kq(88}Q%{2J@UQRaM=$P=b>tO=3G$1^v^(pR$dcq#1pjana%{FO{S*6Q#$H!8*zz zcu=mJhIv){_Q}Z=OC+*)hD2o!kWOfoe8UZ)8P5Y}7~Q{re;IYtO}e|lJN2Bf$%znD zDwhVcu0`SHB)`v3b#yjh(xF3#%GFn2t%IAvLNm4fOO^D)*bf#g3b|W!@qnj&bF(D^ zQ9lc%Hge?1)&RToi`9a(gjf-7X+BgeJ+gD9*R?~n?S;%ioeNASD=SOvsEHAZA3K&9 z+;3+`l^h<1V}LYvfZjSz*VoIKn{U==z^H)E(vBaal9k`=lB!iJ#SKaL8=8cBguWBT z=?L8KZTb3Z89i!L=oxl%xNtET5dzK#GUINT4m645wfc5#9r`hV2M!!4DOjSo7UP|1 zI+3kH;2e$-c31;H>6dtfSXW+kRoGA+_zP~b9A2|lsNWX0F5ap#>G{+9q)TR|*6rQ9 zSNCigef#S3@txmD&DKrgPU$KB+S3vvNz!L@2sl9)AllgeG4Hx|=^}#$4N?`yI}PfA za0FB{O2MK1ATtO#zy&omHC2Z(gM<%!(f_awwr{Ggk&<`+AraCA#*Xv@I%M8Gg&RQa zx*p*cHA6ir-jsZ{O5ZzB@2RhllwagY=d{rL+qQ3)Pe0WxgK-?%mOnK@cb22B^`lZX38G>8yS`qfsqi0WvL3jwT zx-$R_F6{j*tP7ENlWY^_AUK9Y1VzB)PJ1t-@FmMvY9xWIinKIVO7g56iS5->$=R`U zr|#6v9`G2}x`va7#d!txYh_iEaP_s4JmNZSTTxLVFGK+pTUI=U5($DOWEu1Nkn3@2FeUhhuxE>%;KQu zgj-W7{ds?oS^18l5btSF=$>Kerx+e3;DmrCr}MmYm7 z%;11F!cxsee!+Z+=$0md7OyVyeQ%kdbx1zR2BaC%($ZwZ#*Na9P4W+Dp^bx1?hJTQ z+l(|JH3vMuGZCx2M*kE!ZH>Y5KG+4rFLr2GLAwAZX!-j*>1=g_`ap#mj!VMqIr2SX zR0nMB3nYIg-*Jb;*^($*zd;ya#l}WS%i-^&+k{EdW9Sf_uJrI>sX;c43-#_@yDmxs z>BEj(X{A6+f$awAzRGbikZ@z;Cr8T4kl51f+wDk0KzSY2=Q-0LCHWu0qlO9>@Qj>naYaSx3!Fdb)@By=Z|y02_w13A zNLVqM#6ro@JJLa^FW?Wh?oto+VWAFl5v4@`eGkQQ6u-Gx&$4gDO2me+jrbVxR+LJ2 z?B9|G4b-|ln4F2&{`UHL632vQ`R8hzFMrB#=g(E6mNJ&KNZh(@=%(+`! zHYYbSNJbop@Q6c8>6feRMcyr*>Z8)@z6Y?#XK3Aa?991S=+mcWcdJi-Bhnt4G5M{aR|#>x{?``v!2J5+-EchU@pfC>emGlNSk z71*NG7Ht%FGSU!r4S*OeX`^n^x(3)BQwgK&aO-SUwUmBPU@!8pO|`~aAQO%w6=F5jy_m?HN-z5tW zNbmpr3!O_RrTFcc4=h`u{~c~b8K=INlt&(rM0-hLx}57;GP2SvfQ&o8InZClsiKbMxWJd z*2uW5Ec`mx8t&2R(K-CL(Ed&>Sh2H9~EfCqdZJVYXk;v6O z9V+)PUc9(mM?mbi8S8`(FP%UR=7mz)93dWCdW{IN9g2+YDW(4?6iTTHuH6g6uh>!~ zYk&Q;sum*yU)c#sL@FWGmIPA?M~@zr>+DoQ9kk-u8y`wULT_E*-X0Eos*bnW|16xg>JV_@0@2iYJbl$C7 zx9Sqm8!1P~$D)Uaq}6s@CUuS%%WZH0oX}XMM~=v5L6ksfQ&L3f>Xi_fWsp9L1HDm8I?|U|EIO z?mPoRBO%>jd|aI4W908gV{0-JIgKVPkUQr-ry-I{;>1dbhj)W2l-Faiu2$00XWlEf z{^>Q{!*TEuq!P|xiC_|lrK)(JR4!X2F4|@@_U5op7Ap~(R0o0b`N9Al&>E|v3Ne*S zJt%E{^XAQZBE&>7q~=Hd($(VeEJ60Gp1C1Cz+;wnaehA8w~WRNaDJYK?%h``YY;Ng zpvOMyK{{`@AJF+rp@XVT~p_aDK5T-51W(Iv5qy#K)mnpdPN?=$9Ry}W0eq!ET3gb(VJ z)K#KsPqufXD<@aEbz&;vzYxl?fMGIlMy~YddIoSInQ2wKekf0l?X(%SZ0SoyESQcD7V0?T2e0ln*r&QNTlsh^~ z5;FRpLlh@AM3ay`b}Av$PA$+z;!;!2>2tXc-(c7B?tAZP))~N5YKXM_Sib*zhdBI+^J8x z{dSrC;Dh=#1N)E|qhibeb8ExRZ%2zVgX(QF3fd%p{oCKv`|=wV0>eDqy;xY&p2cSy zFB*E!pX-9)*vLdK=y(m%5MM%qJ)jBc30> zun#XIdA2@^qb+qC3=>3A2*9n!ZgDDfug}yi&R$56O4XSB)IG zyfE)^3|k@Yx|!DCAwJtMxoSW`>Iiu)7afP+>-`+kdx%R_I6b8AVx?W+*x7s~!1WMc z6=dMRfIJBp_GJfSZV%#8eAx1wa1i#p$ zKLI3w!q{ans^_qNE#M?ZllZ@_(r$2Opzy)L!I5w_zd_wy2-z$K%psc>exgVR0WH$f zx?FG^*0BH}!RUoYZj=%9yR3SgBJ_qqNA6+^UgcWr*=qM;qzP; zI5PlspFyhOCZ8b*o(qoyfrBvkRbX>p$cf4R@I{Ykn}NC#V&q3DdvSe*k8p|*)t@xu zQ%jJX#fkPsxMLb#MiDjjkVUrn$ gcQe+H0cFPfKX~R5kNg8mSO5S307*qoM6N<$g7Qwml>h($ literal 0 HcmV?d00001 diff --git a/lib-ext/ethercard.git/Doxymods.css b/lib-ext/ethercard.git/Doxymods.css new file mode 100644 index 0000000..ec01e9e --- /dev/null +++ b/lib-ext/ethercard.git/Doxymods.css @@ -0,0 +1,73 @@ +/* Get rid of all those overriden font families */ +body, table, div, p, dl, +#projectname, +#projectbrief, +#nav-tree .label { + font: 15px/21px Georgia,serif +} + +#projectname { + color: #990000; + font-weight: bold; + font-size: 24px; +} + +#titlearea table { + padding: 20px; +} + +dl.reflist dt, div.memproto { + border: 1px solid #A8B8D9; +} + +dl.reflist dd, div.memdoc { + border-width: 0; +} + +div.contents { + margin-left: 20px; margin-right: 16px; + width: 700 px; +} + +/* Get rid of the gradient backgrounds and background colors */ +div.header, +#nav-tree, +.navpath ul, +.memproto, dl.reflist dt { + background: none; +} +#nav-tree .selected { + background: none; + background-color: #990000; + text-shadow: none; +} + +a, a:link, a:visited { + color: #2A5685; + text-decoration: underline; +} +a:active, a:hover { + color: #CC0000; +} + +.directory tr.even, +pre.fragment, +.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams, +.memproto, dl.reflist dt { + background-color: #EEE; + box-shadow: none; + border-radius: 0; +} +.memdoc, dl.reflist dd { + background: none; + box-shadow: none; + border-radius: 0; +} +pre.fragment { + background-color: #FAFAFA; + border: 1px solid #DADADA; + margin: 1em 1em 1em 1.6em; + overflow-x: auto; + overflow-y: hidden; + width: auto; +} diff --git a/lib-ext/ethercard.git/EtherCard.cpp b/lib-ext/ethercard.git/EtherCard.cpp new file mode 100644 index 0000000..485deee --- /dev/null +++ b/lib-ext/ethercard.git/EtherCard.cpp @@ -0,0 +1,416 @@ +// This code slightly follows the conventions of, but is not derived from: +// EHTERSHIELD_H library for Arduino etherShield +// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1) +// It is however derived from the enc28j60 and ip code (which is GPL v2) +// Author: Pascal Stang +// Modified by: Guido Socher +// DHCP code: Andrew Lindsay +// Hence: GPL V2 +// +// 2010-05-19 + +#include +#include +#include + +//#define FLOATEMIT // uncomment line to enable $T in emit_P for float emitting + +byte Stash::map[256/8]; +Stash::Block Stash::bufs[2]; + +uint8_t Stash::allocBlock () { + for (uint8_t i = 0; i < sizeof map; ++i) + if (map[i] != 0) + for (uint8_t j = 0; j < 8; ++j) + if (bitRead(map[i], j)) { + bitClear(map[i], j); + return (i << 3) + j; + } + return 0; +} + +void Stash::freeBlock (uint8_t block) { + bitSet(map[block>>3], block & 7); +} + +uint8_t Stash::fetchByte (uint8_t blk, uint8_t off) { + return blk == bufs[0].bnum ? bufs[0].bytes[off] : + blk == bufs[1].bnum ? bufs[1].bytes[off] : + ether.peekin(blk, off); +} + +void Stash::initMap (uint8_t last) { + while (--last > 0) + freeBlock(last); +} + +void Stash::load (uint8_t idx, uint8_t blk) { + if (blk != bufs[idx].bnum) { + if (idx == 0) { + ether.copyout(bufs[idx].bnum, bufs[idx].bytes); + if (blk == bufs[1].bnum) + bufs[1].bnum = 255; // forget read page if same + } else if (blk == bufs[0].bnum) { + // special case: read page is same as write buffer + memcpy(&bufs[1], &bufs[0], sizeof bufs[0]); + return; + } + bufs[idx].bnum = blk; + ether.copyin(bufs[idx].bnum, bufs[idx].bytes); + } +} + +uint8_t Stash::freeCount () { + uint8_t count = 0; + for (uint8_t i = 0; i < 256/8; ++i) + for (uint8_t m = 0x80; m != 0; m >>= 1) + if (map[i] & m) + ++count; + return count; +} + +uint8_t Stash::create () { + uint8_t blk = allocBlock(); + load(0, blk); + bufs[0].head.count = 0; + bufs[0].head.first = bufs[0].head.last = blk; + bufs[0].tail = sizeof (StashHeader); + bufs[0].next = 0; + return open(blk); +} + +uint8_t Stash::open (uint8_t blk) { + curr = blk; + offs = sizeof (StashHeader); + load(1, curr); + memcpy((StashHeader*) this, bufs[1].bytes, sizeof (StashHeader)); + return curr; +} + +void Stash::save () { + load(0, first); + memcpy(bufs[0].bytes, (StashHeader*) this, sizeof (StashHeader)); + if (bufs[1].bnum == first) + load(1, 0); // invalidates original in case it was the same block +} + +void Stash::release () { + while (first > 0) { + freeBlock(first); + first = ether.peekin(first, 63); + } +} + +void Stash::put (char c) { + load(0, last); + uint8_t t = bufs[0].tail; + bufs[0].bytes[t++] = c; + if (t <= 62) + bufs[0].tail = t; + else { + bufs[0].next = allocBlock(); + last = bufs[0].next; + load(0, last); + bufs[0].tail = bufs[0].next = 0; + ++count; + } +} + +char Stash::get () { + load(1, curr); + if (curr == last && offs >= bufs[1].tail) + return 0; + uint8_t b = bufs[1].bytes[offs]; + if (++offs >= 63 && curr != last) { + curr = bufs[1].next; + offs = 0; + } + return b; +} + +uint16_t Stash::size () { + return 63 * count + fetchByte(last, 62) - sizeof (StashHeader); +} + +static char* wtoa (uint16_t value, char* ptr) { + if (value > 9) + ptr = wtoa(value / 10, ptr); + *ptr = '0' + value % 10; + *++ptr = 0; + return ptr; +} + +void Stash::prepare (PGM_P fmt, ...) { + Stash::load(0, 0); + uint16_t* segs = Stash::bufs[0].words; + *segs++ = strlen_P(fmt); +#ifdef __AVR__ + *segs++ = (uint16_t) fmt; +#else + *segs++ = (uint32_t) fmt; + *segs++ = (uint32_t) fmt >> 16; +#endif + va_list ap; + va_start(ap, fmt); + for (;;) { + char c = pgm_read_byte(fmt++); + if (c == 0) + break; + if (c == '$') { +#ifdef __AVR__ + uint16_t argval = va_arg(ap, uint16_t), arglen = 0; +#else + uint32_t argval = va_arg(ap, int), arglen = 0; +#endif + switch (pgm_read_byte(fmt++)) { + case 'D': { + char buf[7]; + wtoa(argval, buf); + arglen = strlen(buf); + break; + } + case 'S': + arglen = strlen((const char*) argval); + break; + case 'F': + arglen = strlen_P((PGM_P) argval); + break; + case 'E': { + byte* s = (byte*) argval; + char d; + while ((d = eeprom_read_byte(s++)) != 0) + ++arglen; + break; + } + case 'H': { + Stash stash (argval); + arglen = stash.size(); + break; + } + } +#ifdef __AVR__ + *segs++ = argval; +#else + *segs++ = argval; + *segs++ = argval >> 16; +#endif + Stash::bufs[0].words[0] += arglen - 2; + } + } + va_end(ap); +} + +uint16_t Stash::length () { + Stash::load(0, 0); + return Stash::bufs[0].words[0]; +} + +void Stash::extract (uint16_t offset, uint16_t count, void* buf) { + Stash::load(0, 0); + uint16_t* segs = Stash::bufs[0].words; +#ifdef __AVR__ + PGM_P fmt = (PGM_P) *++segs; +#else + PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]); + segs += 2; +#endif + Stash stash; + char mode = '@', tmp[7], *ptr = NULL, *out = (char*) buf; + for (uint16_t i = 0; i < offset + count; ) { + char c = 0; + switch (mode) { + case '@': { + c = pgm_read_byte(fmt++); + if (c == 0) + return; + if (c != '$') + break; +#ifdef __AVR__ + uint16_t arg = *++segs; +#else + uint32_t arg = *++segs; + arg |= *++segs << 16; +#endif + mode = pgm_read_byte(fmt++); + switch (mode) { + case 'D': + wtoa(arg, tmp); + ptr = tmp; + break; + case 'S': + case 'F': + case 'E': + ptr = (char*) arg; + break; + case 'H': + stash.open(arg); + ptr = (char*) &stash; + break; + } + continue; + } + case 'D': + case 'S': + c = *ptr++; + break; + case 'F': + c = pgm_read_byte(ptr++); + break; + case 'E': + c = eeprom_read_byte((byte*) ptr++); + break; + case 'H': + c = ((Stash*) ptr)->get(); + break; + } + if (c == 0) { + mode = '@'; + continue; + } + if (i >= offset) + *out++ = c; + ++i; + } +} + +void Stash::cleanup () { + Stash::load(0, 0); + uint16_t* segs = Stash::bufs[0].words; +#ifdef __AVR__ + PGM_P fmt = (PGM_P) *++segs; +#else + PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]); + segs += 2; +#endif + for (;;) { + char c = pgm_read_byte(fmt++); + if (c == 0) + break; + if (c == '$') { +#ifdef __AVR__ + uint16_t arg = *++segs; +#else + uint32_t arg = *++segs; + arg |= *++segs << 16; +#endif + if (pgm_read_byte(fmt++) == 'H') { + Stash stash (arg); + stash.release(); + } + } + } +} + +void BufferFiller::emit_p(PGM_P fmt, ...) { + va_list ap; + va_start(ap, fmt); + for (;;) { + char c = pgm_read_byte(fmt++); + if (c == 0) + break; + if (c != '$') { + *ptr++ = c; + continue; + } + c = pgm_read_byte(fmt++); + switch (c) { + case 'D': +#ifdef __AVR__ + wtoa(va_arg(ap, uint16_t), (char*) ptr); +#else + wtoa(va_arg(ap, int), (char*) ptr); +#endif + break; +#ifdef FLOATEMIT + case 'T': + dtostrf ( va_arg(ap, double), 10, 3, (char*)ptr ); + break; +#endif + case 'H': { +#ifdef __AVR__ + char p1 = va_arg(ap, uint16_t); +#else + char p1 = va_arg(ap, int); +#endif + char p2; + p2 = (p1 >> 4) & 0x0F; + p1 = p1 & 0x0F; + if (p1 > 9) p1 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f' + p1 += 0x30; // and complete + if (p2 > 9) p2 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f' + p2 += 0x30; // and complete + *ptr++ = p2; + *ptr++ = p1; + continue; + } + case 'L': + ltoa(va_arg(ap, long), (char*) ptr, 10); + break; + case 'S': + strcpy((char*) ptr, va_arg(ap, const char*)); + break; + case 'F': { + PGM_P s = va_arg(ap, PGM_P); + char d; + while ((d = pgm_read_byte(s++)) != 0) + *ptr++ = d; + continue; + } + case 'E': { + byte* s = va_arg(ap, byte*); + char d; + while ((d = eeprom_read_byte(s++)) != 0) + *ptr++ = d; + continue; + } + default: + *ptr++ = c; + continue; + } + ptr += strlen((char*) ptr); + } + va_end(ap); +} + +EtherCard ether; + +uint8_t EtherCard::mymac[6]; // my MAC address +uint8_t EtherCard::myip[4]; // my ip address +uint8_t EtherCard::netmask[4]; // subnet mask +uint8_t EtherCard::broadcastip[4]; // broadcast address +uint8_t EtherCard::gwip[4]; // gateway +uint8_t EtherCard::dhcpip[4]; // dhcp server +uint8_t EtherCard::dnsip[4]; // dns server +uint8_t EtherCard::hisip[4]; // ip address of remote host +uint16_t EtherCard::hisport = 80; // tcp port to browse to +bool EtherCard::using_dhcp = false; +bool EtherCard::persist_tcp_connection = false; +int16_t EtherCard::delaycnt = 0; //request gateway ARP lookup + +uint8_t EtherCard::begin (const uint16_t size, + const uint8_t* macaddr, + uint8_t csPin) { + using_dhcp = false; + Stash::initMap(56); + copyMac(mymac, macaddr); + return initialize(size, mymac, csPin); +} + +bool EtherCard::staticSetup (const uint8_t* my_ip, + const uint8_t* gw_ip, + const uint8_t* dns_ip, + const uint8_t* mask) { + using_dhcp = false; + + if (my_ip != 0) + copyIp(myip, my_ip); + if (gw_ip != 0) + setGwIp(gw_ip); + if (dns_ip != 0) + copyIp(dnsip, dns_ip); + if(mask != 0) + copyIp(netmask, mask); + updateBroadcastAddress(); + delaycnt = 0; //request gateway ARP lookup + return true; +} diff --git a/lib-ext/ethercard.git/EtherCard.h b/lib-ext/ethercard.git/EtherCard.h new file mode 100644 index 0000000..531c488 --- /dev/null +++ b/lib-ext/ethercard.git/EtherCard.h @@ -0,0 +1,587 @@ +// This code slightly follows the conventions of, but is not derived from: +// EHTERSHIELD_H library for Arduino etherShield +// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1) +// It is however derived from the enc28j60 and ip code (which is GPL v2) +// Author: Pascal Stang +// Modified by: Guido Socher +// DHCP code: Andrew Lindsay +// Hence: GPL V2 +// +// 2010-05-19 +// +// +// PIN Connections (Using Arduino UNO): +// VCC - 3.3V +// GND - GND +// SCK - Pin 13 +// SO - Pin 12 +// SI - Pin 11 +// CS - Pin 8 +// +#define __PROG_TYPES_COMPAT__ + +#ifndef EtherCard_h +#define EtherCard_h + + +#if ARDUINO >= 100 +#include // Arduino 1.0 +#define WRITE_RESULT size_t +#define WRITE_RETURN return 1; +#else +#include // Arduino 0022 +#define WRITE_RESULT void +#define WRITE_RETURN +#endif + +#include +#include "enc28j60.h" +#include "net.h" + +/** This type definition defines the structure of a UDP server event handler callback funtion */ +typedef void (*UdpServerCallback)( + uint16_t dest_port, ///< Port the packet was sent to + uint8_t src_ip[4], ///< IP address of the sender + const char *data, ///< UDP payload data + uint16_t len); ///< Length of the payload data + +/** This type definition defines the structure of a DHCP Option callback funtion */ +typedef void (*DhcpOptionCallback)( + uint8_t option, ///< The option number + const byte* data, ///< DHCP option data + uint8_t len); ///< Length of the DHCP option data + + +/** This structure describes the structure of memory used within the ENC28J60 network interface. */ +typedef struct { + uint8_t count; ///< Number of allocated pages + uint8_t first; ///< First allocated page + uint8_t last; ///< Last allocated page +} StashHeader; + +/** This class provides access to the memory within the ENC28J60 network interface. */ +class Stash : public /*Stream*/ Print, private StashHeader { + uint8_t curr; //!< Current page + uint8_t offs; //!< Current offset in page + + typedef struct { + union { + uint8_t bytes[64]; + uint16_t words[32]; + struct { + StashHeader head; + uint8_t filler[59]; + uint8_t tail; + uint8_t next; + }; + }; + uint8_t bnum; + } Block; + + static uint8_t allocBlock (); + static void freeBlock (uint8_t block); + static uint8_t fetchByte (uint8_t blk, uint8_t off); + + static Block bufs[2]; + static uint8_t map[256/8]; + +public: + static void initMap (uint8_t last); + static void load (uint8_t idx, uint8_t blk); + static uint8_t freeCount (); + + Stash () : curr (0) { first = 0; } + Stash (uint8_t fd) { open(fd); } + + uint8_t create (); + uint8_t open (uint8_t blk); + void save (); + void release (); + + void put (char c); + char get (); + uint16_t size (); + + virtual WRITE_RESULT write(uint8_t b) { put(b); WRITE_RETURN } + + // virtual int available() { + // if (curr != last) + // return 1; + // load(1, last); + // return offs < bufs[1].tail; + // } + // virtual int read() { + // return available() ? get() : -1; + // } + // virtual int peek() { + // return available() ? bufs[1].bytes[offs] : -1; + // } + // virtual void flush() { + // curr = last; + // offs = 63; + // } + + static void prepare (PGM_P fmt, ...); + static uint16_t length (); + static void extract (uint16_t offset, uint16_t count, void* buf); + static void cleanup (); + + friend void dumpBlock (const char* msg, uint8_t idx); // optional + friend void dumpStash (const char* msg, void* ptr); // optional +}; + +/** This class populates network send and receive buffers. +* +* This class provides formatted printing into memory. Users can use it to write into send buffers. +* +* Nota: PGM_P: is a pointer to a string in program space (defined in the source code) +* +* # Format string +* +* | Format | Parameter | Output +* |--------|-------------|---------- +* | $D | uint16_t | Decimal representation +* | $T ¤ | double | Decimal representation with 3 digits after decimal sign ([-]d.ddd) +* | $H | uint16_t | Hexadecimal value of lsb (from 00 to ff) +* | $L | long | Decimal representation +* | $S | const char* | Copy null terminated string from main memory +* | $F | PGM_P | Copy null terminated string from program space +* | $E | byte* | Copy null terminated string from EEPROM space +* | $$ | _none_ | '$' +* +* ¤ _Available only if FLOATEMIT is defined_ +* +* # Examples +* ~~~~~~~~~~~~~{.c} +* uint16_t ddd = 123; +* double ttt = 1.23; +* uint16_t hhh = 0xa4; +* long lll = 123456789; +* char * sss; +* char fff[] PROGMEM = "MyMemory"; +* +* sss[0] = 'G'; +* sss[1] = 'P'; +* sss[2] = 'L'; +* sss[3] = 0; +* buf.emit_p( PSTR("ddd=$D\n"), ddd ); // "ddd=123\n" +* buf.emit_p( PSTR("ttt=$T\n"), ttt ); // "ttt=1.23\n" **TO CHECK** +* buf.emit_p( PSTR("hhh=$H\n"), hhh ); // "hhh=a4\n" +* buf.emit_p( PSTR("lll=$L\n"), lll ); // "lll=123456789\n" +* buf.emit_p( PSTR("sss=$S\n"), sss ); // "sss=GPL\n" +* buf.emit_p( PSTR("fff=$F\n"), fff ); // "fff=MyMemory\n" +* ~~~~~~~~~~~~~ +* +*/ +class BufferFiller : public Print { + uint8_t *start; //!< Pointer to start of buffer + uint8_t *ptr; //!< Pointer to cursor position +public: + /** @brief Empty constructor + */ + BufferFiller () {} + + /** @brief Constructor + * @param buf Pointer to the ethernet data buffer + */ + BufferFiller (uint8_t* buf) : start (buf), ptr (buf) {} + + /** @brief Add formatted text to buffer + * @param fmt Format string (see Class description) + * @param ... parameters for format string + */ + void emit_p (PGM_P fmt, ...); + + /** @brief Add data to buffer from main memory + * @param s Pointer to data + * @param n Number of characters to copy + */ + void emit_raw (const char* s, uint16_t n) { memcpy(ptr, s, n); ptr += n; } + + /** @brief Add data to buffer from program space string + * @param p Program space string pointer + * @param n Number of characters to copy + */ + void emit_raw_p (PGM_P p, uint16_t n) { memcpy_P(ptr, p, n); ptr += n; } + + /** @brief Get pointer to start of buffer + * @return uint8_t* Pointer to start of buffer + */ + uint8_t* buffer () const { return start; } + + /** @brief Get cursor position + * @return uint16_t Cursor postion + */ + uint16_t position () const { return ptr - start; } + + /** @brief Write one byte to buffer + * @param v Byte to add to buffer + */ + virtual WRITE_RESULT write (uint8_t v) { *ptr++ = v; WRITE_RETURN } +}; + +/** This class provides the main interface to a ENC28J60 based network interface card and is the class most users will use. +* @note All TCP/IP client (outgoing) connections are made from source port in range 2816-3071. Do not use these source ports for other purposes. +*/ +class EtherCard : public Ethernet { +public: + static uint8_t mymac[6]; ///< MAC address + static uint8_t myip[4]; ///< IP address + static uint8_t netmask[4]; ///< Netmask + static uint8_t broadcastip[4]; ///< Subnet broadcast address + static uint8_t gwip[4]; ///< Gateway + static uint8_t dhcpip[4]; ///< DHCP server IP address + static uint8_t dnsip[4]; ///< DNS server IP address + static uint8_t hisip[4]; ///< DNS lookup result + static uint16_t hisport; ///< TCP port to connect to (default 80) + static bool using_dhcp; ///< True if using DHCP + static bool persist_tcp_connection; ///< False to break connections on first packet received + static int16_t delaycnt; ///< Counts number of cycles of packetLoop when no packet received - used to trigger periodic gateway ARP request + + // EtherCard.cpp + /** @brief Initialise the network interface + * @param size Size of data buffer + * @param macaddr Hardware address to assign to the network interface (6 bytes) + * @param csPin Arduino pin number connected to chip select. Default = 8 + * @return uint8_t Firmware version or zero on failure. + */ + static uint8_t begin (const uint16_t size, const uint8_t* macaddr, + uint8_t csPin =8); + + /** @brief Configure network interface with static IP + * @param my_ip IP address (4 bytes). 0 for no change. + * @param gw_ip Gateway address (4 bytes). 0 for no change. Default = 0 + * @param dns_ip DNS address (4 bytes). 0 for no change. Default = 0 + * @param mask Subnet mask (4 bytes). 0 for no change. Default = 0 + * @return bool Returns true on success - actually always true + */ + static bool staticSetup (const uint8_t* my_ip, + const uint8_t* gw_ip = 0, + const uint8_t* dns_ip = 0, + const uint8_t* mask = 0); + + // tcpip.cpp + /** @brief Sends a UDP packet to the IP address of last processed received packet + * @param data Pointer to data payload + * @param len Size of data payload (max 220) + * @param port Source IP port + */ + static void makeUdpReply (const char *data, uint8_t len, uint16_t port); + + /** @brief Parse received data + * @param plen Size of data to parse (e.g. return value of packetReceive()). + * @return uint16_t Offset of TCP payload data in data buffer or zero if packet processed + * @note Data buffer is shared by receive and transmit functions + * @note Only handles ARP and IP + */ + static uint16_t packetLoop (uint16_t plen); + + /** @brief Accept a TCP/IP connection + * @param port IP port to accept on - do nothing if wrong port + * @param plen Number of bytes in packet + * @return uint16_t Offset within packet of TCP payload. Zero for no data. + */ + static uint16_t accept (uint16_t port, uint16_t plen); + + /** @brief Send a response to a HTTP request + * @param dlen Size of the HTTP (TCP) payload + */ + static void httpServerReply (uint16_t dlen); + + /** @brief Send a response to a HTTP request + * @param dlen Size of the HTTP (TCP) payload + * @param flags TCP flags + */ + static void httpServerReply_with_flags (uint16_t dlen , uint8_t flags); + + /** @brief Acknowledge TCP message + * @todo Is this / should this be private? + */ + static void httpServerReplyAck (); + + /** @brief Set the gateway address + * @param gwipaddr Gateway address (4 bytes) + */ + static void setGwIp (const uint8_t *gwipaddr); + + /** @brief Updates the broadcast address based on current IP address and subnet mask + */ + static void updateBroadcastAddress(); + + /** @brief Check if got gateway hardware address (ARP lookup) + * @return unit8_t True if gateway found + */ + static uint8_t clientWaitingGw (); + + /** @brief Check if got gateway DNS address (ARP lookup) + * @return unit8_t True if DNS found + */ + static uint8_t clientWaitingDns (); + + /** @brief Prepare a TCP request + * @param result_cb Pointer to callback function that handles TCP result + * @param datafill_cb Pointer to callback function that handles TCP data payload + * @param port Remote TCP/IP port to connect to + * @return unit8_t ID of TCP/IP session (0-7) + * @note Return value provides id of the request to allow up to 7 concurrent requests + */ + static uint8_t clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t), + uint16_t (*datafill_cb)(uint8_t),uint16_t port); + + /** @brief Prepare HTTP request + * @param urlbuf Pointer to c-string URL folder + * @param urlbuf_varpart Pointer to c-string URL file + * @param hoststr Pointer to c-string hostname + * @param additionalheaderline Pointer to c-string with additional HTTP header info + * @param callback Pointer to callback function to handle response + * @note Request sent in main packetloop + */ + static void browseUrl (const char *urlbuf, const char *urlbuf_varpart, + const char *hoststr, const char *additionalheaderline, + void (*callback)(uint8_t,uint16_t,uint16_t)); + + /** @brief Prepare HTTP request + * @param urlbuf Pointer to c-string URL folder + * @param urlbuf_varpart Pointer to c-string URL file + * @param hoststr Pointer to c-string hostname + * @param callback Pointer to callback function to handle response + * @note Request sent in main packetloop + */ + static void browseUrl (const char *urlbuf, const char *urlbuf_varpart, + const char *hoststr, + void (*callback)(uint8_t,uint16_t,uint16_t)); + + /** @brief Prepare HTTP post message + * @param urlbuf Pointer to c-string URL folder + * @param hoststr Pointer to c-string hostname + * @param additionalheaderline Pointer to c-string with additional HTTP header info + * @param postval Pointer to c-string HTML Post value + * @param callback Pointer to callback function to handle response + * @note Request sent in main packetloop + */ + static void httpPost (const char *urlbuf, const char *hoststr, + const char *additionalheaderline, const char *postval, + void (*callback)(uint8_t,uint16_t,uint16_t)); + + /** @brief Send NTP request + * @param ntpip IP address of NTP server + * @param srcport IP port to send from + */ + static void ntpRequest (uint8_t *ntpip,uint8_t srcport); + + /** @brief Process network time protocol response + * @param time Pointer to integer to hold result + * @param dstport_l Destination port to expect response. Set to zero to accept on any port + * @return uint8_t True (1) on success + */ + static uint8_t ntpProcessAnswer (uint32_t *time, uint8_t dstport_l); + + /** @brief Prepare a UDP message for transmission + * @param sport Source port + * @param dip Pointer to 4 byte destination IP address + * @param dport Destination port + */ + static void udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport); + + /** @brief Transmit UDP packet + * @param len Size of payload + */ + static void udpTransmit (uint16_t len); + + /** @brief Sends a UDP packet + * @param data Pointer to data + * @param len Size of payload (maximum 220 octets / bytes) + * @param sport Source port + * @param dip Pointer to 4 byte destination IP address + * @param dport Destination port + */ + static void sendUdp (const char *data, uint8_t len, uint16_t sport, + const uint8_t *dip, uint16_t dport); + + /** @brief Resister the function to handle ping events + * @param cb Pointer to function + */ + static void registerPingCallback (void (*cb)(uint8_t*)); + + /** @brief Send ping + * @param destip Ponter to 4 byte destination IP address + */ + static void clientIcmpRequest (const uint8_t *destip); + + /** @brief Check for ping response + * @param ip_monitoredhost Pointer to 4 byte IP address of host to check + * @return uint8_t True (1) if ping response from specified host + */ + static uint8_t packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost); + + /** @brief Send a wake on lan message + * @param wolmac Pointer to 6 byte hardware (MAC) address of host to send message to + */ + static void sendWol (uint8_t *wolmac); + + // new stash-based API + /** @brief Send TCP request + */ + static uint8_t tcpSend (); + + /** @brief Get TCP reply + * @return char* Pointer to TCP reply payload. NULL if no data. + */ + static const char* tcpReply (uint8_t fd); + + /** @brief Configure TCP connections to be persistent or not + * @param persist True to maintain TCP connection. False to finish TCP connection after first packet. + */ + static void persistTcpConnection(bool persist); + + //udpserver.cpp + /** @brief Register function to handle incomint UDP events + * @param callback Function to handle event + * @param port Port to listen on + */ + static void udpServerListenOnPort(UdpServerCallback callback, uint16_t port); + + /** @brief Pause listing on UDP port + * @brief port Port to pause + */ + static void udpServerPauseListenOnPort(uint16_t port); + + /** @brief Resume listing on UDP port + * @brief port Port to pause + */ + static void udpServerResumeListenOnPort(uint16_t port); + + /** @brief Check if UDP server is listening on any ports + * @return bool True if listening on any ports + */ + static bool udpServerListening(); //called by tcpip, in packetLoop + + /** @brief Passes packet to UDP Server + * @param len Not used + * @return bool True if packet processed + */ + static bool udpServerHasProcessedPacket(uint16_t len); //called by tcpip, in packetLoop + + // dhcp.cpp + /** @brief Update DHCP state + * @param len Length of received data packet + */ + static void DhcpStateMachine(uint16_t len); + + /** @brief Not implemented + * @todo Implement dhcpStartTime or remove declaration + */ + static uint32_t dhcpStartTime (); + + /** @brief Not implemented + * @todo Implement dhcpLeaseTime or remove declaration + */ + static uint32_t dhcpLeaseTime (); + + /** @brief Not implemented + * @todo Implement dhcpLease or remove declaration + */ + static bool dhcpLease (); + + /** @brief Configure network interface with DHCP + * @return bool True if DHCP successful + * @note Blocks until DHCP complete or timeout after 60 seconds + */ + static bool dhcpSetup (const char *hname = NULL, bool fromRam =false); + + /** @brief Register a callback for a specific DHCP option number + * @param option The option number to request from the DHCP server + * @param callback The function to be call when the option is received + */ + static void dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback); + + // dns.cpp + /** @brief Perform DNS lookup + * @param name Host name to lookup + * @param fromRam Set true to look up cached name. Default = false + * @return bool True on success. + * @note Result is stored in hisip member + */ + static bool dnsLookup (const char* name, bool fromRam =false); + + // webutil.cpp + /** @brief Copies an IP address + * @param dst Pointer to the 4 byte destination + * @param src Pointer to the 4 byte source + * @note There is no check of source or destination size. Ensure both are 4 bytes + */ + static void copyIp (uint8_t *dst, const uint8_t *src); + + /** @brief Copies a hardware address + * @param dst Pointer to the 6 byte destination + * @param src Pointer to the 6 byte destination + * @note There is no check of source or destination size. Ensure both are 6 bytes + */ + static void copyMac (uint8_t *dst, const uint8_t *src); + + /** @brief Output to serial port in dotted decimal IP format + * @param buf Pointer to 4 byte IP address + * @note There is no check of source or destination size. Ensure both are 4 bytes + */ + static void printIp (const uint8_t *buf); + + /** @brief Output message and IP address to serial port in dotted decimal IP format + * @param msg Pointer to null terminated string + * @param buf Pointer to 4 byte IP address + * @note There is no check of source or destination size. Ensure both are 4 bytes + */ + static void printIp (const char* msg, const uint8_t *buf); + + /** @brief Output Flash String Helper and IP address to serial port in dotted decimal IP format + * @param ifsh Pointer to Flash String Helper + * @param buf Pointer to 4 byte IP address + * @note There is no check of source or destination size. Ensure both are 4 bytes + * @todo What is a FlashStringHelper? + */ + static void printIp (const __FlashStringHelper *ifsh, const uint8_t *buf); + + /** @brief Search for a string of the form key=value in a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\\r\\n + * @param str Pointer to the null terminated string to search + * @param strbuf Pointer to buffer to hold null terminated result string + * @param maxlen Maximum length of result + * @param key Pointer to null terminated string holding the key to search for + * @return unit_t Length of the value. 0 if not found + * @note Ensure strbuf has memory allocated of at least maxlen + 1 (to accomodate result plus terminating null) + */ + static uint8_t findKeyVal(const char *str,char *strbuf, + uint8_t maxlen, const char *key); + + /** @brief Decode a URL string e.g "hello%20joe" or "hello+joe" becomes "hello joe" + * @param urlbuf Pointer to the null terminated URL + * @note urlbuf is modified + */ + static void urlDecode(char *urlbuf); + + /** @brief Encode a URL, replacing illegal charaters like ' ' + * @param str Pointer to the null terminated string to encode + * @param urlbuf Pointer to a buffer to contain the null terminated encoded URL + * @note There must be enough space in urlbuf. In the worst case that is 3 times the length of str + */ + static void urlEncode(char *str,char *urlbuf); + + /** @brief Convert an IP address from dotted decimal formated string to 4 bytes + * @param bytestr Pointer to the 4 byte array to store IP address + * @param str Pointer to string to parse + * @return uint8_t 0 on success + */ + static uint8_t parseIp(uint8_t *bytestr,char *str); + + /** @brief Convert a byte array to a human readable display string + * @param resultstr Pointer to a buffer to hold the resulting null terminated string + * @param bytestr Pointer to the byte array containing the address to convert + * @param len Length of the array (4 for IP address, 6 for hardware (MAC) address) + * @param separator Delimiter character (typically '.' for IP address and ':' for hardware (MAC) address) + * @param base Base for numerical representation (typically 10 for IP address and 16 for hardware (MAC) address + */ + static void makeNetStr(char *resultstr,uint8_t *bytestr,uint8_t len, + char separator,uint8_t base); +}; + +extern EtherCard ether; //!< Global presentation of EtherCard class + +#endif diff --git a/lib-ext/ethercard.git/README.md b/lib-ext/ethercard.git/README.md new file mode 100644 index 0000000..2dd61e4 --- /dev/null +++ b/lib-ext/ethercard.git/README.md @@ -0,0 +1,46 @@ +# EtherCard + +**EtherCard** is a driver for the ENC28J60 chip, compatible with Arduino IDE. +Adapted and extended from code written by Guido Socher and Pascal Stang. + +License: GPL2 + +The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/. + +## Library Installation + +1. Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip +2. From the Arduino IDE: Sketch -> Import Library... -> Add Library... +3. Restart the Arduino IDE to see the new "EtherCard" library with examples + +See the comments in the example sketches for details about how to try them out. + +## Physical Installation + +### PIN Connections (Using Arduino UNO): + + VCC - 3.3V + GND - GND + SCK - Pin 13 + SO - Pin 12 + SI - Pin 11 + CS - Pin 8 # Selectable with the ether.begin() function + +### PIN Connections using an Arduino Mega + + VCC - 3.3V + GND - GND + SCK - Pin 52 + SO - Pin 50 + SI - Pin 51 + CS - Pin 53 # Selectable with the ether.begin() function + # The default CS pin defaults to 8, so you have to set it on a mega: + ether.begin(sizeof Ethernet::buffer, mymac, 53) + +## Support + +For questions and help, see the [forums][F] (at JeeLabs.net). +The issue tracker has been moved back to [Github][I] again. + +[F]: http://jeenet.net/projects/cafe/boards +[I]: https://github.com/jcw/ethercard/issues diff --git a/lib-ext/ethercard.git/dhcp.cpp b/lib-ext/ethercard.git/dhcp.cpp new file mode 100644 index 0000000..00da4cb --- /dev/null +++ b/lib-ext/ethercard.git/dhcp.cpp @@ -0,0 +1,432 @@ +// DHCP look-up functions based on the udp client +// http://www.ietf.org/rfc/rfc2131.txt +// +// Author: Andrew Lindsay +// Rewritten and optimized by Jean-Claude Wippler, http://jeelabs.org/ +// +// Rewritten dhcpStateMachine by Chris van den Hooven +// as to implement dhcp-renew when lease expires (jun 2012) +// +// Various modifications and bug fixes contributed by Victor Aprea (oct 2012) +// +// Copyright: GPL V2 +// See http://www.gnu.org/licenses/gpl.html + +//#define DHCPDEBUG + +#include "EtherCard.h" +#include "net.h" + +#define gPB ether.buffer + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTRESPONSE 2 + +// DHCP Message Type (option 53) (ref RFC 2132) +#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 + +// DHCP States for access in applications (ref RFC 2131) +enum { + DHCP_STATE_INIT, + DHCP_STATE_SELECTING, + DHCP_STATE_REQUESTING, + DHCP_STATE_BOUND, + DHCP_STATE_RENEWING, +}; + +/* + op 1 Message op code / message type. + 1 = BOOTREQUEST, 2 = BOOTREPLY + htype 1 Hardware address type, see ARP section in "Assigned + Numbers" RFC; e.g., '1' = 10mb ethernet. + hlen 1 Hardware address length (e.g. '6' for 10mb + ethernet). + hops 1 Client sets to zero, optionally used by relay agents + when booting via a relay agent. + xid 4 Transaction ID, a random number chosen by the + client, used by the client and server to associate + messages and responses between a client and a + server. + secs 2 Filled in by client, seconds elapsed since client + began address acquisition or renewal process. + flags 2 Flags (see figure 2). + ciaddr 4 Client IP address; only filled in if client is in + BOUND, RENEW or REBINDING state and can respond + to ARP requests. + yiaddr 4 'your' (client) IP address. + siaddr 4 IP address of next server to use in bootstrap; + returned in DHCPOFFER, DHCPACK by server. + giaddr 4 Relay agent IP address, used in booting via a + relay agent. + chaddr 16 Client hardware address. + sname 64 Optional server host name, null terminated string. + file 128 Boot file name, null terminated string; "generic" + name or null in DHCPDISCOVER, fully qualified + directory-path name in DHCPOFFER. + options var Optional parameters field. See the options + documents for a list of defined options. + */ + + + + +// size 236 +typedef struct { + byte op, htype, hlen, hops; + uint32_t xid; + uint16_t secs, flags; + byte ciaddr[4], yiaddr[4], siaddr[4], giaddr[4]; + byte chaddr[16], sname[64], file[128]; + // options +} DHCPdata; + +#define DHCP_SERVER_PORT 67 +#define DHCP_CLIENT_PORT 68 + +// timeouts im ms +#define DHCP_REQUEST_TIMEOUT 10000 + +#define DHCP_HOSTNAME_MAX_LEN 32 + +// RFC 2132 Section 3.3: +// The time value of 0xffffffff is reserved to represent "infinity". +#define DHCP_INFINITE_LEASE 0xffffffff + +static byte dhcpState = DHCP_STATE_INIT; +static char hostname[DHCP_HOSTNAME_MAX_LEN] = "Arduino-00"; +static uint32_t currentXid; +static uint32_t stateTimer; +static uint32_t leaseStart; +static uint32_t leaseTime; +static byte* bufPtr; + +static uint8_t dhcpCustomOptionNum = 0; +static DhcpOptionCallback dhcpCustomOptionCallback = NULL; + +// static uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +static void addToBuf (byte b) { + *bufPtr++ = b; +} + +static void addBytes (byte len, const byte* data) { + while (len-- > 0) + addToBuf(*data++); +} + + +// Main DHCP sending function + +// implemented +// state / msgtype +// INIT / DHCPDISCOVER +// SELECTING / DHCPREQUEST +// BOUND (RENEWING) / DHCPREQUEST + +// ---------------------------------------------------------- +// | |SELECTING |RENEWING |INIT | +// ---------------------------------------------------------- +// |broad/unicast |broadcast |unicast |broadcast | +// |server-ip |MUST |MUST NOT |MUST NOT | option 54 +// |requested-ip |MUST |MUST NOT |MUST NOT | option 50 +// |ciaddr |zero |IP address |zero | +// ---------------------------------------------------------- + +// options used (both send/receive) +// 12 Host Name Option +// 50 Requested IP Address +// 51 IP Address Lease Time +// 53 DHCP message type +// 54 Server-identifier +// 55 Parameter request list +// 58 Renewal (T1) Time Value +// 61 Client-identifier +// 255 End + +static void send_dhcp_message(uint8_t *requestip) { + + uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + memset(gPB, 0, UDP_DATA_P + sizeof( DHCPdata )); + + EtherCard::udpPrepare(DHCP_CLIENT_PORT, + (dhcpState == DHCP_STATE_BOUND ? EtherCard::dhcpip : allOnes), + DHCP_SERVER_PORT); + + // If we ever don't do this, the DHCP renewal gets sent to whatever random + // destmacaddr was used by other code. Rather than cache the MAC address of + // the DHCP server, just force a broadcast here in all cases. + EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes); //force broadcast mac + + // Build DHCP Packet from buf[UDP_DATA_P] + DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P); + dhcpPtr->op = DHCP_BOOTREQUEST; + dhcpPtr->htype = 1; + dhcpPtr->hlen = 6; + dhcpPtr->xid = currentXid; + if (dhcpState == DHCP_STATE_BOUND) { + EtherCard::copyIp(dhcpPtr->ciaddr, EtherCard::myip); + } + EtherCard::copyMac(dhcpPtr->chaddr, EtherCard::mymac); + + // options defined as option, length, value + bufPtr = gPB + UDP_DATA_P + sizeof( DHCPdata ); + // DHCP magic cookie, followed by message type + static byte cookie[] = { 99, 130, 83, 99, 53, 1 }; + addBytes(sizeof cookie, cookie); + // addToBuf(53); // DHCP_STATE_SELECTING, DHCP_STATE_REQUESTING + // addToBuf(1); // Length + addToBuf(dhcpState == DHCP_STATE_INIT ? DHCP_DISCOVER : DHCP_REQUEST); + + // Client Identifier Option, this is the client mac address + addToBuf(61); // Client identifier + addToBuf(7); // Length + addToBuf(0x01); // Ethernet + addBytes(6, EtherCard::mymac); + + addToBuf(12); // Host name Option + addToBuf(10); + addBytes(10, (byte*) hostname); + + if (requestip != NULL) { + addToBuf(50); // Request IP address + addToBuf(4); + addBytes(4, requestip); + + addToBuf(54); // DHCP Server IP address + addToBuf(4); + addBytes(4, EtherCard::dhcpip); + } + + // Additional info in parameter list - minimal list for what we need + byte len = 3; + if (dhcpCustomOptionNum) + len++; + addToBuf(55); // Parameter request list + addToBuf(len); // Length + addToBuf(1); // Subnet mask + addToBuf(3); // Route/Gateway + addToBuf(6); // DNS Server + if (dhcpCustomOptionNum) + addToBuf(dhcpCustomOptionNum); // Custom option + addToBuf(255); // end option + + // packet size will be under 300 bytes + EtherCard::udpTransmit((bufPtr - gPB) - UDP_DATA_P); +} + +static void process_dhcp_offer(uint16_t len, uint8_t *offeredip) { + // Map struct onto payload + DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P); + + // Offered IP address is in yiaddr + EtherCard::copyIp(offeredip, dhcpPtr->yiaddr); + + // Search for the + byte *ptr = (byte*) (dhcpPtr + 1) + 4; + do { + byte option = *ptr++; + byte optionLen = *ptr++; + if (option == 54) { + EtherCard::copyIp(EtherCard::dhcpip, ptr); + break; + } + ptr += optionLen; + } while (ptr < gPB + len); +} + +static void process_dhcp_ack(uint16_t len) { + // Map struct onto payload + DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P); + + // Allocated IP address is in yiaddr + EtherCard::copyIp(EtherCard::myip, dhcpPtr->yiaddr); + + // Scan through variable length option list identifying options we want + byte *ptr = (byte*) (dhcpPtr + 1) + 4; + bool done = false; + do { + byte option = *ptr++; + byte optionLen = *ptr++; + switch (option) { + case 1: + EtherCard::copyIp(EtherCard::netmask, ptr); + break; + case 3: + EtherCard::copyIp(EtherCard::gwip, ptr); + break; + case 6: + EtherCard::copyIp(EtherCard::dnsip, ptr); + break; + case 51: + case 58: + leaseTime = 0; // option 58 = Renewal Time, 51 = Lease Time + for (byte i = 0; i<4; i++) + leaseTime = (leaseTime << 8) + ptr[i]; + if (leaseTime != DHCP_INFINITE_LEASE) { + leaseTime *= 1000; // milliseconds + } + break; + case 255: + done = true; + break; + default: { + // Is is a custom configured option? + if (dhcpCustomOptionCallback && option == dhcpCustomOptionNum) { + dhcpCustomOptionCallback(option, ptr, optionLen); + } + } + } + ptr += optionLen; + } while (!done && ptr < gPB + len); +} + +static bool dhcp_received_message_type (uint16_t len, byte msgType) { + // Map struct onto payload + DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P); + + if (len >= 70 && gPB[UDP_SRC_PORT_L_P] == DHCP_SERVER_PORT && + dhcpPtr->xid == currentXid ) { + + byte *ptr = (byte*) (dhcpPtr + 1) + 4; + do { + byte option = *ptr++; + byte optionLen = *ptr++; + if(option == 53 && *ptr == msgType ) { + // DHCP Message type match found + return true; + } + ptr += optionLen; + } while (ptr < gPB + len); + } + return false; +} + +static char toAsciiHex(byte b) { + char c = b & 0x0f; + c += (c <= 9) ? '0' : 'A'-10; + return c; +} + +bool EtherCard::dhcpSetup (const char *hname, bool fromRam) { + // Use during setup, as this discards all incoming requests until it returns. + // That shouldn't be a problem, because we don't have an IP-address yet. + // Will try 60 secs to obtain DHCP-lease. + + using_dhcp = true; + + if(hname != NULL) { + if(fromRam) { + strncpy(hostname, hname, DHCP_HOSTNAME_MAX_LEN); + } + else { + strncpy_P(hostname, hname, DHCP_HOSTNAME_MAX_LEN); + } + } + else { + // Set a unique hostname, use Arduino-?? with last octet of mac address + hostname[8] = toAsciiHex(mymac[5] >> 4); + hostname[9] = toAsciiHex(mymac[5]); + } + + dhcpState = DHCP_STATE_INIT; + uint16_t start = millis(); + + while (dhcpState != DHCP_STATE_BOUND && (uint16_t) (millis() - start) < 60000) { + if (isLinkUp()) DhcpStateMachine(packetReceive()); + } + updateBroadcastAddress(); + delaycnt = 0; + return dhcpState == DHCP_STATE_BOUND ; +} + +void EtherCard::dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback) +{ + dhcpCustomOptionNum = option; + dhcpCustomOptionCallback = callback; +} + +void EtherCard::DhcpStateMachine (uint16_t len) +{ + +#ifdef DHCPDEBUG + if (dhcpState != DHCP_STATE_BOUND) { + Serial.print(millis()); + Serial.print(" State: "); + } + switch (dhcpState) { + case DHCP_STATE_INIT: + Serial.println("Init"); + break; + case DHCP_STATE_SELECTING: + Serial.println("Selecting"); + break; + case DHCP_STATE_REQUESTING: + Serial.println("Requesting"); + break; + case DHCP_STATE_RENEWING: + Serial.println("Renew"); + break; + } +#endif + + switch (dhcpState) { + + case DHCP_STATE_BOUND: + //!@todo Due to millis() 49 day wrap-around, DHCP renewal may not work as expected + if (leaseTime != DHCP_INFINITE_LEASE && millis() >= leaseStart + leaseTime) { + send_dhcp_message(myip); + dhcpState = DHCP_STATE_RENEWING; + stateTimer = millis(); + } + break; + + case DHCP_STATE_INIT: + currentXid = millis(); + memset(myip,0,4); // force ip 0.0.0.0 + send_dhcp_message(NULL); + enableBroadcast(true); //Temporarily enable broadcasts + dhcpState = DHCP_STATE_SELECTING; + stateTimer = millis(); + break; + + case DHCP_STATE_SELECTING: + if (dhcp_received_message_type(len, DHCP_OFFER)) { + uint8_t offeredip[4]; + process_dhcp_offer(len, offeredip); + send_dhcp_message(offeredip); + dhcpState = DHCP_STATE_REQUESTING; + stateTimer = millis(); + } else { + if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) { + dhcpState = DHCP_STATE_INIT; + } + } + break; + + case DHCP_STATE_REQUESTING: + case DHCP_STATE_RENEWING: + if (dhcp_received_message_type(len, DHCP_ACK)) { + disableBroadcast(true); //Disable broadcast after temporary enable + process_dhcp_ack(len); + leaseStart = millis(); + if (gwip[0] != 0) setGwIp(gwip); // why is this? because it initiates an arp request + dhcpState = DHCP_STATE_BOUND; + } else { + if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) { + dhcpState = DHCP_STATE_INIT; + } + } + break; + + } +} + + + diff --git a/lib-ext/ethercard.git/dns.cpp b/lib-ext/ethercard.git/dns.cpp new file mode 100644 index 0000000..059c321 --- /dev/null +++ b/lib-ext/ethercard.git/dns.cpp @@ -0,0 +1,117 @@ +// DNS look-up functions based on the udp client +// Author: Guido Socher +// Copyright: GPL V2 +// +// 2010-05-20 + +#include "EtherCard.h" +#include "net.h" + +#define gPB ether.buffer + +static byte dnstid_l; // a counter for transaction ID +#define DNSCLIENT_SRC_PORT_H 0xE0 + +static void dnsRequest (const char *hostname, bool fromRam) { + ++dnstid_l; // increment for next request, finally wrap + if (ether.dnsip[0] == 0) + memset(ether.dnsip, 8, 4); // use 8.8.8.8 Google DNS as default + ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l, ether.dnsip, 53); + memset(gPB + UDP_DATA_P, 0, 12); + + byte *p = gPB + UDP_DATA_P + 12; + char c; + do { + byte n = 0; + for(;;) { + c = fromRam ? *hostname : pgm_read_byte(hostname); + ++hostname; + if (c == '.' || c == 0) + break; + p[++n] = c; + } + *p++ = n; + p += n; + } while (c != 0); + + *p++ = 0; // terminate with zero, means root domain. + *p++ = 0; + *p++ = 1; // type A + *p++ = 0; + *p++ = 1; // class IN + byte i = p - gPB - UDP_DATA_P; + gPB[UDP_DATA_P] = i; + gPB[UDP_DATA_P+1] = dnstid_l; + gPB[UDP_DATA_P+2] = 1; // flags, standard recursive query + gPB[UDP_DATA_P+5] = 1; // 1 question + ether.udpTransmit(i); +} + +/** @brief Check if packet is DNS response. + @param plen Size of packet + @return bool True if DNS response has error. False if not DNS response or DNS response OK. + @note hisip contains IP address of requested host or 0.0.0.0 on failure +*/ +static bool checkForDnsAnswer (uint16_t plen) { + byte *p = gPB + UDP_DATA_P; //start of UDP payload + if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != 53 || //from DNS source port + gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H || //response to same port as we sent from (MSB) + gPB[UDP_DST_PORT_L_P] != dnstid_l || //response to same port as we sent from (LSB) + p[1] != dnstid_l) //message id same as we sent + return false; //not our DNS response + if((p[3] & 0x0F) != 0) + return true; //DNS response recieved with error + + p += *p; // we encoded the query len into tid + for (;;) { + if (*p & 0xC0) + p += 2; + else + while (++p < gPB + plen) { + if (*p == 0) { + ++p; + break; + } + } + if (p + 14 > gPB + plen) + break; + if (p[1] == 1 && p[9] == 4) { // type "A" and IPv4 + ether.copyIp(ether.hisip, p + 10); + break; + } + p += p[9] + 10; + } + return false; //No error +} + +// use during setup, as this discards all incoming requests until it returns +bool EtherCard::dnsLookup (const char* name, bool fromRam) { + word start = millis(); + + while(!isLinkUp()) + { + if ((word) (millis() - start) >= 30000) + return false; //timeout waiting for link + } + while(clientWaitingDns()) + { + packetLoop(packetReceive()); + if ((word) (millis() - start) >= 30000) + return false; //timeout waiting for gateway ARP + } + + memset(hisip, 0, 4); + dnsRequest(name, fromRam); + + start = millis(); + while (hisip[0] == 0) { + if ((word) (millis() - start) >= 30000) + return false; //timout waiting for dns response + word len = packetReceive(); + if (len > 0 && packetLoop(len) == 0) //packet not handled by tcp/ip packet loop + if(checkForDnsAnswer(len)) + return false; //DNS response recieved with error + } + + return true; +} diff --git a/lib-ext/ethercard.git/docu.dox b/lib-ext/ethercard.git/docu.dox new file mode 100644 index 0000000..d36659a --- /dev/null +++ b/lib-ext/ethercard.git/docu.dox @@ -0,0 +1,96 @@ +/** +@mainpage EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.
+Adapted and extended from code written by Guido Socher and Pascal Stang.
+The home page for this library is at http://jeelabs.net/projects/ethercard/wiki.
+License: GPL2

+PIN Connections (Using Arduino UNO): + + + + + + + + +
EtherCardArduino UNO
VCC3.3V
GNDGND
SCKPin 13
SOPin 12
SIPin 11
CSPin 8
+ +@section intro_sec Introduction +EtherCard is a library that performs low-level interfacing with network interfaces based on the MicroChip (C) ENC28J60. +High-level routines are provided to allow a variety of purposes including simple data transfer through to HTTP handling. +EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE. + +Adapted and extended from code written by Guido Socher and Pascal Stang. + +The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/ + +The code is available on GitHub, at https://github.com/jcw/ethercard - to install: + +Download the ZIP file from https://github.com/jcw/ethercard/archive/master.zip +From the Arduino IDE: Sketch -> Import Library... -> Add Library... +Restart the Arduino IDE to see the new "EtherCard" library with examples +See the comments in the example sketches for details about how to try them out. + +For questions and help, see the forums. For bugs and feature requests, see the issue tracker. +@section eg_sec Examples +Several @link examples example scripts @endlink are provided with the library which demonstrate various features. Below are descriptions on how to use the library. + +

Note: ether is defined globally and may be used to access the library thus: ether.member. + +@subsection Initiate To initiate the library call EtherCard::begin +

+uint8_t Ethernet::buffer[700]; // configure buffer size to 700 octets
+static uint8_t mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; // define (unique on LAN) hardware (MAC) address
+
+uint8_type nFirmwareVersion ether.begin(sizeof Ethernet::buffer, mymac);
+if(0 == nFirmwareVersion)
+{
+    // handle failure to initiate network interface
+}
+
+ +@subsection DHCP To configure IP address via DHCP use EtherCard::dhcpSetup +
+if(!ether.dhcpSetup())
+{
+// handle failure to obtain IP address via DHCP
+}
+ether.printIp("IP:   ", ether.myip); // output IP address to Serial
+ether.printIp("GW:   ", ether.gwip); // output gateway address to Serial
+ether.printIp("Mask: ", ether.mymask); // output netmask to Serial
+ether.printIp("DHCP server: ", ether.dhcpip); // output IP address of the DHCP server
+
+ +@subsection StaticIP To configure a static IP address use EtherCard::staticSetup +
+const static uint8_t ip[] = {192,168,0,100};
+const static uint8_t gw[] = {192,168,0,254};
+const static uint8_t dns[] = {192,168,0,1};
+
+if(!ether.staticSetup(ip, gw, dns);
+{
+    // handle failure to configure static IP address (current implementation always returns true!)
+}
+
+ +@subsection SendUDP Send UDP packet +To send a UDP packet use EtherCard::sendUdp +
+char payload[] = "My UDP message";
+uint8_t nSourcePort = 1234;
+uint8_t nDestinationPort = 5678;
+uint8_t ipDestinationAddress[4];
+ether.parseIp(ipDestinationAddress, "192.168.0.200");
+
+ether.sendUdp(payload, sizeof(payload), nSourcePort, ipDestinationAddress, nDestinationPort);
+
+ +@subsection DNSLookup DNS Lookup +To perform a DNS lookup use EtherCard::dnsLookup +
+if(!ether.dnsLookup("google.com"))
+{
+    // handle failure of DNS lookup
+}
+ether.printIp("Server: ", ether.hispip); // Result of DNS lookup is placed in the hisip member of EtherCard.
+
+*/ diff --git a/lib-ext/ethercard.git/enc28j60.cpp b/lib-ext/ethercard.git/enc28j60.cpp new file mode 100644 index 0000000..12896ff --- /dev/null +++ b/lib-ext/ethercard.git/enc28j60.cpp @@ -0,0 +1,611 @@ +// Microchip ENC28J60 Ethernet Interface Driver +// Author: Guido Socher +// Copyright: GPL V2 +// +// Based on the enc28j60.c file from the AVRlib library by Pascal Stang. +// For AVRlib See http://www.procyonengineering.com/ +// Used with explicit permission of Pascal Stang. +// +// 2010-05-20 + +#if ARDUINO >= 100 +#include // Arduino 1.0 +#else +#include // Arduino 0022 +#endif +#include "enc28j60.h" + +uint16_t ENC28J60::bufferSize; +bool ENC28J60::broadcast_enabled = false; + +// ENC28J60 Control Registers +// Control register definitions are a combination of address, +// bank number, and Ethernet/MAC/PHY indicator bits. +// - Register address (bits 0-4) +// - Bank number (bits 5-6) +// - MAC/PHY indicator (bit 7) +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +// All-bank registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +// Bank 0 registers +#define ERDPT (0x00|0x00) +#define EWRPT (0x02|0x00) +#define ETXST (0x04|0x00) +#define ETXND (0x06|0x00) +#define ERXST (0x08|0x00) +#define ERXND (0x0A|0x00) +#define ERXRDPT (0x0C|0x00) +// #define ERXWRPT (0x0E|0x00) +#define EDMAST (0x10|0x00) +#define EDMAND (0x12|0x00) +// #define EDMADST (0x14|0x00) +#define EDMACS (0x16|0x00) +// Bank 1 registers +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCS (0x10|0x20) +// #define EPMO (0x14|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +// Bank 2 registers +#define MACON1 (0x00|0x40|0x80) +#define MACON2 (0x01|0x40|0x80) +#define MACON3 (0x02|0x40|0x80) +#define MACON4 (0x03|0x40|0x80) +#define MABBIPG (0x04|0x40|0x80) +#define MAIPG (0x06|0x40|0x80) +#define MACLCON1 (0x08|0x40|0x80) +#define MACLCON2 (0x09|0x40|0x80) +#define MAMXFL (0x0A|0x40|0x80) +#define MAPHSUP (0x0D|0x40|0x80) +#define MICON (0x11|0x40|0x80) +#define MICMD (0x12|0x40|0x80) +#define MIREGADR (0x14|0x40|0x80) +#define MIWR (0x16|0x40|0x80) +#define MIRD (0x18|0x40|0x80) +// Bank 3 registers +#define MAADR1 (0x00|0x60|0x80) +#define MAADR0 (0x01|0x60|0x80) +#define MAADR3 (0x02|0x60|0x80) +#define MAADR2 (0x03|0x60|0x80) +#define MAADR5 (0x04|0x60|0x80) +#define MAADR4 (0x05|0x60|0x80) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCS (0x08|0x60) +#define MISTAT (0x0A|0x60|0x80) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUS (0x18|0x60) + +// ENC28J60 ERXFCON Register Bit Definitions +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 +// ENC28J60 EIE Register Bit Definitions +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +#define EIE_WOLIE 0x04 +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +// ENC28J60 EIR Register Bit Definitions +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +#define EIR_WOLIF 0x04 +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +// ENC28J60 ESTAT Register Bit Definitions +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +// ENC28J60 ECON2 Register Bit Definitions +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +// ENC28J60 ECON1 Register Bit Definitions +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +// ENC28J60 MACON1 Register Bit Definitions +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +// ENC28J60 MACON2 Register Bit Definitions +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +// ENC28J60 MACON3 Register Bit Definitions +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +// ENC28J60 MICMD Register Bit Definitions +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +// ENC28J60 MISTAT Register Bit Definitions +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 + +// ENC28J60 EBSTCON Register Bit Definitions +#define EBSTCON_PSV2 0x80 +#define EBSTCON_PSV1 0x40 +#define EBSTCON_PSV0 0x20 +#define EBSTCON_PSEL 0x10 +#define EBSTCON_TMSEL1 0x08 +#define EBSTCON_TMSEL0 0x04 +#define EBSTCON_TME 0x02 +#define EBSTCON_BISTST 0x01 + +// PHY registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +// ENC28J60 PHY PHCON1 Register Bit Definitions +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +// ENC28J60 PHY PHSTAT1 Register Bit Definitions +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +// ENC28J60 PHY PHCON2 Register Bit Definitions +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 + +// ENC28J60 Packet Control Byte Bit Definitions +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +// SPI operation codes +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + +// The RXSTART_INIT must be zero. See Rev. B4 Silicon Errata point 5. +// Buffer boundaries applied to internal 8K ram +// the entire available packet buffer space is allocated + +#define RXSTART_INIT 0x0000 // start of RX buffer, room for 2 packets +#define RXSTOP_INIT 0x0BFF // end of RX buffer + +#define TXSTART_INIT 0x0C00 // start of TX buffer, room for 1 packet +#define TXSTOP_INIT 0x11FF // end of TX buffer + +#define SCRATCH_START 0x1200 // start of scratch area +#define SCRATCH_LIMIT 0x2000 // past end of area, i.e. 3.5 Kb +#define SCRATCH_PAGE_SHIFT 6 // addressing is in pages of 64 bytes +#define SCRATCH_PAGE_SIZE (1 << SCRATCH_PAGE_SHIFT) + +// max frame length which the conroller will accept: +// (note: maximum ethernet frame length would be 1518) +#define MAX_FRAMELEN 1500 + +#define FULL_SPEED 1 // switch to full-speed SPI for bulk transfers + +static byte Enc28j60Bank; +static int gNextPacketPtr; +static byte selectPin; + +void ENC28J60::initSPI () { + pinMode(SS, OUTPUT); + digitalWrite(SS, HIGH); + pinMode(MOSI, OUTPUT); + pinMode(SCK, OUTPUT); + pinMode(MISO, INPUT); + + digitalWrite(MOSI, HIGH); + digitalWrite(MOSI, LOW); + digitalWrite(SCK, LOW); + + SPCR = bit(SPE) | bit(MSTR); // 8 MHz @ 16 + bitSet(SPSR, SPI2X); +} + +static void enableChip () { + cli(); + digitalWrite(selectPin, LOW); +} + +static void disableChip () { + digitalWrite(selectPin, HIGH); + sei(); +} + +static void xferSPI (byte data) { + SPDR = data; + while (!(SPSR&(1<>5); + } +} + +static byte readRegByte (byte address) { + SetBank(address); + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +static uint16_t readReg(byte address) { + return readRegByte(address) + (readRegByte(address+1) << 8); +} + +static void writeRegByte (byte address, byte data) { + SetBank(address); + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +static void writeReg(byte address, uint16_t data) { + writeRegByte(address, data); + writeRegByte(address + 1, data >> 8); +} + +static uint16_t readPhyByte (byte address) { + writeRegByte(MIREGADR, address); + writeRegByte(MICMD, MICMD_MIIRD); + while (readRegByte(MISTAT) & MISTAT_BUSY) + ; + writeRegByte(MICMD, 0x00); + return readRegByte(MIRD+1); +} + +static void writePhy (byte address, uint16_t data) { + writeRegByte(MIREGADR, address); + writeReg(MIWR, data); + while (readRegByte(MISTAT) & MISTAT_BUSY) + ; +} + +byte ENC28J60::initialize (uint16_t size, const byte* macaddr, byte csPin) { + bufferSize = size; + if (bitRead(SPCR, SPE) == 0) + initSPI(); + selectPin = csPin; + pinMode(selectPin, OUTPUT); + disableChip(); + + writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + delay(2); // errata B7/2 + while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) + ; + + gNextPacketPtr = RXSTART_INIT; + writeReg(ERXST, RXSTART_INIT); + writeReg(ERXRDPT, RXSTART_INIT); + writeReg(ERXND, RXSTOP_INIT); + writeReg(ETXST, TXSTART_INIT); + writeReg(ETXND, TXSTOP_INIT); + enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam + writeReg(EPMM0, 0x303f); + writeReg(EPMCS, 0xf7f9); + writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + writeRegByte(MACON2, 0x00); + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, + MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + writeReg(MAIPG, 0x0C12); + writeRegByte(MABBIPG, 0x12); + writeReg(MAMXFL, MAX_FRAMELEN); + writeRegByte(MAADR5, macaddr[0]); + writeRegByte(MAADR4, macaddr[1]); + writeRegByte(MAADR3, macaddr[2]); + writeRegByte(MAADR2, macaddr[3]); + writeRegByte(MAADR1, macaddr[4]); + writeRegByte(MAADR0, macaddr[5]); + writePhy(PHCON2, PHCON2_HDLDIS); + SetBank(ECON1); + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + + byte rev = readRegByte(EREVID); + // microchip forgot to step the number on the silcon when they + // released the revision B7. 6 is now rev B7. We still have + // to see what they do when they release B8. At the moment + // there is no B8 out yet + if (rev > 5) ++rev; + return rev; +} + +bool ENC28J60::isLinkUp() { + return (readPhyByte(PHSTAT2) >> 2) & 1; +} + +void ENC28J60::packetSend(uint16_t len) { + // see http://forum.mysensors.org/topic/536/ + // while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS) + if (readRegByte(EIR) & EIR_TXERIF) { + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); + writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF); + } + writeReg(EWRPT, TXSTART_INIT); + writeReg(ETXND, TXSTART_INIT+len); + writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); + writeBuf(len, buffer); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); +} + +uint16_t ENC28J60::packetReceive() { + uint16_t len = 0; + if (readRegByte(EPKTCNT) > 0) { + writeReg(ERDPT, gNextPacketPtr); + + struct { + uint16_t nextPacket; + uint16_t byteCount; + uint16_t status; + } header; + + readBuf(sizeof header, (byte*) &header); + + gNextPacketPtr = header.nextPacket; + len = header.byteCount - 4; //remove the CRC count + if (len>bufferSize-1) + len=bufferSize-1; + if ((header.status & 0x80)==0) + len = 0; + else + readBuf(len, buffer); + buffer[len] = 0; + if (gNextPacketPtr - 1 > RXSTOP_INIT) + writeReg(ERXRDPT, RXSTOP_INIT); + else + writeReg(ERXRDPT, gNextPacketPtr - 1); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + } + return len; +} + +void ENC28J60::copyout (byte page, const byte* data) { + uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT); + if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE) + return; + writeReg(EWRPT, destPos); + writeBuf(SCRATCH_PAGE_SIZE, data); +} + +void ENC28J60::copyin (byte page, byte* data) { + uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT); + if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE) + return; + writeReg(ERDPT, destPos); + readBuf(SCRATCH_PAGE_SIZE, data); +} + +byte ENC28J60::peekin (byte page, byte off) { + byte result = 0; + uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT) + off; + if (SCRATCH_START <= destPos && destPos < SCRATCH_LIMIT) { + writeReg(ERDPT, destPos); + readBuf(1, &result); + } + return result; +} + +// Contributed by Alex M. Based on code from: http://blog.derouineau.fr +// /2011/07/putting-enc28j60-ethernet-controler-in-sleep-mode/ +void ENC28J60::powerDown() { + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + while(readRegByte(ESTAT) & ESTAT_RXBUSY); + while(readRegByte(ECON1) & ECON1_TXRTS); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +void ENC28J60::powerUp() { + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + while(!readRegByte(ESTAT) & ESTAT_CLKRDY); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); +} + +void ENC28J60::enableBroadcast (bool temporary) { + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN); + if(!temporary) + broadcast_enabled = true; +} + +void ENC28J60::disableBroadcast (bool temporary) { + if(!temporary) + broadcast_enabled = false; + if(!broadcast_enabled) + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN); +} + +void ENC28J60::enableMulticast () { + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN); +} + +void ENC28J60::disableMulticast () { + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN); +} + +uint8_t ENC28J60::doBIST ( byte csPin) { +#define RANDOM_FILL 0b0000 +#define ADDRESS_FILL 0b0100 +#define PATTERN_SHIFT 0b1000 +#define RANDOM_RACE 0b1100 + +// init + if (bitRead(SPCR, SPE) == 0) + initSPI(); + selectPin = csPin; + pinMode(selectPin, OUTPUT); + disableChip(); + + writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + delay(2); // errata B7/2 + while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ; + + + // now we can start the memory test + + uint16_t macResult; + uint16_t bitsResult; + + // clear some of the registers registers + writeRegByte(ECON1, 0); + writeReg(EDMAST, 0); + + // Set up necessary pointers for the DMA to calculate over the entire memory + writeReg(EDMAND, 0x1FFFu); + writeReg(ERXND, 0x1FFFu); + + // Enable Test Mode and do an Address Fill + SetBank(EBSTCON); + writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_BISTST | ADDRESS_FILL); + + // wait for BISTST to be reset, only after that are we actually ready to + // start the test + // this was undocumented :( + while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST); + writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME); + + + // now start the actual reading an calculating the checksum until the end is + // reached + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN); + SetBank(EDMACS); + while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); + macResult = readReg(EDMACS); + bitsResult = readReg(EBSTCS); + // Compare the results + // 0xF807 should always be generated in Address fill mode + if ((macResult != bitsResult) || (bitsResult != 0xF807)) { + return 0; + } + // reset test flag + writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME); + + + // Now start the BIST with random data test, and also keep on swapping the + // DMA/BIST memory ports. + writeRegByte(EBSTSD, 0b10101010 | millis()); + writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_PSEL | EBSTCON_BISTST | RANDOM_FILL); + + + // wait for BISTST to be reset, only after that are we actually ready to + // start the test + // this was undocumented :( + while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST); + writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME); + + + // now start the actual reading an calculating the checksum until the end is + // reached + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN); + SetBank(EDMACS); + while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); + + macResult = readReg(EDMACS); + bitsResult = readReg(EBSTCS); + // The checksum should be equal + return macResult == bitsResult; +} + diff --git a/lib-ext/ethercard.git/enc28j60.h b/lib-ext/ethercard.git/enc28j60.h new file mode 100644 index 0000000..f0b3f70 --- /dev/null +++ b/lib-ext/ethercard.git/enc28j60.h @@ -0,0 +1,114 @@ +// Microchip ENC28J60 Ethernet Interface Driver +// Author: Pascal Stang +// Modified by: Guido Socher +// Copyright: GPL V2 +// +// This driver provides initialization and transmit/receive +// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY. +// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin +// chip, using an SPI interface to the host processor. +// +// 2010-05-20 + +#ifndef ENC28J60_H +#define ENC28J60_H + +/** This class provide low-level interfacing with the ENC28J60 network interface. This is used by the EtherCard class and not intended for use by (normal) end users. */ +class ENC28J60 { +public: + static uint8_t buffer[]; //!< Data buffer (shared by recieve and transmit) + static uint16_t bufferSize; //!< Size of data buffer + static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions) + + static uint8_t* tcpOffset () { return buffer + 0x36; } //!< Pointer to the start of TCP payload + + /** @brief Initialise SPI interface + * @note Configures Arduino pins as input / output, etc. + */ + static void initSPI (); + + /** @brief Initialise network interface + * @param size Size of data buffer + * @param macaddr Pointer to 6 byte hardware (MAC) address + * @param csPin Arduino pin used for chip select (enable network interface SPI bus). Default = 8 + * @return uint8_t ENC28J60 firmware version or zero on failure. + */ + static uint8_t initialize (const uint16_t size, const uint8_t* macaddr, + uint8_t csPin = 8); + + /** @brief Check if network link is connected + * @return bool True if link is up + */ + static bool isLinkUp (); + + /** @brief Sends data to network interface + * @param len Size of data to send + * @note Data buffer is shared by recieve and transmit functions + */ + static void packetSend (uint16_t len); + + /** @brief Copy recieved packets to data buffer + * @return uint16_t Size of recieved data + * @note Data buffer is shared by recieve and transmit functions + */ + static uint16_t packetReceive (); + + /** @brief Copy data from ENC28J60 memory + * @param page Data page of memory + * @param data Pointer to buffer to copy data to + */ + static void copyout (uint8_t page, const uint8_t* data); + + /** @brief Copy data to ENC28J60 memory + * @param page Data page of memory + * @param data Pointer to buffer to copy data from + */ + static void copyin (uint8_t page, uint8_t* data); + + /** @brief Get single byte of data from ENC28J60 memory + * @param page Data page of memory + * @param off Offset of data within page + * @return Data value + */ + static uint8_t peekin (uint8_t page, uint8_t off); + + /** @brief Put ENC28J60 in sleep mode + */ + static void powerDown(); // contrib by Alex M. + + /** @brief Wake ENC28J60 from sleep mode + */ + static void powerUp(); // contrib by Alex M. + + /** @brief Enable reception of broadcast messages + * @param temporary Set true to temporarily enable broadcast + * @note This will increase load on recieved data handling + */ + static void enableBroadcast(bool temporary = false); + + /** @brief Disable reception of broadcast messages + * @param temporary Set true to only disable if temporarily enabled + * @note This will reduce load on recieved data handling + */ + static void disableBroadcast(bool temporary = false); + + /** @brief Enables reception of mulitcast messages + * @note This will increase load on recieved data handling + */ + static void enableMulticast (); + + /** @brief Disable reception of mulitcast messages + * @note This will reduce load on recieved data handling + */ + static void disableMulticast(); + + /** @brief Reset and fully initialise ENC28J60 + * @param csPin Arduino pin used for chip select (enable SPI bus) + * @return uint8_t 0 on failure + */ + static uint8_t doBIST(uint8_t csPin = 8); +}; + +typedef ENC28J60 Ethernet; //!< Define alias Ethernet for ENC28J60 + +#endif diff --git a/lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino b/lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino new file mode 100644 index 0000000..467a62e --- /dev/null +++ b/lib-ext/ethercard.git/examples/JeeUdp/JeeUdp.ino @@ -0,0 +1,320 @@ +// Collect RF12 packets and send them on as UDP collectd packets on Ethernet. +// 2010-05-20 http://opensource.org/licenses/mit-license.php + +// This sketch is derived from RF12eth.pde (and etherNode.ino): +// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php + +#include +#include +#include + +#define DEBUG 1 // set to 1 to display free RAM on web page +#define SERIAL 1 // set to 1 to show incoming requests on serial port + +#define CONFIG_EEPROM_ADDR ((byte*) 0x10) + +// configuration, as stored in EEPROM +struct Config { + byte band; + byte group; + byte collect; + word port; + byte valid; // keep this as last byte +} config; + +// ethernet interface mac address - must be unique on your network +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +// buffer for an outgoing data packet +static byte outBuf[RF12_MAXDATA], outDest; +static char outCount = -1; + +// this buffer will be used to construct a collectd UDP packet +static byte collBuf [200], collPos; + +#define NUM_MESSAGES 3 // Number of messages saved in history +#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use + +static BufferFiller bfill; // used as cursor while filling the buffer + +static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record +static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history +static byte next_msg; // pointer to next rf12rcvd line +static word msgs_rcvd; // total number of lines received modulo 10,000 + +byte Ethernet::buffer[700]; // tcp/ip send and receive buffer + +static void loadConfig () { + for (byte i = 0; i < sizeof config; ++i) + ((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i); + if (config.valid != 253) { + config.valid = 253; + config.band = 8; + config.group = 1; + config.collect = 1; + config.port = 25827; + } + byte freq = config.band == 4 ? RF12_433MHZ : + config.band == 8 ? RF12_868MHZ : + RF12_915MHZ; + rf12_initialize(31, freq, config.group); +} + +static void saveConfig () { + for (byte i = 0; i < sizeof config; ++i) + eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]); +} + +#if DEBUG +static int freeRam () { +extern int __heap_start, *__brkval; +int v; +return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} +#endif + +void setup (){ + Serial.begin(57600); + Serial.println("\n[JeeUdp]"); + loadConfig(); + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); + if (!ether.dhcpSetup()) + Serial.println("DHCP failed"); + ether.printIp("IP: ", ether.myip); +} + +const char okHeader[] PROGMEM = + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "Pragma: no-cache\r\n" +; + +static void homePage (BufferFiller& buf) { + word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915; + buf.emit_p(PSTR("$F\r\n" + "RF12 JeeUdp" + "

RF12 JeeUdp @ $D - RF12 @ $D.$D

" + "Configure - Send Packet" + "

Last $D messages:

" + "
"), okHeader, config.port, mhz, config.group, NUM_MESSAGES);
+  for (byte i = 0; i < NUM_MESSAGES; ++i) {
+    byte j = (next_msg + i) % NUM_MESSAGES;
+    if (history_len[j] > 0) {
+      word n = msgs_rcvd - NUM_MESSAGES + i;
+      buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
+                          n/1000, (n/100) % 10, (n/10) % 10, n % 10);
+      for (byte k = 0; k < history_len[j]; ++k)
+        buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
+    }
+  }
+  long t = millis() / 1000;
+  word h = t / 3600;
+  byte m = (t / 60) % 60;
+  byte s = t % 60;
+  buf.emit_p(PSTR(
+    "
" + "Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10); +#if DEBUG + buf.emit_p(PSTR(" ($D bytes free)"), freeRam()); +#endif +} + +static int getIntArg(const char* data, const char* key, int value =-1) { + char temp[10]; + if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0) + value = atoi(temp); + return value; +} + +static void configPage (const char* data, BufferFiller& buf) { + // pick up submitted data, if present + if (data[6] == '?') { + byte b = getIntArg(data, "b", 8); + byte g = getIntArg(data, "g", 1); + byte c = getIntArg(data, "c", 0); + word p = getIntArg(data, "p", 25827); + if (1 <= g && g <= 250 && 1024 <= p && p <= 30000) { + // store values as new settings + config.band = b; + config.group = g; + config.collect = c; + config.port = p; + saveConfig(); + // re-init RF12 driver + loadConfig(); + // clear history + memset(history_len, 0, sizeof history_len); + // redirect to the home page + buf.emit_p(PSTR( + "HTTP/1.0 302 found\r\n" + "Location: /\r\n" + "\r\n")); + return; + } + } + // else show a configuration form + buf.emit_p(PSTR("$F\r\n" + "

Server node configuration

" + "
" + "

" + "Freq band (4, 8, or 9)
" + "Net group (1..250)
" + "Collect mode: " + "(don't send ACKs)

" + "UDP Port (1024..30000)" + "

" + "" + "
"), okHeader, config.band, config.group, + config.collect ? "CHECKED" : "", + config.port); +} + +static void sendPage (const char* data, BufferFiller& buf) { + // pick up submitted data, if present + const char* p = strstr(data, "b="); + byte d = getIntArg(data, "d"); + if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) { + // prepare to send data as soon as possible in loop() + outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0; + outCount = 0; + // convert the input string to a number of decimal data bytes in outBuf + ++p; + while (*p != 0 && *p != '&') { + outBuf[outCount] = 0; + while ('0' <= *++p && *p <= '9') + outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0'); + ++outCount; + } +#if SERIAL + Serial.print("Send to "); + Serial.print(outDest, DEC); + Serial.print(':'); + for (byte i = 0; i < outCount; ++i) { + Serial.print(' '); + Serial.print(outBuf[i], DEC); + } + Serial.println(); +#endif + // redirect to home page + buf.emit_p(PSTR( + "HTTP/1.0 302 found\r\n" + "Location: /\r\n" + "\r\n")); + return; + } + // else show a send form + buf.emit_p(PSTR("$F\r\n" + "

Send a wireless data packet

" + "
" + "

" + "Data bytes (decimal)
" + "Destination node " + "(1..31, or 0 to broadcast)
" + "

" + "" + "
"), okHeader); +} + +static void collectTypeLen (word type, word len) { + len += 4; + collBuf[collPos++] = type >> 8; + collBuf[collPos++] = (byte) type; + collBuf[collPos++] = len >> 8; + collBuf[collPos++] = (byte) len; +} + +static void collectStr (word type, const char* data) { + word len = strlen(data) + 1; + collectTypeLen(type, len); + strcpy((char*) collBuf + collPos, data); + collPos += len; +} + +static void collectPayload (word type) { + // Copy the received RF12 data into a as many values as needed. + byte num = rf12_len / 8 + 1; // this many values will be needed + collectTypeLen(type, 2 + 9 * num); + collBuf[collPos++] = 0; + collBuf[collPos++] = num; + for (byte i = 0; i < num; ++i) + collBuf[collPos++] = 0; // counter + for (char i = 0; i < 8 * num; ++i) // include -1, i.e. the length byte + collBuf[collPos++] = i <= rf12_len ? rf12_data[i-1] : 0; +} + +static void forwardToUDP () { + static byte destIp[] = { 239,192,74,66 }; // UDP multicast address + char buf[10]; + + collPos = 0; + collectStr(0x0000, "JeeUdp"); + collectStr(0x0002, "RF12"); + word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915; + sprintf(buf, "%d.%d", mhz, config.group); + collectStr(0x0003, buf); + collectStr(0x0004, "OK"); + sprintf(buf, "%d", rf12_hdr); + collectStr(0x0005, buf); + collectPayload(0x0006); + + ether.sendUdp ((char*) collBuf, collPos, 23456, destIp, config.port); +#if SERIAL + Serial.println("UDP sent"); +#endif +} + +void loop (){ + word len = ether.packetReceive(); + word pos = ether.packetLoop(len); + // check if valid tcp data is received + if (pos) { + bfill = ether.tcpOffset(); + char* data = (char *) Ethernet::buffer + pos; +#if SERIAL + Serial.println(data); +#endif + // receive buf hasn't been clobbered by reply yet + if (strncmp("GET / ", data, 6) == 0) + homePage(bfill); + else if (strncmp("GET /c", data, 6) == 0) + configPage(data, bfill); + else if (strncmp("GET /s", data, 6) == 0) + sendPage(data, bfill); + else + bfill.emit_p(PSTR( + "HTTP/1.0 401 Unauthorized\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "

401 Unauthorized

")); + ether.httpServerReply(bfill.position()); // send web page data + } + + // RFM12 loop runner, don't report acks + if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) { + history_rcvd[next_msg][0] = rf12_hdr; + for (byte i = 0; i < rf12_len; ++i) + if (i < MESSAGE_TRUNC) + history_rcvd[next_msg][i+1] = rf12_data[i]; + history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1 + : MESSAGE_TRUNC+1; + next_msg = (next_msg + 1) % NUM_MESSAGES; + msgs_rcvd = (msgs_rcvd + 1) % 10000; + + if (RF12_WANTS_ACK && !config.collect) { +#if SERIAL + Serial.println(" -> ack"); +#endif + rf12_sendStart(RF12_ACK_REPLY, 0, 0); + } + + forwardToUDP(); + } + + // send a data packet out if requested + if (outCount >= 0 && rf12_canSend()) { + rf12_sendStart(outDest, outBuf, outCount, 1); + outCount = -1; + } +} + diff --git a/lib-ext/ethercard.git/examples/SSDP/SSDP.ino b/lib-ext/ethercard.git/examples/SSDP/SSDP.ino new file mode 100644 index 0000000..03afd03 --- /dev/null +++ b/lib-ext/ethercard.git/examples/SSDP/SSDP.ino @@ -0,0 +1,144 @@ +#include // |Mac adress| +const char SSDP_RESPONSE[] PROGMEM = "HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1200\r\nEXT:\r\nSERVER:Arduino\r\nST: upnp:rootdevice\r\nUSN: uuid:abcdefgh-7dec-11d0-a765-7499692d3040\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr +const char SSDP_RESPONSE_XML[] PROGMEM = "/??\r\n\r\n"; // here is the adress of xml file /?? in this exemple but you could use another /upnp.xml\r\n\r\n +const char XML_DESCRIP[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n\rurn:schemas-upnp-org:device:BinaryLight:1/ArduinoFredycpuhttp://fredycpu.pro1uuid:abcdefgh-7dec-11d0-a765-7499692d3040 "; +const char SSDP_NOTIFY[] PROGMEM = "NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1200\r\nNT: upnp:rootdevice\r\nUSN: uuid:abcdefga-7dec-11d0-a765-7499692d3040::upnp:rootdevice\r\nNTS: ssdp:alive\r\nSERVER: Arduino UPnP/1.0\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr +// in XML_DESCRIP // urn:schemas-upnp-org:device:BinaryLight:1 // declare as home automation +// in XML_DESCRIP // Arduino // declare the name of the service here Arduino +// in XML_DESCRIP // / // adress of the page who would opened on service double click ,you could use http://ip but if you use dhcp it's better so and dont wase memory +// this is the entire protocol, but you can try to use SSDP_NOTIFY as SSDP_RESPONSE with most systems will work and you can free a bit of flash mem. +static byte myip[] = { + 192,168,0,67 }; +static byte gwip[] = { + 192,168,0,250 }; +static byte ssdp[] = { + 239,255,255,250 }; +static byte mymac[] = { + 0x74,0x99,0x69,0x2D,0x30,0x40 }; // if you change it you must update SSDP_RESPONSE and XML_DESCRIP +byte Ethernet::buffer[750]; // tcp ip send and receive buffer +unsigned long timer=9999; +const char pageA[] PROGMEM = +"HTTP/1.0 200 OK\r\n" +"Content-Type: text/html\r\n" +"\r\n" +"" +"" +"multipackets Test" +"" +"" +"Start here
" +"Image test
" +"

packet 1

" +"

" +"the first packet send " +"

" +; +const char pageB[] PROGMEM = +"

packet 2

" +"

" +"if you read this it mean it works" +"

" +; +const char pageC[] PROGMEM = +"

packet 3

" +"

" +"if you read this it mean it works" +"

" +; +const char pageD[] PROGMEM = +"

packet 4

" +"

" +"if you read this it mean it works" +"

" +; + +void setup(){ + ether.begin(sizeof Ethernet::buffer, mymac , 10);// 53 for the mega ethernet shield and 10 for normal ethernet shield + ether.staticSetup(myip, gwip); + ENC28J60::disableMulticast(); //disable multicast filter means enable multicast reception + Serial.begin(115200); +} + +void loop(){ +wait: + word pos = ether.packetLoop(ether.packetReceive()); + // check if valid tcp data is received + if (pos) { + char* data = (char *) Ethernet::buffer + pos; + if (strncmp("GET / ", data, 6) == 0) { + ether.httpServerReplyAck(); // send ack to the request + memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and send the terminate flag + ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); + goto wait; + } + if (strncmp("GET /??", data, 7) == 0) { // description of services (normaly an xml file but here .....) + ether.httpServerReplyAck(); + memcpy_P(Ethernet::buffer + TCP_OPTIONS_P,XML_DESCRIP, sizeof XML_DESCRIP); + ether.httpServerReply_with_flags(sizeof XML_DESCRIP - 1 ,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); + goto wait; + } + if (strncmp("M-SEARCH", data, 8) == 0) { // service discovery request comes here (udp protocol) + ssdpresp(); + goto wait; + } + } + if (((millis()-timer)>50000)||(timer>millis())) { + timer=millis(); + ssdpnotify(); + } +} +void ssdpresp() { //response to m-search + byte ip_dst[4]; + unsigned int port_dst=Ethernet::buffer[34]*256+Ethernet::buffer[35];//extract source port of request + for( int i=0; i<4;i++) { //extract source IP of request + ip_dst[i]=Ethernet::buffer[i+26]; + } + int udppos = UDP_DATA_P; + + EtherCard::udpPrepare(1900,ip_dst,port_dst); + memcpy_P(Ethernet::buffer + udppos, SSDP_RESPONSE, sizeof SSDP_RESPONSE); + udppos = udppos + sizeof SSDP_RESPONSE-1; + addip(udppos); +} + +void ssdpnotify() { //Notification + int udppos = UDP_DATA_P; + EtherCard::udpPrepare(1900,ssdp,1900); + memcpy_P(Ethernet::buffer + udppos, SSDP_NOTIFY, sizeof SSDP_NOTIFY); +udppos = udppos + sizeof SSDP_NOTIFY-1; +addip(udppos); +} + +void addip(int udppos) { // add current ip to the request and send it + int adr; + for(int i=0;i<4;i++) { // extract the current ip of arduino + adr = ether.myip[i]/100; + if (adr) { + Ethernet::buffer[udppos]=adr+48; + udppos++; + } + adr=(ether.myip[i]%100)/10; + if (adr) { + Ethernet::buffer[udppos]=adr+48; + udppos++; + } + adr=ether.myip[i]%10; + Ethernet::buffer[udppos]=adr+48; + udppos++; + Ethernet::buffer[udppos]=46; + udppos++; //"." + } + udppos--;//erase the last point + memcpy_P(Ethernet::buffer + udppos,SSDP_RESPONSE_XML,sizeof SSDP_RESPONSE_XML); + udppos = udppos + sizeof SSDP_RESPONSE_XML; + udppos--; + EtherCard::udpTransmit(udppos-UDP_DATA_P); // send all to the computer who make the request on her ip and port who make the request +} + + diff --git a/lib-ext/ethercard.git/examples/backSoon/backSoon.ino b/lib-ext/ethercard.git/examples/backSoon/backSoon.ino new file mode 100644 index 0000000..b648017 --- /dev/null +++ b/lib-ext/ethercard.git/examples/backSoon/backSoon.ino @@ -0,0 +1,63 @@ +// Present a "Will be back soon web page", as stand-in webserver. +// 2011-01-30 http://opensource.org/licenses/mit-license.php + +#include + +#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below) + +#if STATIC +// ethernet interface ip address +static byte myip[] = { 192,168,1,200 }; +// gateway ip address +static byte gwip[] = { 192,168,1,1 }; +#endif + +// ethernet mac address - must be unique on your network +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[500]; // tcp/ip send and receive buffer + +const char page[] PROGMEM = +"HTTP/1.0 503 Service Unavailable\r\n" +"Content-Type: text/html\r\n" +"Retry-After: 600\r\n" +"\r\n" +"" + "" + "Service Temporarily Unavailable" + "" + "" + "

This service is currently unavailable

" + "

" + "The main server is currently off-line.
" + "Please try again later." + "

" + "" +"" +; + +void setup(){ + Serial.begin(57600); + Serial.println("\n[backSoon]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); +#if STATIC + ether.staticSetup(myip, gwip); +#else + if (!ether.dhcpSetup()) + Serial.println("DHCP failed"); +#endif + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + ether.printIp("DNS: ", ether.dnsip); +} + +void loop(){ + // wait for an incoming TCP packet, but ignore its contents + if (ether.packetLoop(ether.packetReceive())) { + memcpy_P(ether.tcpOffset(), page, sizeof page); + ether.httpServerReply(sizeof page - 1); + } +} diff --git a/lib-ext/ethercard.git/examples/etherNode/etherNode.ino b/lib-ext/ethercard.git/examples/etherNode/etherNode.ino new file mode 100644 index 0000000..00e0e92 --- /dev/null +++ b/lib-ext/ethercard.git/examples/etherNode/etherNode.ino @@ -0,0 +1,276 @@ +// Arduino demo sketch for testing RFM12B + ethernet +// 2010-05-20 http://opensource.org/licenses/mit-license.php + +// Listens for RF12 messages and displays valid messages on a webpage +// Memory usage exceeds 1K, so use Atmega328 or decrease history/buffers +// +// This sketch is derived from RF12eth.pde: +// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php + +#include +#include +#include + +#define DEBUG 1 // set to 1 to display free RAM on web page +#define SERIAL 0 // set to 1 to show incoming requests on serial port + +#define CONFIG_EEPROM_ADDR ((byte*) 0x10) + +// configuration, as stored in EEPROM +struct Config { + byte band; + byte group; + byte collect; + word refresh; + byte valid; // keep this as last byte +} config; + +// ethernet interface mac address - must be unique on your network +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +// buffer for an outgoing data packet +static byte outBuf[RF12_MAXDATA], outDest; +static char outCount = -1; + +#define NUM_MESSAGES 10 // Number of messages saved in history +#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use + +static BufferFiller bfill; // used as cursor while filling the buffer + +static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record +static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history +static byte next_msg; // pointer to next rf12rcvd line +static word msgs_rcvd; // total number of lines received modulo 10,000 + +byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer + +static void loadConfig() { + for (byte i = 0; i < sizeof config; ++i) + ((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i); + if (config.valid != 253) { + config.valid = 253; + config.band = 8; + config.group = 1; + config.collect = 1; + config.refresh = 5; + } + byte freq = config.band == 4 ? RF12_433MHZ : + config.band == 8 ? RF12_868MHZ : + RF12_915MHZ; + rf12_initialize(31, freq, config.group); +} + +static void saveConfig() { + for (byte i = 0; i < sizeof config; ++i) + eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]); +} + +#if DEBUG +static int freeRam () { + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} +#endif + +void setup(){ +#if SERIAL + Serial.begin(57600); + Serial.println("\n[etherNode]"); +#endif + loadConfig(); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); + if (!ether.dhcpSetup()) + Serial.println("DHCP failed"); +#if SERIAL + ether.printIp("IP: ", ether.myip); +#endif +} + +const char okHeader[] PROGMEM = + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "Pragma: no-cache\r\n" +; + +static void homePage(BufferFiller& buf) { + word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915; + buf.emit_p(PSTR("$F\r\n" + "" + "RF12 etherNode - $D MHz, group $D" + "RF12 etherNode - $D MHz, group $D " + "- configure - send packet" + "

Last $D messages:

" + "
"), okHeader, config.refresh, mhz, config.group,
+                                            mhz, config.group, NUM_MESSAGES);
+    for (byte i = 0; i < NUM_MESSAGES; ++i) {
+        byte j = (next_msg + i) % NUM_MESSAGES;
+        if (history_len[j] > 0) {
+            word n = msgs_rcvd - NUM_MESSAGES + i;
+            buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
+                                n/1000, (n/100) % 10, (n/10) % 10, n % 10);
+            for (byte k = 0; k < history_len[j]; ++k)
+                buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
+        }
+    }
+    long t = millis() / 1000;
+    word h = t / 3600;
+    byte m = (t / 60) % 60;
+    byte s = t % 60;
+    buf.emit_p(PSTR(
+        "
" + "Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10); +#if DEBUG + buf.emit_p(PSTR(" ($D bytes free)"), freeRam()); +#endif +} + +static int getIntArg(const char* data, const char* key, int value =-1) { + char temp[10]; + if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0) + value = atoi(temp); + return value; +} + +static void configPage(const char* data, BufferFiller& buf) { + // pick up submitted data, if present + if (data[6] == '?') { + byte b = getIntArg(data, "b"); + byte g = getIntArg(data, "g"); + byte c = getIntArg(data, "c", 0); + word r = getIntArg(data, "r"); + if (1 <= g && g <= 250 && 1 <= r && r <= 3600) { + // store values as new settings + config.band = b; + config.group = g; + config.collect = c; + config.refresh = r; + saveConfig(); + // re-init RF12 driver + loadConfig(); + // clear history + memset(history_len, 0, sizeof history_len); + // redirect to the home page + buf.emit_p(PSTR( + "HTTP/1.0 302 found\r\n" + "Location: /\r\n" + "\r\n")); + return; + } + } + // else show a configuration form + buf.emit_p(PSTR("$F\r\n" + "

Server node configuration

" + "
" + "

" + "Freq band (4, 8, or 9)
" + "Net group (1..250)
" + "Collect mode: " + "Don't send ACKs

" + "Refresh rate (1..3600 seconds)" + "

" + "" + "
"), okHeader, config.band, config.group, + config.collect ? "CHECKED" : "", + config.refresh); +} + +static void sendPage(const char* data, BufferFiller& buf) { + // pick up submitted data, if present + const char* p = strstr(data, "b="); + byte d = getIntArg(data, "d"); + if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) { + // prepare to send data as soon as possible in loop() + outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0; + outCount = 0; + // convert the input string to a number of decimal data bytes in outBuf + ++p; + while (*p != 0 && *p != '&') { + outBuf[outCount] = 0; + while ('0' <= *++p && *p <= '9') + outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0'); + ++outCount; + } +#if SERIAL + Serial.print("Send to "); + Serial.print(outDest, DEC); + Serial.print(':'); + for (byte i = 0; i < outCount; ++i) { + Serial.print(' '); + Serial.print(outBuf[i], DEC); + } + Serial.println(); +#endif + // redirect to home page + buf.emit_p(PSTR( + "HTTP/1.0 302 found\r\n" + "Location: /\r\n" + "\r\n")); + return; + } + // else show a send form + buf.emit_p(PSTR("$F\r\n" + "

Send a wireless data packet

" + "
" + "

" + "Data bytes (decimal)
" + "Destination node " + "(1..31, or 0 to broadcast)
" + "

" + "" + "
"), okHeader); +} + +void loop(){ + word len = ether.packetReceive(); + word pos = ether.packetLoop(len); + // check if valid tcp data is received + if (pos) { + bfill = ether.tcpOffset(); + char* data = (char *) Ethernet::buffer + pos; +#if SERIAL + Serial.println(data); +#endif + // receive buf hasn't been clobbered by reply yet + if (strncmp("GET / ", data, 6) == 0) + homePage(bfill); + else if (strncmp("GET /c", data, 6) == 0) + configPage(data, bfill); + else if (strncmp("GET /s", data, 6) == 0) + sendPage(data, bfill); + else + bfill.emit_p(PSTR( + "HTTP/1.0 401 Unauthorized\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "

401 Unauthorized

")); + ether.httpServerReply(bfill.position()); // send web page data + } + + // RFM12 loop runner, don't report acks + if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) { + history_rcvd[next_msg][0] = rf12_hdr; + for (byte i = 0; i < rf12_len; ++i) + if (i < MESSAGE_TRUNC) + history_rcvd[next_msg][i+1] = rf12_data[i]; + history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1 + : MESSAGE_TRUNC+1; + next_msg = (next_msg + 1) % NUM_MESSAGES; + msgs_rcvd = (msgs_rcvd + 1) % 10000; + + if (RF12_WANTS_ACK && !config.collect) { +#if SERIAL + Serial.println(" -> ack"); +#endif + rf12_sendStart(RF12_ACK_REPLY, 0, 0); + } + } + + // send a data packet out if requested + if (outCount >= 0 && rf12_canSend()) { + rf12_sendStart(outDest, outBuf, outCount, 1); + outCount = -1; + } +} diff --git a/lib-ext/ethercard.git/examples/getDHCPandDNS/getDHCPandDNS.ino b/lib-ext/ethercard.git/examples/getDHCPandDNS/getDHCPandDNS.ino new file mode 100644 index 0000000..ce03a89 --- /dev/null +++ b/lib-ext/ethercard.git/examples/getDHCPandDNS/getDHCPandDNS.ino @@ -0,0 +1,55 @@ +// This demo does web requests via DHCP and DNS lookup. +// 2011-07-05 http://opensource.org/licenses/mit-license.php + +#include + +#define REQUEST_RATE 5000 // milliseconds + +// ethernet interface mac address +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; +// remote website name +const char website[] PROGMEM = "google.com"; + +byte Ethernet::buffer[700]; +static long timer; + +// called when the client request is complete +static void my_result_cb (byte status, word off, word len) { + Serial.print("<<< reply "); + Serial.print(millis() - timer); + Serial.println(" ms"); + Serial.println((const char*) Ethernet::buffer + off); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[getDHCPandDNS]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); + + if (!ether.dhcpSetup()) + Serial.println("DHCP failed"); + + ether.printIp("My IP: ", ether.myip); + // ether.printIp("Netmask: ", ether.mymask); + ether.printIp("GW IP: ", ether.gwip); + ether.printIp("DNS IP: ", ether.dnsip); + + if (!ether.dnsLookup(website)) + Serial.println("DNS failed"); + ether.printIp("Server: ", ether.hisip); + + timer = - REQUEST_RATE; // start timing out right away +} + +void loop () { + + ether.packetLoop(ether.packetReceive()); + + if (millis() > timer + REQUEST_RATE) { + timer = millis(); + Serial.println("\n>>> REQ"); + ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb); + } +} diff --git a/lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino b/lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino new file mode 100644 index 0000000..6f9a5d2 --- /dev/null +++ b/lib-ext/ethercard.git/examples/getStaticIP/getStaticIP.ino @@ -0,0 +1,57 @@ +// This demo does web requests to a fixed IP address, using a fixed gateway. +// 2010-11-27 http://opensource.org/licenses/mit-license.php + +#include + +#define REQUEST_RATE 5000 // milliseconds + +// ethernet interface mac address +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; +// ethernet interface ip address +static byte myip[] = { 192,168,1,203 }; +// gateway ip address +static byte gwip[] = { 192,168,1,1 }; +// remote website ip address and port +static byte hisip[] = { 74,125,79,99 }; +// remote website name +const char website[] PROGMEM = "google.com"; + +byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here +static long timer; + +// called when the client request is complete +static void my_result_cb (byte status, word off, word len) { + Serial.print("<<< reply "); + Serial.print(millis() - timer); + Serial.println(" ms"); + Serial.println((const char*) Ethernet::buffer + off); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[getStaticIP]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); + + ether.staticSetup(myip, gwip); + + ether.copyIp(ether.hisip, hisip); + ether.printIp("Server: ", ether.hisip); + + while (ether.clientWaitingGw()) + ether.packetLoop(ether.packetReceive()); + Serial.println("Gateway found"); + + timer = - REQUEST_RATE; // start timing out right away +} + +void loop () { + ether.packetLoop(ether.packetReceive()); + + if (millis() > timer + REQUEST_RATE) { + timer = millis(); + Serial.println("\n>>> REQ"); + ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb); + } +} diff --git a/lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino b/lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino new file mode 100644 index 0000000..586a35e --- /dev/null +++ b/lib-ext/ethercard.git/examples/getViaDNS/getViaDNS.ino @@ -0,0 +1,52 @@ +// This demo does web requests via DNS lookup, using a fixed gateway. +// 2010-11-27 http://opensource.org/licenses/mit-license.php + +#include + +#define REQUEST_RATE 5000 // milliseconds + +// ethernet interface mac address +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; +// ethernet interface ip address +static byte myip[] = { 192,168,1,203 }; +// gateway ip address +static byte gwip[] = { 192,168,1,1 }; +// remote website name +const char website[] PROGMEM = "google.com"; + +byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here +static long timer; + +// called when the client request is complete +static void my_result_cb (byte status, word off, word len) { + Serial.print("<<< reply "); + Serial.print(millis() - timer); + Serial.println(" ms"); + Serial.println((const char*) Ethernet::buffer + off); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[getViaDNS]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println( "Failed to access Ethernet controller"); + + ether.staticSetup(myip, gwip); + + if (!ether.dnsLookup(website)) + Serial.println("DNS failed"); + ether.printIp("Server: ", ether.hisip); + + timer = - REQUEST_RATE; // start timing out right away +} + +void loop () { + ether.packetLoop(ether.packetReceive()); + + if (millis() > timer + REQUEST_RATE) { + timer = millis(); + Serial.println("\n>>> REQ"); + ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb); + } +} diff --git a/lib-ext/ethercard.git/examples/multipacket/multipacket.ino b/lib-ext/ethercard.git/examples/multipacket/multipacket.ino new file mode 100644 index 0000000..a19f1b6 --- /dev/null +++ b/lib-ext/ethercard.git/examples/multipacket/multipacket.ino @@ -0,0 +1,77 @@ +#include +#define TCP_FLAGS_FIN_V 1 //as declared in net.h +#define TCP_FLAGS_ACK_V 0x10 //as declared in net.h +static byte myip[] = { 192,168,0,66 }; +static byte gwip[] = { 192,168,0,250 }; +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 }; +byte Ethernet::buffer[900]; // tcp ip send and receive buffer +const char pageA[] PROGMEM = +"HTTP/1.0 200 OK\r\n" +"Content-Type: text/html\r\n" +"\r\n" +"" + "" + "multipackets Test" + "" + "" + "Start here
" + "

packet 1

" + "

" + "the first packet send " + "

" +; +const char pageB[] PROGMEM = + "

packet 2

" + "

" + "if you read this it mean it works" + "

" +; +const char pageC[] PROGMEM = + "

packet 3

" + "

" + "if you read this it mean it works" + "

" +; +const char pageD[] PROGMEM = + "

packet 4

" + "

" + "if you read this it mean it works" + "

" +; +const char pageE[] PROGMEM = + "

packet 5

" + "

" + "this is the last packet" + "

" +; + + +void setup(){ + ether.begin(sizeof Ethernet::buffer, mymac , 10);// 53 for the mega ethernet shield and 10 for normal ethernet shield + ether.staticSetup(myip, gwip); +} +void loop(){ + word pos = ether.packetLoop(ether.packetReceive()); + // check if valid tcp data is received + if (pos) { + char* data = (char *) Ethernet::buffer + pos; + if (strncmp("GET / ", data, 6) == 0) { + ether.httpServerReplyAck(); // send ack to the request + memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and not send the terminate flag + ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V); + memcpy_P(ether.tcpOffset(), pageE, sizeof pageE); // send fiveth packet and send the terminate flag + ether.httpServerReply_with_flags(sizeof pageE - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); } + else + { + ether.httpServerReplyAck(); // send ack to the request + memcpy_P(ether.tcpOffset(), pageA, sizeof pageA);//only the first part will sended + ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); + } + } +} diff --git a/lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino b/lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino new file mode 100644 index 0000000..92206c3 --- /dev/null +++ b/lib-ext/ethercard.git/examples/multipacketSD/multipacketSD.ino @@ -0,0 +1,129 @@ +// works only with tinyfat library +// with SD library packets lost will occurs +// don't know why ! +// tested with arduino mega 1280 and uno +// send 240 Megabyte file without packet loss +// at 100 kbyte/s +// tinyfat read a block of 512 bytes on SD card , +// so the buffer must be 512 + 60 bytes +// on the arduino mega with bigger buffer you can adjust +// if (cur>=512) { // 512 to 1024 with 1100 bytes buffer + +#include +#include +#include +#define TCP_FLAGS_FIN_V 1 //as declared in net.h +#define TCP_FLAGS_ACK_V 16 //as declared in net.h +static byte myip[] = { 192,168,0,66 }; +static byte gwip[] = { 192,168,0,250 }; +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 }; +byte Ethernet::buffer[700]; // tcp/ip send and receive buffer +unsigned long cur; +unsigned long pos; +byte res; + +void setup() { + // Initialize serial communication at 115200 baud + Serial.begin(115200); + // Initialize tinyFAT + // You might need to select a lower speed than the default SPISPEED_HIGH + file.setSSpin(4); + res=file.initFAT(0); + if (res==NO_ERROR) Serial.println("SD started"); + ether.begin(sizeof Ethernet::buffer, mymac , 10); //53 on mega ethernet shield 10 on others + ether.staticSetup(myip, gwip); + Serial.println("ETH started"); +} + +void loop() +{ + wait: + pos = ether.packetLoop(ether.packetReceive());// check if valid tcp data is received + if (pos) { + char* data = (char *) Ethernet::buffer + pos; + cur=0; + if (strncmp("GET / ", data, 6) == 0) {// nothing specified + sendfiles("index.htm"); + goto wait; + } + if (strncmp("GET /", data, 5) == 0) { // serve anything on sd card + int i =0; + char temp[15]=""; // here will be the name of requested file + while (data[i+5]!=32) {temp[i]=data[i+5];i++;}//search the end + sendfiles((char*) temp); + goto wait; + } + not_found(); + + } + +} + +void not_found() { //content not found + cur=0; + streamfile ("404.hea",TCP_FLAGS_FIN_V); + // Serial.println("not found"); +} + +byte streamfile (char* name , byte lastflag) { //send a file to the buffer + if (!file.exists(name)) {return 0;} + res=file.openFile(name, FILEMODE_BINARY); + int car=512; + while (car==512) { + car=file.readBinary(); + for(int i=0;i=512) { + ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V); + cur=0; + } else { + + if (lastflag==TCP_FLAGS_FIN_V) { + ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V+TCP_FLAGS_FIN_V); + } + } +} + file.closeFile(); + return 1; +} + +byte sendfiles(char* name) { // function to find the correct header and send a file + ether.httpServerReplyAck(); + int i =0; + char dtype[13]=""; + while (name[i]!=0) { + i++; + }//search the end + int b=i-1; + while ((name[b]!=46)&&(b>0)) { + b--; + }//search the point + int a=b+1; + while (a + +#define BUF_SIZE 512 + +byte mac[] = { 0x00, 0x04, 0xA3, 0x21, 0xCA, 0x38 }; // Nanode MAC address. + +uint8_t ip[] = { 192, 168, 1, 8 }; // The fallback board address. +uint8_t dns[] = { 192, 168, 1, 20 }; // The DNS server address. +uint8_t gateway[] = { 192, 168, 1, 20 }; // The gateway router address. +uint8_t subnet[] = { 255, 255, 255, 0 }; // The subnet mask. +byte Ethernet::buffer[BUF_SIZE]; +byte fixed; // Address fixed, no DHCP + +void setup(void) +{ + Serial.begin(57600); + delay(2000); + + /* Check that the Ethernet controller exists */ + Serial.println("Initialising the Ethernet controller"); + if (ether.begin(sizeof Ethernet::buffer, mac, 8) == 0) { + Serial.println( "Ethernet controller NOT initialised"); + while (true) + /* MT */ ; + } + + /* Get a DHCP connection */ + Serial.println("Attempting to get an IP address using DHCP"); + fixed = false; + if (ether.dhcpSetup()) { + ether.printIp("Got an IP address using DHCP: ", ether.myip); + } + /* If DHCP fails, start with a hard-coded address */ + else { + ether.staticSetup(ip, gateway, dns); + ether.printIp("DHCP FAILED, using fixed address: ", ether.myip); + fixed = true; + } + + return; +} + +void loop(void) +{ + word rc; + + /* These function calls are required if ICMP packets are to be accepted */ + rc = ether.packetLoop(ether.packetReceive()); + Serial.print("ether.packetLoop() returned "); + Serial.println(rc, DEC); + + // For debugging + delay(5000); + + return; +} diff --git a/lib-ext/ethercard.git/examples/noipClient/noipClient.ino b/lib-ext/ethercard.git/examples/noipClient/noipClient.ino new file mode 100644 index 0000000..4e3bf60 --- /dev/null +++ b/lib-ext/ethercard.git/examples/noipClient/noipClient.ino @@ -0,0 +1,279 @@ +// NoIP client sketch for ENC28J60 based Ethernet Shield. +// You need a free account from www.no-ip.com +// +// 1. On NoIP website, create a host of type DNS Host (A) +// 2. Insert your host name in noIP_host[] variable +// 3. Encode "username:password" in base64 using an online tool like +// 4. Paste the encoded string in noIP_auth[] variable +// +// Contributed by Luca Dentella +// http://www.lucadentella.it/2012/04/28/enc28j60-e-arduino-6/ + + +#include + +// Finite-State Machine states +#define STATUS_IDLE 0 +#define STATUS_WAITING_FOR_PUBLIC_IP 1 +#define STATUS_NOIP_NEEDS_UPDATE 2 +#define STATUS_WAITING_FOR_NOIP 3 +#define STATUS_ERROR 99 + +// The sketch will check your public IP every CHECK_IP_INTERVAL ms, +// and wait for REQUEST_TIMEOUT ms for a response. +// It will retry for maximum of MAX_ATTEMPTS attemps. +#define CHECK_IP_INTERVAL 60000 +#define REQUEST_TIMEOUT 10000 +#define MAX_ATTEMPTS 3 + +// MAC Address of Ethernet Shield +static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01}; + +// Insert your hostname and authentication string +const char noIP_host[] PROGMEM = "myhost.no-ip.info"; +const char noIP_auth[] PROGMEM = "XXXXXXXXXX"; + +// Don't change these ones... +const char getIP_web[] PROGMEM = "www.lucadentella.it"; +const char noIP_web[] PROGMEM = "dynupdate.no-ip.com"; + +// Some global variables +byte Ethernet::buffer[700]; +byte getIP_address[4]; +byte noIP_address[4]; +byte actual_status; +static byte session_id; +static uint32_t check_ip_timer; +static uint32_t request_timer; +int attempt; +Stash stash; + +void setup () { + + Serial.begin(57600); + Serial.println(F("NoIP Client Demo")); + Serial.println(); + + if (!ether.begin(sizeof Ethernet::buffer, mymac, 10)) + Serial.println(F( "Failed to access Ethernet controller")); + else + Serial.println(F("Ethernet controller initialized")); + Serial.println(); + + if (!ether.dhcpSetup()) + Serial.println(F("Failed to get configuration from DHCP")); + else + Serial.println(F("DHCP configuration done")); + + ether.printIp("IP Address:\t", ether.myip); + ether.printIp("Netmask:\t", ether.netmask); + ether.printIp("Gateway:\t", ether.gwip); + Serial.println(); + + actual_status = STATUS_IDLE; + attempt = 0; + + // Resolve IP for getIP_web and noIP_web + // and store them into global variables + if (!ether.dnsLookup(getIP_web)) { + Serial.print(F("Unable to resolve IP for ")); + SerialPrint_P(getIP_web); + actual_status = STATUS_ERROR; + } else { + ether.copyIp(getIP_address, ether.hisip); + SerialPrint_P(getIP_web); + ether.printIp(" resolved to:\t", ether.hisip); + } + if (!ether.dnsLookup(noIP_web)) { + Serial.print(F("Unable to resolve IP for ")); + SerialPrint_P(noIP_web); + actual_status = STATUS_ERROR; + } else { + ether.copyIp(noIP_address, ether.hisip); + SerialPrint_P(noIP_web); + ether.printIp(" resolved to:\t", ether.hisip); + } + + Serial.println(); +} + + +void loop() { + + ether.packetLoop(ether.packetReceive()); + + // FSM + switch(actual_status) { + + case STATUS_IDLE: + checkPublicIP(); + break; + case STATUS_WAITING_FOR_PUBLIC_IP: + checkPublicIPResponse(); + break; + case STATUS_NOIP_NEEDS_UPDATE: + updateNoIP(); + break; + case STATUS_WAITING_FOR_NOIP: + checkNoIPResponse(); + break; + } +} + +void checkPublicIP() { + + if(millis() > check_ip_timer) { + + Serial.print(F("Checking public IP... ")); + + // Create a request for GetIP service, + // set destination IP and send request saving session_id + Stash::prepare(PSTR("GET /demo/getip.php HTTP/1.1" "\r\n" "Host: $F" "\r\n" "\r\n"), getIP_web); + ether.copyIp(ether.hisip, getIP_address); + session_id = ether.tcpSend(); + + // Change FSM state, prepare for timeout and increment attempts counter + actual_status = STATUS_WAITING_FOR_PUBLIC_IP; + request_timer = millis() + REQUEST_TIMEOUT; + attempt++; + } +} + +void checkPublicIPResponse() { + + String actualIp, dnsIp; + + const char* reply = ether.tcpReply(session_id); + + // We got a valid response + if(reply != 0) { + + // Parse response for public IP + for(int i = 0; i < strlen(reply) - 189; i++) actualIp = actualIp + reply[187 + i]; + Serial.println(actualIp); + + // If we can't resolve actual IP for our hostname on NoIP, + // return to IDLE state and wait for the next interval + if(!ether.dnsLookup(noIP_host)) { + Serial.print(F("Unable to resolve actual IP for ")); + SerialPrint_P(noIP_host); + Serial.println(); + actual_status = STATUS_IDLE; + attempt = 0; + check_ip_timer = millis() + CHECK_IP_INTERVAL; + + // If we can resolve the IP for our hostname, save it in xxx.xxx.xxx.xxx form + // and compare it with our public IP + } else { + for(int i = 0; i < 4; i++) { + dnsIp = dnsIp + String(ether.hisip[i]); + if(i < 3) dnsIp = dnsIp + "."; + } + SerialPrint_P(noIP_host); + Serial.print(F(" resolved to ")); + Serial.println(dnsIp); + + // If they are the same, we can sit down and wait for the next interval + if(actualIp.compareTo(dnsIp) == 0) { + Serial.println(F("No update needed :)")); + actual_status = STATUS_IDLE; + attempt = 0; + check_ip_timer = millis() + CHECK_IP_INTERVAL; + + // Different? We'd better to update NoIP! + } else { + Serial.println(F("Update needed :(")); + actual_status = STATUS_NOIP_NEEDS_UPDATE; + attempt = 0; + } + } + + // No valid response? Check for timeout + // If we've already sent a max number of requests, return to IDLE state + // and wait for the next interval + } else { + if(millis() > request_timer) { + Serial.println(F(" no response :(")); + actual_status = STATUS_IDLE; + if(attempt == MAX_ATTEMPTS) { + Serial.println(F("Max number of attempts reached")); + attempt = 0; + check_ip_timer = millis() + CHECK_IP_INTERVAL; + } + } + } +} + +void updateNoIP() { + + Serial.print(F("Updating NoIP...")); + + // Create a request for updating NoIP using NoIP API, + // set destination IP and send request saving session_id + Stash::prepare(PSTR("GET /nic/update?hostname=$F HTTP/1.0" "\r\n" + "Host: $F" "\r\n" + "Authorization: Basic $F" "\r\n" + "User-Agent: NoIP_Client" "\r\n" "\r\n"), + noIP_host, noIP_web, noIP_auth); + ether.copyIp(ether.hisip, noIP_address); + session_id = ether.tcpSend(); + + // Wait for response or timeout... + actual_status = STATUS_WAITING_FOR_NOIP; + request_timer = millis() + REQUEST_TIMEOUT; + attempt++; +} + +void checkNoIPResponse() { + + const char* reply = ether.tcpReply(session_id); + boolean done; + + // We got a valid response... + if(reply != 0) { + + // Parse NoIP response looking for status/error codes... + if(strstr(reply, "good") != 0) { + Serial.println(F(" done!")); + done = true; + } + else if(strstr(reply, "nochg") != 0) { + Serial.println(F(" no change required!")); + done = true; + } + else if(strstr(reply, "nohost") != 0) Serial.println(F(" host not found :(")); + else if(strstr(reply, "badauth") != 0) Serial.println(F(" invalid username or password :(")); + else if(strstr(reply, "badagent") != 0) Serial.println(F(" agent banned :(")); + else if(strstr(reply, "!donator") != 0) Serial.println(F(" feature not available for specified username :(")); + else if(strstr(reply, "abuse") != 0) Serial.println(F(" username blocked due to abuse :(")); + else Serial.println(F(" generic error :(")); + + // Record has been updated? Ok wait for next interval... + if(done) { + actual_status = STATUS_IDLE; + attempt = 0; + check_ip_timer = millis() + CHECK_IP_INTERVAL; + } + + // No valid response? Check for timeout + // If we've already sent a max number of requests, return to IDLE state + // and wait for the next interval + } else { + + if(millis() > request_timer) { + Serial.println(F("No response from NoIP")); + if(attempt == MAX_ATTEMPTS) { + Serial.println(F("Max number of attempts reached")); + actual_status = STATUS_IDLE; + attempt = 0; + check_ip_timer = millis() + CHECK_IP_INTERVAL; + } + else + actual_status = STATUS_NOIP_NEEDS_UPDATE; + } + } +} + +void SerialPrint_P(PGM_P str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c); +} diff --git a/lib-ext/ethercard.git/examples/pings/pings.ino b/lib-ext/ethercard.git/examples/pings/pings.ino new file mode 100644 index 0000000..ffb7c60 --- /dev/null +++ b/lib-ext/ethercard.git/examples/pings/pings.ino @@ -0,0 +1,62 @@ +// Ping a remote server, also uses DHCP and DNS. +// 2011-06-12 http://opensource.org/licenses/mit-license.php + +#include + +// ethernet interface mac address, must be unique on the LAN +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[700]; +static uint32_t timer; + +// called when a ping comes in (replies to it are automatic) +static void gotPinged (byte* ptr) { + ether.printIp(">>> ping from: ", ptr); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[pings]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); + if (!ether.dhcpSetup()) + Serial.println(F("DHCP failed")); + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + +#if 1 + // use DNS to locate the IP address we want to ping + if (!ether.dnsLookup(PSTR("www.google.com"))) + Serial.println("DNS failed"); +#else + ether.parseIp(ether.hisip, "74.125.77.99"); +#endif + ether.printIp("SRV: ", ether.hisip); + + // call this to report others pinging us + ether.registerPingCallback(gotPinged); + + timer = -9999999; // start timing out right away + Serial.println(); +} + +void loop () { + word len = ether.packetReceive(); // go receive new packets + word pos = ether.packetLoop(len); // respond to incoming pings + + // report whenever a reply to our outgoing ping comes back + if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) { + Serial.print(" "); + Serial.print((micros() - timer) * 0.001, 3); + Serial.println(" ms"); + } + + // ping a remote server once every few seconds + if (micros() - timer >= 5000000) { + ether.printIp("Pinging: ", ether.hisip); + timer = micros(); + ether.clientIcmpRequest(ether.hisip); + } +} diff --git a/lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino b/lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino new file mode 100644 index 0000000..cacd69a --- /dev/null +++ b/lib-ext/ethercard.git/examples/rbbb_server/rbbb_server.ino @@ -0,0 +1,43 @@ +// This is a demo of the RBBB running as webserver with the Ether Card +// 2010-05-28 http://opensource.org/licenses/mit-license.php + +#include + +// ethernet interface mac address, must be unique on the LAN +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; +static byte myip[] = { 192,168,1,203 }; + +byte Ethernet::buffer[500]; +BufferFiller bfill; + +void setup () { + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); + ether.staticSetup(myip); +} + +static word homePage() { + long t = millis() / 1000; + word h = t / 3600; + byte m = (t / 60) % 60; + byte s = t % 60; + bfill = ether.tcpOffset(); + bfill.emit_p(PSTR( + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "Pragma: no-cache\r\n" + "\r\n" + "" + "RBBB server" + "

$D$D:$D$D:$D$D

"), + h/10, h%10, m/10, m%10, s/10, s%10); + return bfill.position(); +} + +void loop () { + word len = ether.packetReceive(); + word pos = ether.packetLoop(len); + + if (pos) // check if valid tcp data is received + ether.httpServerReply(homePage()); // send web page data +} diff --git a/lib-ext/ethercard.git/examples/stashTest/stashTest.ino b/lib-ext/ethercard.git/examples/stashTest/stashTest.ino new file mode 100644 index 0000000..5dd31da --- /dev/null +++ b/lib-ext/ethercard.git/examples/stashTest/stashTest.ino @@ -0,0 +1,118 @@ +// Test the offloaded RAM stash mechanism. +// 2011-07-10 http://opensource.org/licenses/mit-license.php + +#include +#include + +// ethernet interface mac address, must be unique on the LAN +byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[700]; + +void dumpBlock (const char* msg, byte idx) { + Serial.print(msg); + Serial.print(" ["); + Serial.print(idx, DEC); + Serial.print("] @ "); + Serial.print(Stash::bufs[idx].bnum, DEC); + Serial.print(" free "); + Serial.print(Stash::freeCount(), DEC); + for (byte i = 0; i < 64; ++i) { + if (i % 16 == 0) + Serial.println(); + Serial.print(' '); + Serial.print(Stash::bufs[idx].bytes[i], DEC); + } + Serial.println(); +} + +void dumpStash (const char* msg, void* ptr) { + Stash& buf = *(Stash*) ptr; + Serial.print(msg); + Serial.print(" c"); + Serial.print(buf.count, DEC); + Serial.print(" f"); + Serial.print(buf.first, DEC); + Serial.print(" l"); + Serial.print(buf.last, DEC); + Serial.print(" u"); + Serial.print(buf.curr, DEC); + Serial.print(" o"); + Serial.print(buf.offs, DEC); + Serial.print(" #"); + Serial.println(buf.size()); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[stashTest]"); + ether.begin(sizeof Ethernet::buffer, mymac); + +#if 1 + Stash buf; + dumpStash("> AAA", &buf); + byte fd = buf.create(); + Serial.print("fd "); + Serial.println(fd, DEC); + dumpStash("> BBB", &buf); + dumpBlock("EMPTY", 0); + for (char c = 'a'; c <= 'z'; ++c) + buf.put(c); + for (char c = 'A'; c <= 'Z'; ++c) + buf.put(c); + dumpBlock("LETTERS", 0); + dumpStash("> CCC", &buf); + for (char c = '0'; c <= '9'; ++c) + buf.put(c); + dumpBlock("DIGITS", 0); + dumpStash("> DDD", &buf); + buf.print(" x = "); + buf.println(123.45); + dumpBlock("PRINT", 0); + dumpStash("> EEE", &buf); + buf.load(1, 1); + dumpBlock("FIRST", 1); + buf.save(); + buf.load(1, 1); + dumpBlock("FLUSHED", 1); + dumpStash("> FFF", &buf); + for (;;) { + char c = buf.get(); + if (c == 0) + break; + Serial.print(c); + } + Serial.println(); + dumpStash("> GGG", &buf); +#endif + + Stash buf2; + byte fd2 = buf2.create(); + buf2.print(""); + buf2.save(); + buf2.load(1, fd2); + dumpBlock("SECOND", 1); + dumpStash("> HHH", &buf2); + + Stash::prepare(PSTR("a $S b $F c $D d $H e"), + "123", PSTR("4567"), -12345, fd2); + dumpBlock("BUFFER", 0); + Serial.println(Stash::length()); + for (word i = 0, n = Stash::length(); i < n; ++i) { + char c; + Stash::extract(i, 1, &c); + Serial.print(c); + } + Serial.println(); + Stash::cleanup(); +#if 1 + buf.release(); +#endif + Serial.print("free "); + Serial.println(Stash::freeCount(), DEC); + Serial.println("DONE"); +} + +void loop () { + // ether.packetLoop(ether.packetReceive()); +} diff --git a/lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino b/lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino new file mode 100644 index 0000000..e75c275 --- /dev/null +++ b/lib-ext/ethercard.git/examples/testDHCP/testDHCP.ino @@ -0,0 +1,40 @@ +// Arduino demo sketch for testing the DHCP client code +// +// Original author: Andrew Lindsay +// Major rewrite and API overhaul by jcw, 2011-06-07 +// +// Copyright: GPL V2 +// See http://www.gnu.org/licenses/gpl.html + +#include + +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[700]; + +void setup () { + Serial.begin(57600); + Serial.println(F("\n[testDHCP]")); + + Serial.print("MAC: "); + for (byte i = 0; i < 6; ++i) { + Serial.print(mymac[i], HEX); + if (i < 5) + Serial.print(':'); + } + Serial.println(); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); + + Serial.println(F("Setting up DHCP")); + if (!ether.dhcpSetup()) + Serial.println(F("DHCP failed")); + + ether.printIp("My IP: ", ether.myip); + ether.printIp("Netmask: ", ether.netmask); + ether.printIp("GW IP: ", ether.gwip); + ether.printIp("DNS IP: ", ether.dnsip); +} + +void loop () {} diff --git a/lib-ext/ethercard.git/examples/twitter/twitter.ino b/lib-ext/ethercard.git/examples/twitter/twitter.ino new file mode 100644 index 0000000..88f3920 --- /dev/null +++ b/lib-ext/ethercard.git/examples/twitter/twitter.ino @@ -0,0 +1,84 @@ +// Twitter client sketch for ENC28J60 based Ethernet Shield. Uses +// arduino-tweet.appspot.com as a OAuth gateway. +// Step by step instructions: +// +// 1. Get a oauth token: +// http://arduino-tweet.appspot.com/oauth/twitter/login +// 2. Put the token value in the TOKEN define below +// 3. Run the sketch! +// +// WARNING: Don't send more than 1 tweet per minute! +// NOTE: Twitter rejects tweets with identical content as dupes (returns 403) + +#include + +// OAUTH key from http://arduino-tweet.appspot.com/ +#define TOKEN "Insert-your-token-here" + +// ethernet interface mac address, must be unique on the LAN +byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +const char website[] PROGMEM = "arduino-tweet.appspot.com"; + +static byte session; + +byte Ethernet::buffer[700]; +Stash stash; + +static void sendToTwitter () { + Serial.println("Sending tweet..."); + byte sd = stash.create(); + + const char tweet[] = "@solarkennedy the test Twitter sketch works!"; + stash.print("token="); + stash.print(TOKEN); + stash.print("&status="); + stash.println(tweet); + stash.save(); + int stash_size = stash.size(); + + // Compose the http POST request, taking the headers below and appending + // previously created stash in the sd holder. + Stash::prepare(PSTR("POST http://$F/update HTTP/1.0" "\r\n" + "Host: $F" "\r\n" + "Content-Length: $D" "\r\n" + "\r\n" + "$H"), + website, website, stash_size, sd); + + // send the packet - this also releases all stash buffers once done + // Save the session ID so we can watch for it in the main loop. + session = ether.tcpSend(); +} + +void setup () { + Serial.begin(57600); + Serial.println("\n[Twitter Client]"); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); + if (!ether.dhcpSetup()) + Serial.println(F("DHCP failed")); + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + ether.printIp("DNS: ", ether.dnsip); + + if (!ether.dnsLookup(website)) + Serial.println(F("DNS failed")); + + ether.printIp("SRV: ", ether.hisip); + + sendToTwitter(); +} + +void loop () { + ether.packetLoop(ether.packetReceive()); + + const char* reply = ether.tcpReply(session); + if (reply != 0) { + Serial.println("Got a response!"); + Serial.println(reply); + } +} + diff --git a/lib-ext/ethercard.git/examples/udpListener/udpListener.ino b/lib-ext/ethercard.git/examples/udpListener/udpListener.ino new file mode 100644 index 0000000..34f9fad --- /dev/null +++ b/lib-ext/ethercard.git/examples/udpListener/udpListener.ino @@ -0,0 +1,95 @@ +// Demonstrates usage of the new udpServer feature. +//You can register the same function to multiple ports, and multiple functions to the same port. +// +// 2013-4-7 Brian Lee + +#include +#include + +#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below) + +#if STATIC +// ethernet interface ip address +static byte myip[] = { 192,168,0,200 }; +// gateway ip address +static byte gwip[] = { 192,168,0,1 }; +#endif + +// ethernet mac address - must be unique on your network +static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[500]; // tcp/ip send and receive buffer + +//callback that prints received packets to the serial port +void udpSerialPrint(word port, byte ip[4], const char *data, word len) { + IPAddress src(ip[0], ip[1], ip[2], ip[3]); + Serial.println(src); + Serial.println(port); + Serial.println(data); + Serial.println(len); +} + +void setup(){ + Serial.begin(57600); + Serial.println(F("\n[backSoon]")); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); +#if STATIC + ether.staticSetup(myip, gwip); +#else + if (!ether.dhcpSetup()) + Serial.println(F("DHCP failed")); +#endif + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + ether.printIp("DNS: ", ether.dnsip); + + //register udpSerialPrint() to port 1337 + ether.udpServerListenOnPort(&udpSerialPrint, 1337); + + //register udpSerialPrint() to port 42. + ether.udpServerListenOnPort(&udpSerialPrint, 42); +} + +void loop(){ + //this must be called for ethercard functions to work. + ether.packetLoop(ether.packetReceive()); +} + + +/* +//Processing sketch to send test UDP packets. + +import hypermedia.net.*; + + UDP udp; // define the UDP object + + + void setup() { + udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 + //udp.log( true ); // <-- printout the connection activity + udp.listen( true ); // and wait for incoming message + } + + void draw() + { + } + + void keyPressed() { + String ip = "192.168.0.200"; // the remote IP address + int port = 1337; // the destination port + + udp.send("Greetings via UDP!", ip, port ); // the message to send + + } + + void receive( byte[] data ) { // <-- default handler + //void receive( byte[] data, String ip, int port ) { // <-- extended handler + + for(int i=0; i < data.length; i++) + print(char(data[i])); + println(); + } +*/ diff --git a/lib-ext/ethercard.git/examples/webClient/webClient.ino b/lib-ext/ethercard.git/examples/webClient/webClient.ino new file mode 100644 index 0000000..c5535b1 --- /dev/null +++ b/lib-ext/ethercard.git/examples/webClient/webClient.ino @@ -0,0 +1,50 @@ +// Demo using DHCP and DNS to perform a web client request. +// 2011-06-08 http://opensource.org/licenses/mit-license.php + +#include + +// ethernet interface mac address, must be unique on the LAN +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +byte Ethernet::buffer[700]; +static uint32_t timer; + +const char website[] PROGMEM = "www.google.com"; + +// called when the client request is complete +static void my_callback (byte status, word off, word len) { + Serial.println(">>>"); + Ethernet::buffer[off+300] = 0; + Serial.print((const char*) Ethernet::buffer + off); + Serial.println("..."); +} + +void setup () { + Serial.begin(57600); + Serial.println(F("\n[webClient]")); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) + Serial.println(F("Failed to access Ethernet controller")); + if (!ether.dhcpSetup()) + Serial.println(F("DHCP failed")); + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + ether.printIp("DNS: ", ether.dnsip); + + if (!ether.dnsLookup(website)) + Serial.println("DNS failed"); + + ether.printIp("SRV: ", ether.hisip); +} + +void loop () { + ether.packetLoop(ether.packetReceive()); + + if (millis() > timer) { + timer = millis() + 5000; + Serial.println(); + Serial.print("<<< REQ "); + ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback); + } +} diff --git a/lib-ext/ethercard.git/examples/xively/xively.ino b/lib-ext/ethercard.git/examples/xively/xively.ino new file mode 100644 index 0000000..9e9a87b --- /dev/null +++ b/lib-ext/ethercard.git/examples/xively/xively.ino @@ -0,0 +1,139 @@ +// Simple demo for feeding some random data to Pachube. +// 2011-07-08 http://opensource.org/licenses/mit-license.php + +// Handle returning code and reset ethernet module if needed +// 2013-10-22 hneiraf@gmail.com + +#include + +// change these settings to match your own setup +#define FEED "000" +#define APIKEY "xxx" + +// ethernet interface mac address, must be unique on the LAN +static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; + +const char website[] PROGMEM = "api.xively.com"; + +byte Ethernet::buffer[350]; +uint32_t timer; +Stash stash; +byte session; + +//timing variable +int res = 0; + + + +void setup () { + Serial.begin(57600); + Serial.println("\n[Xively example]"); + + //Initialize Ethernet + initialize_ethernet(); +} + + +void loop () { + + //if correct answer is not received then re-initialize ethernet module + if (res > 220){ + initialize_ethernet(); + } + + res = res + 1; + + ether.packetLoop(ether.packetReceive()); + + //200 res = 10 seconds (50ms each res) + if (res == 200) { + + + //Generate random info + float demo = random(0,500); + word one = random(0,500); + String msje; + + if (demo < 250){ + msje = "low"; + } + else{ + msje = "high"; + } + + + // generate two fake values as payload - by using a separate stash, + // we can determine the size of the generated message ahead of time + byte sd = stash.create(); + stash.print("demo,"); + stash.println(demo); + stash.print("one,"); + stash.println(one); + stash.print("mensaje,"); + stash.println(msje); + stash.save(); + + //Display data to be sent + Serial.println(demo); + Serial.println(one); + + + // generate the header with payload - note that the stash size is used, + // and that a "stash descriptor" is passed in as argument using "$H" + Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n" + "Host: $F" "\r\n" + "X-PachubeApiKey: $F" "\r\n" + "Content-Length: $D" "\r\n" + "\r\n" + "$H"), + website, PSTR(FEED), website, PSTR(APIKEY), stash.size(), sd); + + // send the packet - this also releases all stash buffers once done + session = ether.tcpSend(); + } + + const char* reply = ether.tcpReply(session); + + if (reply != 0) { + res = 0; + Serial.println(reply); + } + delay(50); +} + + + +void initialize_ethernet(void){ + for(;;){ // keep trying until you succeed + //Reinitialize ethernet module + pinMode(5, OUTPUT); + Serial.println("Reseting Ethernet..."); + digitalWrite(5, LOW); + delay(1000); + digitalWrite(5, HIGH); + delay(500); + + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0){ + Serial.println( "Failed to access Ethernet controller"); + continue; + } + + if (!ether.dhcpSetup()){ + Serial.println("DHCP failed"); + continue; + } + + ether.printIp("IP: ", ether.myip); + ether.printIp("GW: ", ether.gwip); + ether.printIp("DNS: ", ether.dnsip); + + if (!ether.dnsLookup(website)) + Serial.println("DNS failed"); + + ether.printIp("SRV: ", ether.hisip); + + //reset init value + res = 0; + break; + } +} diff --git a/lib-ext/ethercard.git/net.h b/lib-ext/ethercard.git/net.h new file mode 100755 index 0000000..a80c5b9 --- /dev/null +++ b/lib-ext/ethercard.git/net.h @@ -0,0 +1,123 @@ +// Based on the net.h file from the AVRlib library by Pascal Stang. +// Author: Guido Socher +// Copyright: GPL V2 +// +// For AVRlib See http://www.procyonengineering.com/ +// Used with explicit permission of Pascal Stang. +// +// 2010-05-20 + +// notation: _P = position of a field +// _V = value of a field + +#ifndef NET_H +#define NET_H + +// ******* ETH ******* +#define ETH_HEADER_LEN 14 +// values of certain bytes: +#define ETHTYPE_ARP_H_V 0x08 +#define ETHTYPE_ARP_L_V 0x06 +#define ETHTYPE_IP_H_V 0x08 +#define ETHTYPE_IP_L_V 0x00 +// byte positions in the ethernet frame: +// +// Ethernet type field (2bytes): +#define ETH_TYPE_H_P 12 +#define ETH_TYPE_L_P 13 +// +#define ETH_DST_MAC 0 +#define ETH_SRC_MAC 6 + + +// ******* ARP ******* +#define ETH_ARP_OPCODE_REPLY_H_V 0x0 +#define ETH_ARP_OPCODE_REPLY_L_V 0x02 +#define ETH_ARP_OPCODE_REQ_H_V 0x0 +#define ETH_ARP_OPCODE_REQ_L_V 0x01 +// start of arp header: +#define ETH_ARP_P 0xe +// +#define ETHTYPE_ARP_L_V 0x06 +// arp.dst.ip +#define ETH_ARP_DST_IP_P 0x26 +// arp.opcode +#define ETH_ARP_OPCODE_H_P 0x14 +#define ETH_ARP_OPCODE_L_P 0x15 +// arp.src.mac +#define ETH_ARP_SRC_MAC_P 0x16 +#define ETH_ARP_SRC_IP_P 0x1c +#define ETH_ARP_DST_MAC_P 0x20 +#define ETH_ARP_DST_IP_P 0x26 + +// ******* IP ******* +#define IP_HEADER_LEN 20 +// ip.src +#define IP_SRC_P 0x1a +#define IP_DST_P 0x1e +#define IP_HEADER_LEN_VER_P 0xe +#define IP_CHECKSUM_P 0x18 +#define IP_TTL_P 0x16 +#define IP_FLAGS_P 0x14 +#define IP_P 0xe +#define IP_TOTLEN_H_P 0x10 +#define IP_TOTLEN_L_P 0x11 + +#define IP_PROTO_P 0x17 + +#define IP_PROTO_ICMP_V 1 +#define IP_PROTO_TCP_V 6 +// 17=0x11 +#define IP_PROTO_UDP_V 17 +// ******* ICMP ******* +#define ICMP_TYPE_ECHOREPLY_V 0 +#define ICMP_TYPE_ECHOREQUEST_V 8 +// +#define ICMP_TYPE_P 0x22 +#define ICMP_CHECKSUM_P 0x24 +#define ICMP_CHECKSUM_H_P 0x24 +#define ICMP_CHECKSUM_L_P 0x25 +#define ICMP_IDENT_H_P 0x26 +#define ICMP_IDENT_L_P 0x27 +#define ICMP_DATA_P 0x2a + +// ******* UDP ******* +#define UDP_HEADER_LEN 8 +// +#define UDP_SRC_PORT_H_P 0x22 +#define UDP_SRC_PORT_L_P 0x23 +#define UDP_DST_PORT_H_P 0x24 +#define UDP_DST_PORT_L_P 0x25 +// +#define UDP_LEN_H_P 0x26 +#define UDP_LEN_L_P 0x27 +#define UDP_CHECKSUM_H_P 0x28 +#define UDP_CHECKSUM_L_P 0x29 +#define UDP_DATA_P 0x2a + +// ******* TCP ******* +#define TCP_SRC_PORT_H_P 0x22 +#define TCP_SRC_PORT_L_P 0x23 +#define TCP_DST_PORT_H_P 0x24 +#define TCP_DST_PORT_L_P 0x25 +// the tcp seq number is 4 bytes 0x26-0x29 +#define TCP_SEQ_H_P 0x26 +#define TCP_SEQACK_H_P 0x2a +// flags: SYN=2 +#define TCP_FLAGS_P 0x2f +#define TCP_FLAGS_SYN_V 2 +#define TCP_FLAGS_FIN_V 1 +#define TCP_FLAGS_RST_V 4 +#define TCP_FLAGS_PUSH_V 8 +#define TCP_FLAGS_SYNACK_V 0x12 +#define TCP_FLAGS_ACK_V 0x10 +#define TCP_FLAGS_PSHACK_V 0x18 +// plain len without the options: +#define TCP_HEADER_LEN_PLAIN 20 +#define TCP_HEADER_LEN_P 0x2e +#define TCP_WIN_SIZE 0x30 +#define TCP_CHECKSUM_H_P 0x32 +#define TCP_CHECKSUM_L_P 0x33 +#define TCP_OPTIONS_P 0x36 +// +#endif diff --git a/lib-ext/ethercard.git/tcpip.cpp b/lib-ext/ethercard.git/tcpip.cpp new file mode 100644 index 0000000..47bf4ee --- /dev/null +++ b/lib-ext/ethercard.git/tcpip.cpp @@ -0,0 +1,810 @@ +// IP, ARP, UDP and TCP functions. +// Author: Guido Socher +// Copyright: GPL V2 +// +// The TCP implementation uses some size optimisations which are valid +// only if all data can be sent in one single packet. This is however +// not a big limitation for a microcontroller as you will anyhow use +// small web-pages. The web server must send the entire web page in one +// packet. The client "web browser" as implemented here can also receive +// large pages. +// +// 2010-05-20 + +#include "EtherCard.h" +#include "net.h" +#undef word // arduino nonsense + +#define gPB ether.buffer + +#define PINGPATTERN 0x42 + +// Avoid spurious pgmspace warnings - http://forum.jeelabs.net/node/327 +// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734 +//#undef PROGMEM +//#define PROGMEM __attribute__(( section(".progmem.data") )) +//#undef PSTR +//#define PSTR(s) (__extension__({static prog_char c[] PROGMEM = (s); &c[0];})) + +#define TCPCLIENT_SRC_PORT_H 11 //Source port (MSB) for TCP/IP client connections - hardcode all TCP/IP client connection from ports in range 2816-3071 +static uint8_t tcpclient_src_port_l=1; // Source port (LSB) for tcp/ip client connections - increments on each TCP/IP request +static uint8_t tcp_fd; // a file descriptor, will be encoded into the port +static uint8_t tcp_client_state; //TCP connection state: 1=Send SYN, 2=SYN sent awaiting SYN+ACK, 3=Established, 4=Not used, 5=Closing, 6=Closed +static uint8_t tcp_client_port_h; // Destination port (MSB) of TCP/IP client connection +static uint8_t tcp_client_port_l; // Destination port (LSB) of TCP/IP client connection +static uint8_t (*client_tcp_result_cb)(uint8_t,uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle response to current TCP/IP request +static uint16_t (*client_tcp_datafill_cb)(uint8_t); //Pointer to callback function to handle payload data in response to current TCP/IP request +static uint8_t www_fd; // ID of current http request (only one http request at a time - one of the 8 possible concurrent TCP/IP connections) +static void (*client_browser_cb)(uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle result of current HTTP request +static const char *client_additionalheaderline; // Pointer to c-string additional http request header info +static const char *client_postval; +static const char *client_urlbuf; // Pointer to c-string path part of HTTP request URL +static const char *client_urlbuf_var; // Pointer to c-string filename part of HTTP request URL +static const char *client_hoststr; // Pointer to c-string hostname of current HTTP request +static void (*icmp_cb)(uint8_t *ip); // Pointer to callback function for ICMP ECHO response handler (triggers when localhost recieves ping respnse (pong)) +static uint8_t destmacaddr[6]; // storing both dns server and destination mac addresses, but at different times because both are never needed at same time. +static boolean waiting_for_dns_mac = false; //might be better to use bit flags and bitmask operations for these conditions +static boolean has_dns_mac = false; +static boolean waiting_for_dest_mac = false; +static boolean has_dest_mac = false; +static uint8_t gwmacaddr[6]; // Hardware (MAC) address of gateway router +static uint8_t waitgwmac; // Bitwise flags of gateway router status - see below for states +//Define gatweay router ARP statuses +#define WGW_INITIAL_ARP 1 // First request, no answer yet +#define WGW_HAVE_GW_MAC 2 // Have gateway router MAC +#define WGW_REFRESHING 4 // Refreshing but already have gateway MAC +#define WGW_ACCEPT_ARP_REPLY 8 // Accept an ARP reply + +static uint16_t info_data_len; // Length of TCP/IP payload +static uint8_t seqnum = 0xa; // My initial tcp sequence number +static uint8_t result_fd = 123; // Session id of last reply +static const char* result_ptr; // Pointer to TCP/IP data +static unsigned long SEQ; // TCP/IP sequence number + +#define CLIENTMSS 550 +#define TCP_DATA_START ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4) // Get offset of TCP/IP payload data + +const unsigned char arpreqhdr[] PROGMEM = { 0,1,8,0,6,4,0,1 }; // ARP request header +const unsigned char iphdr[] PROGMEM = { 0x45,0,0,0x82,0,0,0x40,0,0x20 }; //IP header +const unsigned char ntpreqhdr[] PROGMEM = { 0xE3,0,4,0xFA,0,1,0,0,0,1 }; //NTP request header +const uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Used for hardware (MAC) and IP broadcast addresses + +static void fill_checksum(uint8_t dest, uint8_t off, uint16_t len,uint8_t type) { + const uint8_t* ptr = gPB + off; + uint32_t sum = type==1 ? IP_PROTO_UDP_V+len-8 : + type==2 ? IP_PROTO_TCP_V+len-8 : 0; + while(len >1) { + sum += (uint16_t) (((uint32_t)*ptr<<8)|*(ptr+1)); + ptr+=2; + len-=2; + } + if (len) + sum += ((uint32_t)*ptr)<<8; + while (sum>>16) + sum = (uint16_t) sum + (sum >> 16); + uint16_t ck = ~ (uint16_t) sum; + gPB[dest] = ck>>8; + gPB[dest+1] = ck; +} + +static void setMACs (const uint8_t *mac) { + EtherCard::copyMac(gPB + ETH_DST_MAC, mac); + EtherCard::copyMac(gPB + ETH_SRC_MAC, EtherCard::mymac); +} + +static void setMACandIPs (const uint8_t *mac, const uint8_t *dst) { + setMACs(mac); + EtherCard::copyIp(gPB + IP_DST_P, dst); + EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip); +} + +static uint8_t check_ip_message_is_from(const uint8_t *ip) { + return memcmp(gPB + IP_SRC_P, ip, 4) == 0; +} + +static boolean is_lan(const uint8_t source[4], const uint8_t destination[4]) { + if(source[0] == 0 || destination[0] == 0) { + return false; + } + for(int i = 0; i < 4; i++) + if((source[i] & EtherCard::netmask[i]) != (destination[i] & EtherCard::netmask[i])) { + return false; + } + return true; +} + +static uint8_t eth_type_is_arp_and_my_ip(uint16_t len) { + return len >= 41 && gPB[ETH_TYPE_H_P] == ETHTYPE_ARP_H_V && + gPB[ETH_TYPE_L_P] == ETHTYPE_ARP_L_V && + memcmp(gPB + ETH_ARP_DST_IP_P, EtherCard::myip, 4) == 0; +} + +static uint8_t eth_type_is_ip_and_my_ip(uint16_t len) { + return len >= 42 && gPB[ETH_TYPE_H_P] == ETHTYPE_IP_H_V && + gPB[ETH_TYPE_L_P] == ETHTYPE_IP_L_V && + gPB[IP_HEADER_LEN_VER_P] == 0x45 && + (memcmp(gPB + IP_DST_P, EtherCard::myip, 4) == 0 //not my IP + || (memcmp(gPB + IP_DST_P, EtherCard::broadcastip, 4) == 0) //not subnet broadcast + || (memcmp(gPB + IP_DST_P, allOnes, 4) == 0)); //not global broadcasts + //!@todo Handle multicast +} + +static void fill_ip_hdr_checksum() { + gPB[IP_CHECKSUM_P] = 0; + gPB[IP_CHECKSUM_P+1] = 0; + gPB[IP_FLAGS_P] = 0x40; // don't fragment + gPB[IP_FLAGS_P+1] = 0; // fragement offset + gPB[IP_TTL_P] = 64; // ttl + fill_checksum(IP_CHECKSUM_P, IP_P, IP_HEADER_LEN,0); +} + +static void make_eth_ip() { + setMACs(gPB + ETH_SRC_MAC); + EtherCard::copyIp(gPB + IP_DST_P, gPB + IP_SRC_P); + EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip); + fill_ip_hdr_checksum(); +} + +static void step_seq(uint16_t rel_ack_num,uint8_t cp_seq) { + uint8_t i; + uint8_t tseq; + i = 4; + while(i>0) { + rel_ack_num = gPB[TCP_SEQ_H_P+i-1]+rel_ack_num; + tseq = gPB[TCP_SEQACK_H_P+i-1]; + gPB[TCP_SEQACK_H_P+i-1] = rel_ack_num; + if (cp_seq) + gPB[TCP_SEQ_H_P+i-1] = tseq; + else + gPB[TCP_SEQ_H_P+i-1] = 0; // some preset value + rel_ack_num = rel_ack_num>>8; + i--; + } +} + +static void make_tcphead(uint16_t rel_ack_num,uint8_t cp_seq) { + uint8_t i = gPB[TCP_DST_PORT_H_P]; + gPB[TCP_DST_PORT_H_P] = gPB[TCP_SRC_PORT_H_P]; + gPB[TCP_SRC_PORT_H_P] = i; + uint8_t j = gPB[TCP_DST_PORT_L_P]; + gPB[TCP_DST_PORT_L_P] = gPB[TCP_SRC_PORT_L_P]; + gPB[TCP_SRC_PORT_L_P] = j; + step_seq(rel_ack_num,cp_seq); + gPB[TCP_CHECKSUM_H_P] = 0; + gPB[TCP_CHECKSUM_L_P] = 0; + gPB[TCP_HEADER_LEN_P] = 0x50; +} + +static void make_arp_answer_from_request() { + setMACs(gPB + ETH_SRC_MAC); + gPB[ETH_ARP_OPCODE_H_P] = ETH_ARP_OPCODE_REPLY_H_V; + gPB[ETH_ARP_OPCODE_L_P] = ETH_ARP_OPCODE_REPLY_L_V; + EtherCard::copyMac(gPB + ETH_ARP_DST_MAC_P, gPB + ETH_ARP_SRC_MAC_P); + EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac); + EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, gPB + ETH_ARP_SRC_IP_P); + EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip); + EtherCard::packetSend(42); +} + +static void make_echo_reply_from_request(uint16_t len) { + make_eth_ip(); + gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREPLY_V; + if (gPB[ICMP_CHECKSUM_P] > (0xFF-0x08)) + gPB[ICMP_CHECKSUM_P+1]++; + gPB[ICMP_CHECKSUM_P] += 0x08; + EtherCard::packetSend(len); +} + +void EtherCard::makeUdpReply (const char *data,uint8_t datalen,uint16_t port) { + if (datalen>220) + datalen = 220; + gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >>8; + gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen; + make_eth_ip(); + gPB[UDP_DST_PORT_H_P] = gPB[UDP_SRC_PORT_H_P]; + gPB[UDP_DST_PORT_L_P] = gPB[UDP_SRC_PORT_L_P]; + gPB[UDP_SRC_PORT_H_P] = port>>8; + gPB[UDP_SRC_PORT_L_P] = port; + gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >> 8; + gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen; + gPB[UDP_CHECKSUM_H_P] = 0; + gPB[UDP_CHECKSUM_L_P] = 0; + memcpy(gPB + UDP_DATA_P, data, datalen); + fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1); + packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen); +} + +static void make_tcp_synack_from_syn() { + gPB[IP_TOTLEN_H_P] = 0; + gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4; + make_eth_ip(); + gPB[TCP_FLAGS_P] = TCP_FLAGS_SYNACK_V; + make_tcphead(1,0); + gPB[TCP_SEQ_H_P+0] = 0; + gPB[TCP_SEQ_H_P+1] = 0; + gPB[TCP_SEQ_H_P+2] = seqnum; + gPB[TCP_SEQ_H_P+3] = 0; + seqnum += 3; + gPB[TCP_OPTIONS_P] = 2; + gPB[TCP_OPTIONS_P+1] = 4; + gPB[TCP_OPTIONS_P+2] = 0x05; + gPB[TCP_OPTIONS_P+3] = 0x0; + gPB[TCP_HEADER_LEN_P] = 0x60; + gPB[TCP_WIN_SIZE] = 0x5; // 1400=0x578 + gPB[TCP_WIN_SIZE+1] = 0x78; + fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+4,2); + EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN); +} + +static uint16_t get_tcp_data_len() { + int16_t i = (((int16_t)gPB[IP_TOTLEN_H_P])<<8)|gPB[IP_TOTLEN_L_P]; + i -= IP_HEADER_LEN; + i -= (gPB[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes; + if (i<=0) + i = 0; + return (uint16_t)i; +} + +static void make_tcp_ack_from_any(int16_t datlentoack,uint8_t addflags) { + gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|addflags; + if (addflags!=TCP_FLAGS_RST_V && datlentoack==0) + datlentoack = 1; + make_tcphead(datlentoack,1); // no options + uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN; + gPB[IP_TOTLEN_H_P] = j>>8; + gPB[IP_TOTLEN_L_P] = j; + make_eth_ip(); + gPB[TCP_WIN_SIZE] = 0x4; // 1024=0x400, 1280=0x500 2048=0x800 768=0x300 + gPB[TCP_WIN_SIZE+1] = 0; + fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN,2); + EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN); +} + +static void make_tcp_ack_with_data_noflags(uint16_t dlen) { + uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen; + gPB[IP_TOTLEN_H_P] = j>>8; + gPB[IP_TOTLEN_L_P] = j; + fill_ip_hdr_checksum(); + gPB[TCP_CHECKSUM_H_P] = 0; + gPB[TCP_CHECKSUM_L_P] = 0; + fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+dlen,2); + EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN); +} + +void EtherCard::httpServerReply (uint16_t dlen) { + make_tcp_ack_from_any(info_data_len,0); // send ack for http get + gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V; + make_tcp_ack_with_data_noflags(dlen); // send data +} + +static void get_seq() { //get the sequence number of packets after an ack from GET + SEQ =(((unsigned long)gPB[TCP_SEQ_H_P]*256+gPB[TCP_SEQ_H_P+1])*256+gPB[TCP_SEQ_H_P+2])*256+gPB[TCP_SEQ_H_P+3]; +} //thanks to mstuetz for the missing (unsigned long) + +static void set_seq() { //set the correct sequence number and calculate the next with the lenght of current packet + gPB[TCP_SEQ_H_P]= (SEQ & 0xff000000 ) >> 24; + gPB[TCP_SEQ_H_P+1]= (SEQ & 0xff0000 ) >> 16; + gPB[TCP_SEQ_H_P+2]= (SEQ & 0xff00 ) >> 8; + gPB[TCP_SEQ_H_P+3]= (SEQ & 0xff ); +} + +void EtherCard::httpServerReplyAck () { + make_tcp_ack_from_any(info_data_len,0); // send ack for http get + get_seq(); //get the sequence number of packets after an ack from GET +} + +void EtherCard::httpServerReply_with_flags (uint16_t dlen , uint8_t flags) { + set_seq(); + gPB[TCP_FLAGS_P] = flags; // final packet + make_tcp_ack_with_data_noflags(dlen); // send data + SEQ=SEQ+dlen; +} + +void EtherCard::clientIcmpRequest(const uint8_t *destip) { + if(is_lan(EtherCard::myip, destip)) { + setMACandIPs(destmacaddr, destip); + } else { + setMACandIPs(gwmacaddr, destip); + } + gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V; + memcpy_P(gPB + IP_P,iphdr,9); + gPB[IP_TOTLEN_L_P] = 0x54; + gPB[IP_PROTO_P] = IP_PROTO_ICMP_V; + fill_ip_hdr_checksum(); + gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREQUEST_V; + gPB[ICMP_TYPE_P+1] = 0; // code + gPB[ICMP_CHECKSUM_H_P] = 0; + gPB[ICMP_CHECKSUM_L_P] = 0; + gPB[ICMP_IDENT_H_P] = 5; // some number + gPB[ICMP_IDENT_L_P] = EtherCard::myip[3]; // last byte of my IP + gPB[ICMP_IDENT_L_P+1] = 0; // seq number, high byte + gPB[ICMP_IDENT_L_P+2] = 1; // seq number, low byte, we send only 1 ping at a time + memset(gPB + ICMP_DATA_P, PINGPATTERN, 56); + fill_checksum(ICMP_CHECKSUM_H_P, ICMP_TYPE_P, 56+8,0); + packetSend(98); +} + +void EtherCard::ntpRequest (uint8_t *ntpip,uint8_t srcport) { + if(is_lan(myip, ntpip)) { + setMACandIPs(destmacaddr, ntpip); + } else { + setMACandIPs(gwmacaddr, ntpip); + } + gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V; + memcpy_P(gPB + IP_P,iphdr,9); + gPB[IP_TOTLEN_L_P] = 0x4c; + gPB[IP_PROTO_P] = IP_PROTO_UDP_V; + fill_ip_hdr_checksum(); + gPB[UDP_DST_PORT_H_P] = 0; + gPB[UDP_DST_PORT_L_P] = 0x7b; // ntp = 123 + gPB[UDP_SRC_PORT_H_P] = 10; + gPB[UDP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port + gPB[UDP_LEN_H_P] = 0; + gPB[UDP_LEN_L_P] = 56; // fixed len + gPB[UDP_CHECKSUM_H_P] = 0; + gPB[UDP_CHECKSUM_L_P] = 0; + memset(gPB + UDP_DATA_P, 0, 48); + memcpy_P(gPB + UDP_DATA_P,ntpreqhdr,10); + fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 48,1); + packetSend(90); +} + +uint8_t EtherCard::ntpProcessAnswer (uint32_t *time,uint8_t dstport_l) { + if ((dstport_l && gPB[UDP_DST_PORT_L_P]!=dstport_l) || gPB[UDP_LEN_H_P]!=0 || + gPB[UDP_LEN_L_P]!=56 || gPB[UDP_SRC_PORT_L_P]!=0x7b) + return 0; + ((uint8_t*) time)[3] = gPB[0x52]; + ((uint8_t*) time)[2] = gPB[0x53]; + ((uint8_t*) time)[1] = gPB[0x54]; + ((uint8_t*) time)[0] = gPB[0x55]; + return 1; +} + +void EtherCard::udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport) { + if(is_lan(myip, dip)) { // this works because both dns mac and destinations mac are stored in same variable - destmacaddr + setMACandIPs(destmacaddr, dip); // at different times. The program could have separate variable for dns mac, then here should be + } else { // checked if dip is dns ip and separately if dip is hisip and then use correct mac. + setMACandIPs(gwmacaddr, dip); + } + // see http://tldp.org/HOWTO/Multicast-HOWTO-2.html + // multicast or broadcast address, https://github.com/jcw/ethercard/issues/59 + if ((dip[0] & 0xF0) == 0xE0 || *((unsigned long*) dip) == 0xFFFFFFFF) + EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes); + gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V; + memcpy_P(gPB + IP_P,iphdr,9); + gPB[IP_TOTLEN_H_P] = 0; + gPB[IP_PROTO_P] = IP_PROTO_UDP_V; + gPB[UDP_DST_PORT_H_P] = (dport>>8); + gPB[UDP_DST_PORT_L_P] = dport; + gPB[UDP_SRC_PORT_H_P] = (sport>>8); + gPB[UDP_SRC_PORT_L_P] = sport; + gPB[UDP_LEN_H_P] = 0; + gPB[UDP_CHECKSUM_H_P] = 0; + gPB[UDP_CHECKSUM_L_P] = 0; +} + +void EtherCard::udpTransmit (uint16_t datalen) { + gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >> 8; + gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen; + fill_ip_hdr_checksum(); + gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >>8; + gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen; + fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1); + packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen); +} + +void EtherCard::sendUdp (const char *data, uint8_t datalen, uint16_t sport, + const uint8_t *dip, uint16_t dport) { + udpPrepare(sport, dip, dport); + if (datalen>220) + datalen = 220; + memcpy(gPB + UDP_DATA_P, data, datalen); + udpTransmit(datalen); +} + +void EtherCard::sendWol (uint8_t *wolmac) { + setMACandIPs(allOnes, allOnes); + gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V; + memcpy_P(gPB + IP_P,iphdr,9); + gPB[IP_TOTLEN_L_P] = 0x82; + gPB[IP_PROTO_P] = IP_PROTO_UDP_V; + fill_ip_hdr_checksum(); + gPB[UDP_DST_PORT_H_P] = 0; + gPB[UDP_DST_PORT_L_P] = 0x9; // wol = normally 9 + gPB[UDP_SRC_PORT_H_P] = 10; + gPB[UDP_SRC_PORT_L_P] = 0x42; // source port does not matter + gPB[UDP_LEN_H_P] = 0; + gPB[UDP_LEN_L_P] = 110; // fixed len + gPB[UDP_CHECKSUM_H_P] = 0; + gPB[UDP_CHECKSUM_L_P] = 0; + copyMac(gPB + UDP_DATA_P, allOnes); + uint8_t pos = UDP_DATA_P; + for (uint8_t m = 0; m < 16; ++m) { + pos += 6; + copyMac(gPB + pos, wolmac); + } + fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 102,1); + packetSend(pos + 6); +} + +// make a arp request +static void client_arp_whohas(uint8_t *ip_we_search) { + setMACs(allOnes); + gPB[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V; + memcpy_P(gPB + ETH_ARP_P,arpreqhdr,8); + memset(gPB + ETH_ARP_DST_MAC_P, 0, 6); + EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac); + EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, ip_we_search); + EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip); + EtherCard::packetSend(42); +} + +uint8_t EtherCard::clientWaitingGw () { + return !(waitgwmac & WGW_HAVE_GW_MAC); +} + +uint8_t EtherCard::clientWaitingDns () { + if(is_lan(myip, dnsip)) + return !has_dns_mac; + return !(waitgwmac & WGW_HAVE_GW_MAC); +} + +static uint8_t client_store_mac(uint8_t *source_ip, uint8_t *mac) { + if (memcmp(gPB + ETH_ARP_SRC_IP_P, source_ip, 4) != 0) + return 0; + EtherCard::copyMac(mac, gPB + ETH_ARP_SRC_MAC_P); + return 1; +} + +// static void client_gw_arp_refresh() { +// if (waitgwmac & WGW_HAVE_GW_MAC) +// waitgwmac |= WGW_REFRESHING; +// } + +void EtherCard::setGwIp (const uint8_t *gwipaddr) { + delaycnt = 0; //request gateway ARP lookup + waitgwmac = WGW_INITIAL_ARP; // causes an arp request in the packet loop + copyIp(gwip, gwipaddr); +} + +void EtherCard::updateBroadcastAddress() +{ + for(uint8_t i=0; i<4; i++) + broadcastip[i] = myip[i] | ~netmask[i]; +} + +static void client_syn(uint8_t srcport,uint8_t dstport_h,uint8_t dstport_l) { + if(is_lan(EtherCard::myip, EtherCard::hisip)) { + setMACandIPs(destmacaddr, EtherCard::hisip); + } else { + setMACandIPs(gwmacaddr, EtherCard::hisip); + } + gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V; + gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V; + memcpy_P(gPB + IP_P,iphdr,9); + gPB[IP_TOTLEN_L_P] = 44; // good for syn + gPB[IP_PROTO_P] = IP_PROTO_TCP_V; + fill_ip_hdr_checksum(); + gPB[TCP_DST_PORT_H_P] = dstport_h; + gPB[TCP_DST_PORT_L_P] = dstport_l; + gPB[TCP_SRC_PORT_H_P] = TCPCLIENT_SRC_PORT_H; + gPB[TCP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port + memset(gPB + TCP_SEQ_H_P, 0, 8); + gPB[TCP_SEQ_H_P+2] = seqnum; + seqnum += 3; + gPB[TCP_HEADER_LEN_P] = 0x60; // 0x60=24 len: (0x60>>4) * 4 + gPB[TCP_FLAGS_P] = TCP_FLAGS_SYN_V; + gPB[TCP_WIN_SIZE] = 0x3; // 1024 = 0x400 768 = 0x300, initial window + gPB[TCP_WIN_SIZE+1] = 0x0; + gPB[TCP_CHECKSUM_H_P] = 0; + gPB[TCP_CHECKSUM_L_P] = 0; + gPB[TCP_CHECKSUM_L_P+1] = 0; + gPB[TCP_CHECKSUM_L_P+2] = 0; + gPB[TCP_OPTIONS_P] = 2; + gPB[TCP_OPTIONS_P+1] = 4; + gPB[TCP_OPTIONS_P+2] = (CLIENTMSS>>8); + gPB[TCP_OPTIONS_P+3] = (uint8_t) CLIENTMSS; + fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8 +TCP_HEADER_LEN_PLAIN+4,2); + // 4 is the tcp mss option: + EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN+4); +} + +uint8_t EtherCard::clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t), + uint16_t (*datafill_cb)(uint8_t),uint16_t port) { + client_tcp_result_cb = result_cb; + client_tcp_datafill_cb = datafill_cb; + tcp_client_port_h = port>>8; + tcp_client_port_l = port; + tcp_client_state = 1; // Flag to packetloop to initiate a TCP/IP session by send a syn + tcp_fd = (tcp_fd + 1) & 7; + return tcp_fd; +} + +static uint16_t www_client_internal_datafill_cb(uint8_t fd) { + BufferFiller bfill = EtherCard::tcpOffset(); + if (fd==www_fd) { + if (client_postval == 0) { + bfill.emit_p(PSTR("GET $F$S HTTP/1.0\r\n" + "Host: $F\r\n" + "$F\r\n" + "\r\n"), client_urlbuf, + client_urlbuf_var, + client_hoststr, client_additionalheaderline); + } else { + const char* ahl = client_additionalheaderline; + bfill.emit_p(PSTR("POST $F HTTP/1.0\r\n" + "Host: $F\r\n" + "$F$S" + "Accept: */*\r\n" + "Content-Length: $D\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n" + "$S"), client_urlbuf, + client_hoststr, + ahl != 0 ? ahl : PSTR(""), + ahl != 0 ? "\r\n" : "", + strlen(client_postval), + client_postval); + } + } + return bfill.position(); +} + +static uint8_t www_client_internal_result_cb(uint8_t fd, uint8_t statuscode, uint16_t datapos, uint16_t len_of_data) { + if (fd!=www_fd) + (*client_browser_cb)(4,0,0); + else if (statuscode==0 && len_of_data>12 && client_browser_cb) { + uint8_t f = strncmp("200",(char *)&(gPB[datapos+9]),3) != 0; + (*client_browser_cb)(f, ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4),len_of_data); + } + return 0; +} + +void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, void (*callback)(uint8_t,uint16_t,uint16_t)) { + browseUrl(urlbuf, urlbuf_varpart, hoststr, PSTR("Accept: text/html"), callback); +} + +void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, const char *additionalheaderline, void (*callback)(uint8_t,uint16_t,uint16_t)) { + client_urlbuf = urlbuf; + client_urlbuf_var = urlbuf_varpart; + client_hoststr = hoststr; + client_additionalheaderline = additionalheaderline; + client_postval = 0; + client_browser_cb = callback; + www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport); +} + +void EtherCard::httpPost (const char *urlbuf, const char *hoststr, const char *additionalheaderline, const char *postval, void (*callback)(uint8_t,uint16_t,uint16_t)) { + client_urlbuf = urlbuf; + client_hoststr = hoststr; + client_additionalheaderline = additionalheaderline; + client_postval = postval; + client_browser_cb = callback; + www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport); +} + +static uint16_t tcp_datafill_cb(uint8_t fd) { + uint16_t len = Stash::length(); + Stash::extract(0, len, EtherCard::tcpOffset()); + Stash::cleanup(); + EtherCard::tcpOffset()[len] = 0; +#if SERIAL + Serial.print("REQUEST: "); + Serial.println(len); + Serial.println((char*) EtherCard::tcpOffset()); +#endif + result_fd = 123; // bogus value + return len; +} + +static uint8_t tcp_result_cb(uint8_t fd, uint8_t status, uint16_t datapos, uint16_t datalen) { + if (status == 0) { + result_fd = fd; // a valid result has been received, remember its session id + result_ptr = (char*) ether.buffer + datapos; + // result_ptr[datalen] = 0; + } + return 1; +} + +uint8_t EtherCard::tcpSend () { + www_fd = clientTcpReq(&tcp_result_cb, &tcp_datafill_cb, hisport); + return www_fd; +} + +const char* EtherCard::tcpReply (uint8_t fd) { + if (result_fd != fd) + return 0; + result_fd = 123; // set to a bogus value to prevent future match + return result_ptr; +} + +void EtherCard::registerPingCallback (void (*callback)(uint8_t *srcip)) { + icmp_cb = callback; +} + +uint8_t EtherCard::packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost) { + return gPB[IP_PROTO_P]==IP_PROTO_ICMP_V && + gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREPLY_V && + gPB[ICMP_DATA_P]== PINGPATTERN && + check_ip_message_is_from(ip_monitoredhost); +} + +uint16_t EtherCard::accept(const uint16_t port, uint16_t plen) { + uint16_t pos; + + if (gPB[TCP_DST_PORT_H_P] == (port >> 8) && + gPB[TCP_DST_PORT_L_P] == ((uint8_t) port)) + { //Packet targetted at specified port + if (gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) + make_tcp_synack_from_syn(); //send SYN+ACK + else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V) + { //This is an acknowledgement to our SYN+ACK so let's start processing that payload + info_data_len = get_tcp_data_len(); + if (info_data_len > 0) + { //Got some data + pos = TCP_DATA_START; // TCP_DATA_START is a formula + if (pos <= plen - 8) + return pos; + } + else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) + make_tcp_ack_from_any(0,0); //No data so close connection + } + } + return 0; +} + +uint16_t EtherCard::packetLoop (uint16_t plen) { + uint16_t len; + if(using_dhcp) { + ether.DhcpStateMachine(plen); + } + + if (plen==0) { + //Check every 65536 (no-packet) cycles whether we need to retry ARP request for gateway + if ((waitgwmac & WGW_INITIAL_ARP || waitgwmac & WGW_REFRESHING) && + delaycnt==0 && isLinkUp()) { + client_arp_whohas(gwip); + waitgwmac |= WGW_ACCEPT_ARP_REPLY; + } + delaycnt++; + //Initiate TCP/IP session if pending + if (tcp_client_state==1 && (waitgwmac & WGW_HAVE_GW_MAC)) { // send a syn + tcp_client_state = 2; + tcpclient_src_port_l++; // allocate a new port + client_syn(((tcp_fd<<5) | (0x1f & tcpclient_src_port_l)),tcp_client_port_h,tcp_client_port_l); + } + //!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed. + if(is_lan(myip, dnsip) && !has_dns_mac && !waiting_for_dns_mac) { + client_arp_whohas(dnsip); + waiting_for_dns_mac = true; + } + //!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed. + if(is_lan(myip, hisip) && !has_dest_mac && !waiting_for_dest_mac) { + client_arp_whohas(hisip); + waiting_for_dest_mac = true; + } + + return 0; + } + + if (eth_type_is_arp_and_my_ip(plen)) + { //Service ARP request + if (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V) + make_arp_answer_from_request(); + if (waitgwmac & WGW_ACCEPT_ARP_REPLY && (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V) && client_store_mac(gwip, gwmacaddr)) + waitgwmac = WGW_HAVE_GW_MAC; + if (!has_dns_mac && waiting_for_dns_mac && client_store_mac(dnsip, destmacaddr)) { + has_dns_mac = true; + waiting_for_dns_mac = false; + } + if (!has_dest_mac && waiting_for_dest_mac && client_store_mac(hisip, destmacaddr)) { + has_dest_mac = true; + waiting_for_dest_mac = false; + } + return 0; + } + + if (eth_type_is_ip_and_my_ip(plen)==0) + { //Not IP so ignoring + //!@todo Add other protocols (and make each optional at compile time) + return 0; + } + if (gPB[IP_PROTO_P]==IP_PROTO_ICMP_V && gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V) + { //Service ICMP echo request (ping) + if (icmp_cb) + (*icmp_cb)(&(gPB[IP_SRC_P])); + make_echo_reply_from_request(plen); + return 0; + } + if (ether.udpServerListening() && gPB[IP_PROTO_P]==IP_PROTO_UDP_V) + { //Call UDP server handler (callback) if one is defined for this packet + if(ether.udpServerHasProcessedPacket(plen)) + return 0; //An UDP server handler (callback) has processed this packet + } + if (plen<54 && gPB[IP_PROTO_P]!=IP_PROTO_TCP_V ) + return 0; //Packet flagged as TCP but shorter than minimum TCP packet length + if (gPB[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H) + { //Source port is in range reserved (by EtherCard) for client TCP/IP connections + if (check_ip_message_is_from(hisip)==0) + return 0; //Not current TCP/IP connection (only handle one at a time) + if (gPB[TCP_FLAGS_P] & TCP_FLAGS_RST_V) + { //TCP reset flagged + if (client_tcp_result_cb) + (*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0); + tcp_client_state = 5; + return 0; + } + len = get_tcp_data_len(); + if (tcp_client_state==2) + { //Waiting for SYN-ACK + if ((gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) && (gPB[TCP_FLAGS_P] &TCP_FLAGS_ACK_V)) + { //SYN and ACK flags set so this is an acknowledgement to our SYN + make_tcp_ack_from_any(0,0); + gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V; + if (client_tcp_datafill_cb) + len = (*client_tcp_datafill_cb)((gPB[TCP_SRC_PORT_L_P]>>5)&0x7); + else + len = 0; + tcp_client_state = 3; + make_tcp_ack_with_data_noflags(len); + } + else + { //Expecting SYN+ACK so reset and resend SYN + tcp_client_state = 1; // retry + len++; + if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V) + len = 0; + make_tcp_ack_from_any(len,TCP_FLAGS_RST_V); + } + return 0; + } + if (tcp_client_state==3 && len>0) + { //TCP connection established so read data + if (client_tcp_result_cb) { + uint16_t tcpstart = TCP_DATA_START; // TCP_DATA_START is a formula + if (tcpstart>plen-8) + tcpstart = plen-8; // dummy but save + uint16_t save_len = len; + if (tcpstart+len>plen) + save_len = plen-tcpstart; + (*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,0,tcpstart,save_len); //Call TCP handler (callback) function + + if(persist_tcp_connection) + { //Keep connection alive by sending ACK + make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V); + } + else + { //Close connection + make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V); + tcp_client_state = 6; + } + return 0; + } + } + if (tcp_client_state != 5) + { // + if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) { + if(tcp_client_state == 3) { + return 0; // In some instances FIN is received *before* DATA. If that is the case, we just return here and keep looking for the data packet + } + make_tcp_ack_from_any(len+1,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V); + tcp_client_state = 6; // connection terminated + } else if (len>0) { + make_tcp_ack_from_any(len,0); + } + } + return 0; + } + + //If we are here then this is a TCP/IP packet targetted at us and not related to out client connection so accept + return accept(hisport, plen); +} + +void EtherCard::persistTcpConnection(bool persist) { + persist_tcp_connection = persist; +} diff --git a/lib-ext/ethercard.git/udpserver.cpp b/lib-ext/ethercard.git/udpserver.cpp new file mode 100644 index 0000000..047b92d --- /dev/null +++ b/lib-ext/ethercard.git/udpserver.cpp @@ -0,0 +1,72 @@ +// Simple UDP listening server +// +// Author: Brian Lee +// +// Copyright: GPL V2 +// See http://www.gnu.org/licenses/gpl.html + +#include "EtherCard.h" +#include "net.h" + +#define gPB ether.buffer + +#define UDPSERVER_MAXLISTENERS 8 //the maximum number of port listeners. + +typedef struct { + UdpServerCallback callback; + uint16_t port; + bool listening; +} UdpServerListener; + +UdpServerListener listeners[UDPSERVER_MAXLISTENERS]; +byte numListeners = 0; + +void EtherCard::udpServerListenOnPort(UdpServerCallback callback, uint16_t port) { + if(numListeners < UDPSERVER_MAXLISTENERS) + { + listeners[numListeners] = (UdpServerListener) { + callback, port, true + }; + numListeners++; + } +} + +void EtherCard::udpServerPauseListenOnPort(uint16_t port) { + for(int i = 0; i < numListeners; i++) + { + if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) { + listeners[i].listening = false; + } + } +} + +void EtherCard::udpServerResumeListenOnPort(uint16_t port) { + for(int i = 0; i < numListeners; i++) + { + if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) { + listeners[i].listening = true; + } + } +} + +bool EtherCard::udpServerListening() { + return numListeners > 0; +} + +bool EtherCard::udpServerHasProcessedPacket(uint16_t plen) { + bool packetProcessed = false; + for(int i = 0; i < numListeners; i++) + { + if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port) && listeners[i].listening) + { + uint16_t datalen = (uint16_t) (gPB[UDP_LEN_H_P] << 8) + gPB[UDP_LEN_L_P] - UDP_HEADER_LEN; + listeners[i].callback( + listeners[i].port, + gPB + IP_SRC_P, + (const char *) (gPB + UDP_DATA_P), + datalen); + packetProcessed = true; + } + } + return packetProcessed; +} diff --git a/lib-ext/ethercard.git/webutil.cpp b/lib-ext/ethercard.git/webutil.cpp new file mode 100644 index 0000000..d15c462 --- /dev/null +++ b/lib-ext/ethercard.git/webutil.cpp @@ -0,0 +1,202 @@ +// Some common utilities needed for IP and web applications +// Author: Guido Socher +// Copyright: GPL V2 +// +// 2010-05-20 + +#include "EtherCard.h" + +void EtherCard::copyIp (uint8_t *dst, const uint8_t *src) { + memcpy(dst, src, 4); +} + +void EtherCard::copyMac (uint8_t *dst, const uint8_t *src) { + memcpy(dst, src, 6); +} + +void EtherCard::printIp (const char* msg, const uint8_t *buf) { + Serial.print(msg); + EtherCard::printIp(buf); + Serial.println(); +} + +void EtherCard::printIp (const __FlashStringHelper *ifsh, const uint8_t *buf) { + Serial.print(ifsh); + EtherCard::printIp(buf); + Serial.println(); +} + +void EtherCard::printIp (const uint8_t *buf) { + for (uint8_t i = 0; i < 4; ++i) { + Serial.print( buf[i], DEC ); + if (i < 3) + Serial.print('.'); + } +} + +// search for a string of the form key=value in +// a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\r\n +// +// The returned value is stored in strbuf. You must allocate +// enough storage for strbuf, maxlen is the size of strbuf. +// I.e the value it is declated with: strbuf[5]-> maxlen=5 +uint8_t EtherCard::findKeyVal (const char *str,char *strbuf, uint8_t maxlen,const char *key) +{ + uint8_t found=0; + uint8_t i=0; + const char *kp; + kp=key; + while(*str && *str!=' ' && *str!='\n' && found==0) { + if (*str == *kp) { + kp++; + if (*kp == '\0') { + str++; + kp=key; + if (*str == '=') { + found=1; + } + } + } else { + kp=key; + } + str++; + } + if (found==1) { + // copy the value to a buffer and terminate it with '\0' + while(*str && *str!=' ' && *str!='\n' && *str!='&' && i= '0' && c <='9') { + return((unsigned char)c - '0'); + } + if (c >= 'a' && c <='f') { + return((unsigned char)c - 'a' + 10); + } + if (c >= 'A' && c <='F') { + return((unsigned char)c - 'A' + 10); + } + return(0); +} + +// decode a url string e.g "hello%20joe" or "hello+joe" becomes "hello joe" +void EtherCard::urlDecode (char *urlbuf) +{ + char c; + char *dst = urlbuf; + while ((c = *urlbuf) != 0) { + if (c == '+') c = ' '; + if (c == '%') { + c = *++urlbuf; + c = (h2int(c) << 4) | h2int(*++urlbuf); + } + *dst++ = c; + urlbuf++; + } + *dst = '\0'; +} + +// convert a single character to a 2 digit hex str +// a terminating '\0' is added +void int2h(char c, char *hstr) +{ + hstr[1]=(c & 0xf)+'0'; + if ((c & 0xf) >9) { + hstr[1]=(c & 0xf) - 10 + 'a'; + } + c=(c>>4)&0xf; + hstr[0]=c+'0'; + if (c > 9) { + hstr[0]=c - 10 + 'a'; + } + hstr[2]='\0'; +} + +// there must be enough space in urlbuf. In the worst case that is +// 3 times the length of str +void EtherCard::urlEncode (char *str,char *urlbuf) +{ + char c; + while ((c = *str) != 0) { + if (c == ' '||isalnum(c)) { + if (c == ' ') { + c = '+'; + } + *urlbuf=c; + str++; + urlbuf++; + continue; + } + *urlbuf='%'; + urlbuf++; + int2h(c,urlbuf); + urlbuf++; + urlbuf++; + str++; + } + *urlbuf='\0'; +} + +// parse a string and extract the IP to bytestr +uint8_t EtherCard::parseIp (uint8_t *bytestr,char *str) +{ + char *sptr; + uint8_t i=0; + sptr=NULL; + while(i<4) { + bytestr[i]=0; + i++; + } + i=0; + while(*str && i<4) { + // if a number then start + if (sptr==NULL && isdigit(*str)) { + sptr=str; + } + if (*str == '.') { + *str ='\0'; + bytestr[i]=(atoi(sptr)&0xff); + i++; + sptr=NULL; + } + str++; + } + *str ='\0'; + if (i==3) { + bytestr[i]=(atoi(sptr)&0xff); + return(0); + } + return(1); +} + +// take a byte string and convert it to a human readable display string (base is 10 for ip and 16 for mac addr), len is 4 for IP addr and 6 for mac. +void EtherCard::makeNetStr (char *resultstr,uint8_t *bytestr,uint8_t len,char separator,uint8_t base) +{ + uint8_t i=0; + uint8_t j=0; + while(i. +*/ + +#include +#include +#include +//#include + +#include +#include +#include "Narcoleptic.h" + +SIGNAL(WDT_vect) { + wdt_disable(); + wdt_reset(); + WDTCSR &= ~_BV(WDIE); +} + +void NarcolepticClass::sleep(uint8_t wdt_period) { + wdt_enable(wdt_period); + wdt_reset(); + WDTCSR |= _BV(WDIE); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_mode(); + wdt_disable(); + WDTCSR &= ~_BV(WDIE); +} + +void NarcolepticClass::delay(int milliseconds) { + while (milliseconds >= 8000) { sleep(WDTO_8S); milliseconds -= 8000; } + if (milliseconds >= 4000) { sleep(WDTO_4S); milliseconds -= 4000; } + if (milliseconds >= 2000) { sleep(WDTO_2S); milliseconds -= 2000; } + if (milliseconds >= 1000) { sleep(WDTO_1S); milliseconds -= 1000; } + if (milliseconds >= 500) { sleep(WDTO_500MS); milliseconds -= 500; } + if (milliseconds >= 250) { sleep(WDTO_250MS); milliseconds -= 250; } + if (milliseconds >= 125) { sleep(WDTO_120MS); milliseconds -= 120; } + if (milliseconds >= 64) { sleep(WDTO_60MS); milliseconds -= 60; } + if (milliseconds >= 32) { sleep(WDTO_30MS); milliseconds -= 30; } + if (milliseconds >= 16) { sleep(WDTO_15MS); milliseconds -= 15; } +} + +NarcolepticClass Narcoleptic; diff --git a/lib-ext/narcoleptic/Narcoleptic.h b/lib-ext/narcoleptic/Narcoleptic.h new file mode 100644 index 0000000..9b1f255 --- /dev/null +++ b/lib-ext/narcoleptic/Narcoleptic.h @@ -0,0 +1,34 @@ +/** + * Narcoleptic - A sleep library for Arduino + * Copyright (C) 2010 Peter Knight (Cathedrow) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef Narcoleptic_h +#define Narcoleptic_h + +#include +#include + +class NarcolepticClass +{ + public: + void delay(int milliseconds); + private: + void sleep(uint8_t); +}; +extern NarcolepticClass Narcoleptic; + +#endif diff --git a/lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino b/lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino new file mode 100644 index 0000000..003af77 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/GarageMote/GarageMote.ino @@ -0,0 +1,418 @@ +// ********************************************************************************************************** +// GarageMote garage door controller sketch that works with Moteinos equipped with RFM69W/RFM69HW +// Can be adapted to use Moteinos/Arduinos using RFM12B or other RFM69 variants (RFM69CW, RFM69HCW) +// http://www.LowPowerLab.com/GarageMote +// 2015-02-02 (C) Felix Rusu of http://www.LowPowerLab.com/ +// ********************************************************************************************************** +// It uses 2 hall effect sensors (and magnets mounted on the garage belt/chain) to detect the position of the +// door, and a small signal relay to be able to toggle the garage opener. +// Implementation details are posted at the LowPowerLab blog +// Door status is reported via RFM69 to a base Moteino, and visually on the onboard Moteino LED: +// - solid ON - door is in open position +// - solid OFF - door is in closed position +// - blinking - door is not in either open/close position +// - pulsing - door is in motion +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// *************************************************************************************************************************** +//#define WEATHERSHIELD //uncomment if WeatherShield is present to report temp/humidity/pressure periodically +// *************************************************************************************************************************** +#include //get it here: http://github.com/lowpowerlab/rfm69 +#include //get it here: http://github.com/lowpowerlab/spiflash +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming +#include //comes with Arduino IDE (www.arduino.cc) + +#ifdef WEATHERSHIELD + #include //get it here: https://github.com/LowPowerLab/SFE_BMP180 + #include //get it here: https://github.com/LowPowerLab/SI7021 + #include +#endif +//***************************************************************************************************************************** +// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/TRANSCEIVER SETTINGS/REQUIREMENTS +//***************************************************************************************************************************** +#define GATEWAYID 1 +#define NODEID 11 +#define NETWORKID 250 +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! + +#define HALLSENSOR1 A0 +#define HALLSENSOR1_EN 4 +#define HALLSENSOR2 A1 +#define HALLSENSOR2_EN 5 + +#define RELAYPIN1 6 +#define RELAYPIN2 7 +#define RELAY_PULSE_MS 250 //just enough that the opener will pick it up + +#define DOOR_MOVEMENT_TIME 14000 // this has to be at least as long as the max between [door opening time, door closing time] + // my door opens and closes in about 12s +#define STATUS_CHANGE_MIN 1500 // this has to be at least as long as the delay + // between a opener button press and door movement start + // most garage doors will start moving immediately (within half a second) +//***************************************************************************************************************************** +#define WEATHERSENDDELAY 300000 // send WeatherShield data every so often (ms). Ie 300000 ~ 5 min +//***************************************************************************************************************************** +#define HALLSENSOR_OPENSIDE 0 +#define HALLSENSOR_CLOSEDSIDE 1 + +#define STATUS_CLOSED 0 +#define STATUS_CLOSING 1 +#define STATUS_OPENING 2 +#define STATUS_OPEN 3 +#define STATUS_UNKNOWN 4 + +#define LED 9 //pin connected to onboard LED +#define LED_PULSE_PERIOD 5000 //5s seems good value for pulsing/blinking (not too fast/slow) +#define SERIAL_BAUD 115200 +#define SERIAL_EN //comment out if you don't want any serial output + +#ifdef SERIAL_EN + #define DEBUG(input) {Serial.print(input); delay(1);} + #define DEBUGln(input) {Serial.println(input); delay(1);} +#else + #define DEBUG(input); + #define DEBUGln(input); +#endif + +#ifdef WEATHERSHIELD + SI7021 weatherShield_SI7021; + SFE_BMP180 weatherShield_BMP180; +#endif + +//function prototypes +void setStatus(byte newSTATUS, boolean reportStatus=true); +boolean hallSensorRead(byte which); +void pulseRelay(); +boolean reportStatus(); + +//global program variables +byte STATUS; +unsigned long lastStatusTimestamp=0; +unsigned long ledPulseTimestamp=0; +unsigned long lastWeatherSent=0; +byte lastRequesterNodeID=GATEWAYID; +int ledPulseValue=0; +boolean ledPulseDirection=false; //false=down, true=up +RFM69 radio; +char* Pstr = "123.45"; +char sendBuf[30]; +SPIFlash flash(8, 0xEF30); //WINDBOND 4MBIT flash chip on CS pin D8 (default for Moteino) + +void setup(void) +{ + Serial.begin(SERIAL_BAUD); + pinMode(HALLSENSOR1, INPUT); + pinMode(HALLSENSOR2, INPUT); + pinMode(HALLSENSOR1_EN, OUTPUT); + pinMode(HALLSENSOR2_EN, OUTPUT); + pinMode(RELAYPIN1, OUTPUT); + pinMode(RELAYPIN2, OUTPUT); + pinMode(LED, OUTPUT); + + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + + char buff[50]; + sprintf(buff, "GarageMote : %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + DEBUGln(buff); + + if (hallSensorRead(HALLSENSOR_OPENSIDE)==true) + setStatus(STATUS_OPEN); + if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true) + setStatus(STATUS_CLOSED); + else setStatus(STATUS_UNKNOWN); + +#ifdef WEATHERSHIELD + //initialize weather shield sensors + weatherShield_SI7021.begin(); + if (weatherShield_BMP180.begin()) + { DEBUGln("BMP180 init success"); } + else { DEBUGln("BMP180 init fail\n"); } +#endif +} + +unsigned long doorPulseCount = 0; +char input; + +void loop() +{ + if (Serial.available()) + input = Serial.read(); + + if (input=='r') + { + DEBUGln("Relay test..."); + pulseRelay(); + input = 0; + } + + // UNKNOWN => OPEN/CLOSED + if (STATUS == STATUS_UNKNOWN && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN) + { + if (hallSensorRead(HALLSENSOR_OPENSIDE)==true) + setStatus(STATUS_OPEN); + if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true) + setStatus(STATUS_CLOSED); + } + + // OPEN => CLOSING + if (STATUS == STATUS_OPEN && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN) + { + if (hallSensorRead(HALLSENSOR_OPENSIDE)==false) + setStatus(STATUS_CLOSING); + } + + // CLOSED => OPENING + if (STATUS == STATUS_CLOSED && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN) + { + if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==false) + setStatus(STATUS_OPENING); + } + + // OPENING/CLOSING => OPEN (when door returns to open due to obstacle or toggle action) + // => CLOSED (when door closes normally from OPEN) + // => UNKNOWN (when more time passes than normally would for a door up/down movement) + if ((STATUS == STATUS_OPENING || STATUS == STATUS_CLOSING) && millis()-(lastStatusTimestamp)>STATUS_CHANGE_MIN) + { + if (hallSensorRead(HALLSENSOR_OPENSIDE)==true) + setStatus(STATUS_OPEN); + else if (hallSensorRead(HALLSENSOR_CLOSEDSIDE)==true) + setStatus(STATUS_CLOSED); + else if (millis()-(lastStatusTimestamp)>DOOR_MOVEMENT_TIME) + setStatus(STATUS_UNKNOWN); + } + + if (radio.receiveDone()) + { + byte newStatus=STATUS; + boolean reportStatusRequest=false; + lastRequesterNodeID = radio.SENDERID; + DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] "); + for (byte i = 0; i < radio.DATALEN; i++) + DEBUG((char)radio.DATA[i]); + + if (radio.DATALEN==3) + { + //check for an OPEN/CLOSE/STATUS request + if (radio.DATA[0]=='O' && radio.DATA[1]=='P' && radio.DATA[2]=='N') + { + if (millis()-(lastStatusTimestamp) > STATUS_CHANGE_MIN && (STATUS == STATUS_CLOSED || STATUS == STATUS_CLOSING || STATUS == STATUS_UNKNOWN)) + newStatus = STATUS_OPENING; + //else radio.Send(requester, "INVALID", 7); + } + if (radio.DATA[0]=='C' && radio.DATA[1]=='L' && radio.DATA[2]=='S') + { + if (millis()-(lastStatusTimestamp) > STATUS_CHANGE_MIN && (STATUS == STATUS_OPEN || STATUS == STATUS_OPENING || STATUS == STATUS_UNKNOWN)) + newStatus = STATUS_CLOSING; + //else radio.Send(requester, "INVALID", 7); + } + if (radio.DATA[0]=='S' && radio.DATA[1]=='T' && radio.DATA[2]=='S') + { + reportStatusRequest = true; + } + } + + // wireless programming token check + // DO NOT REMOVE, or GarageMote will not be wirelessly programmable any more! + CheckForWirelessHEX(radio, flash, true); + + //first send any ACK to request + DEBUG(" [RX_RSSI:");DEBUG(radio.RSSI);DEBUG("]"); + if (radio.ACKRequested()) + { + radio.sendACK(); + DEBUG(" - ACK sent."); + } + + //now take care of the request, if not invalid + if (STATUS != newStatus) + { + pulseRelay(); + setStatus(newStatus); + } + if (reportStatusRequest) + { + reportStatus(); + } + + DEBUGln(); + } + + //use LED to visually indicate STATUS + if (STATUS == STATUS_OPEN || STATUS == STATUS_CLOSED) //solid ON/OFF + { + digitalWrite(LED, STATUS == STATUS_OPEN ? LOW : HIGH); + } + if (STATUS == STATUS_OPENING || STATUS == STATUS_CLOSING) //pulse + { + if (millis()-(ledPulseTimestamp) > LED_PULSE_PERIOD/256) + { + ledPulseValue = ledPulseDirection ? ledPulseValue + LED_PULSE_PERIOD/256 : ledPulseValue - LED_PULSE_PERIOD/256; + + if (ledPulseDirection && ledPulseValue > 255) + { + ledPulseDirection=false; + ledPulseValue = 255; + } + else if (!ledPulseDirection && ledPulseValue < 0) + { + ledPulseDirection=true; + ledPulseValue = 0; + } + + analogWrite(LED, ledPulseValue); + ledPulseTimestamp = millis(); + } + } + if (STATUS == STATUS_UNKNOWN) //blink + { + if (millis()-(ledPulseTimestamp) > LED_PULSE_PERIOD/20) + { + ledPulseDirection = !ledPulseDirection; + digitalWrite(LED, ledPulseDirection ? HIGH : LOW); + ledPulseTimestamp = millis(); + } + } + +#ifdef WEATHERSHIELD + if (millis()-lastWeatherSent > WEATHERSENDDELAY) + { + lastWeatherSent = millis(); + double P = getPressure(); + P*=0.0295333727; //transform to inHg + dtostrf(P, 3,2, Pstr); + sprintf(sendBuf, "F:%d H:%d P:%s", weatherShield_SI7021.getFahrenheitHundredths(), weatherShield_SI7021.getHumidityPercent(), Pstr); + byte sendLen = strlen(sendBuf); + radio.send(GATEWAYID, sendBuf, sendLen); + } +#endif +} + +//returns TRUE if magnet is next to sensor, FALSE if magnet is away +boolean hallSensorRead(byte which) +{ + //while(millis()-lastStatusTimestamp +#include +#include + +//***************************************************************************************************************************** +// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION! +//***************************************************************************************************************************** +#define NODEID 1 +#define GARAGENODEID 99 +#define NETWORKID 100 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define LED 9 +#define SERIAL_BAUD 115200 +#define ACK_TIME 30 // # of ms to wait for an ack +//***************************************************************************************************************************** + +RFM69 radio; +SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip +byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=50); + +void setup() { + Serial.begin(SERIAL_BAUD); + delay(10); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //must include only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + if (flash.initialize()) + Serial.println("SPI Flash Init OK!"); + else + Serial.println("SPI Flash Init FAIL! (is chip present?)"); +} + +byte ackCount=0; +byte inputLen=0; +char input[64]; +void loop() { + //process any serial input + inputLen = readSerialLine(input); + + if (inputLen >= 6) + { + if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='O' && input[4]=='P' && input[5]=='N') + { + Serial.print("OPN ... "); + if (radio.sendWithRetry(GARAGENODEID, "OPN", 3)) + Serial.println("ok ... "); + else Serial.println("nothing ... "); + } + if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='C' && input[4]=='L' && input[5]=='S') + { + Serial.print("CLS ... "); + if (radio.sendWithRetry(GARAGENODEID, "CLS", 3)) + Serial.println("ok ... "); + else Serial.println("nothing ... "); + } + if (input[0]=='G' && input[1]=='R' && input[2]=='G' && input[3]=='S' && input[4]=='T' && input[5]=='S') + { + Serial.print("STS ... "); + if (radio.sendWithRetry(GARAGENODEID, "STS", 3)) + Serial.println("ok ... "); + else Serial.println("nothing ... "); + } + + //if (input == 'i') + //{ + // Serial.print("DeviceID: "); + // word jedecid = flash.readDeviceId(); + // Serial.println(jedecid, HEX); + //} + } + + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i]); + Serial.print(" [RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + + if (radio.ACKRequested()) + { + byte theNodeID = radio.SENDERID; + radio.sendACK(); + Serial.print("[ACK-sent]"); + } + Serial.println(); + Blink(LED,3); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} + +// reads a line feed (\n) terminated line from the serial stream +// returns # of bytes read, up to 255 +// timeout in ms, will timeout and return after so long +byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout) +{ + byte inputLen = 0; + Serial.setTimeout(timeout); + inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength); + input[inputLen]=0;//null-terminate it + Serial.setTimeout(0); + //Serial.println(); + return inputLen; +} diff --git a/lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino b/lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino new file mode 100644 index 0000000..491f743 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/Gateway/Gateway.ino @@ -0,0 +1,173 @@ +// Sample RFM69 receiver/gateway sketch, with ACK and optional encryption +// Passes through any wireless received messages to the serial port & responds to ACKs +// It also looks for an onboard FLASH chip, if present +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get it here: https://www.github.com/lowpowerlab/spiflash + +#define NODEID 1 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +//#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ACK_TIME 30 // max # of ms to wait for an ack +#define SERIAL_BAUD 115200 + +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define FLASH_SS 23 // and FLASH SS on D23 +#else + #define LED 9 // Moteinos have LEDs on D9 + #define FLASH_SS 8 // and FLASH SS on D8 +#endif + +RFM69 radio; +SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL) +bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network + +void setup() { + Serial.begin(SERIAL_BAUD); + delay(10); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + radio.promiscuous(promiscuousMode); + //radio.setFrequency(919000000); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + if (flash.initialize()) + { + Serial.print("SPI Flash Init OK. Unique MAC = ["); + flash.readUniqueId(); + for (byte i=0;i<8;i++) + { + Serial.print(flash.UNIQUEID[i], HEX); + if (i!=8) Serial.print(':'); + } + Serial.println(']'); + + //alternative way to read it: + //byte* MAC = flash.readUniqueId(); + //for (byte i=0;i<8;i++) + //{ + // Serial.print(MAC[i], HEX); + // Serial.print(' '); + //} + + } + else + Serial.println("SPI Flash Init FAIL! (is chip present?)"); +} + +byte ackCount=0; +uint32_t packetCount = 0; +void loop() { + //process any serial input + if (Serial.available() > 0) + { + char input = Serial.read(); + if (input == 'r') //d=dump all register values + radio.readAllRegs(); + if (input == 'E') //E=enable encryption + radio.encrypt(ENCRYPTKEY); + if (input == 'e') //e=disable encryption + radio.encrypt(null); + if (input == 'p') + { + promiscuousMode = !promiscuousMode; + radio.promiscuous(promiscuousMode); + Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off"); + } + + if (input == 'd') //d=dump flash area + { + Serial.println("Flash content:"); + int counter = 0; + + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + while(flash.busy()); + Serial.println(); + } + if (input == 'D') + { + Serial.print("Deleting Flash chip ... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + if (input == 'i') + { + Serial.print("DeviceID: "); + word jedecid = flash.readDeviceId(); + Serial.println(jedecid, HEX); + } + if (input == 't') + { + byte temperature = radio.readTemperature(-1); // -1 = user cal factor, adjust for correct ambient + byte fTemp = 1.8 * temperature + 32; // 9/5=1.8 + Serial.print( "Radio Temp is "); + Serial.print(temperature); + Serial.print("C, "); + Serial.print(fTemp); //converting to F loses some resolution, obvious when C is on edge between 2 values (ie 26C=78F, 27C=80F) + Serial.println('F'); + } + } + + if (radio.receiveDone()) + { + Serial.print("#["); + Serial.print(++packetCount); + Serial.print(']'); + Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); + if (promiscuousMode) + { + Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] "); + } + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i]); + Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + + if (radio.ACKRequested()) + { + byte theNodeID = radio.SENDERID; + radio.sendACK(); + Serial.print(" - ACK sent."); + + // When a node requests an ACK, respond to the ACK + // and also send a packet requesting an ACK (every 3rd one only) + // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY + if (ackCount++%3==0) + { + Serial.print(" Pinging node "); + Serial.print(theNodeID); + Serial.print(" - ACK..."); + delay(3); //need this when sending right after reception .. ? + if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) // 0 = only 1 attempt, no retries + Serial.print("ok!"); + else Serial.print("nothing"); + } + } + Serial.println(); + Blink(LED,3); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/MailboxNotifier/MailboxNotifier4_sender.ino b/lib-ext/rfm-69.git/Examples/MailboxNotifier/MailboxNotifier4_sender.ino new file mode 100644 index 0000000..bbe25db --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/MailboxNotifier/MailboxNotifier4_sender.ino @@ -0,0 +1,176 @@ +// Sample RFM69 sender/node sketch for mailbox motion sensor +// http://www.lowpowerlab.com/mailbox +// PIR motion sensor connected to D3 (INT1) +// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep +// It then wakes up every 32 seconds and sends a message indicating when the last +// motion event happened (days, hours, minutes, seconds ago) and the battery level +// In sleep mode, Moteino + PIR motion sensor use about ~78uA +// Make sure you adjust the settings in the configuration section below !!! + +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** + +#include //get it here: https://github.com/LowPowerLab/RFM69 +#include //get it here: https://github.com/LowPowerLab/SPIFlash +#include //get library from: https://github.com/LowPowerLab/LowPower + //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ + +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 55 //unique for each node on same network +#define NETWORKID 250 //the same on all nodes that talk to each other +#define GATEWAYID 1 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#define SENDEVERYXLOOPS 4 //each loop sleeps 8 seconds, so send status message every this many loops (default "4" = 32 seconds) +//********************************************************************************************* + +#define MOTIONPIN 1 //hardware interrupt 1 (D3) +#define BATTERYSENSE A7 //through 1Meg+470Kohm and 0.1uF cap from battery VCC - this ratio divides the voltage to bring it below 3.3V where it is scaled to a readable range +#define LED 9 // Moteinos have LEDs on D9 +//#define BLINK_EN //uncomment to make LED flash when messages are sent, leave out if you want low power + +#define SERIAL_BAUD 115200 +//#define SERIAL_EN //uncomment this line to enable serial IO debug messages, leave out if you want low power +#ifdef SERIAL_EN + #define DEBUG(input) {Serial.print(input); delay(1);} + #define DEBUGln(input) {Serial.println(input); delay(1);} +#else + #define DEBUG(input); + #define DEBUGln(input); +#endif + +RFM69 radio; +volatile boolean motionDetected=false; + +void setup() { +#ifdef SERIAL_EN + Serial.begin(SERIAL_BAUD); +#endif + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + pinMode(MOTIONPIN, INPUT); + attachInterrupt(MOTIONPIN, motionIRQ, RISING); + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + DEBUGln(buff); +} + +void motionIRQ() +{ + motionDetected=true; + //DEBUGln("I"); +} + +char sendBuf[32]; +byte sendLen; +byte sendLoops=0; +unsigned long MLO=0; //MailLastOpen (ago, in ms) +unsigned long now = 0, time=0, lastSend = 0, temp = 0; + +void loop() { + now = millis(); + int batteryReading = analogRead(BATTERYSENSE); + if (motionDetected && time-MLO > 20000) //avoid duplicates in 20second intervals + { + MLO = time; //save timestamp of event + sprintf(sendBuf, "MOTION BAT:%i", batteryReading); + sendLen = strlen(sendBuf); + if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen)) + { + DEBUGln(" ok!"); + #ifdef BLINK_EN + Blink(LED,3); + #endif + } + else DEBUGln(" nothing..."); + radio.sleep(); + motionDetected=false; + } + else sendLoops++; + + //send readings every SENDEVERYXLOOPS + if (sendLoops>=SENDEVERYXLOOPS) + { + sendLoops=0; + + char periodO='X', periodC='X'; + unsigned long lastOpened = (time - MLO) / 1000; //get seconds + unsigned long LO = lastOpened; + char* MLOstr="LO:99d23h59m"; + char* BATstr="BAT:1024"; + char* BATactual="BATA:5.00v"; + + if (lastOpened <= 59) periodO = 's'; //1-59 seconds + else if (lastOpened <= 3599) { periodO = 'm'; lastOpened/=60; } //1-59 minutes + else if (lastOpened <= 259199) { periodO = 'h'; lastOpened/=3600; } // 1-71 hours + else if (lastOpened >= 259200) { periodO = 'd'; lastOpened/=86400; } // >=3 days + + if (periodO == 'd') + sprintf(MLOstr, "LO:%ldd%ldh", lastOpened, (LO%86400)/3600); + else if (periodO == 'h') + sprintf(MLOstr, "LO:%ldh%ldm", lastOpened, (LO%3600)/60); + else sprintf(MLOstr, "LO:%ld%c", lastOpened, periodO); + + //sprintf(BATstr, "BAT:%i", batteryReading); + float battV = ((float)batteryReading * 3.3 * 9)/(1023*2.976); + dtostrf(battV, 3,2, BATactual); + sprintf(sendBuf, "%s BAT:%sv", MLOstr, BATactual); + sendLen = strlen(sendBuf); + radio.send(GATEWAYID, sendBuf, sendLen); + radio.sleep(); + DEBUG(sendBuf); DEBUG(" ("); DEBUG(sendLen); DEBUGln(")"); + lastSend = time; + #ifdef BLINK_EN + Blink(LED, 5); + #endif + delay(10); motionDetected=false; //fix PIR false positive glitch + } + + DEBUGln("LOOP"); + time = time + 8000 + millis()-now + 480; //correct millis() resonator drift, may need to be tweaked to be accurate + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/MightyBoostControl/MightyBoostControl.ino b/lib-ext/rfm-69.git/Examples/MightyBoostControl/MightyBoostControl.ino new file mode 100644 index 0000000..d9754f9 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/MightyBoostControl/MightyBoostControl.ino @@ -0,0 +1,221 @@ +// ************************************************************************************************************* +// MightyBoost control sample sketch +// ************************************************************************************************************* +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ************************************************************************************************************* +// License +// ************************************************************************************************************* +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ************************************************************************************************************* +// MightyBoost is a smart backup PSU controllable by Moteino, and this sketch is a sample control sketch to run +// MightyBoost in this mode. +// http://moteino.com +// http://github.com/lowpowerlab +// Be sure to check back for code updates and patches +// ************************************************************************************************************* +// This sketch will provide control over the essential features of MightyBoost: +// - provide switched 5V power to a sensitive load like RaspberryPi which should not lose power instantly +// - Control the "5V*" output via Moteino+PowerButton (momentary tactile) +// - Monitor input supply and switch to battery backup when external power is lost +// - Monitor battery voltage and issue a shutdown signal when battery runs low +// This sketch may be extended to include integration with other LowPowerLab automation products +// ************************************************************************************************************* +#define LED 5 // LED pin, should be analog for fading effect (PWM) +#define BUTTON 3 // Power button pin +#define SIG_REQUESTHALT 6 // Signal to Pi to ask for a shutdown +#define SIG_OKTOCUTOFF A0 // Signal from Pi that it's OK to cutoff power + // !!NOTE!! Originally this was D7 but it was moved to A0 at least temporarily. + // On MightyBoost R1 you need to connect D7 and A0 with a jumper wire. + // The explanation for this is given here: http://lowpowerlab.com/mightyboost/#source +#define OUTPUT_5V 4 // HIGH on this pin will switch the "5V*" output ON +#define BATTERYSENSE A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier) + // hence the actual input voltage = analogRead(A7) * 0.00322 (3.3v/1024) * 1.47 (10k+4.7k voltage divider ratio) + // when plugged in this should be 4.80v, nothing to worry about + // when on battery power this should decrease from 4.15v (fully charged Lipoly) to 3.3v (discharged Lipoly) + // trigger a shutdown to the target device once voltage is around 3.4v to allow 30sec safe shutdown +#define LOWBATTERYTHRESHOLD 3.7 // a shutdown will be triggered to the target device when battery voltage drops below this (Volts) + +#define ButtonHoldTime 1800 // Button must be hold this many mseconds before a shutdown sequence is started (should be much less than PIForceShutdownDelay) +#define PIShutdownDelay_Min 6000 // will start checking the SIG_OKTOCUTOFF line after this long +#define PIShutdownDelay_Max 38000 // window of time in which SIG_OKTOCUTOFF is expected to go HIGH + // should be at least 3000 more than Min + // if nothing happens after this window, if button is + // still pressed, force cutoff power, otherwise switch back to normal ON state +#define PIForceShutdownDelay 6500 // when SIG_OKTOCUTOFF==0 (PI in unknown state): if button is held + // for this long, force shutdown (this should be less than PIShutdownDelay_Max) +#define ShutdownFINALDELAY 4000 // after shutdown signal is received, delay for this long + // to allow all PI LEDs to stop activity (pulse LED faster) + +#define PRINTPERIOD 1000 + +int lastValidReading = 1; +unsigned long lastValidReadingTime = 0; +unsigned long now=0; +int PowerState = 0; +long lastPeriod = -1; +float systemVoltage = 5; + +void setup() { + Serial.begin(115200); + pinMode(BUTTON, INPUT_PULLUP); + pinMode(SIG_OKTOCUTOFF, INPUT); + pinMode(SIG_REQUESTHALT, OUTPUT); + pinMode(LED, OUTPUT); + pinMode(OUTPUT_5V, OUTPUT); + pinMode(A7, INPUT); + digitalWrite(SIG_REQUESTHALT, LOW);//added after sudden shutdown quirks, DO NOT REMOVE! + digitalWrite(OUTPUT_5V, LOW);//added after sudden shutdown quirks, DO NOT REMOVE! +} + +void loop() { + int reading = digitalRead(BUTTON); + now = millis(); + digitalWrite(SIG_REQUESTHALT, LOW);//added after sudden shutdown quirks, DO NOT REMOVE! + + boolean batteryLow = systemVoltage < LOWBATTERYTHRESHOLD; + + if (batteryLow || reading != lastValidReading && now - lastValidReadingTime > 200) { + lastValidReading = reading; + lastValidReadingTime = now; + //((PowerState==0 && ()) || (PowerState==1 && (now - lastValidReadingTime > ButtonHoldTime))) + if (batteryLow || reading == 0) + { + //make sure the button is held down for at least 'ButtonHoldTime' before taking action (this is to avoid accidental button presses and consequently Pi shutdowns) + now = millis(); + while (!batteryLow && (PowerState == 1 && millis()-now < ButtonHoldTime)) { delay(10); if (digitalRead(BUTTON) != 0) return; } + + //SIG_OKTOCUTOFF must be HIGH when Pi is ON. During boot, this will take a while to happen (till it executes the "shutdowncheck" script + //so I dont want to cutoff power before it had a chance to fully boot up + //if (batteryLow || (PowerState == 1 && digitalRead(SIG_OKTOCUTOFF)==1)) + if (batteryLow || (PowerState == 1 && analogRead(SIG_OKTOCUTOFF)>800)) + { + // signal Pi to shutdown + digitalWrite(SIG_REQUESTHALT, HIGH); + + //now wait for the Pi to signal back + now = millis(); + float in, out; + boolean forceShutdown = true; + + while (millis()-now < PIShutdownDelay_Max) + { + if (in > 6.283) in = 0; + in += .00628; + + out = sin(in) * 127.5 + 127.5; + analogWrite(LED,out); + delayMicroseconds(1500); + + //account for force-shutdown action (if button held for PIForceShutdownDelay, then force shutdown regardless) + if (millis()-now <= (PIForceShutdownDelay-ButtonHoldTime) && digitalRead(BUTTON) != 0) + forceShutdown = false; + if (millis()-now >= (PIForceShutdownDelay-ButtonHoldTime) && forceShutdown) + { + PowerState = 0; + digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff + digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState); + break; + } + + if (millis() - now > PIShutdownDelay_Min) + { + // Pi signaling OK to turn off + //if (digitalRead(SIG_OKTOCUTOFF) == 0) + if (analogRead(SIG_OKTOCUTOFF) < 800) + { + PowerState = 0; + digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff + + //delay(3500); //takes about 3sec between SIG_OKTOCUTOFF going LOW and Pi LEDs activity to stop + now = millis(); + while (millis()-now < ShutdownFINALDELAY) + { + if (in > 6.283) in = 0; + in += .00628; + + out = sin(in) * 127.5 + 127.5; + analogWrite(LED,out); + delayMicroseconds(300); + } + + digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState); + break; + } + } + } + + // last chance: if power still on but button still pressed, force cutoff power + if (PowerState == 1 && digitalRead(BUTTON) == 0) + { + PowerState = 0; + digitalWrite(OUTPUT_5V, PowerState); + } + + digitalWrite(SIG_REQUESTHALT, LOW); + } + //else if (PowerState == 1 && digitalRead(SIG_OKTOCUTOFF)==0) + else if (PowerState == 1 && analogRead(SIG_OKTOCUTOFF)<800) + { + now = millis(); + unsigned long now2 = millis(); + int analogstep = 255 / ((PIForceShutdownDelay-ButtonHoldTime)/100); //every 500ms decrease LED intensity + while (digitalRead(BUTTON) == 0) + { + if (millis()-now2 > 100) + { + analogWrite(LED, 255 - ((millis()-now)/100)*analogstep); + now2 = millis(); + } + if (millis()-now > PIForceShutdownDelay-ButtonHoldTime) + { + //TODO: add blinking here to signal final shutdown delay + PowerState = 0; + digitalWrite(OUTPUT_5V, PowerState); + break; + } + } + } + else if (PowerState == 0) + { + PowerState = 1; + digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState); + } + } + + digitalWrite(LED, PowerState); + } + + int currPeriod = millis()/PRINTPERIOD; + if (currPeriod != lastPeriod) + { + lastPeriod=currPeriod; + Serial.print("VIN: "); + systemVoltage = analogRead(BATTERYSENSE) * 0.00322 * 1.47; + Serial.print(systemVoltage); + if (systemVoltage > 4.3) + Serial.println(" (plugged in)"); + else Serial.println(" (running from battery!)"); + } +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino b/lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino new file mode 100644 index 0000000..edb0847 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/MotionMote/MotionMote.ino @@ -0,0 +1,150 @@ +// Sample RFM69 sender/node sketch for the MotionMote +// http://lowpowerlab.com/motion +// PIR motion sensor connected to D3 (INT1) +// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep +// In sleep mode, Moteino + PIR motion sensor use about ~78uA +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ +// Make sure you adjust the settings in the configuration section below !!! + +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get library from: https://github.com/lowpowerlab/lowpower + //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ + +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 88 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +#define GATEWAYID 1 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W! +//********************************************************************************************* + +#define ACK_TIME 30 // max # of ms to wait for an ack +#define ONBOARDLED 9 // Moteinos have LEDs on D9 +#define EXTLED 5 // MotionOLEDMote has an external LED on D5 +#define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier) +#define BATT_CYCLES 30 //read and report battery voltage every this many wakeup cycles (ex 30cycles * 8sec sleep = 240sec/4min) +#define MOTIONPIN 1 //hardware interrupt 1 (D3) + +//#define SERIAL_EN //comment this out when deploying to an installed SM to save a few KB of sketch size +#define SERIAL_BAUD 115200 +#ifdef SERIAL_EN +#define DEBUG(input) {Serial.print(input); delay(1);} +#define DEBUGln(input) {Serial.println(input); delay(1);} +#else +#define DEBUG(input); +#define DEBUGln(input); +#endif + +RFM69 radio; +volatile boolean motionDetected=false; +float batteryVolts = 5; +char* BATstr="BAT:5.00v"; +char sendBuf[32]; +byte sendLen; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + pinMode(MOTIONPIN, INPUT); + attachInterrupt(MOTIONPIN, motionIRQ, RISING); + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + DEBUGln(buff); + pinMode(ONBOARDLED, OUTPUT); + pinMode(EXTLED, OUTPUT); +} + +void motionIRQ() +{ + motionDetected=true; +} + +byte batteryReportCycles=0; +void loop() { + checkBattery(); + if (motionDetected) + { + digitalWrite(EXTLED, HIGH); + sprintf(sendBuf, "MOTION BAT:%sv", BATstr); + sendLen = strlen(sendBuf); + + if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen)) + { + DEBUG("MOTION ACK:OK! RSSI:"); + DEBUG(radio.RSSI); + batteryReportCycles = 0; + } + else DEBUG("MOTION ACK:NOK..."); + + DEBUG(" VIN: "); + DEBUGln(BATstr); + + radio.sleep(); + digitalWrite(EXTLED, LOW); + } + else if (batteryReportCycles == BATT_CYCLES) + { + sprintf(sendBuf, "BAT:%sv", BATstr); + sendLen = strlen(sendBuf); + radio.send(GATEWAYID, sendBuf, sendLen); + radio.sleep(); + batteryReportCycles=0; + } + motionDetected=false; //do NOT move this after the SLEEP line below or motion will never be detected + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); + batteryReportCycles++; +} + +byte cycleCount=BATT_CYCLES; +void checkBattery() +{ + if (cycleCount++ == BATT_CYCLES) //only read battery every BATT_CYCLES sleep cycles + { + unsigned int readings=0; + for (byte i=0; i<10; i++) //take 10 samples, and average + readings+=analogRead(BATT_MONITOR); + batteryVolts = (readings / 10.0) * 0.00322 * 1.42; + dtostrf(batteryVolts, 3,2, BATstr); //update the BATStr which gets sent every BATT_CYCLES or along with the MOTION message + cycleCount = 0; + } +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino b/lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino new file mode 100644 index 0000000..41510fb --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.ino @@ -0,0 +1,68 @@ +// Sample RFM69 sender/node sketch for motion sensor +// PIR motion sensor connected to D3 (INT1) +// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep +// In sleep mode, Moteino + PIR motion sensor use about ~78uA +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include //get it here: https://github.com/lowpowerlab/spiflash +#include //get library from: https://github.com/LowPowerLab/LowPower + +#define NODEID 18 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +#define GATEWAYID 1 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ACK_TIME 30 // max # of ms to wait for an ack +#define LED 9 // Moteinos have LEDs on D9 +#define SERIAL_BAUD 115200 +#define MOTIONPIN 1 //hardware interrupt 1 (D3) + +RFM69 radio; +volatile boolean motionDetected=false; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + attachInterrupt(MOTIONPIN, motionIRQ, RISING); + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); +} + +void motionIRQ() +{ + motionDetected=true; +} + +void loop() { + if (motionDetected) + { + if (radio.sendWithRetry(GATEWAYID, "MOTION", 6)) + { + Serial.println(" ok!"); + Blink(LED,3); + } + else Serial.println(" nothing..."); + motionDetected=false; + } + radio.sleep(); + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} diff --git a/lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.jpg b/lib-ext/rfm-69.git/Examples/MotionMote/OLD/MotionMote.jpg new file mode 100644 index 0000000000000000000000000000000000000000..618c9144b643715a8e338d656861f69f2c914d38 GIT binary patch literal 20602 zcmcG$bzED^7C#!O;?hEk7YP(E!M#`@!QG)ikl;>nD!2xBcXw@}#fk)Iac^;l0)^td z^xS(+>3#S9-g|$%1s}48?CkljnKgUXEXnoc^)~=M6bu0a(9i$?G}I5^dIlf?xP^}X z>la10QNMTY-??-9_8rW7_wL@u#>B?P!oRq@6lu8 zhmQ##50CWPhTLfs=odAko zP;a6ABEY}t-t9Yg@83d4!$7^Qj}HLcMMFnN$H2z9i+%4evCvT>+`UI|pYQ?oV-7w| z*SOlc;fF+zXn1(Vl#N{CM~E3fY8uAo&TnILYeu=mRUBS@p{3(icY2M8j>)PX!{C%q zb*x_oW}|NZ@OQ6&_x|g@1pi?9=fBec>|1Ck*tZA(qJV3F+6MsOHUs(~cc}8dMG_Ir znv%k6?EPm>R@H}_N`V?vPNW_U$0X%ep5`La{xWukuk{UYOP7QGZ*^G=dIv1|t$Rj)GvbfY`(P_QNqEH8kATx)&0~001H5X+*B!+NmiI z0~N7lz5n|Dz)VcEoj?O^{eH%YNH)y|&(#N_&x9Ebfy>u`<8QxZT$AfpIV!*(`f&|- zOTQX|WMREk{LtDtfK0GD06COFw9Z;DdhkR&*! zBs&FJ1%%4V8gdX2h6{VTTmS^0|Ca&zd(tWHMy&Eo4dQBORxL=?8xIdwLzxH6J{HrR z67VC2cIuU%LAS1=a3^mMsnvv4CvbG^r-HdTV=4%^*QlCRb4O$%;)jgs&yYj8*MO+5 z-vj>l{i*mBx4g6l-WD`iBkXm(4%K@V|EKy)6G7|-@>Dk-l{ zpihqrk)e$st*3YbK+&R0247kMsi`|c0~`tRqT@wrGE^3-Gbdq+gl|nY{oFhW6#dUR zz9CiN$OE!n3j!~o= zUPq2H<2h#V@lfwO)!9Nhw`?vMG46?`)b~F{*CP{VIu3l#?J+Ac6#vCd!hKBQW?@qX zq6yLkw%)u&#DPWfBk)ckf9BHEEm}6kQ@@;F_yK@0H8X*-WcfBkkGt^Mv zm)Y!wEDWusWN<|y(gIf$y}__Q%{sRrGkVGV!1PqdKe`(a^C=O*S;`Z*Lw&#nO!(m%S?0MHiZT9ej% zs-?oK#1s4dXm!(#QQ2g{$Mr{?pn?fXX9krmcDigSNU}x@2sB5pZ;0_2wL}4c0Lv@) z2>1}b4%{YoeqyQ4^3%cnjU;m*HkWPDSsswQ55#6d_q3<&;T3i3cKMfxvqayBoHOHM z08sz;Oei!4F7nEP-aqPtZ@4^oTvwMu!P4!IJC z(6*nlB5GMooSd5?*_25D z06_%Zfk3I)C2P~Ws&HjxJPx>{xx5Q2s88YcD5A`AGN?iMkzqTG~p49R*!$QX&deyg@meGyb=Ha>J;t0&;BYj>7K8J znwVnGJ&T4R9!hvTI%?nhi-1C`=bcNUdG4y&rL>6wQRa!nqLd*q%FHvxAq@%wKof7~ zVCbyMu}UA*y`G!It_rVJ*e%86Y(h17nIFehOxHA0O9$vstneVLg;I__TK7jkkZy$0 zGrns)8cpxto&57ckm_oXV_wfMnMe{Y5A^n)ZSL8B^xRQHzBU^|ntCMe#<_FZ3;1wz zjp3K(h}T@yfI2|h9tnEElch3eW_k6p3)qmYqxc+ujPeAv6HB#S zK4*NvXM=?-b-|PRZk_!#>u7j2p6=8jUo5LNt~`v==!Oxjkw zrhD*Woa`r4DSvYlPi>VX&=UDuu3%7#spWbvWEBKO_Rl=h!hDi!f4Yl1(LS3oRMW97 zq2{?Xa!Gs*IKtTVH*StPegG?Mex**5-3Q`IeiZH;V8vXNTW7Z!y{Qrmr8&9Z(;(dN zY?pIzot5#TZ||prznUDAa|45?QlVp53P-5h7K^)ecQ9^Z79wSNiV>iquG2Ib(s$84>+%;V`@V%7Gx=;Bn9D(VtRc4%W!?rM?h{4F!W;5wF>!5ot z(c#C`#lrg=SE0UV0c%nRO{c37-;%fsB(~B9u(3!C3Q*&gw7%}(Rm3SAgUp$15Dr~H zoBFG34D|^Y5wdTlYYA#0g>m|Bstc`m4cuL1Fbn@g21vGWJFs4ApAntM&kN2E^rasZ zVy(Gc0Oa`rFf=iRk(DOdHGzMHl6erC%2<0e2oDbKV{A3Im)?c5zA=Hv{AYT6wr(%ht70!zRBiTwl|6(p;OO+1EgjsQw*LruDjp-6> zz`jrSzF$7p;7+ZH*Iqs4F|_EiI&v6swGXZ*aUa*WA68xhndPXtHjkQD5gfVr<^Bgi zjNhY!sTC`jd9XAyE0;eyJ47A{=byP}we{Xw6{mRtQTk;>+yMqQZSAf>(?na@k?yXs zR@JDDAqy;>YW`-*!$V-sI&O*6NgeWYnKlRHCn-HREpr;IuX`L>sw(X7$abmo>S~4e zvhmi95zomO*=E8`dC_>qsI?uqRrG|@kYdUbnyzc}Bq~NbHyWHn!-@i|>8%qw>C&&bt)Fx{CWnp2{G(;^Iw;_|Mmq-}^4Z0IJIwZAZN&`xuU`{>B2KyPD3xTWJZQ`i(`!wvlD21%Gb zI&{H5iVCodk5m{<^X@jCQm6O1b4=kWZCUs3ZGzAz8UpU#fkCfz_>i?EOz*uJ*tAiK zD@l##-C{b4S6ev){6gCq?s}gjn^cs>xxu)CI z*di5g6K+Dnle}{B5Lqm^XRjNAY>LxGFL%cC0BOa|UsV_@DG835<;M|NT+-O%%N|2I zY9zqMkGK#_@1;Y)F)FhmZ(RBL8YrEYfov)HUcD=*N5f=Tv}aWIeo7JUVyW?GmZF-F z3%7~Qf~&qN=BJ31Bk^2P0)pkTcIVGIlVdezx}+XIX{ie<+v^@lHa3oiOMl`zFw0q* zy3}`ksP0<1*k;H?3waT>NLNDU_9muSG2|Pw%wOxFl#{5!YL-fI}&H4R-V+P?#SR{)2t-;yocJ={ zjtp#u+k8o#VH&?8I}m{Ss*Nvvw@Yb^*~}-{l%~_<>c7*M7oC7y#D1UkG}LCuc#G6B zonU+jV~#vk|6Xa~ur{9n*^#b!bpi!c&d0|m&?h6dSwf?$>D(BSzA!iCVAd&n?7*Ul z-BTyZ@J60+eC3_*XpfW!m34ftK*5}Kv-E?V;b}KbM#RpzxMt@b8L!2+O^pILkh=pT zxeveOR8C59^5S*!sGD{i#R_Tc>ZU{WvP3Y@y6n_dd0}JxR@p57YJ>ZLK@xW%Va=?; zE8@}5b~Np-*^AheuWU%ul(Uovpvq2JR-g-G)*%=3kMo9Z9~4aTGMIV=zeL9ai3ewoc zWI4@L;r=+0G07NC2Rcb_Pb>R*W@U$TW377C0&R^9(S*vw$saA%AzPekBe2aW?N9C< zM)Q#_gcNjpeWtDF1p7(zcxn5F?eXyZBsMfb+1<3_x1$W!JH}9BwQ-GvU`9O`zHB&~ zG@MB%Du%0NN7hleEt&N-(vzo46Y+ihiUF=TxYQ(ZN)AUDzmqEx+E+>#-#n8zes7Zl zD?N=YF~QUD`}^q}V+Bi@ayLshsXdiSf7&%yns0_Iv;}3T+I)yQP?4riP>~v(b~|p_ z)~_T&a4p0%H9&<3iw<}K*elDWzLqG7&gNeO8gSR{bW(2|6GR%14YnS6Q#gC{3__I| z$7=f_Hg{_v1f*fnx=94Y=STQB-+uLsp@`+P&o{JTptfFelm8pl@7Mbp^*^QT*A54U zlJc+${jKbrHF14~W>1rqn*DxX^*49J=;~sT=kxk`&uYO|ac$}whtmyP3R-ic@#~}a zGG3M~(%42!ZtOBhf$A&h21=EyNaxq0t6Gp&xZEek~ywpn~|7W6+D-;h@5P3r6Mc`DTe8?rz*iXh@|A8prB}@EwN9g zr2T$IB-p6?@OQ7Xo91CfYQpU(xeB7|NbxP;R=}sRxydp;&B(CO+9!PUMO(fE)rVM@ zqSc+x-tlCwssmLu#}u_7HEN~@eCHvy60p99Wj!%{mTao0*k4aVhBetC95YhSLrS<- ze#q0qtJ4z^o1Nz>1~WV3-nti0gbmQ|b=uaOJ`Tv-@Jaj@KEaW=Hf$Ed)4;-d;<9g4 zsVGv%<)5X%2M5tHB!(90W?1=%X9VG>cUT`~VD~W=J6R9me46QfYWRspn1mO*IS_-T zoTI1<*x5WBvqM~N45Fa{&325v5GwdMM4&OfxGY_Mq=?_tq;H&7^YMw2pf+5YCHA!o z6K@`?Ep?t#z2$mP*Z{rsH0^5jJeyN7n!U&5rwTEV;}QtQ(UlyrER4YM)atO?&nqSF+bH2Fi}on zq)Yw`q19>7=tSfX@@0;u@wGd5kn}HnSrjNqoKf^!d0SZCUmlK2ojjWyPhvlsqibmr zmt!9myOEUM3qsp|Lg}`UpzFB(lYfWkI7ta4Fr51$S|K~O!E(SNf?8=PUq6t?y^>FTscU}Tj#eDg zE)qSEfU9~ELV>`6>ba>4XmUbT_%T~?t z;Nt-MsRH6e^_bzR!MM)l(+9UJG$9H-wwqQKYy~2>^MGyE$Fn~WVb## z-nC=oI9`|m4Nuvsnz^{J+i;}il4fC zCU|Vrz?`KTo?-`DlATFQc+dcXKsc8b4VB9L?z1UoPF)qO5Bk1YYmPItypqRwmW?d! z?jz$a+FI2FI}#VfmW{OT(uKy>(`<20ug(g3CvL8Wm{Y+hbB}p!yC^e{9*LHV6o<@^ z{YayB)=Q(}ovrXb-kfnT1yC9Wwi~z=G-)WU#%(d5h)_jq@msOIHV_%e&Vst=4K?Ac zk<(Zwe5aPtQStUIHAVp3bObc%Gto697vn;9aiAgEj~qwtUkCu@Pb z-4&IayFtckvtyZl3YG#J%kr$I3NQ3a6QRW5kBf@7L1Icd-^jBQ+5GB`R4KA@86%Ca zBj*W2Jr9t`s|OEJiu})>?WgkLS4X#tx0*9>zJm_?i>2tlw3Z8^p3mV9m^u zj$1CKQHv$mc8dv%Y?uatM0d~(&|cx5Rd?+M0K*^(J8j_p4W0UvV_K4Lf8hAf21kLm zWT_3CTx_T0(^H6IqYSNRP#E&A%nc`kMBO<{&NV=2;;J@sk6aTwunnhK!F1fv__t31 zPtblX+ruqteFZ1H{7#tmBt$LmJ)5bJo4$)dv0Is}3ihZkV`7!@nSQ{F!?ctLV=k?W zPr5vM2u&TNIdOQ;0DUf9Sid9fOkLBXPJUeC%SDHb;dez}H2xDVxqf%>#=L|%P4@(P zH%lp9N!o@J<5Kfh@yTf2lL6_2q=?S|cTKGy(h8YdyM7YkevA8y3Jvv=g*&QXSx3U; zU|9%XG`NpOnJ_5QJ1poN#;PCbp*=r>w~uXDLjH&4hHW|B<2<&Xso80a{dgcRo~GM6 z1)fV+4^@dp5Xzv8ozTJnnLqL2*h++}nU2|N7>tQGmpKpTbyP+KPH7`{W4KttB28#O zn>$fc0E}yZ$$Y$9ZO4Vgqs`7eaV`dVYx_`MQ}`+)aCC*AjIN=GmR0ht{(v|k*kT9B z2$gA(gwU{MQ@*|FuEvG-%U6*<3JT|NBkd}3Sc8c*N%R+2n1Rx0Bu!|P>!W8wopwS$ z#F?jk)=@o;`?|aIfAe7d0sek>^O8D=Ywr4(>5dw6@r3Ofqy08**0F}ECd;syKLW80 z1MBNo6FV@CDSGb^pRRTcfIirGQvRrUpHH>;xJ^SaWOKcaXg~8~81gBHjx07fVv1*m zH8&{wEnPib?qA~-6!83Cea3!o*n1Fm6}O@gQhCUW_f86KOPw1VJCPh1HmWP3m%l8Q zV%e_~U3 zCX~{YhM}U` zZuVo)F>M+}xi4i68nQGx_akj1ZCaI$C=JKc>7AnoeNvbx^Ng!w9DZcf^OCVA`h+=SZ#sY{+*{& z+5|+SPMjjD7xs@m+>$rvvo@|cmv!&mcgqqE|!TPyt6Ov`$#*xsPfPmJXUJ{ub z+@X73R7b(-e#!QGo%4v{@7I8Q^}{3fhyDWe99o@0Lo=0uqz)Wp(5T$x2HIb=LxPF- z+jWl?H*EE2{zP=^fiPN9K1sY()Xd80DVIRcI2WgOgo0Z0;txFRU?Hs2;3aXvH?YI!UhvAHuz*Btx7h>0tMSDP@X=lDeCUfzeBA*J6T zuxI2~H&0s!^cDLQd9EJ&nf3Tbj~>UNS5J@iR_oN6%6CIIVfFre*&4k-RtSXT7}?{W z@;egYR~+G_;#lxZU$DJU8G&(DOeFwYUugx8c-_t<8J8V#T@Wtcd@RMTGd0ops+lMI?@pY60?=w=^na) zwD0$XO~DmRUE;fX5_@Q#2g7A;S9H_s8|x|;fbsgk1b)KMqPcp}AdB3zVDMhwm0GmQIN>2I+sJC$aa zC^^W<68kG%l!TmzWIe(3lNxhxLIK=C%Ng zY573~2dP}O1ALVR1WD%kTCqSD@f#+6DrBECH^GA};bX;UsfP2!BB4$s<(z+G&BlXK z2+-E-*61H0L&4u;gjsmwNZ!qUV-!eivJBzQp#oFZL**$kuxJx#M76FRS4&f$_~-0R zt|Sr?5*L!kcW=ZBgV^3#YB1+bkK_?g`AF!8k27(Pn6eFuYg>=nbWb+LdRJ9%fBEcl z-sl@X^}|o+Ubo2_G3_3K6PZnsCsjw4E$#bc0lcqnc>66PQQb95g5vsR@oz2XpX3$g zAqaFio6d;nGIwPv=I&W^qUPvjmlWlgXX+f2$kNR6{Xj3 z?qJ&vP~6*V2|St0khzm-Puh|?w-9bzRdr%dul;q7Ca7xUF-H2SLM z3DJ!Q^}XLK>kbP*mgC(PS7-_MiL2&ae^xCO`Fdk@&Y>a*-(IK1=WGYys87jP$E(0T zCS$acCE+ab-9bC}BI_zCZ!Twu-TmMW9dOU#s_p-VnE-JFK=o|y8 z8*u0yW?Pg9G`~A;quW#AU}XyK*tANcuLfFswQQSykC=4NP-sjYwh{K^%IU3pM3&tc z8LvlHX+Bv$Qnts@!8&Z-oLaCgz}y5G)3V-{r)yGqAca!m2YWR>45{; z`yEfxfN>r?v9vdH<@e369mdM0>tL-n5D1;76!d}jKe(dG!24^#lYLgr?>XO(W6YyT9P+ln&nkd=#c%>g!u{D3$`sBnsbK$FO%VFH4%hu;le47L(CA>O5 zSkkV#j(9`djrAB!8I9?fd8p;bG9|G1>Y@3%%lnnMJKI+03G8d?^8;n_Z@x?$ebRw@ z(k8J2pMEttx$mcpnhV7f|DUf%+wNLl#C_!d(kv`9IzZo1J=Oft30Hqb&gxN4cYeuw zvTj+PS?nR0b2980<)*Pa(8okNZaa>L3~4()DzRP^#8ibBmWY)V;G_I2Av`P1YThvP zoZ$1g{EOasy+|~~@G^GNjV{4`1I6&x55?xTx(B&ICfIOGoMP1Pq@%v?mJ1mf8 zi&lvTv^~~Um+~#2jOP>t@0CoJS9sUY@uXM}FuD7)o6tvll4KZsV+H^Xy4-*Iq`v8_ zGi(q1Jq?*8hR)+DFF6tJQqPNn1K4xw$CBUZ$1juY)a$Y}x9U5~98ya}jL1YaZn+qK zBM~e788St@3e)#}T;PYH`S5b6sbN*>yc4rZ&MIk)Tvl_&el@&{p&4uq2^q5 z$szn`qI8>U zfp1pPWq)=&JwI-gzWl&WwVbb#&Av1%NyKO&;z@hdba=FiQa10DPSCOPUez{w>K_w$ zV_49O|JOUWn8ihVn#}zhM6|x;Maark62S-gF0C2}_f{Zj^zBk_$ER&R>3fgy)vUl7 z#fUdi-eI<^aX*Y3i78Ck>c#2j)2xRBfyt)7U6(ha@WuZp-{v2|^BXw_zk>O3_Bpft zc?Q@Mrvi7>ppDAAro$C?tuE63$%XmX!}pI+cJ__9HtIV1!F`M%df4PPN9^QTgzEP+ zpBmi8B&vMVF|JL*Lk_j+Q$6v|W^p98F|22PMr$_?lL73Y$in2qg6g7;1DHgqzs+Wo zYhzcO6%JX@ixjqKS)AMfaGbTInKzj2#lLX;_rHIncm!QFD(c^L$$K<7KC4(-)|l87 zp*q@Et&5>=9sfCxm!yFh!d=GrHNj@|ISXnpjC$F2TEcgB%ku(%mm@5?1=PK1x3TO| zoj*>in$@$cBA}r!##(n!7z~+XqMhssYuKVetN8^3?MeBfar7p8@#enJ{4i#GEiZ_Y zpSoLrSvzw8lV-BtIYVp0B*|T@m(Z)iI65@u-YAca3E(vLV@WT?Ci=}lCi}}7{GO?RMWN}Ho@&g9m}f1dLT^NraEMhg)saGHW%smMz2(=lrhxUZu%Mowv?nqSxa%4zB46rP(-+Hmyla`_IS|(X^CzGA z+jmo?oboes+%Tf`;l6mOmm;4IvO%By6MAY3BNv_!*%RKgJW`ZHW|Y+^lqluwZrP}G zlI4%=*8pz^?In5LcfldqX?kZqvsL?3eSZfk*Ihi1AfA3VoPw##w-qXa8Q0pm#Z042 zua?qld7$YXTUk{2@eof&G zf}Vtj^CLmgdYDB&naX?N+XkW9z$Fi zR1uGD5T1FC)?~(#YLGsVCPr{LnIiA|?LEs{DjhZboL@)i4{_fo_T20i;$;kT$iUekmVh4r(o2>N?e^wS*@SRL4{7ny-SeB zWb?e?s|(oDWsJn73~c6Yh(>_7n*L2a*(S6*w`4vYvI!DD`j&H&;5X@5H6Jo8Zsgvjwdlp%S1)b4YO&fem zpFH(y(m>5C_7N=CL{3QR$F>j`TFO~}7Yq7nb%=EMD)>F7Gcad8zcz6Z9 z@LAosdISQPju0w;602{afxR};>%Ic%Cn#2`Md4FA{IErEQA4lgBj!>epfvVl;E!v#~ z?Z8|=x&8O{QsZ##Fs%h`1y+H9V7yM(mBifs+}S}mv{-h8-mS|%8$@M`NE;EKvbV{o#KeF;=uw!t>9YVCwyyY()%bauZ#v^kE|n`?_C2Hh16?*)V##tn$XKvG*mP_L zZT>F=H+_D7@WAT&B%@~>(Id$-Y9Dkrz^A7Gd9)r9E96KeJ+Zm-t)?u#* zVmGHjK;|4C^(vIt?*%vMjYm}u^7IFeVSk;V?15|Ta9scg|6$&{k1IGy?-W0Ja1c<5 z>ss3)jw9h8Ks44nf*8RCxYe zQ0zvCG0d=LKyy#k@JCtOLibmRs+m#~G&So0GNSR}ayC|qU`pv?{65nuNbIzLg4!Vo z^)e#8YoZYce8W5Pry2YwraxP8mIbZHpRgT-yITYct8dPcK#U8!HK+ zMwbLOpVTE61H$v-U9a$!eixT)?d`$h0=BL>(fu$_hH4YL;3RhPlVw9{4vt*kLf@yD zLBD~-TTzoG%?H=UfOKjesgHdpgtMx7UZm;zYA19v87oE?X+I)NG&S*L40DX|o~`Kg z5T6Ns*fuVvxOJhpHOY()&-&V16NzPg4S0!4%S@)YNa6clKlJl0>QIl04&8_z6P7>p zOmZ&yn0yUjc>W)u?l=dcT{ryigKq{|P}!-!8-B&XM7VjD3b478P6*L?1}a9!Lf z(`b{{y&`&H0tLoejmB6fM*pWl@nu2%rJ9mA(iCs$Vv&xLXQ)@nMFR7>3rj4rhpgg@ z&!pZAm5b{@JT)FCqxwugen_xQdA)rCpC$2 z+ijKwan`TK#wWdcdgg%E7Lz@ZrT(b%ps?>a)dxMQjohJgnGLQsPK}(6d|*5ifkyFJ zHZZG$q1iaXt~$^|#7FJ$;BaT4Pj{!aYnp=ZMsy058T|_g^|YO5iAPGn$6k{aK7Bd& z{+BavcNy5kr=gU(Fz|wQW~?WzcQ514aiCNI7gjAYQTyt=cu8HfqgZi-?W8lNSQwlqu+Q#X& zF2-YJ&I{b6N`sIK&r6-SyJ^*@b!2KKJ>@hc3#L@_!MS9G zRd6O$m`g;QC=(TMUwSq!B&b}wM9flfH(uLostQ+mk&|Fk;q`-R_a<*=5g*&o1e=it zo=Z<_!8R@K!0%i4&K_}IZS(8jC{R%%Pmg&~Jc9GAbN`M4vy`%WcNu@~kho%sd>;8l zYTwG&1Rn#F8K0>LRCT~jy7!P6_ZY#C`V zI6Trcx8Gp~fKgCN+HvCY<`OIE8sPevoSn(Bwpv@ejZ!`Y^e(LluhU45Ybm%jJ&qBl z$cl>&8P-c*M?$cJ^sdtRV>8Fhyouny@fZczX#>s5-{KSzwT#9$_SRo{<0!hhOGc>L zFTS%xx7w%^6eupWv1LtEUKZn-0+z{g6(rNd)uR+HDa_ik{^y-V^cYHCz8=SrP$A<% zPecU~32bItwnD;6th&R@U|b>>=9!@F^_$j8x`{bgKzChH`(gLM6*=} z1N%D^z4`kKjP_MLvjcR2rgD)8g7MtOKG|;)cwDcyj&ru>x+_PLvJE(cV5J2OOwF58 zp8cm#!KyikuhlhR2TchL#B!)Y42#_`R(X#MSAZ$^w#AsxCAVDzXqOwf(=WY(O)%OM zMK7Iv^tWbwzb^;GmRy=5e4b%)cOkJo%GKjgLC(4_O15omx<&B(DE&G{OAsBx%gk7s z8Prqv#Z>>bATMeAxZzS$$(Mm7!Y|i=I<1-D+0)PlM))!fh^Mzh1ZKO%MN_SwtLrs5 z|4FHAu~88$IAS-dOwKku88EEUr)D_d08#b76q*0=nN*G!JAdTD5lD3Vq2{<0(2*;S z(NZNgM`gUOa6nck)>0)thno?~i6V{`lnUUds^a%>(+oYULKL}sgJ@x#FQnh7Ez>>g zXMGy|8p2Ovc~!&x7;pDx;44tyzE&GoEK+}HOz84l;9fdH@3hws+&*V&-3XJyGnuO^ zY`)@ncZ}Px_r8#7f2-{cnmU@`!URoC|BnX>du(QG?epEQ9~L>zLLrI*^(uL#y>yab zGc#{V$)|tmiZ8#Z3Yz(SP+stux_$q zJ$k0lLQZUR;meh?Dr5%U8)#_9_1A8WTl^CxrEloSqlQ}M{Kcu(hw1{ac zF`hm1e+I2n{pu;z>Rx#$SBaSZ7~o9l07F%&{BGP) z0|5TWIQ^pm@X@HP_h*FCnS;(4Ma|KJx36`E>hmbmfcuW`MYW6c* z5|U{CSrt_z3=GrV8}-HiilNbXo;^&3J$>l>9k-tXf3LUT8UTHAY2m819_S-4dZv7D zOG*vk@KT{3KA$%wtRH0F*scDepMiQZHi2MOU`8?efozH4)2`9Lcvg<3CCWcNP3rE^S8qEgh z6YR|ueOmKDkLjCV|?PbWXEapA~u9O2dAPc}0}X$CjqgZx_C#RBSyPQ5X{2`*fB^Ew@N! z7I_vfBbMaD=p`X>!+82b^H6p1HZC0j$uLdMvQqmKLThsYyWS|T66 zinkGOL!CfsP^L#p90Lt1W^MuN`fg*|1BMs)YQ4y?v$_`rmV;`K_P3^8cACZmQe@#O z^{8aqXs{>#+%I`?4OO3^D%0=Qb;AaHnu^xNy)_?3+j7BmG~(!D!7*D9RH(x#{eSh( z5tpOsnncWP>RaeKQK~d~wnm8+Mg7eGom_LT6JvdJSui_$VPr$)U&WXiYdX4|j0230 z$*JW&>^9nlY?TRwTyCGYK;#jNy%2ZI$zEmM$$s0ZFh!HFwbrpu!CS4FDj#l-OfK>7 z)j2GB>=ly9i;M*GnRZ>)ML>AzYnym5HXhJc4$){squ=JSWC1UhW|0jPe^o%C+~Hkc zkgwxyn%CHF7~IBzOBtS2aX z%|TyUmn}UtfXx9tz4SG*R-AOZx$$dbO$prs62)(GIQblqL#4=R#h)17sbHFY`M@76 z^+P-)?rq>`)NZ#lCW?>w`9C0itKdGD<4A$4yOBl)t4(zoO4B^t>M4EK*Opz&*v^&F z0~7qh`UQGYO**KtZKkiiQtvZmgUGlt0z_Kj;gcGgRCwGGV9PZI8EMYU@PlM|t2Aa| z<@r$jf`+swogNDj_oTha<4 zj@BVcQX zXvTyyiw~PYA*hmnRNftNVvn(h!uHShaTrglIqh73Jl~4AY0T0 z{MiI$>5AyirK{_OGo#WINp4A$>EgdpJ>$hmt6cqe2`v6$8e(Bhh^~!`fOOZ)HGbgL-AmM{v zpKy??#GnURnMeRaE@W-Ltk_}mk(2i1p4|=c zpQ}s08Pgs#FFdVtQ7|N=47D|2QqrofzwrD>sZ=S7vg7JgG^mzOxoTgzxsi@ zcA|XvMOJ-z$|ujTLETAP-^d()F>OvQWX*t1%&3l$we>B_FcccB%vS-? zFWo-1c3l0p5q>H|p`bZUr-I3zY6OS!@JGf^>PVOjB#GeBQN%lx;@mdJ_!73HSb3&r zoTG}LT>R2TEF@w7SYv@}8p61$DWjX-sqcwxBm1Ukk}Y*bo0c?^Q1!==%C@c%(j{9q z1Rlo+;bd^5;Z$g!=L>f%OK{3ger1TxSz|8ysq}Fq$y?G{moBgaqc|$Uj#}iXFUELA zA%*>k#bPV(eFOBuY|fC;TCWd6vUBw%omT57e(kfT%qF7YmgtmbobqL&FB0xm2j2$k z#u|nNbllXO;-ERsrYpA?v-!*c<1dPvs{qyPvg<~nc4;v&1HY>u+nc8#QOH$ZL1VxwRq$=VA2JE_oudqr>2?)f}5~!w=(_dF0`UPp@uDqBo9mW zt$+M--2XL6d40`K^Nv+ZJpVhbxc{(C^RfP4$s4ZBnYz-noX=~{@-?~Pvb+vopY9HE z%iOx-;Yz)2E^Qawwk+k%%Th9(`Nl2!Bt!X5x$+efM>kKsv^o2@oO7;4R@ybk<*D1I zb8lN@cd5H>-Mz=rZ#K`VlYAm)Qh!;xH*itep+~+?BCiT%pVRT}on5iI;#=Yp$r6?4 zo;!gXGj^80GQ4*3gj7~(^Se05YJZuvr7NziJ)3i8T4ArQ%A)*p?LqG~XSX%I_L_R8 z`dy;cx5#t$JfHZb>|gdBTUS?|?C)<`wNQYR2t~{T$ZqoL1Q9*&11$nl8&Q=cB3VEn_St+nM@0Qu`eS1~6 zEjZfQ{>Vsr{mLynbBj}?FHL*gcepSpWXpWF>74BQ{v7dBbg93>Ja@yDy$-A9tBLH{ zt&|j!9&&oE*2TXUw#=N=@pu1$l;np9|I6B0SEuR=I!}>g7Wt_?tw<%>?rV2J+@xER zZf>bnx-u!s)8*R>W#hZipXUAUJ-YXtYT4{`mEDrBvRHnqomja3;xtOk3XDO__+ArjB1_d@@3*JEdDy zTQ4WRb1uDh$#-q~uE0~NJ145wet*qpE_LoJv(}01%tdL}dr!?*+;LX-btFqu&=pVR zz)3yd?)+miTwfl#dD@&Pe&Z87zzvSKfWuVHe-rl{D&&~sj+9NQ03GQ@?o8KY)g0Ymam&u8kpcUtL@Hop+h?V8re2IEA-v+ zs2{k$cuhxtZbPk7*0e&cXr0TY=cUd`mzWk===rU5g7?>b z(HpDkW8&RCPb~H~*SCDT@9x?&Ws<#nD-$;*p4uMsvT*Ifo%~m)e|&Rg8pk}Fwb_AR)Gtn+b1G2P z%XFsPvoxlBL^LDC$CcfV7n61F{CXO=@fiL}Ly2T&k6E+#Z zh46BxEssB(=lIzDui=fyW}jvr-&l0)lY~i*`}40KXA0l$$=i8(#m_srZtjY*f(tq| zRliM%**!nrpV?|jW6+XI=Q`sVpQhxS^Ilyr#q-6a9Uf8qAAen#{C35z?M961h)mV+ z>($k6v75UuOH8?QsY*oD;&-0#oOiz_&YN=9^>( + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/Node/Node.ino b/lib-ext/rfm-69.git/Examples/Node/Node.ino new file mode 100644 index 0000000..028c84b --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/Node/Node.ino @@ -0,0 +1,172 @@ +// Sample RFM69 sender/node sketch, with ACK and optional encryption +// Sends periodic messages of increasing length to gateway (id=1) +// It also looks for an onboard FLASH chip, if present +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get it here: https://www.github.com/lowpowerlab/spiflash + +#define NODEID 2 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +#define GATEWAYID 1 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +//#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ACK_TIME 30 // max # of ms to wait for an ack +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define FLASH_SS 23 // and FLASH SS on D23 +#else + #define LED 9 // Moteinos have LEDs on D9 + #define FLASH_SS 8 // and FLASH SS on D8 +#endif + +#define SERIAL_BAUD 115200 + +int TRANSMITPERIOD = 150; //transmit a packet to gateway so often (in ms) +char payload[] = "123 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char buff[20]; +byte sendSize=0; +boolean requestACK = false; +SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL) +RFM69 radio; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + //radio.setFrequency(919000000); //set frequency to some custom frequency + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + + if (flash.initialize()) + { + Serial.print("SPI Flash Init OK ... UniqueID (MAC): "); + flash.readUniqueId(); + for (byte i=0;i<8;i++) + { + Serial.print(flash.UNIQUEID[i], HEX); + Serial.print(' '); + } + Serial.println(); + } + else + Serial.println("SPI Flash Init FAIL! (is chip present?)"); +} + +long lastPeriod = 0; +void loop() { + //process any serial input + if (Serial.available() > 0) + { + char input = Serial.read(); + if (input >= 48 && input <= 57) //[0,9] + { + TRANSMITPERIOD = 100 * (input-48); + if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000; + Serial.print("\nChanging delay to "); + Serial.print(TRANSMITPERIOD); + Serial.println("ms\n"); + } + + if (input == 'r') //d=dump register values + radio.readAllRegs(); + //if (input == 'E') //E=enable encryption + // radio.encrypt(KEY); + //if (input == 'e') //e=disable encryption + // radio.encrypt(null); + + if (input == 'd') //d=dump flash area + { + Serial.println("Flash content:"); + uint16_t counter = 0; + + Serial.print("0-256: "); + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + while(flash.busy()); + Serial.println(); + } + if (input == 'e') + { + Serial.print("Erasing Flash chip ... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + if (input == 'i') + { + Serial.print("DeviceID: "); + word jedecid = flash.readDeviceId(); + Serial.println(jedecid, HEX); + } + } + + //check for any received packets + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i]); + Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + + if (radio.ACKRequested()) + { + radio.sendACK(); + Serial.print(" - ACK sent"); + } + Blink(LED,3); + Serial.println(); + } + + int currPeriod = millis()/TRANSMITPERIOD; + if (currPeriod != lastPeriod) + { + lastPeriod=currPeriod; + + //send FLASH id + if(sendSize==0) + { + sprintf(buff, "FLASH_MEM_ID:0x%X", flash.readDeviceId()); + byte buffLen=strlen(buff); + if (radio.sendWithRetry(GATEWAYID, buff, buffLen)) + Serial.print(" ok!"); + else Serial.print(" nothing..."); + //sendSize = (sendSize + 1) % 31; + } + else + { + Serial.print("Sending["); + Serial.print(sendSize); + Serial.print("]: "); + for(byte i = 0; i < sendSize; i++) + Serial.print((char)payload[i]); + + if (radio.sendWithRetry(GATEWAYID, payload, sendSize)) + Serial.print(" ok!"); + else Serial.print(" nothing..."); + } + sendSize = (sendSize + 1) % 31; + Serial.println(); + Blink(LED,3); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino b/lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino new file mode 100644 index 0000000..31be141 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/OLEDMote/OLEDMote.ino @@ -0,0 +1,242 @@ +// Sample RFM69 sketch for the MotionOLED mote containing the OLED +// Displays any messages on the network on the OLED display and beeps the buzzer every time a message is received +// The side button will step through 10 past received messages +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get libraries at: https://github.com/LowPowerLab/ +// Make sure you adjust the settings in the configuration section below !!! + +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get library from: https://github.com/lowpowerlab/lowpower +#include "U8glib.h" //get library from: https://code.google.com/p/u8glib/ + +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 122 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W! +//********************************************************************************************* + +#define SERIAL_BAUD 115200 +#define LED 5 // Moteinos have LEDs on D9, but for MotionMote we are using the external led on D5 +#define BUZZER 6 +#define BUTTON_INT 1 //user button on interrupt 1 +#define BUTTON_PIN 3 //user button on interrupt 1 + +RFM69 radio; +U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI SSD1306 OLED 128x64 +bool promiscuousMode = true; //set to 'true' to sniff all packets on the same network + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + radio.promiscuous(promiscuousMode); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + pinMode(BUZZER, OUTPUT); + + //configure OLED + u8g.setRot180(); //flip screen + // assign default color value + if ( u8g.getMode() == U8G_MODE_R3G3B2 ) + u8g.setColorIndex(255); // white + else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) + u8g.setColorIndex(3); // max intensity + else if ( u8g.getMode() == U8G_MODE_BW ) + u8g.setColorIndex(1); // pixel on + else if ( u8g.getMode() == U8G_MODE_HICOLOR ) + u8g.setHiColorByRGB(255,255,255); + u8g.begin(); + Serial.flush(); + pinMode(BUTTON_PIN, INPUT_PULLUP); + attachInterrupt(BUTTON_INT, handleButton, FALLING); +} + +#define FLAG_INTERRUPT 0x01 +volatile int mainEventFlags = 0; +boolean buttonPressed = false; +void handleButton() +{ + mainEventFlags |= FLAG_INTERRUPT; +} + +byte ackCount=0; + +#define MSG_MAX_LEN 17 //OLED 1 line max # of chars (16 + EOL) +#define HISTORY_LEN 10 //hold this many past messages +typedef struct { + char data[MSG_MAX_LEN]; + int rssi; + byte from; +} Message; +Message * messageHistory = new Message[HISTORY_LEN]; + +byte lastMessageIndex = HISTORY_LEN; +byte currMessageIndex = HISTORY_LEN; +byte historyLength = 0; +void loop() { + if (mainEventFlags & FLAG_INTERRUPT) + { + LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON); + mainEventFlags &= ~FLAG_INTERRUPT; + if (!digitalRead(BUTTON_PIN)) { + buttonPressed=true; + } + } + + if (buttonPressed) + { + buttonPressed = false; + Beep(10, false); + + //save non-ACK messages in a circular buffer + if (!radio.ACK_RECEIVED && historyLength > 1) //only care if at least 2 messages saved. if only 1 message it should be displayed already + { + if (currMessageIndex==0) + currMessageIndex=historyLength-1; + else currMessageIndex--; + + //Serial.print("HIST currIndex/histLen=");Serial.print(currMessageIndex+1);Serial.print("/");Serial.print(historyLength); + //Serial.print(" - "); + //Serial.println(messageHistory[currMessageIndex].data); + + u8g.firstPage(); + do { + draw(messageHistory[currMessageIndex].data, messageHistory[currMessageIndex].rssi, messageHistory[currMessageIndex].from, true); + } while(u8g.nextPage()); + //delay(10); //give OLED time to draw? + } + } + + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] "); + if (promiscuousMode) + Serial.print("to [");Serial.print(radio.TARGETID);Serial.print("] "); + + Serial.print((char*)radio.DATA); + Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + Serial.println(); + + saveToHistory((char *)radio.DATA, radio.RSSI, radio.SENDERID); + Blink(LED,3); + Beep(20, true); + u8g.firstPage(); + do { + draw((char*)radio.DATA, radio.RSSI, radio.SENDERID, false); + } while(u8g.nextPage()); + //delay(10); //give OLED time to draw? + } + radio.receiveDone(); + Serial.flush(); + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON); +} + +float batteryVolts = 5; +char* BATstr="BAT:5.00v"; +void draw(char * data, int rssi, byte from, boolean isHist) { + char buff[20]; + // graphic commands to redraw the complete screen should be placed here + u8g.setFont(u8g_font_unifont); + u8g.drawStr( 0, 10, data); + sprintf(buff, "ID:%d", from); + u8g.drawStr( 0, 25, buff); + sprintf(buff, "RSSI:%d", rssi); + u8g.drawStr( 60, 25, buff); + + if (!isHist) + { + batteryVolts = analogRead(A7) * 0.00322 * 1.42; + dtostrf(batteryVolts, 3,2, BATstr); + sprintf(buff, "BAT:%sv", BATstr); + u8g.drawStr( 0, 55, buff); + } +} + +void Beep(byte theDelay, boolean both) +{ + if (theDelay > 20) theDelay = 20; + tone(BUZZER, 4200); //4200 + delay(theDelay); + noTone(BUZZER); + LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_ON); + if (both) + { + tone(BUZZER, 4500); //4500 + delay(theDelay); + noTone(BUZZER); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} + +void saveToHistory(char * msg, int rssi, byte from) +{ + byte length = strlen(msg); + byte i = 0; + if (lastMessageIndex >=9) lastMessageIndex = 0; + else lastMessageIndex++; + currMessageIndex = lastMessageIndex; + if (historyLength < HISTORY_LEN) historyLength++; + + //Serial.print("HIST SAVE lastIndex=");Serial.print(lastMessageIndex);Serial.print(" strlen=");Serial.print(length); + //Serial.print(" msg=["); + + for (; i<(MSG_MAX_LEN-1) && (i < length); i++) + { + messageHistory[lastMessageIndex].data[i] = msg[i]; + Serial.print(msg[i]); + } + //Serial.print("] copied:"); + messageHistory[lastMessageIndex].data[i] = '\0'; //terminate string + //Serial.println((char*)messageHistory[lastMessageIndex].data); + + messageHistory[lastMessageIndex].rssi = rssi; + messageHistory[lastMessageIndex].from = from; +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino b/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino new file mode 100644 index 0000000..c95c677 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway.ino @@ -0,0 +1,146 @@ +// ********************************************************************************************************** +// GarageMote garage door controller base receiver sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW +// Can be adapted to use Moteinos using RFM12B +// This is the sketch for the base, not the controller itself, and meant as another example on how to use a +// Moteino as a gateway/base/receiver +// 2014-07-14 (C) felix@lowpowerlab.com, http://www.LowPowerLab.com +// ********************************************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this code/library but please abide with the CCSA license: +// http://creativecommons.org/licenses/by-sa/4.0/ +// ********************************************************************************** + +#include //get it here: http://github.com/lowpowerlab/rfm69 +#include //get it here: http://github.com/lowpowerlab/spiflash +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming +#include //comes with Arduino IDE (www.arduino.cc) + +//***************************************************************************************************************************** +// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION! +//***************************************************************************************************************************** +#define NODEID 1 +#define NETWORKID 200 +#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +#define ENCRYPTKEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define LED 9 +#define FLASH_CS 8 +#define SERIAL_BAUD 115200 +#define SERIAL_EN //comment out if you don't want any serial verbose output +#define ACK_TIME 30 // # of ms to wait for an ack +//***************************************************************************************************************************** + +#ifdef SERIAL_EN + #define DEBUG(input) {Serial.print(input); delay(1);} + #define DEBUGln(input) {Serial.println(input); delay(1);} +#else + #define DEBUG(input); + #define DEBUGln(input); +#endif + +RFM69 radio; +SPIFlash flash(FLASH_CS, 0xEF30); //EF40 for 16mbit windbond chip + +void setup() { + Serial.begin(SERIAL_BAUD); + delay(10); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + DEBUGln(buff); + if (flash.initialize()) + { + DEBUGln("SPI Flash Init OK!"); + } + else + DEBUGln("SPI Flash Init FAIL! (is chip present?)"); +} + +byte ackCount=0; +byte inputLen=0; +char input[64]; +byte buff[61]; +String inputstr; +void loop() { + inputLen = readSerialLine(input); + inputstr = String(input); + inputstr.toUpperCase(); + + if (inputLen > 0) + { + if (inputstr.equals("KEY?")) + { + DEBUG("ENCRYPTKEY:"); + DEBUG(ENCRYPTKEY); + } + + byte targetId = inputstr.toInt(); //extract ID if any + byte colonIndex = inputstr.indexOf(":"); //find position of first colon + if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any + if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0) + { + + inputstr.getBytes(buff, 61); + //DEBUGln((char*)buff); + //DEBUGln(targetId); + //DEBUGln(colonIndex); + if (radio.sendWithRetry(targetId, buff, inputstr.length())) + { + DEBUGln("ACK:OK"); + } + else + DEBUGln("ACK:NOK"); + } + } + + if (radio.receiveDone()) + { + int rssi = radio.RSSI; + DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] "); + if (radio.DATALEN > 0) + { + for (byte i = 0; i < radio.DATALEN; i++) + DEBUG((char)radio.DATA[i]); + DEBUG(" [RSSI:");DEBUG(rssi);DEBUG("]"); + } + + CheckForWirelessHEX(radio, flash, false); //non verbose DEBUG + + if (radio.ACKRequested()) + { + byte theNodeID = radio.SENDERID; + radio.sendACK(); + DEBUG("[ACK-sent]"); + } + DEBUGln(); + Blink(LED,3); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} + +//readSerialLine already defined in WirelessHEX69 +// reads a line feed (\n) terminated line from the serial stream +// returns # of bytes read, up to 255 +// timeout in ms, will timeout and return after so long +//byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10); +//byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout) +//{ +// byte inputLen = 0; +// Serial.setTimeout(timeout); +// inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength); +// input[inputLen]=0;//null-terminate it +// Serial.setTimeout(0); +// //Serial.println(); +// return inputLen; +//} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino b/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino new file mode 100644 index 0000000..da80fe5 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/PiGateway/PiGateway_withLCD.ino @@ -0,0 +1,186 @@ +// ********************************************************************************************************** +// GarageMote garage door controller base receiver sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW +// Can be adapted to use Moteinos using RFM12B +// This is the sketch for the base, not the controller itself, and meant as another example on how to use a +// Moteino as a gateway/base/receiver +// 2014-07-14 (C) felix@lowpowerlab.com, http://www.LowPowerLab.com +// ********************************************************************************************************** +// Creative Commons Attrib Share-Alike License +// You are free to use/extend this code/library but please abide with the CCSA license: +// http://creativecommons.org/licenses/by-sa/4.0/ +// ********************************************************************************** + +#include //get it here: http://github.com/lowpowerlab/rfm69 +#include //get it here: http://github.com/lowpowerlab/spiflash +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming +#include //comes with Arduino IDE (www.arduino.cc) +#include "ST7036.h" //get it from here: https://bitbucket.org/fmalpartida/st7036-display-driver/src/ +#include "LCD_C0220BiZ.h" //get it from here: https://bitbucket.org/fmalpartida/st7036-display-driver/src/ +#include //comes with Arduino + +//***************************************************************************************************************************** +// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION! +//***************************************************************************************************************************** +#define NODEID 1 +#define NETWORKID 200 +#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +#define ENCRYPTKEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define LED 9 +#define FLASH_CS 8 +#define SERIAL_BAUD 115200 +#define SERIAL_EN //comment out if you don't want any serial verbose output +#define ACK_TIME 30 // # of ms to wait for an ack +#define BACKLIGHTPIN 5 //3=R,5=G,6=B +//***************************************************************************************************************************** + +#ifdef SERIAL_EN + #define DEBUG(input) {Serial.print(input); delay(1);} + #define DEBUGln(input) {Serial.println(input); delay(1);} +#else + #define DEBUG(input); + #define DEBUGln(input); +#endif + +RFM69 radio; +SPIFlash flash(FLASH_CS, 0xEF30); //EF40 for 16mbit windbond chip + +//initialize LCD +ST7036 lcd = ST7036(2, 20, 0x78, BACKLIGHTPIN); //row count, column count, I2C addr, pin for backlight PWM +byte battChar[8] = {0b00000,0b01110,0b11111,0b11111,0b11111,0b11111,0b11111,0}; +byte rssiChar[8] = {0b00000,0b00100,0b10101,0b01110,0b00100,0b00100,0b00100,0}; + +void setup() { + Serial.begin(SERIAL_BAUD); + delay(10); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + char buff[50]; + sprintf(buff, "\nListening @ %dmhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + DEBUGln(buff); + if (flash.initialize()) + { + DEBUGln("SPI Flash Init OK!"); + } + else + DEBUGln("SPI Flash Init FAIL! (is chip present?)"); + + lcd.init(); + lcd.setContrast(10); + lcd.clear(); + lcd.load_custom_character(0, battChar); + lcd.load_custom_character(1, rssiChar); + lcd.setCursor(0,0); + lcd.print(buff); +} + +byte ackCount=0; +byte inputLen=0; +char input[64]; +byte buff[61]; +char LO[20]; +char BAT[20]; +char temp[25]; +String inputstr; +void loop() { + inputLen = readSerialLine(input, 10, 64, 10); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10); + inputstr = String(input); + inputstr.toUpperCase(); + + if (inputLen > 0) + { + if (inputstr.equals("KEY?")) + { + DEBUG("ENCRYPTKEY:"); + DEBUG(ENCRYPTKEY); + } + + byte targetId = inputstr.toInt(); //extract ID if any + byte colonIndex = inputstr.indexOf(":"); //find position of first colon + if (targetId > 0) inputstr = inputstr.substring(colonIndex+1); //trim "ID:" if any + if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0) + { + + inputstr.getBytes(buff, 61); + //DEBUGln((char*)buff); + //DEBUGln(targetId); + //DEBUGln(colonIndex); + if (radio.sendWithRetry(targetId, buff, inputstr.length())) + { + DEBUGln("ACK:OK"); + } + else + DEBUGln("ACK:NOK"); + } + } + + if (radio.receiveDone()) + { + int rssi = radio.RSSI; + DEBUG('[');DEBUG(radio.SENDERID);DEBUG("] "); + if (radio.DATALEN > 0) + { + for (byte i = 0; i < radio.DATALEN; i++) + DEBUG((char)radio.DATA[i]); + DEBUG(" [RSSI:");DEBUG(rssi);DEBUG("]"); + } + + CheckForWirelessHEX(radio, flash, false); //non verbose DEBUG + + if (radio.ACKRequested()) + { + byte theNodeID = radio.SENDERID; + radio.sendACK(); + DEBUG("[ACK-sent]"); + } + DEBUGln(); + Blink(LED,3); + + lcd.clear(); + lcd.setCursor(0,0); + + //if (radio.DATALEN < RF69_MAX_DATA_LEN) radio.DATA[radio.DATALEN]=0; + byte matches = sscanf((const char*)radio.DATA, "%s BAT:%s", LO, BAT); + if (matches==2) + { + lcd.print(LO); + lcd.setCursor(0,14); + lcd.print(char(0)); + lcd.setCursor(0,15); + lcd.print(BAT); + } + else lcd.print((const char*)radio.DATA); + + lcd.setCursor(1,14); + lcd.print(char(1)); + lcd.setCursor(1,16); + lcd.print(rssi); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} + +//readSerialLine already defined in WirelessHEX69 +// reads a line feed (\n) terminated line from the serial stream +// returns # of bytes read, up to 255 +// timeout in ms, will timeout and return after so long +//byte readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=10); +//byte readSerialLine(char* input, char endOfLineChar, byte maxLength, uint16_t timeout) +//{ +// byte inputLen = 0; +// Serial.setTimeout(timeout); +// inputLen = Serial.readBytesUntil(endOfLineChar, input, maxLength); +// input[inputLen]=0;//null-terminate it +// Serial.setTimeout(0); +// //Serial.println(); +// return inputLen; +//} diff --git a/lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino b/lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino new file mode 100644 index 0000000..78f372e --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/Struct_receive/Struct_receive.ino @@ -0,0 +1,139 @@ +#include +#include +#include + +#define NODEID 1 +#define NETWORKID 100 +#define FREQUENCY RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +#define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +#define LED 9 +#define SERIAL_BAUD 115200 +#define ACK_TIME 30 // # of ms to wait for an ack + +RFM69 radio; +SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip +bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network + +typedef struct { + int nodeId; //store this nodeId + unsigned long uptime; //uptime in ms + float temp; //temperature maybe? +} Payload; +Payload theData; + +void setup() { + Serial.begin(SERIAL_BAUD); + delay(10); + radio.initialize(FREQUENCY,NODEID,NETWORKID); + //radio.setHighPower(); //uncomment only for RFM69HW! + radio.encrypt(KEY); + radio.promiscuous(promiscuousMode); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + if (flash.initialize()) + Serial.println("SPI Flash Init OK!"); + else + Serial.println("SPI Flash Init FAIL! (is chip present?)"); +} + +byte ackCount=0; +void loop() { + //process any serial input + if (Serial.available() > 0) + { + char input = Serial.read(); + if (input == 'r') //d=dump all register values + radio.readAllRegs(); + if (input == 'E') //E=enable encryption + radio.encrypt(KEY); + if (input == 'e') //e=disable encryption + radio.encrypt(null); + if (input == 'p') + { + promiscuousMode = !promiscuousMode; + radio.promiscuous(promiscuousMode); + Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off"); + } + + if (input == 'd') //d=dump flash area + { + Serial.println("Flash content:"); + int counter = 0; + + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + while(flash.busy()); + Serial.println(); + } + if (input == 'D') + { + Serial.print("Deleting Flash chip content... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + if (input == 'i') + { + Serial.print("DeviceID: "); + word jedecid = flash.readDeviceId(); + Serial.println(jedecid, HEX); + } + } + + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); + Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]"); + if (promiscuousMode) + { + Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] "); + } + + if (radio.DATALEN != sizeof(Payload)) + Serial.print("Invalid payload received, not matching Payload struct!"); + else + { + theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else + Serial.print(" nodeId="); + Serial.print(theData.nodeId); + Serial.print(" uptime="); + Serial.print(theData.uptime); + Serial.print(" temp="); + Serial.print(theData.temp); + } + + if (radio.ACKRequested()) + { + byte theNodeID = radio.SENDERID; + radio.sendACK(); + Serial.print(" - ACK sent."); + + // When a node requests an ACK, respond to the ACK + // and also send a packet requesting an ACK (every 3rd one only) + // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY + if (ackCount++%3==0) + { + Serial.print(" Pinging node "); + Serial.print(theNodeID); + Serial.print(" - ACK..."); + delay(3); //need this when sending right after reception .. ? + if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) // 0 = only 1 attempt, no retries + Serial.print("ok!"); + else Serial.print("nothing"); + } + } + Serial.println(); + Blink(LED,3); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} diff --git a/lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino b/lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino new file mode 100644 index 0000000..9414033 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/Struct_send/Struct_send.ino @@ -0,0 +1,135 @@ +#include +#include +#include + +#define NODEID 99 +#define NETWORKID 100 +#define GATEWAYID 1 +#define FREQUENCY RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +#define KEY "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +#define LED 9 +#define SERIAL_BAUD 115200 +#define ACK_TIME 30 // # of ms to wait for an ack + +int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms) +byte sendSize=0; +boolean requestACK = false; +SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip +RFM69 radio; + +typedef struct { + int nodeId; //store this nodeId + unsigned long uptime; //uptime in ms + float temp; //temperature maybe? +} Payload; +Payload theData; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); + //radio.setHighPower(); //uncomment only for RFM69HW! + radio.encrypt(KEY); + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + + if (flash.initialize()) + Serial.println("SPI Flash Init OK!"); + else + Serial.println("SPI Flash Init FAIL! (is chip present?)"); +} + +long lastPeriod = -1; +void loop() { + //process any serial input + if (Serial.available() > 0) + { + char input = Serial.read(); + if (input >= 48 && input <= 57) //[0,9] + { + TRANSMITPERIOD = 100 * (input-48); + if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000; + Serial.print("\nChanging delay to "); + Serial.print(TRANSMITPERIOD); + Serial.println("ms\n"); + } + + if (input == 'r') //d=dump register values + radio.readAllRegs(); + //if (input == 'E') //E=enable encryption + // radio.encrypt(KEY); + //if (input == 'e') //e=disable encryption + // radio.encrypt(null); + + if (input == 'd') //d=dump flash area + { + Serial.println("Flash content:"); + int counter = 0; + + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + while(flash.busy()); + Serial.println(); + } + if (input == 'e') + { + Serial.print("Erasing Flash chip ... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + if (input == 'i') + { + Serial.print("DeviceID: "); + word jedecid = flash.readDeviceId(); + Serial.println(jedecid, HEX); + } + } + + //check for any received packets + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i]); + Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]"); + + if (radio.ACKRequested()) + { + radio.sendACK(); + Serial.print(" - ACK sent"); + delay(10); + } + Blink(LED,5); + Serial.println(); + } + + int currPeriod = millis()/TRANSMITPERIOD; + if (currPeriod != lastPeriod) + { + //fill in the struct with new values + theData.nodeId = NODEID; + theData.uptime = millis(); + theData.temp = 91.23; //it's hot! + + Serial.print("Sending struct ("); + Serial.print(sizeof(theData)); + Serial.print(" bytes) ... "); + if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData))) + Serial.print(" ok!"); + else Serial.print(" nothing..."); + Serial.println(); + Blink(LED,3); + lastPeriod=currPeriod; + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} diff --git a/lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino b/lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino new file mode 100644 index 0000000..05b038b --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/TxRxBlinky/TxRxBlinky.ino @@ -0,0 +1,191 @@ +// *************************************************************************************** +// Sample RFM69 sketch for Moteino to illustrate sending and receiving, button interrupts +// *************************************************************************************** +// When you press the button on the SENDER Moteino, it will send a short message to the +// RECEIVER Moteino and wait for an ACK (acknowledgement that message was received) from +// the RECEIVER Moteino. If the ACK was received, the SENDER will blink the onboard LED +// a few times. The RECEIVER listens to a specific token, and it alternates the onboard LED +// state from HIGH to LOW or vice versa whenever this token is received. +// *************************************************************************************** +// Hardware setup: +// *************************************************************************************** +// On the sender, hook up a momentary tactile button to D3 like this: +// __-__ +// __| |___ +// GND ----> BTN ----> D3 (D11 on MoteinoMEGA) +// Load this sketch on the RECEIVER with NODEID=RECEIVER (adjust in config section below) +// Load this sketch on the SENDER with NODEID=SENDER (adjust in config section below) +// RFM69 library and code by Felix Rusu - felix@lowpowerlab.com +// Get libraries at: https://github.com/LowPowerLab/ +// Make sure you adjust the settings in the configuration section below !!! +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get library from: https://github.com/lowpowerlab/lowpower + +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NETWORKID 100 //the same on all nodes that talk to each other +#define RECEIVER 1 //unique ID of the gateway/receiver +#define SENDER 2 +#define NODEID RECEIVER //change to "SENDER" if this is the sender node (the one with the button) +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W! +//********************************************************************************************* +#define SERIAL_BAUD 115200 +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define BUTTON_INT 1 //user button on interrupt 1 (D3) + #define BUTTON_PIN 11 //user button on interrupt 1 (D3) +#else + #define LED 9 // Moteinos have LEDs on D9 + #define BUTTON_INT 1 //user button on interrupt 1 (D3) + #define BUTTON_PIN 3 //user button on interrupt 1 (D3) +#endif + +#define LED_GREEN 4 //GREEN LED on the SENDER +#define LED_RED 5 //RED LED on the SENDER +#define RX_TOGGLE_PIN 7 //GPIO to toggle on the RECEIVER + +RFM69 radio; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + Serial.flush(); + pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(LED, OUTPUT); + attachInterrupt(BUTTON_INT, handleButton, FALLING); + + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_RED, OUTPUT); + pinMode(RX_TOGGLE_PIN, OUTPUT); + digitalWrite(LED_GREEN, LOW); + digitalWrite(LED_RED, HIGH); +} + +//******** THIS IS INTERRUPT BASED DEBOUNCING FOR BUTTON ATTACHED TO D3 (INTERRUPT 1) +#define FLAG_INTERRUPT 0x01 +volatile int mainEventFlags = 0; +boolean buttonPressed = false; +void handleButton() +{ + mainEventFlags |= FLAG_INTERRUPT; +} + +byte LEDSTATE=LOW; //LOW=0 +void loop() { + //******** THIS IS INTERRUPT BASED DEBOUNCING FOR BUTTON ATTACHED TO D3 (INTERRUPT 1) + if (mainEventFlags & FLAG_INTERRUPT) + { + LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_ON); + mainEventFlags &= ~FLAG_INTERRUPT; + if (!digitalRead(BUTTON_PIN)) { + buttonPressed=true; + } + } + + if (buttonPressed) + { + Serial.println("Button pressed!"); + buttonPressed = false; + + if(LEDSTATE==LOW) + { + LEDSTATE=HIGH; + digitalWrite(LED_GREEN, HIGH); + digitalWrite(LED_RED, LOW); + } + else + { + LEDSTATE=LOW; + digitalWrite(LED_GREEN, LOW); + digitalWrite(LED_RED, HIGH); + } + + if (radio.sendWithRetry(RECEIVER, "Hi", 2)) //target node Id, message as string or byte array, message length + Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks + } + + //check if something was received (could be an interrupt from the radio) + if (radio.receiveDone()) + { + //print message received to serial + Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] "); + Serial.print((char*)radio.DATA); + Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + Serial.println(); + + //check if received message is 2 bytes long, and check if the message is specifically "Hi" + if (radio.DATALEN==2 && radio.DATA[0]=='H' && radio.DATA[1]=='i') + { + if(LEDSTATE==LOW) + LEDSTATE=HIGH; + else LEDSTATE=LOW; + digitalWrite(LED, LEDSTATE); + digitalWrite(RX_TOGGLE_PIN, LEDSTATE); + } + + //check if sender wanted an ACK + if (radio.ACKRequested()) + { + radio.sendACK(); + Serial.print(" - ACK sent"); + } + } + + radio.receiveDone(); //put radio in RX mode + Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON); //sleep Moteino in low power mode (to save battery) +} + +void Blink(byte PIN, byte DELAY_MS, byte loops) +{ + for (byte i=0; i. +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get it here: https://www.github.com/lowpowerlab/spiflash +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming/tree/master/WirelessHEX69 + +#define NODEID 254 //this node's ID, should be unique among nodes on this NETWORKID +#define NETWORKID 250 //what network this node is on +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +#define ENCRYPTKEY "sampleEncryptKey" //(16 bytes of your choice - keep the same on all encrypted nodes) +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! + +#define SERIAL_BAUD 115200 +#define ACK_TIME 50 // # of ms to wait for an ack +#define TIMEOUT 3000 + +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 +#else + #define LED 9 // Moteinos hsave LEDs on D9 +#endif + +RFM69 radio; +char c = 0; +char input[64]; //serial input buffer +byte targetID=0; + +void setup(){ + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); + radio.encrypt(ENCRYPTKEY); //OPTIONAL +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + Serial.println("Start wireless gateway..."); +} + +void loop(){ + byte inputLen = readSerialLine(input, 10, 64, 100); //readSerialLine(char* input, char endOfLineChar=10, byte maxLength=64, uint16_t timeout=1000); + + if (inputLen==4 && input[0]=='F' && input[1]=='L' && input[2]=='X' && input[3]=='?') { + if (targetID==0) + Serial.println("TO?"); + else + CheckForSerialHEX((byte*)input, inputLen, radio, targetID, TIMEOUT, ACK_TIME, true); + } + else if (inputLen>3 && inputLen<=6 && input[0]=='T' && input[1]=='O' && input[2]==':') + { + byte newTarget=0; + for (byte i = 3; i=48 && input[i]<=57) + newTarget = newTarget*10+input[i]-48; + else + { + newTarget=0; + break; + } + if (newTarget>0) + { + targetID = newTarget; + Serial.print("TO:"); + Serial.print(newTarget); + Serial.println(":OK"); + } + else + { + Serial.print(input); + Serial.print(":INV"); + } + } + else if (inputLen>0) { //just echo back + Serial.print("SERIAL IN > ");Serial.println(input); + } + + if (radio.receiveDone()) + { + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i]); + + if (radio.ACK_REQUESTED) + { + radio.sendACK(); + Serial.print(" - ACK sent"); + } + + Serial.println(); + } + Blink(LED,5); //heartbeat +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/Examples/WirelessProgramming_node/WirelessProgramming_node.ino b/lib-ext/rfm-69.git/Examples/WirelessProgramming_node/WirelessProgramming_node.ino new file mode 100644 index 0000000..267c677 --- /dev/null +++ b/lib-ext/rfm-69.git/Examples/WirelessProgramming_node/WirelessProgramming_node.ino @@ -0,0 +1,167 @@ +// ********************************************************************************** +// This sketch is an example of how wireless programming can be achieved with a Moteino +// that was loaded with a custom 1k bootloader (DualOptiboot) that is capable of loading +// a new sketch from an external SPI flash chip +// The sketch includes logic to receive the new sketch 'over-the-air' and store it in +// the FLASH chip, then restart the Moteino so the bootloader can continue the job of +// actually reflashing the internal flash memory from the external FLASH memory chip flash image +// The handshake protocol that receives the sketch wirelessly by means of the RFM69 radio +// is handled by the SPIFLash/WirelessHEX69 library, which also relies on the RFM69 library +// These libraries and custom 1k Optiboot bootloader are at: http://github.com/lowpowerlab +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get it here: https://www.github.com/lowpowerlab/spiflash +#include +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming/tree/master/WirelessHEX69 + +#define NODEID 123 // node ID used for this unit +#define NETWORKID 250 +//Match frequency to the hardware version of the radio on your Moteino (uncomment one): +//#define FREQUENCY RF69_433MHZ +//#define FREQUENCY RF69_868MHZ +#define FREQUENCY RF69_915MHZ +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define SERIAL_BAUD 115200 +#define ACK_TIME 30 // # of ms to wait for an ack +#define ENCRYPTKEY "sampleEncryptKey" //(16 bytes of your choice - keep the same on all encrypted nodes) +#define BLINKPERIOD 500 + +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define FLASH_SS 23 // and FLASH SS on D23 +#else + #define LED 9 // Moteinos hsave LEDs on D9 + #define FLASH_SS 8 // and FLASH SS on D8 +#endif + +RFM69 radio; +char input = 0; +long lastPeriod = -1; + +///////////////////////////////////////////////////////////////////////////// +// flash(SPI_CS, MANUFACTURER_ID) +// SPI_CS - CS pin attached to SPI flash chip (8 in case of Moteino) +// MANUFACTURER_ID - OPTIONAL, 0x1F44 for adesto(ex atmel) 4mbit flash +// 0xEF30 for windbond 4mbit flash +// 0xEF40 for windbond 16/64mbit flash +///////////////////////////////////////////////////////////////////////////// +SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for windbond 4mbit flash + +void setup(){ + pinMode(LED, OUTPUT); + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); + radio.encrypt(ENCRYPTKEY); //OPTIONAL +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + Serial.print("Start node..."); + + if (flash.initialize()) + Serial.println("SPI Flash Init OK!"); + else + Serial.println("SPI Flash Init FAIL!"); +} + +void loop(){ + // This part is optional, useful for some debugging. + // Handle serial input (to allow basic DEBUGGING of FLASH chip) + // ie: display first 256 bytes in FLASH, erase chip, write bytes at first 10 positions, etc + if (Serial.available() > 0) { + input = Serial.read(); + if (input == 'd') //d=dump first page + { + Serial.println("Flash content:"); + int counter = 0; + + while(counter<=256){ + Serial.print(flash.readByte(counter++), HEX); + Serial.print('.'); + } + + Serial.println(); + } + else if (input == 'e') + { + Serial.print("Erasing Flash chip ... "); + flash.chipErase(); + while(flash.busy()); + Serial.println("DONE"); + } + else if (input == 'i') + { + Serial.print("DeviceID: "); + Serial.println(flash.readDeviceId(), HEX); + } + else if (input == 'r') + { + Serial.print("Rebooting"); + resetUsingWatchdog(true); + } + else if (input == 'R') + { + Serial.print("RFM69 registers:"); + radio.readAllRegs(); + } + else if (input >= 48 && input <= 57) //0-9 + { + Serial.print("\nWriteByte("); Serial.print(input); Serial.print(")"); + flash.writeByte(input-48, millis()%2 ? 0xaa : 0xbb); + } + } + + // Check for existing RF data, potentially for a new sketch wireless upload + // For this to work this check has to be done often enough to be + // picked up when a GATEWAY is trying hard to reach this node for a new sketch wireless upload + if (radio.receiveDone()) + { + Serial.print("Got ["); + Serial.print(radio.SENDERID); + Serial.print(':'); + Serial.print(radio.DATALEN); + Serial.print("] > "); + for (byte i = 0; i < radio.DATALEN; i++) + Serial.print((char)radio.DATA[i], HEX); + Serial.println(); + CheckForWirelessHEX(radio, flash, true); + Serial.println(); + } + //else Serial.print('.'); + + //////////////////////////////////////////////////////////////////////////////////////////// + // Real sketch code here, let's blink the onboard LED + if ((int)(millis()/BLINKPERIOD) > lastPeriod) + { + lastPeriod++; + digitalWrite(LED, lastPeriod%2); + } + //////////////////////////////////////////////////////////////////////////////////////////// +} \ No newline at end of file diff --git a/lib-ext/rfm-69.git/License.txt b/lib-ext/rfm-69.git/License.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib-ext/rfm-69.git/License.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib-ext/rfm-69.git/README.md b/lib-ext/rfm-69.git/README.md new file mode 100644 index 0000000..7d563ee --- /dev/null +++ b/lib-ext/rfm-69.git/README.md @@ -0,0 +1,60 @@ +RFM69 Library +---------------- +By Felix Rusu (felix@lowpowerlab.com) +
+RFM69 library for RFM69W, RFM69HW, RFM69CW, RFM69HCW (semtech SX1231, SX1231H) + +##License +GPL 3.0, please see the License.txt file + + +##Features +Among others, this is a set of features implemented in this library: + +- easy to use API with a few simple functions for basic usage +- 255 possible nodes on 256 possible networks +- 61 bytes max message length (limited to 61 to support AES hardware encryption) +- customizable transmit power (32 levels) for low-power transmission control +- sleep function for power saving +- automatic ACKs with the sendWithRetry() function +- hardware 128bit AES encryption +- hardware preamble, synch recognition and CRC check +- digital RSSI can be read at any time with readRSSI() +- interrupt driven +- tested on [Moteino R3, R4, R4-USB (ATMega328p)](http://lowpowerlab.com/shop/Moteino-R4) +- works with RFM69W, RFM69HW, RFM69CW, RFM69HCW, Semtech SX1231/SX1231H transceivers +- promiscuous mode allows any node to listen to any packet on same network + +I consider this an initial beta release, it could contain bugs, but the provided Gateway and Node examples should work out of the box. Please let me know if you find issues. + +###Installation +Copy the content of this library in the "Arduino/libraries/RFM69" folder. +
+To find your Arduino folder go to File>Preferences in the Arduino IDE. +
+See [this tutorial](http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries) on Arduino libraries. + +###MISC / possible issues +- The library and examples are continuously improved as bugs and stability issues are discovered. Be sure to check back often for changes. +- Moteino boards are loaded with fuses that will delay startup. This means that other boards like Duemilanove/UNO might need a delay() in the setup() function before doing anything - to allow the transceiver to power up. + +###Sample usage +- [Node](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Node/Node.ino) +- [Gateway](https://github.com/LowPowerLab/RFM69/blob/master/Examples/Gateway/Gateway.ino) + +##Blog writeup +http://lowpowerlab.com/blog/2013/06/20/rfm69-library/ + +##Why +- I have spent a lot of time developing this library for RFM69W/HW transceivers. I made it open source because I believe a lot of people can benefit from this new powerful transceiver. I hope people will also contribute and build on my work +- I have long researched alternative transceivers for RFM12B which is still an excellent transceiver but it is much lower output power and has limited built in features which need to be implemented in firmware (PREAMBLE, SYNC, CRC, packet engine, encryption etc). +- I wanted a transceiver that could still be very small, easy to use, but have the longer range that I wanted +- RFM69 comes in 2 variants that have the same layout/connections: RFM69W (13dBm, 45mA TX) and RFM69HW (20dBm, 130mA TX) + +##RFM69W range +- I have tested open-air range on these transceivers (the W only) in various combinations. +- I am happy to say that a range of upwards of 350m can be achieved. I went to local parks and in very large parking spaces and I ran out of space, so more than 350m is possible. Some users reported upwards of 500m by lowering the bitrate, and a forum user reported 1.5miles at 1.2Kbps: see http://lowpowerlab.com/forum/index.php/topic,112.msg288.html and http://lowpowerlab.com/moteino/#antennas +- The caveat with these higher RF power units is that they need more DC power when they transmit. For battery powered motes, you will need to keep them powered down and only transmit periodically. Use the sleep() function to put the radios in low power mode and use the [LowPower](https://github.com/rocketscream/Low-Power) or [Narcoleptic](https://code.google.com/p/narcoleptic/) libraries to power down your arduino + +##License +GPL 3.0. See License.txt file. diff --git a/lib-ext/rfm-69.git/RFM69.cpp b/lib-ext/rfm-69.git/RFM69.cpp new file mode 100644 index 0000000..b63b00c --- /dev/null +++ b/lib-ext/rfm-69.git/RFM69.cpp @@ -0,0 +1,498 @@ +// ********************************************************************************** +// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#include +#include +#include + +volatile uint8_t RFM69::DATA[RF69_MAX_DATA_LEN]; +volatile uint8_t RFM69::_mode; // current transceiver state +volatile uint8_t RFM69::DATALEN; +volatile uint8_t RFM69::SENDERID; +volatile uint8_t RFM69::TARGETID; // should match _address +volatile uint8_t RFM69::PAYLOADLEN; +volatile uint8_t RFM69::ACK_REQUESTED; +volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request +volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception) +RFM69* RFM69::selfPointer; + +bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) +{ + const uint8_t CONFIG[][2] = + { + /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, + /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping + /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS + /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, + /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) + /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, + + /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, + /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, + /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, + + // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm + // +17dBm and +20dBm are possible on RFM69HW + // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**) + // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)** + // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) + ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, + ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA) + + // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz) + /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw) + //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, + /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using + /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving + /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset + /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm + ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA + /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, + /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib + /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID + /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, + /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX + ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering + /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty + /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0 + {255, 0} + }; + + digitalWrite(_slaveSelectPin, HIGH); + pinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + + do writeReg(REG_SYNCVALUE1, 0xAA); while (readReg(REG_SYNCVALUE1) != 0xAA); + do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55); + + for (uint8_t i = 0; CONFIG[i][0] != 255; i++) + writeReg(CONFIG[i][0], CONFIG[i][1]); + + // Encryption is persistent between resets and can trip you up during debugging. + // Disable it during initialization so we always start from a known state. + encrypt(0); + + setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW + setMode(RF69_MODE_STANDBY); + while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady + attachInterrupt(_interruptNum, RFM69::isr0, RISING); + + selfPointer = this; + _address = nodeID; + return true; +} + +// return the frequency (in Hz) +uint32_t RFM69::getFrequency() +{ + return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg(REG_FRFMID) << 8) + readReg(REG_FRFLSB)); +} + +// set the frequency (in Hz) +void RFM69::setFrequency(uint32_t freqHz) +{ + uint8_t oldMode = _mode; + if (oldMode == RF69_MODE_TX) { + setMode(RF69_MODE_RX); + } + freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF + writeReg(REG_FRFMSB, freqHz >> 16); + writeReg(REG_FRFMID, freqHz >> 8); + writeReg(REG_FRFLSB, freqHz); + if (oldMode == RF69_MODE_RX) { + setMode(RF69_MODE_SYNTH); + } + setMode(oldMode); +} + +void RFM69::setMode(uint8_t newMode) +{ + if (newMode == _mode) + return; + + switch (newMode) { + case RF69_MODE_TX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); + if (_isRFM69HW) setHighPowerRegs(true); + break; + case RF69_MODE_RX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); + if (_isRFM69HW) setHighPowerRegs(false); + break; + case RF69_MODE_SYNTH: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); + break; + case RF69_MODE_STANDBY: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY); + break; + case RF69_MODE_SLEEP: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP); + break; + default: + return; + } + + // we are using packet mode, so this check is not really needed + // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode + while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady + + _mode = newMode; +} + +void RFM69::sleep() { + setMode(RF69_MODE_SLEEP); +} + +void RFM69::setAddress(uint8_t addr) +{ + _address = addr; + writeReg(REG_NODEADRS, _address); +} + +void RFM69::setNetwork(uint8_t networkID) +{ + writeReg(REG_SYNCVALUE2, networkID); +} + +// set output power: 0 = min, 31 = max +// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver +void RFM69::setPowerLevel(uint8_t powerLevel) +{ + _powerLevel = powerLevel; + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel)); +} + +bool RFM69::canSend() +{ + if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) // if signal stronger than -100dBm is detected assume channel activity + { + setMode(RF69_MODE_STANDBY); + return true; + } + return false; +} + +void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK) +{ + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + uint32_t now = millis(); + while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone(); + sendFrame(toAddress, buffer, bufferSize, requestACK, false); +} + +// to increase the chance of getting a packet across, call this function instead of send +// and it handles all the ACK requesting/retrying for you :) +// The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs +// The reason for the semi-automaton is that the lib is interrupt driven and +// requires user action to read the received data and decide what to do with it +// replies usually take only 5..8ms at 50kbps@915MHz +bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) { + uint32_t sentTime; + for (uint8_t i = 0; i <= retries; i++) + { + send(toAddress, buffer, bufferSize, true); + sentTime = millis(); + while (millis() - sentTime < retryWaitTime) + { + if (ACKReceived(toAddress)) + { + //Serial.print(" ~ms:"); Serial.print(millis() - sentTime); + return true; + } + } + //Serial.print(" RETRY#"); Serial.println(i + 1); + } + return false; +} + +// should be polled immediately after sending a packet with ACK request +bool RFM69::ACKReceived(uint8_t fromNodeID) { + if (receiveDone()) + return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED; + return false; +} + +// check whether an ACK was requested in the last received packet (non-broadcasted packet) +bool RFM69::ACKRequested() { + return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR); +} + +// should be called immediately after reception in case sender wants ACK +void RFM69::sendACK(const void* buffer, uint8_t bufferSize) { + uint8_t sender = SENDERID; + int16_t _RSSI = RSSI; // save payload received RSSI value + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + uint32_t now = millis(); + while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone(); + sendFrame(sender, buffer, bufferSize, false, true); + RSSI = _RSSI; // restore payload RSSI +} + +void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK) +{ + setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo + while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady + writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent" + if (bufferSize > RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN; + + // control byte + uint8_t CTLbyte = 0x00; + if (sendACK) + CTLbyte = 0x80; + else if (requestACK) + CTLbyte = 0x40; + + // write to FIFO + select(); + SPI.transfer(REG_FIFO | 0x80); + SPI.transfer(bufferSize + 3); + SPI.transfer(toAddress); + SPI.transfer(_address); + SPI.transfer(CTLbyte); + + for (uint8_t i = 0; i < bufferSize; i++) + SPI.transfer(((uint8_t*) buffer)[i]); + unselect(); + + // no need to wait for transmit mode to be ready since its handled by the radio + setMode(RF69_MODE_TX); + uint32_t txStart = millis(); + while (digitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish + //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady + setMode(RF69_MODE_STANDBY); +} + +void RFM69::interruptHandler() { + //pinMode(4, OUTPUT); + //digitalWrite(4, 1); + if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) + { + //RSSI = readRSSI(); + setMode(RF69_MODE_STANDBY); + select(); + SPI.transfer(REG_FIFO & 0x7F); + PAYLOADLEN = SPI.transfer(0); + PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution + TARGETID = SPI.transfer(0); + if(!(_promiscuousMode || TARGETID == _address || TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode + || PAYLOADLEN < 3) // address situation could receive packets that are malformed and don't fit this libraries extra fields + { + PAYLOADLEN = 0; + unselect(); + receiveBegin(); + //digitalWrite(4, 0); + return; + } + + DATALEN = PAYLOADLEN - 3; + SENDERID = SPI.transfer(0); + uint8_t CTLbyte = SPI.transfer(0); + + ACK_RECEIVED = CTLbyte & 0x80; // extract ACK-received flag + ACK_REQUESTED = CTLbyte & 0x40; // extract ACK-requested flag + + for (uint8_t i = 0; i < DATALEN; i++) + { + DATA[i] = SPI.transfer(0); + } + if (DATALEN < RF69_MAX_DATA_LEN) DATA[DATALEN] = 0; // add null at end of string + unselect(); + setMode(RF69_MODE_RX); + } + RSSI = readRSSI(); + //digitalWrite(4, 0); +} + +void RFM69::isr0() { selfPointer->interruptHandler(); } + +void RFM69::receiveBegin() { + DATALEN = 0; + SENDERID = 0; + TARGETID = 0; + PAYLOADLEN = 0; + ACK_REQUESTED = 0; + ACK_RECEIVED = 0; + RSSI = 0; + if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode + setMode(RF69_MODE_RX); +} + +bool RFM69::receiveDone() { +//ATOMIC_BLOCK(ATOMIC_FORCEON) +//{ + noInterrupts(); // re-enabled in unselect() via setMode() or via receiveBegin() + if (_mode == RF69_MODE_RX && PAYLOADLEN > 0) + { + setMode(RF69_MODE_STANDBY); // enables interrupts + return true; + } + else if (_mode == RF69_MODE_RX) // already in RX no payload yet + { + interrupts(); // explicitly re-enable interrupts + return false; + } + receiveBegin(); + return false; +//} +} + +// To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP"); +// To disable encryption: radio.encrypt(null) or radio.encrypt(0) +// KEY HAS TO BE 16 bytes !!! +void RFM69::encrypt(const char* key) { + setMode(RF69_MODE_STANDBY); + if (key != 0) + { + select(); + SPI.transfer(REG_AESKEY1 | 0x80); + for (uint8_t i = 0; i < 16; i++) + SPI.transfer(key[i]); + unselect(); + } + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); +} + +int16_t RFM69::readRSSI(bool forceTrigger) { + int16_t rssi = 0; + if (forceTrigger) + { + // RSSI trigger not needed if DAGC is in continuous mode + writeReg(REG_RSSICONFIG, RF_RSSI_START); + while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // wait for RSSI_Ready + } + rssi = -readReg(REG_RSSIVALUE); + rssi >>= 1; + return rssi; +} + +uint8_t RFM69::readReg(uint8_t addr) +{ + select(); + SPI.transfer(addr & 0x7F); + uint8_t regval = SPI.transfer(0); + unselect(); + return regval; +} + +void RFM69::writeReg(uint8_t addr, uint8_t value) +{ + select(); + SPI.transfer(addr | 0x80); + SPI.transfer(value); + unselect(); +} + +// select the transceiver +void RFM69::select() { + noInterrupts(); + // save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + // set RFM69 SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + digitalWrite(_slaveSelectPin, LOW); +} + +// UNselect the transceiver chip +void RFM69::unselect() { + digitalWrite(_slaveSelectPin, HIGH); + // restore SPI settings to what they were before talking to RFM69 + SPCR = _SPCR; + SPSR = _SPSR; + interrupts(); +} + +// ON = disable filtering to capture all frames on network +// OFF = enable node/broadcast filtering to capture only frames sent to this/broadcast address +void RFM69::promiscuous(bool onOff) { + _promiscuousMode = onOff; + //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST)); +} + +void RFM69::setHighPower(bool onOff) { + _isRFM69HW = onOff; + writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); + if (_isRFM69HW) // turning ON + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages + else + writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only +} + +void RFM69::setHighPowerRegs(bool onOff) { + writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55); + writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); +} + +void RFM69::setCS(uint8_t newSPISlaveSelect) { + _slaveSelectPin = newSPISlaveSelect; + digitalWrite(_slaveSelectPin, HIGH); + pinMode(_slaveSelectPin, OUTPUT); +} + +// for debugging +void RFM69::readAllRegs() +{ + uint8_t regVal; + + for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) + { + select(); + SPI.transfer(regAddr & 0x7F); // send address + r/w bit + regVal = SPI.transfer(0); + unselect(); + + Serial.print(regAddr, HEX); + Serial.print(" - "); + Serial.print(regVal,HEX); + Serial.print(" - "); + Serial.println(regVal,BIN); + } + unselect(); +} + +uint8_t RFM69::readTemperature(uint8_t calFactor) // returns centigrade +{ + setMode(RF69_MODE_STANDBY); + writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); + while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)); + return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val +} // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction + +void RFM69::rcCalibration() +{ + writeReg(REG_OSC1, RF_OSC1_RCCAL_START); + while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); +} diff --git a/lib-ext/rfm-69.git/RFM69.h b/lib-ext/rfm-69.git/RFM69.h new file mode 100644 index 0000000..7e49c68 --- /dev/null +++ b/lib-ext/rfm-69.git/RFM69.h @@ -0,0 +1,143 @@ +// ********************************************************************************** +// Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2014), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program. +// If not, see . +// +// Licence can be viewed at +// http://www.gnu.org/licenses/gpl-3.0.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +#ifndef RFM69_h +#define RFM69_h +#include // assumes Arduino IDE v1.0 or greater + +#define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc) +#define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on ATmega328 + +// INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2) +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 0 +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + #define RF69_IRQ_PIN 2 + #define RF69_IRQ_NUM 2 +#elif defined(__AVR_ATmega32U4__) + #define RF69_IRQ_PIN 3 + #define RF69_IRQ_NUM 0 +#endif + + +#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access +#define RF69_MODE_SLEEP 0 // XTAL OFF +#define RF69_MODE_STANDBY 1 // XTAL ON +#define RF69_MODE_SYNTH 2 // PLL ON +#define RF69_MODE_RX 3 // RX MODE +#define RF69_MODE_TX 4 // TX MODE + +// available frequency bands +#define RF69_315MHZ 31 // non trivial values to avoid misconfiguration +#define RF69_433MHZ 43 +#define RF69_868MHZ 86 +#define RF69_915MHZ 91 + +#define null 0 +#define COURSE_TEMP_COEF -90 // puts the temperature reading in the ballpark, user can fine tune the returned value +#define RF69_BROADCAST_ADDR 255 +#define RF69_CSMA_LIMIT_MS 1000 +#define RF69_TX_LIMIT_MS 1000 +#define RF69_FSTEP 61.03515625 // == FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet) + +class RFM69 { + public: + static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; // recv/xmit buf, including header & crc bytes + static volatile uint8_t DATALEN; + static volatile uint8_t SENDERID; + static volatile uint8_t TARGETID; // should match _address + static volatile uint8_t PAYLOADLEN; + static volatile uint8_t ACK_REQUESTED; + static volatile uint8_t ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request + static volatile int16_t RSSI; // most accurate RSSI during reception (closest to the reception) + static volatile uint8_t _mode; // should be protected? + + RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM) { + _slaveSelectPin = slaveSelectPin; + _interruptPin = interruptPin; + _interruptNum = interruptNum; + _mode = RF69_MODE_STANDBY; + _promiscuousMode = false; + _powerLevel = 31; + _isRFM69HW = isRFM69HW; + } + + bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); + void setAddress(uint8_t addr); + void setNetwork(uint8_t networkID); + bool canSend(); + void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false); + bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); // 40ms roundtrip req for 61byte packets + bool receiveDone(); + bool ACKReceived(uint8_t fromNodeID); + bool ACKRequested(); + void sendACK(const void* buffer = "", uint8_t bufferSize=0); + uint32_t getFrequency(); + void setFrequency(uint32_t freqHz); + void encrypt(const char* key); + void setCS(uint8_t newSPISlaveSelect); + int16_t readRSSI(bool forceTrigger=false); + void promiscuous(bool onOff=true); + void setHighPower(bool onOFF=true); // has to be called after initialize() for RFM69HW + void setPowerLevel(uint8_t level); // reduce/increase transmit power level + void sleep(); + uint8_t readTemperature(uint8_t calFactor=0); // get CMOS temperature (8bit) + void rcCalibration(); // calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy] + + // allow hacking registers by making these public + uint8_t readReg(uint8_t addr); + void writeReg(uint8_t addr, uint8_t val); + void readAllRegs(); + + protected: + static void isr0(); + void virtual interruptHandler(); + void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); + + static RFM69* selfPointer; + uint8_t _slaveSelectPin; + uint8_t _interruptPin; + uint8_t _interruptNum; + uint8_t _address; + bool _promiscuousMode; + uint8_t _powerLevel; + bool _isRFM69HW; + uint8_t _SPCR; + uint8_t _SPSR; + + void receiveBegin(); + void setMode(uint8_t mode); + void setHighPowerRegs(bool onOff); + void select(); + void unselect(); +}; + +#endif diff --git a/lib-ext/rfm-69.git/RFM69registers.h b/lib-ext/rfm-69.git/RFM69registers.h new file mode 100644 index 0000000..2d815ec --- /dev/null +++ b/lib-ext/rfm-69.git/RFM69registers.h @@ -0,0 +1,1109 @@ +// ********************************************************************************** +// Registers used in driver definition for HopeRF RFM69W/RFM69HW, Semtech SX1231/1231H +// ********************************************************************************** +// Copyright Felix Rusu (2015), felix@lowpowerlab.com +// http://lowpowerlab.com/ +// ********************************************************************************** +// License +// ********************************************************************************** +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will +// be useful, but WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A +// PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// ********************************************************************************** +// RFM69/SX1231 Internal registers addresses +//************************************************** +#define REG_FIFO 0x00 +#define REG_OPMODE 0x01 +#define REG_DATAMODUL 0x02 +#define REG_BITRATEMSB 0x03 +#define REG_BITRATELSB 0x04 +#define REG_FDEVMSB 0x05 +#define REG_FDEVLSB 0x06 +#define REG_FRFMSB 0x07 +#define REG_FRFMID 0x08 +#define REG_FRFLSB 0x09 +#define REG_OSC1 0x0A +#define REG_AFCCTRL 0x0B +#define REG_LOWBAT 0x0C +#define REG_LISTEN1 0x0D +#define REG_LISTEN2 0x0E +#define REG_LISTEN3 0x0F +#define REG_VERSION 0x10 +#define REG_PALEVEL 0x11 +#define REG_PARAMP 0x12 +#define REG_OCP 0x13 +#define REG_AGCREF 0x14 // not present on RFM69/SX1231 +#define REG_AGCTHRESH1 0x15 // not present on RFM69/SX1231 +#define REG_AGCTHRESH2 0x16 // not present on RFM69/SX1231 +#define REG_AGCTHRESH3 0x17 // not present on RFM69/SX1231 +#define REG_LNA 0x18 +#define REG_RXBW 0x19 +#define REG_AFCBW 0x1A +#define REG_OOKPEAK 0x1B +#define REG_OOKAVG 0x1C +#define REG_OOKFIX 0x1D +#define REG_AFCFEI 0x1E +#define REG_AFCMSB 0x1F +#define REG_AFCLSB 0x20 +#define REG_FEIMSB 0x21 +#define REG_FEILSB 0x22 +#define REG_RSSICONFIG 0x23 +#define REG_RSSIVALUE 0x24 +#define REG_DIOMAPPING1 0x25 +#define REG_DIOMAPPING2 0x26 +#define REG_IRQFLAGS1 0x27 +#define REG_IRQFLAGS2 0x28 +#define REG_RSSITHRESH 0x29 +#define REG_RXTIMEOUT1 0x2A +#define REG_RXTIMEOUT2 0x2B +#define REG_PREAMBLEMSB 0x2C +#define REG_PREAMBLELSB 0x2D +#define REG_SYNCCONFIG 0x2E +#define REG_SYNCVALUE1 0x2F +#define REG_SYNCVALUE2 0x30 +#define REG_SYNCVALUE3 0x31 +#define REG_SYNCVALUE4 0x32 +#define REG_SYNCVALUE5 0x33 +#define REG_SYNCVALUE6 0x34 +#define REG_SYNCVALUE7 0x35 +#define REG_SYNCVALUE8 0x36 +#define REG_PACKETCONFIG1 0x37 +#define REG_PAYLOADLENGTH 0x38 +#define REG_NODEADRS 0x39 +#define REG_BROADCASTADRS 0x3A +#define REG_AUTOMODES 0x3B +#define REG_FIFOTHRESH 0x3C +#define REG_PACKETCONFIG2 0x3D +#define REG_AESKEY1 0x3E +#define REG_AESKEY2 0x3F +#define REG_AESKEY3 0x40 +#define REG_AESKEY4 0x41 +#define REG_AESKEY5 0x42 +#define REG_AESKEY6 0x43 +#define REG_AESKEY7 0x44 +#define REG_AESKEY8 0x45 +#define REG_AESKEY9 0x46 +#define REG_AESKEY10 0x47 +#define REG_AESKEY11 0x48 +#define REG_AESKEY12 0x49 +#define REG_AESKEY13 0x4A +#define REG_AESKEY14 0x4B +#define REG_AESKEY15 0x4C +#define REG_AESKEY16 0x4D +#define REG_TEMP1 0x4E +#define REG_TEMP2 0x4F +#define REG_TESTLNA 0x58 +#define REG_TESTPA1 0x5A // only present on RFM69HW/SX1231H +#define REG_TESTPA2 0x5C // only present on RFM69HW/SX1231H +#define REG_TESTDAGC 0x6F + +//****************************************************** +// RF69/SX1231 bit control definition +//****************************************************** + +// RegOpMode +#define RF_OPMODE_SEQUENCER_OFF 0x80 +#define RF_OPMODE_SEQUENCER_ON 0x00 // Default + +#define RF_OPMODE_LISTEN_ON 0x40 +#define RF_OPMODE_LISTEN_OFF 0x00 // Default + +#define RF_OPMODE_LISTENABORT 0x20 + +#define RF_OPMODE_SLEEP 0x00 +#define RF_OPMODE_STANDBY 0x04 // Default +#define RF_OPMODE_SYNTHESIZER 0x08 +#define RF_OPMODE_TRANSMITTER 0x0C +#define RF_OPMODE_RECEIVER 0x10 + + +// RegDataModul +#define RF_DATAMODUL_DATAMODE_PACKET 0x00 // Default +#define RF_DATAMODUL_DATAMODE_CONTINUOUS 0x40 +#define RF_DATAMODUL_DATAMODE_CONTINUOUSNOBSYNC 0x60 + +#define RF_DATAMODUL_MODULATIONTYPE_FSK 0x00 // Default +#define RF_DATAMODUL_MODULATIONTYPE_OOK 0x08 + +#define RF_DATAMODUL_MODULATIONSHAPING_00 0x00 // Default +#define RF_DATAMODUL_MODULATIONSHAPING_01 0x01 +#define RF_DATAMODUL_MODULATIONSHAPING_10 0x02 +#define RF_DATAMODUL_MODULATIONSHAPING_11 0x03 + + +// RegBitRate (bits/sec) example bit rates +#define RF_BITRATEMSB_1200 0x68 +#define RF_BITRATELSB_1200 0x2B +#define RF_BITRATEMSB_2400 0x34 +#define RF_BITRATELSB_2400 0x15 +#define RF_BITRATEMSB_4800 0x1A // Default +#define RF_BITRATELSB_4800 0x0B // Default +#define RF_BITRATEMSB_9600 0x0D +#define RF_BITRATELSB_9600 0x05 +#define RF_BITRATEMSB_19200 0x06 +#define RF_BITRATELSB_19200 0x83 +#define RF_BITRATEMSB_38400 0x03 +#define RF_BITRATELSB_38400 0x41 + +#define RF_BITRATEMSB_38323 0x03 +#define RF_BITRATELSB_38323 0x43 + +#define RF_BITRATEMSB_34482 0x03 +#define RF_BITRATELSB_34482 0xA0 + +#define RF_BITRATEMSB_76800 0x01 +#define RF_BITRATELSB_76800 0xA1 +#define RF_BITRATEMSB_153600 0x00 +#define RF_BITRATELSB_153600 0xD0 +#define RF_BITRATEMSB_57600 0x02 +#define RF_BITRATELSB_57600 0x2C +#define RF_BITRATEMSB_115200 0x01 +#define RF_BITRATELSB_115200 0x16 +#define RF_BITRATEMSB_12500 0x0A +#define RF_BITRATELSB_12500 0x00 +#define RF_BITRATEMSB_25000 0x05 +#define RF_BITRATELSB_25000 0x00 +#define RF_BITRATEMSB_50000 0x02 +#define RF_BITRATELSB_50000 0x80 +#define RF_BITRATEMSB_100000 0x01 +#define RF_BITRATELSB_100000 0x40 +#define RF_BITRATEMSB_150000 0x00 +#define RF_BITRATELSB_150000 0xD5 +#define RF_BITRATEMSB_200000 0x00 +#define RF_BITRATELSB_200000 0xA0 +#define RF_BITRATEMSB_250000 0x00 +#define RF_BITRATELSB_250000 0x80 +#define RF_BITRATEMSB_300000 0x00 +#define RF_BITRATELSB_300000 0x6B +#define RF_BITRATEMSB_32768 0x03 +#define RF_BITRATELSB_32768 0xD1 +// custom bit rates +#define RF_BITRATEMSB_55555 0x02 +#define RF_BITRATELSB_55555 0x40 +#define RF_BITRATEMSB_200KBPS 0x00 +#define RF_BITRATELSB_200KBPS 0xa0 + + +// RegFdev - frequency deviation (Hz) +#define RF_FDEVMSB_2000 0x00 +#define RF_FDEVLSB_2000 0x21 +#define RF_FDEVMSB_5000 0x00 // Default +#define RF_FDEVLSB_5000 0x52 // Default +#define RF_FDEVMSB_7500 0x00 +#define RF_FDEVLSB_7500 0x7B +#define RF_FDEVMSB_10000 0x00 +#define RF_FDEVLSB_10000 0xA4 +#define RF_FDEVMSB_15000 0x00 +#define RF_FDEVLSB_15000 0xF6 +#define RF_FDEVMSB_20000 0x01 +#define RF_FDEVLSB_20000 0x48 +#define RF_FDEVMSB_25000 0x01 +#define RF_FDEVLSB_25000 0x9A +#define RF_FDEVMSB_30000 0x01 +#define RF_FDEVLSB_30000 0xEC +#define RF_FDEVMSB_35000 0x02 +#define RF_FDEVLSB_35000 0x3D +#define RF_FDEVMSB_40000 0x02 +#define RF_FDEVLSB_40000 0x8F +#define RF_FDEVMSB_45000 0x02 +#define RF_FDEVLSB_45000 0xE1 +#define RF_FDEVMSB_50000 0x03 +#define RF_FDEVLSB_50000 0x33 +#define RF_FDEVMSB_55000 0x03 +#define RF_FDEVLSB_55000 0x85 +#define RF_FDEVMSB_60000 0x03 +#define RF_FDEVLSB_60000 0xD7 +#define RF_FDEVMSB_65000 0x04 +#define RF_FDEVLSB_65000 0x29 +#define RF_FDEVMSB_70000 0x04 +#define RF_FDEVLSB_70000 0x7B +#define RF_FDEVMSB_75000 0x04 +#define RF_FDEVLSB_75000 0xCD +#define RF_FDEVMSB_80000 0x05 +#define RF_FDEVLSB_80000 0x1F +#define RF_FDEVMSB_85000 0x05 +#define RF_FDEVLSB_85000 0x71 +#define RF_FDEVMSB_90000 0x05 +#define RF_FDEVLSB_90000 0xC3 +#define RF_FDEVMSB_95000 0x06 +#define RF_FDEVLSB_95000 0x14 +#define RF_FDEVMSB_100000 0x06 +#define RF_FDEVLSB_100000 0x66 +#define RF_FDEVMSB_110000 0x07 +#define RF_FDEVLSB_110000 0x0A +#define RF_FDEVMSB_120000 0x07 +#define RF_FDEVLSB_120000 0xAE +#define RF_FDEVMSB_130000 0x08 +#define RF_FDEVLSB_130000 0x52 +#define RF_FDEVMSB_140000 0x08 +#define RF_FDEVLSB_140000 0xF6 +#define RF_FDEVMSB_150000 0x09 +#define RF_FDEVLSB_150000 0x9A +#define RF_FDEVMSB_160000 0x0A +#define RF_FDEVLSB_160000 0x3D +#define RF_FDEVMSB_170000 0x0A +#define RF_FDEVLSB_170000 0xE1 +#define RF_FDEVMSB_180000 0x0B +#define RF_FDEVLSB_180000 0x85 +#define RF_FDEVMSB_190000 0x0C +#define RF_FDEVLSB_190000 0x29 +#define RF_FDEVMSB_200000 0x0C +#define RF_FDEVLSB_200000 0xCD +#define RF_FDEVMSB_210000 0x0D +#define RF_FDEVLSB_210000 0x71 +#define RF_FDEVMSB_220000 0x0E +#define RF_FDEVLSB_220000 0x14 +#define RF_FDEVMSB_230000 0x0E +#define RF_FDEVLSB_230000 0xB8 +#define RF_FDEVMSB_240000 0x0F +#define RF_FDEVLSB_240000 0x5C +#define RF_FDEVMSB_250000 0x10 +#define RF_FDEVLSB_250000 0x00 +#define RF_FDEVMSB_260000 0x10 +#define RF_FDEVLSB_260000 0xA4 +#define RF_FDEVMSB_270000 0x11 +#define RF_FDEVLSB_270000 0x48 +#define RF_FDEVMSB_280000 0x11 +#define RF_FDEVLSB_280000 0xEC +#define RF_FDEVMSB_290000 0x12 +#define RF_FDEVLSB_290000 0x8F +#define RF_FDEVMSB_300000 0x13 +#define RF_FDEVLSB_300000 0x33 + + +// RegFrf (MHz) - carrier frequency +// 315Mhz band +#define RF_FRFMSB_314 0x4E +#define RF_FRFMID_314 0x80 +#define RF_FRFLSB_314 0x00 +#define RF_FRFMSB_315 0x4E +#define RF_FRFMID_315 0xC0 +#define RF_FRFLSB_315 0x00 +#define RF_FRFMSB_316 0x4F +#define RF_FRFMID_316 0x00 +#define RF_FRFLSB_316 0x00 +// 433mhz band +#define RF_FRFMSB_433 0x6C +#define RF_FRFMID_433 0x40 +#define RF_FRFLSB_433 0x00 +#define RF_FRFMSB_434 0x6C +#define RF_FRFMID_434 0x80 +#define RF_FRFLSB_434 0x00 +#define RF_FRFMSB_435 0x6C +#define RF_FRFMID_435 0xC0 +#define RF_FRFLSB_435 0x00 +// 868Mhz band +#define RF_FRFMSB_863 0xD7 +#define RF_FRFMID_863 0xC0 +#define RF_FRFLSB_863 0x00 +#define RF_FRFMSB_864 0xD8 +#define RF_FRFMID_864 0x00 +#define RF_FRFLSB_864 0x00 +#define RF_FRFMSB_865 0xD8 +#define RF_FRFMID_865 0x40 +#define RF_FRFLSB_865 0x00 +#define RF_FRFMSB_866 0xD8 +#define RF_FRFMID_866 0x80 +#define RF_FRFLSB_866 0x00 +#define RF_FRFMSB_867 0xD8 +#define RF_FRFMID_867 0xC0 +#define RF_FRFLSB_867 0x00 +#define RF_FRFMSB_868 0xD9 +#define RF_FRFMID_868 0x00 +#define RF_FRFLSB_868 0x00 +#define RF_FRFMSB_869 0xD9 +#define RF_FRFMID_869 0x40 +#define RF_FRFLSB_869 0x00 +#define RF_FRFMSB_870 0xD9 +#define RF_FRFMID_870 0x80 +#define RF_FRFLSB_870 0x00 +// 915Mhz band +#define RF_FRFMSB_902 0xE1 +#define RF_FRFMID_902 0x80 +#define RF_FRFLSB_902 0x00 +#define RF_FRFMSB_903 0xE1 +#define RF_FRFMID_903 0xC0 +#define RF_FRFLSB_903 0x00 +#define RF_FRFMSB_904 0xE2 +#define RF_FRFMID_904 0x00 +#define RF_FRFLSB_904 0x00 +#define RF_FRFMSB_905 0xE2 +#define RF_FRFMID_905 0x40 +#define RF_FRFLSB_905 0x00 +#define RF_FRFMSB_906 0xE2 +#define RF_FRFMID_906 0x80 +#define RF_FRFLSB_906 0x00 +#define RF_FRFMSB_907 0xE2 +#define RF_FRFMID_907 0xC0 +#define RF_FRFLSB_907 0x00 +#define RF_FRFMSB_908 0xE3 +#define RF_FRFMID_908 0x00 +#define RF_FRFLSB_908 0x00 +#define RF_FRFMSB_909 0xE3 +#define RF_FRFMID_909 0x40 +#define RF_FRFLSB_909 0x00 +#define RF_FRFMSB_910 0xE3 +#define RF_FRFMID_910 0x80 +#define RF_FRFLSB_910 0x00 +#define RF_FRFMSB_911 0xE3 +#define RF_FRFMID_911 0xC0 +#define RF_FRFLSB_911 0x00 +#define RF_FRFMSB_912 0xE4 +#define RF_FRFMID_912 0x00 +#define RF_FRFLSB_912 0x00 +#define RF_FRFMSB_913 0xE4 +#define RF_FRFMID_913 0x40 +#define RF_FRFLSB_913 0x00 +#define RF_FRFMSB_914 0xE4 +#define RF_FRFMID_914 0x80 +#define RF_FRFLSB_914 0x00 +#define RF_FRFMSB_915 0xE4 // Default +#define RF_FRFMID_915 0xC0 // Default +#define RF_FRFLSB_915 0x00 // Default +#define RF_FRFMSB_916 0xE5 +#define RF_FRFMID_916 0x00 +#define RF_FRFLSB_916 0x00 +#define RF_FRFMSB_917 0xE5 +#define RF_FRFMID_917 0x40 +#define RF_FRFLSB_917 0x00 +#define RF_FRFMSB_918 0xE5 +#define RF_FRFMID_918 0x80 +#define RF_FRFLSB_918 0x00 +#define RF_FRFMSB_919 0xE5 +#define RF_FRFMID_919 0xC0 +#define RF_FRFLSB_919 0x00 +#define RF_FRFMSB_920 0xE6 +#define RF_FRFMID_920 0x00 +#define RF_FRFLSB_920 0x00 +#define RF_FRFMSB_921 0xE6 +#define RF_FRFMID_921 0x40 +#define RF_FRFLSB_921 0x00 +#define RF_FRFMSB_922 0xE6 +#define RF_FRFMID_922 0x80 +#define RF_FRFLSB_922 0x00 +#define RF_FRFMSB_923 0xE6 +#define RF_FRFMID_923 0xC0 +#define RF_FRFLSB_923 0x00 +#define RF_FRFMSB_924 0xE7 +#define RF_FRFMID_924 0x00 +#define RF_FRFLSB_924 0x00 +#define RF_FRFMSB_925 0xE7 +#define RF_FRFMID_925 0x40 +#define RF_FRFLSB_925 0x00 +#define RF_FRFMSB_926 0xE7 +#define RF_FRFMID_926 0x80 +#define RF_FRFLSB_926 0x00 +#define RF_FRFMSB_927 0xE7 +#define RF_FRFMID_927 0xC0 +#define RF_FRFLSB_927 0x00 +#define RF_FRFMSB_928 0xE8 +#define RF_FRFMID_928 0x00 +#define RF_FRFLSB_928 0x00 + + +// RegOsc1 +#define RF_OSC1_RCCAL_START 0x80 +#define RF_OSC1_RCCAL_DONE 0x40 + + +// RegAfcCtrl +#define RF_AFCCTRL_LOWBETA_OFF 0x00 // Default +#define RF_AFCCTRL_LOWBETA_ON 0x20 + + +// RegLowBat +#define RF_LOWBAT_MONITOR 0x10 +#define RF_LOWBAT_ON 0x08 +#define RF_LOWBAT_OFF 0x00 // Default + +#define RF_LOWBAT_TRIM_1695 0x00 +#define RF_LOWBAT_TRIM_1764 0x01 +#define RF_LOWBAT_TRIM_1835 0x02 // Default +#define RF_LOWBAT_TRIM_1905 0x03 +#define RF_LOWBAT_TRIM_1976 0x04 +#define RF_LOWBAT_TRIM_2045 0x05 +#define RF_LOWBAT_TRIM_2116 0x06 +#define RF_LOWBAT_TRIM_2185 0x07 + + +// RegListen1 +#define RF_LISTEN1_RESOL_64 0x50 +#define RF_LISTEN1_RESOL_4100 0xA0 // Default +#define RF_LISTEN1_RESOL_262000 0xF0 + +#define RF_LISTEN1_RESOL_IDLE_64 0x40 +#define RF_LISTEN1_RESOL_IDLE_4100 0x80 // Default +#define RF_LISTEN1_RESOL_IDLE_262000 0xC0 + +#define RF_LISTEN1_RESOL_RX_64 0x10 +#define RF_LISTEN1_RESOL_RX_4100 0x20 // Default +#define RF_LISTEN1_RESOL_RX_262000 0x30 + +#define RF_LISTEN1_CRITERIA_RSSI 0x00 // Default +#define RF_LISTEN1_CRITERIA_RSSIANDSYNC 0x08 + +#define RF_LISTEN1_END_00 0x00 +#define RF_LISTEN1_END_01 0x02 // Default +#define RF_LISTEN1_END_10 0x04 + + +// RegListen2 +#define RF_LISTEN2_COEFIDLE_VALUE 0xF5 // Default + + +// RegListen3 +#define RF_LISTEN3_COEFRX_VALUE 0x20 // Default + + +// RegVersion +#define RF_VERSION_VER 0x24 // Default + + +// RegPaLevel +#define RF_PALEVEL_PA0_ON 0x80 // Default +#define RF_PALEVEL_PA0_OFF 0x00 +#define RF_PALEVEL_PA1_ON 0x40 +#define RF_PALEVEL_PA1_OFF 0x00 // Default +#define RF_PALEVEL_PA2_ON 0x20 +#define RF_PALEVEL_PA2_OFF 0x00 // Default + +#define RF_PALEVEL_OUTPUTPOWER_00000 0x00 +#define RF_PALEVEL_OUTPUTPOWER_00001 0x01 +#define RF_PALEVEL_OUTPUTPOWER_00010 0x02 +#define RF_PALEVEL_OUTPUTPOWER_00011 0x03 +#define RF_PALEVEL_OUTPUTPOWER_00100 0x04 +#define RF_PALEVEL_OUTPUTPOWER_00101 0x05 +#define RF_PALEVEL_OUTPUTPOWER_00110 0x06 +#define RF_PALEVEL_OUTPUTPOWER_00111 0x07 +#define RF_PALEVEL_OUTPUTPOWER_01000 0x08 +#define RF_PALEVEL_OUTPUTPOWER_01001 0x09 +#define RF_PALEVEL_OUTPUTPOWER_01010 0x0A +#define RF_PALEVEL_OUTPUTPOWER_01011 0x0B +#define RF_PALEVEL_OUTPUTPOWER_01100 0x0C +#define RF_PALEVEL_OUTPUTPOWER_01101 0x0D +#define RF_PALEVEL_OUTPUTPOWER_01110 0x0E +#define RF_PALEVEL_OUTPUTPOWER_01111 0x0F +#define RF_PALEVEL_OUTPUTPOWER_10000 0x10 +#define RF_PALEVEL_OUTPUTPOWER_10001 0x11 +#define RF_PALEVEL_OUTPUTPOWER_10010 0x12 +#define RF_PALEVEL_OUTPUTPOWER_10011 0x13 +#define RF_PALEVEL_OUTPUTPOWER_10100 0x14 +#define RF_PALEVEL_OUTPUTPOWER_10101 0x15 +#define RF_PALEVEL_OUTPUTPOWER_10110 0x16 +#define RF_PALEVEL_OUTPUTPOWER_10111 0x17 +#define RF_PALEVEL_OUTPUTPOWER_11000 0x18 +#define RF_PALEVEL_OUTPUTPOWER_11001 0x19 +#define RF_PALEVEL_OUTPUTPOWER_11010 0x1A +#define RF_PALEVEL_OUTPUTPOWER_11011 0x1B +#define RF_PALEVEL_OUTPUTPOWER_11100 0x1C +#define RF_PALEVEL_OUTPUTPOWER_11101 0x1D +#define RF_PALEVEL_OUTPUTPOWER_11110 0x1E +#define RF_PALEVEL_OUTPUTPOWER_11111 0x1F // Default + + +// RegPaRamp +#define RF_PARAMP_3400 0x00 +#define RF_PARAMP_2000 0x01 +#define RF_PARAMP_1000 0x02 +#define RF_PARAMP_500 0x03 +#define RF_PARAMP_250 0x04 +#define RF_PARAMP_125 0x05 +#define RF_PARAMP_100 0x06 +#define RF_PARAMP_62 0x07 +#define RF_PARAMP_50 0x08 +#define RF_PARAMP_40 0x09 // Default +#define RF_PARAMP_31 0x0A +#define RF_PARAMP_25 0x0B +#define RF_PARAMP_20 0x0C +#define RF_PARAMP_15 0x0D +#define RF_PARAMP_12 0x0E +#define RF_PARAMP_10 0x0F + + +// RegOcp +#define RF_OCP_OFF 0x0F +#define RF_OCP_ON 0x1A // Default + +#define RF_OCP_TRIM_45 0x00 +#define RF_OCP_TRIM_50 0x01 +#define RF_OCP_TRIM_55 0x02 +#define RF_OCP_TRIM_60 0x03 +#define RF_OCP_TRIM_65 0x04 +#define RF_OCP_TRIM_70 0x05 +#define RF_OCP_TRIM_75 0x06 +#define RF_OCP_TRIM_80 0x07 +#define RF_OCP_TRIM_85 0x08 +#define RF_OCP_TRIM_90 0x09 +#define RF_OCP_TRIM_95 0x0A // Default +#define RF_OCP_TRIM_100 0x0B +#define RF_OCP_TRIM_105 0x0C +#define RF_OCP_TRIM_110 0x0D +#define RF_OCP_TRIM_115 0x0E +#define RF_OCP_TRIM_120 0x0F + + +// RegAgcRef - not present on RFM69/SX1231 +#define RF_AGCREF_AUTO_ON 0x40 // Default +#define RF_AGCREF_AUTO_OFF 0x00 + +#define RF_AGCREF_LEVEL_MINUS80 0x00 // Default +#define RF_AGCREF_LEVEL_MINUS81 0x01 +#define RF_AGCREF_LEVEL_MINUS82 0x02 +#define RF_AGCREF_LEVEL_MINUS83 0x03 +#define RF_AGCREF_LEVEL_MINUS84 0x04 +#define RF_AGCREF_LEVEL_MINUS85 0x05 +#define RF_AGCREF_LEVEL_MINUS86 0x06 +#define RF_AGCREF_LEVEL_MINUS87 0x07 +#define RF_AGCREF_LEVEL_MINUS88 0x08 +#define RF_AGCREF_LEVEL_MINUS89 0x09 +#define RF_AGCREF_LEVEL_MINUS90 0x0A +#define RF_AGCREF_LEVEL_MINUS91 0x0B +#define RF_AGCREF_LEVEL_MINUS92 0x0C +#define RF_AGCREF_LEVEL_MINUS93 0x0D +#define RF_AGCREF_LEVEL_MINUS94 0x0E +#define RF_AGCREF_LEVEL_MINUS95 0x0F +#define RF_AGCREF_LEVEL_MINUS96 0x10 +#define RF_AGCREF_LEVEL_MINUS97 0x11 +#define RF_AGCREF_LEVEL_MINUS98 0x12 +#define RF_AGCREF_LEVEL_MINUS99 0x13 +#define RF_AGCREF_LEVEL_MINUS100 0x14 +#define RF_AGCREF_LEVEL_MINUS101 0x15 +#define RF_AGCREF_LEVEL_MINUS102 0x16 +#define RF_AGCREF_LEVEL_MINUS103 0x17 +#define RF_AGCREF_LEVEL_MINUS104 0x18 +#define RF_AGCREF_LEVEL_MINUS105 0x19 +#define RF_AGCREF_LEVEL_MINUS106 0x1A +#define RF_AGCREF_LEVEL_MINUS107 0x1B +#define RF_AGCREF_LEVEL_MINUS108 0x1C +#define RF_AGCREF_LEVEL_MINUS109 0x1D +#define RF_AGCREF_LEVEL_MINUS110 0x1E +#define RF_AGCREF_LEVEL_MINUS111 0x1F +#define RF_AGCREF_LEVEL_MINUS112 0x20 +#define RF_AGCREF_LEVEL_MINUS113 0x21 +#define RF_AGCREF_LEVEL_MINUS114 0x22 +#define RF_AGCREF_LEVEL_MINUS115 0x23 +#define RF_AGCREF_LEVEL_MINUS116 0x24 +#define RF_AGCREF_LEVEL_MINUS117 0x25 +#define RF_AGCREF_LEVEL_MINUS118 0x26 +#define RF_AGCREF_LEVEL_MINUS119 0x27 +#define RF_AGCREF_LEVEL_MINUS120 0x28 +#define RF_AGCREF_LEVEL_MINUS121 0x29 +#define RF_AGCREF_LEVEL_MINUS122 0x2A +#define RF_AGCREF_LEVEL_MINUS123 0x2B +#define RF_AGCREF_LEVEL_MINUS124 0x2C +#define RF_AGCREF_LEVEL_MINUS125 0x2D +#define RF_AGCREF_LEVEL_MINUS126 0x2E +#define RF_AGCREF_LEVEL_MINUS127 0x2F +#define RF_AGCREF_LEVEL_MINUS128 0x30 +#define RF_AGCREF_LEVEL_MINUS129 0x31 +#define RF_AGCREF_LEVEL_MINUS130 0x32 +#define RF_AGCREF_LEVEL_MINUS131 0x33 +#define RF_AGCREF_LEVEL_MINUS132 0x34 +#define RF_AGCREF_LEVEL_MINUS133 0x35 +#define RF_AGCREF_LEVEL_MINUS134 0x36 +#define RF_AGCREF_LEVEL_MINUS135 0x37 +#define RF_AGCREF_LEVEL_MINUS136 0x38 +#define RF_AGCREF_LEVEL_MINUS137 0x39 +#define RF_AGCREF_LEVEL_MINUS138 0x3A +#define RF_AGCREF_LEVEL_MINUS139 0x3B +#define RF_AGCREF_LEVEL_MINUS140 0x3C +#define RF_AGCREF_LEVEL_MINUS141 0x3D +#define RF_AGCREF_LEVEL_MINUS142 0x3E +#define RF_AGCREF_LEVEL_MINUS143 0x3F + + +// RegAgcThresh1 - not present on RFM69/SX1231 +#define RF_AGCTHRESH1_SNRMARGIN_000 0x00 +#define RF_AGCTHRESH1_SNRMARGIN_001 0x20 +#define RF_AGCTHRESH1_SNRMARGIN_010 0x40 +#define RF_AGCTHRESH1_SNRMARGIN_011 0x60 +#define RF_AGCTHRESH1_SNRMARGIN_100 0x80 +#define RF_AGCTHRESH1_SNRMARGIN_101 0xA0 // Default +#define RF_AGCTHRESH1_SNRMARGIN_110 0xC0 +#define RF_AGCTHRESH1_SNRMARGIN_111 0xE0 + +#define RF_AGCTHRESH1_STEP1_0 0x00 +#define RF_AGCTHRESH1_STEP1_1 0x01 +#define RF_AGCTHRESH1_STEP1_2 0x02 +#define RF_AGCTHRESH1_STEP1_3 0x03 +#define RF_AGCTHRESH1_STEP1_4 0x04 +#define RF_AGCTHRESH1_STEP1_5 0x05 +#define RF_AGCTHRESH1_STEP1_6 0x06 +#define RF_AGCTHRESH1_STEP1_7 0x07 +#define RF_AGCTHRESH1_STEP1_8 0x08 +#define RF_AGCTHRESH1_STEP1_9 0x09 +#define RF_AGCTHRESH1_STEP1_10 0x0A +#define RF_AGCTHRESH1_STEP1_11 0x0B +#define RF_AGCTHRESH1_STEP1_12 0x0C +#define RF_AGCTHRESH1_STEP1_13 0x0D +#define RF_AGCTHRESH1_STEP1_14 0x0E +#define RF_AGCTHRESH1_STEP1_15 0x0F +#define RF_AGCTHRESH1_STEP1_16 0x10 // Default +#define RF_AGCTHRESH1_STEP1_17 0x11 +#define RF_AGCTHRESH1_STEP1_18 0x12 +#define RF_AGCTHRESH1_STEP1_19 0x13 +#define RF_AGCTHRESH1_STEP1_20 0x14 +#define RF_AGCTHRESH1_STEP1_21 0x15 +#define RF_AGCTHRESH1_STEP1_22 0x16 +#define RF_AGCTHRESH1_STEP1_23 0x17 +#define RF_AGCTHRESH1_STEP1_24 0x18 +#define RF_AGCTHRESH1_STEP1_25 0x19 +#define RF_AGCTHRESH1_STEP1_26 0x1A +#define RF_AGCTHRESH1_STEP1_27 0x1B +#define RF_AGCTHRESH1_STEP1_28 0x1C +#define RF_AGCTHRESH1_STEP1_29 0x1D +#define RF_AGCTHRESH1_STEP1_30 0x1E +#define RF_AGCTHRESH1_STEP1_31 0x1F + + +// RegAgcThresh2 - not present on RFM69/SX1231 +#define RF_AGCTHRESH2_STEP2_0 0x00 +#define RF_AGCTHRESH2_STEP2_1 0x10 +#define RF_AGCTHRESH2_STEP2_2 0x20 +#define RF_AGCTHRESH2_STEP2_3 0x30 // XXX wrong -- Default +#define RF_AGCTHRESH2_STEP2_4 0x40 +#define RF_AGCTHRESH2_STEP2_5 0x50 +#define RF_AGCTHRESH2_STEP2_6 0x60 +#define RF_AGCTHRESH2_STEP2_7 0x70 // default +#define RF_AGCTHRESH2_STEP2_8 0x80 +#define RF_AGCTHRESH2_STEP2_9 0x90 +#define RF_AGCTHRESH2_STEP2_10 0xA0 +#define RF_AGCTHRESH2_STEP2_11 0xB0 +#define RF_AGCTHRESH2_STEP2_12 0xC0 +#define RF_AGCTHRESH2_STEP2_13 0xD0 +#define RF_AGCTHRESH2_STEP2_14 0xE0 +#define RF_AGCTHRESH2_STEP2_15 0xF0 + +#define RF_AGCTHRESH2_STEP3_0 0x00 +#define RF_AGCTHRESH2_STEP3_1 0x01 +#define RF_AGCTHRESH2_STEP3_2 0x02 +#define RF_AGCTHRESH2_STEP3_3 0x03 +#define RF_AGCTHRESH2_STEP3_4 0x04 +#define RF_AGCTHRESH2_STEP3_5 0x05 +#define RF_AGCTHRESH2_STEP3_6 0x06 +#define RF_AGCTHRESH2_STEP3_7 0x07 +#define RF_AGCTHRESH2_STEP3_8 0x08 +#define RF_AGCTHRESH2_STEP3_9 0x09 +#define RF_AGCTHRESH2_STEP3_10 0x0A +#define RF_AGCTHRESH2_STEP3_11 0x0B // Default +#define RF_AGCTHRESH2_STEP3_12 0x0C +#define RF_AGCTHRESH2_STEP3_13 0x0D +#define RF_AGCTHRESH2_STEP3_14 0x0E +#define RF_AGCTHRESH2_STEP3_15 0x0F + + +// RegAgcThresh3 - not present on RFM69/SX1231 +#define RF_AGCTHRESH3_STEP4_0 0x00 +#define RF_AGCTHRESH3_STEP4_1 0x10 +#define RF_AGCTHRESH3_STEP4_2 0x20 +#define RF_AGCTHRESH3_STEP4_3 0x30 +#define RF_AGCTHRESH3_STEP4_4 0x40 +#define RF_AGCTHRESH3_STEP4_5 0x50 +#define RF_AGCTHRESH3_STEP4_6 0x60 +#define RF_AGCTHRESH3_STEP4_7 0x70 +#define RF_AGCTHRESH3_STEP4_8 0x80 +#define RF_AGCTHRESH3_STEP4_9 0x90 // Default +#define RF_AGCTHRESH3_STEP4_10 0xA0 +#define RF_AGCTHRESH3_STEP4_11 0xB0 +#define RF_AGCTHRESH3_STEP4_12 0xC0 +#define RF_AGCTHRESH3_STEP4_13 0xD0 +#define RF_AGCTHRESH3_STEP4_14 0xE0 +#define RF_AGCTHRESH3_STEP4_15 0xF0 + +#define RF_AGCTHRESH3_STEP5_0 0x00 +#define RF_AGCTHRESH3_STEP5_1 0x01 +#define RF_AGCTHRESH3_STEP5_2 0x02 +#define RF_AGCTHRESH3_STEP5_3 0x03 +#define RF_AGCTHRESH3_STEP5_4 0x04 +#define RF_AGCTHRESH3_STEP5_5 0x05 +#define RF_AGCTHRESH3_STEP5_6 0x06 +#define RF_AGCTHRESH3_STEP5_7 0x07 +#define RF_AGCTHRES33_STEP5_8 0x08 +#define RF_AGCTHRESH3_STEP5_9 0x09 +#define RF_AGCTHRESH3_STEP5_10 0x0A +#define RF_AGCTHRESH3_STEP5_11 0x0B // Default +#define RF_AGCTHRESH3_STEP5_12 0x0C +#define RF_AGCTHRESH3_STEP5_13 0x0D +#define RF_AGCTHRESH3_STEP5_14 0x0E +#define RF_AGCTHRESH3_STEP5_15 0x0F + + +// RegLna +#define RF_LNA_ZIN_50 0x00 // Reset value +#define RF_LNA_ZIN_200 0x80 // Recommended default + +#define RF_LNA_LOWPOWER_OFF 0x00 // Default +#define RF_LNA_LOWPOWER_ON 0x40 + +#define RF_LNA_CURRENTGAIN 0x08 + +#define RF_LNA_GAINSELECT_AUTO 0x00 // Default +#define RF_LNA_GAINSELECT_MAX 0x01 +#define RF_LNA_GAINSELECT_MAXMINUS6 0x02 +#define RF_LNA_GAINSELECT_MAXMINUS12 0x03 +#define RF_LNA_GAINSELECT_MAXMINUS24 0x04 +#define RF_LNA_GAINSELECT_MAXMINUS36 0x05 +#define RF_LNA_GAINSELECT_MAXMINUS48 0x06 + + +// RegRxBw +#define RF_RXBW_DCCFREQ_000 0x00 +#define RF_RXBW_DCCFREQ_001 0x20 +#define RF_RXBW_DCCFREQ_010 0x40 // Recommended default +#define RF_RXBW_DCCFREQ_011 0x60 +#define RF_RXBW_DCCFREQ_100 0x80 // Reset value +#define RF_RXBW_DCCFREQ_101 0xA0 +#define RF_RXBW_DCCFREQ_110 0xC0 +#define RF_RXBW_DCCFREQ_111 0xE0 + +#define RF_RXBW_MANT_16 0x00 // Reset value +#define RF_RXBW_MANT_20 0x08 +#define RF_RXBW_MANT_24 0x10 // Recommended default + +#define RF_RXBW_EXP_0 0x00 +#define RF_RXBW_EXP_1 0x01 +#define RF_RXBW_EXP_2 0x02 +#define RF_RXBW_EXP_3 0x03 +#define RF_RXBW_EXP_4 0x04 +#define RF_RXBW_EXP_5 0x05 // Recommended default +#define RF_RXBW_EXP_6 0x06 // Reset value +#define RF_RXBW_EXP_7 0x07 + + +// RegAfcBw +#define RF_AFCBW_DCCFREQAFC_000 0x00 +#define RF_AFCBW_DCCFREQAFC_001 0x20 +#define RF_AFCBW_DCCFREQAFC_010 0x40 +#define RF_AFCBW_DCCFREQAFC_011 0x60 +#define RF_AFCBW_DCCFREQAFC_100 0x80 // Default +#define RF_AFCBW_DCCFREQAFC_101 0xA0 +#define RF_AFCBW_DCCFREQAFC_110 0xC0 +#define RF_AFCBW_DCCFREQAFC_111 0xE0 + +#define RF_AFCBW_MANTAFC_16 0x00 +#define RF_AFCBW_MANTAFC_20 0x08 // Default +#define RF_AFCBW_MANTAFC_24 0x10 + +#define RF_AFCBW_EXPAFC_0 0x00 +#define RF_AFCBW_EXPAFC_1 0x01 +#define RF_AFCBW_EXPAFC_2 0x02 // Reset value +#define RF_AFCBW_EXPAFC_3 0x03 // Recommended default +#define RF_AFCBW_EXPAFC_4 0x04 +#define RF_AFCBW_EXPAFC_5 0x05 +#define RF_AFCBW_EXPAFC_6 0x06 +#define RF_AFCBW_EXPAFC_7 0x07 + + +// RegOokPeak +#define RF_OOKPEAK_THRESHTYPE_FIXED 0x00 +#define RF_OOKPEAK_THRESHTYPE_PEAK 0x40 // Default +#define RF_OOKPEAK_THRESHTYPE_AVERAGE 0x80 + +#define RF_OOKPEAK_PEAKTHRESHSTEP_000 0x00 // Default +#define RF_OOKPEAK_PEAKTHRESHSTEP_001 0x08 +#define RF_OOKPEAK_PEAKTHRESHSTEP_010 0x10 +#define RF_OOKPEAK_PEAKTHRESHSTEP_011 0x18 +#define RF_OOKPEAK_PEAKTHRESHSTEP_100 0x20 +#define RF_OOKPEAK_PEAKTHRESHSTEP_101 0x28 +#define RF_OOKPEAK_PEAKTHRESHSTEP_110 0x30 +#define RF_OOKPEAK_PEAKTHRESHSTEP_111 0x38 + +#define RF_OOKPEAK_PEAKTHRESHDEC_000 0x00 // Default +#define RF_OOKPEAK_PEAKTHRESHDEC_001 0x01 +#define RF_OOKPEAK_PEAKTHRESHDEC_010 0x02 +#define RF_OOKPEAK_PEAKTHRESHDEC_011 0x03 +#define RF_OOKPEAK_PEAKTHRESHDEC_100 0x04 +#define RF_OOKPEAK_PEAKTHRESHDEC_101 0x05 +#define RF_OOKPEAK_PEAKTHRESHDEC_110 0x06 +#define RF_OOKPEAK_PEAKTHRESHDEC_111 0x07 + + +// RegOokAvg +#define RF_OOKAVG_AVERAGETHRESHFILT_00 0x00 +#define RF_OOKAVG_AVERAGETHRESHFILT_01 0x40 +#define RF_OOKAVG_AVERAGETHRESHFILT_10 0x80 // Default +#define RF_OOKAVG_AVERAGETHRESHFILT_11 0xC0 + + +// RegOokFix +#define RF_OOKFIX_FIXEDTHRESH_VALUE 0x06 // Default + + +// RegAfcFei +#define RF_AFCFEI_FEI_DONE 0x40 +#define RF_AFCFEI_FEI_START 0x20 +#define RF_AFCFEI_AFC_DONE 0x10 +#define RF_AFCFEI_AFCAUTOCLEAR_ON 0x08 +#define RF_AFCFEI_AFCAUTOCLEAR_OFF 0x00 // Default + +#define RF_AFCFEI_AFCAUTO_ON 0x04 +#define RF_AFCFEI_AFCAUTO_OFF 0x00 // Default + +#define RF_AFCFEI_AFC_CLEAR 0x02 +#define RF_AFCFEI_AFC_START 0x01 + + +// RegRssiConfig +#define RF_RSSI_FASTRX_ON 0x08 // not present on RFM69/SX1231 +#define RF_RSSI_FASTRX_OFF 0x00 // Default + +#define RF_RSSI_DONE 0x02 +#define RF_RSSI_START 0x01 + + +// RegDioMapping1 +#define RF_DIOMAPPING1_DIO0_00 0x00 // Default +#define RF_DIOMAPPING1_DIO0_01 0x40 +#define RF_DIOMAPPING1_DIO0_10 0x80 +#define RF_DIOMAPPING1_DIO0_11 0xC0 + +#define RF_DIOMAPPING1_DIO1_00 0x00 // Default +#define RF_DIOMAPPING1_DIO1_01 0x10 +#define RF_DIOMAPPING1_DIO1_10 0x20 +#define RF_DIOMAPPING1_DIO1_11 0x30 + +#define RF_DIOMAPPING1_DIO2_00 0x00 // Default +#define RF_DIOMAPPING1_DIO2_01 0x04 +#define RF_DIOMAPPING1_DIO2_10 0x08 +#define RF_DIOMAPPING1_DIO2_11 0x0C + +#define RF_DIOMAPPING1_DIO3_00 0x00 // Default +#define RF_DIOMAPPING1_DIO3_01 0x01 +#define RF_DIOMAPPING1_DIO3_10 0x02 +#define RF_DIOMAPPING1_DIO3_11 0x03 + + +// RegDioMapping2 +#define RF_DIOMAPPING2_DIO4_00 0x00 // Default +#define RF_DIOMAPPING2_DIO4_01 0x40 +#define RF_DIOMAPPING2_DIO4_10 0x80 +#define RF_DIOMAPPING2_DIO4_11 0xC0 + +#define RF_DIOMAPPING2_DIO5_00 0x00 // Default +#define RF_DIOMAPPING2_DIO5_01 0x10 +#define RF_DIOMAPPING2_DIO5_10 0x20 +#define RF_DIOMAPPING2_DIO5_11 0x30 + +#define RF_DIOMAPPING2_CLKOUT_32 0x00 +#define RF_DIOMAPPING2_CLKOUT_16 0x01 +#define RF_DIOMAPPING2_CLKOUT_8 0x02 +#define RF_DIOMAPPING2_CLKOUT_4 0x03 +#define RF_DIOMAPPING2_CLKOUT_2 0x04 +#define RF_DIOMAPPING2_CLKOUT_1 0x05 // Reset value +#define RF_DIOMAPPING2_CLKOUT_RC 0x06 +#define RF_DIOMAPPING2_CLKOUT_OFF 0x07 // Recommended default + + +// RegIrqFlags1 +#define RF_IRQFLAGS1_MODEREADY 0x80 +#define RF_IRQFLAGS1_RXREADY 0x40 +#define RF_IRQFLAGS1_TXREADY 0x20 +#define RF_IRQFLAGS1_PLLLOCK 0x10 +#define RF_IRQFLAGS1_RSSI 0x08 +#define RF_IRQFLAGS1_TIMEOUT 0x04 +#define RF_IRQFLAGS1_AUTOMODE 0x02 +#define RF_IRQFLAGS1_SYNCADDRESSMATCH 0x01 + + +// RegIrqFlags2 +#define RF_IRQFLAGS2_FIFOFULL 0x80 +#define RF_IRQFLAGS2_FIFONOTEMPTY 0x40 +#define RF_IRQFLAGS2_FIFOLEVEL 0x20 +#define RF_IRQFLAGS2_FIFOOVERRUN 0x10 +#define RF_IRQFLAGS2_PACKETSENT 0x08 +#define RF_IRQFLAGS2_PAYLOADREADY 0x04 +#define RF_IRQFLAGS2_CRCOK 0x02 +#define RF_IRQFLAGS2_LOWBAT 0x01 // not present on RFM69/SX1231 + + +// RegRssiThresh +#define RF_RSSITHRESH_VALUE 0xE4 // Default + + +// RegRxTimeout1 +#define RF_RXTIMEOUT1_RXSTART_VALUE 0x00 // Default + + +// RegRxTimeout2 +#define RF_RXTIMEOUT2_RSSITHRESH_VALUE 0x00 // Default + + +// RegPreamble +#define RF_PREAMBLESIZE_MSB_VALUE 0x00 // Default +#define RF_PREAMBLESIZE_LSB_VALUE 0x03 // Default + + +// RegSyncConfig +#define RF_SYNC_ON 0x80 // Default +#define RF_SYNC_OFF 0x00 + +#define RF_SYNC_FIFOFILL_AUTO 0x00 // Default -- when sync interrupt occurs +#define RF_SYNC_FIFOFILL_MANUAL 0x40 + +#define RF_SYNC_SIZE_1 0x00 +#define RF_SYNC_SIZE_2 0x08 +#define RF_SYNC_SIZE_3 0x10 +#define RF_SYNC_SIZE_4 0x18 // Default +#define RF_SYNC_SIZE_5 0x20 +#define RF_SYNC_SIZE_6 0x28 +#define RF_SYNC_SIZE_7 0x30 +#define RF_SYNC_SIZE_8 0x38 + +#define RF_SYNC_TOL_0 0x00 // Default +#define RF_SYNC_TOL_1 0x01 +#define RF_SYNC_TOL_2 0x02 +#define RF_SYNC_TOL_3 0x03 +#define RF_SYNC_TOL_4 0x04 +#define RF_SYNC_TOL_5 0x05 +#define RF_SYNC_TOL_6 0x06 +#define RF_SYNC_TOL_7 0x07 + + +// RegSyncValue1-8 +#define RF_SYNC_BYTE1_VALUE 0x00 // Default +#define RF_SYNC_BYTE2_VALUE 0x00 // Default +#define RF_SYNC_BYTE3_VALUE 0x00 // Default +#define RF_SYNC_BYTE4_VALUE 0x00 // Default +#define RF_SYNC_BYTE5_VALUE 0x00 // Default +#define RF_SYNC_BYTE6_VALUE 0x00 // Default +#define RF_SYNC_BYTE7_VALUE 0x00 // Default +#define RF_SYNC_BYTE8_VALUE 0x00 // Default + + +// RegPacketConfig1 +#define RF_PACKET1_FORMAT_FIXED 0x00 // Default +#define RF_PACKET1_FORMAT_VARIABLE 0x80 + +#define RF_PACKET1_DCFREE_OFF 0x00 // Default +#define RF_PACKET1_DCFREE_MANCHESTER 0x20 +#define RF_PACKET1_DCFREE_WHITENING 0x40 + +#define RF_PACKET1_CRC_ON 0x10 // Default +#define RF_PACKET1_CRC_OFF 0x00 + +#define RF_PACKET1_CRCAUTOCLEAR_ON 0x00 // Default +#define RF_PACKET1_CRCAUTOCLEAR_OFF 0x08 + +#define RF_PACKET1_ADRSFILTERING_OFF 0x00 // Default +#define RF_PACKET1_ADRSFILTERING_NODE 0x02 +#define RF_PACKET1_ADRSFILTERING_NODEBROADCAST 0x04 + + +// RegPayloadLength +#define RF_PAYLOADLENGTH_VALUE 0x40 // Default + + +// RegBroadcastAdrs +#define RF_BROADCASTADDRESS_VALUE 0x00 + + +// RegAutoModes +#define RF_AUTOMODES_ENTER_OFF 0x00 // Default +#define RF_AUTOMODES_ENTER_FIFONOTEMPTY 0x20 +#define RF_AUTOMODES_ENTER_FIFOLEVEL 0x40 +#define RF_AUTOMODES_ENTER_CRCOK 0x60 +#define RF_AUTOMODES_ENTER_PAYLOADREADY 0x80 +#define RF_AUTOMODES_ENTER_SYNCADRSMATCH 0xA0 +#define RF_AUTOMODES_ENTER_PACKETSENT 0xC0 +#define RF_AUTOMODES_ENTER_FIFOEMPTY 0xE0 + +#define RF_AUTOMODES_EXIT_OFF 0x00 // Default +#define RF_AUTOMODES_EXIT_FIFOEMPTY 0x04 +#define RF_AUTOMODES_EXIT_FIFOLEVEL 0x08 +#define RF_AUTOMODES_EXIT_CRCOK 0x0C +#define RF_AUTOMODES_EXIT_PAYLOADREADY 0x10 +#define RF_AUTOMODES_EXIT_SYNCADRSMATCH 0x14 +#define RF_AUTOMODES_EXIT_PACKETSENT 0x18 +#define RF_AUTOMODES_EXIT_RXTIMEOUT 0x1C + +#define RF_AUTOMODES_INTERMEDIATE_SLEEP 0x00 // Default +#define RF_AUTOMODES_INTERMEDIATE_STANDBY 0x01 +#define RF_AUTOMODES_INTERMEDIATE_RECEIVER 0x02 +#define RF_AUTOMODES_INTERMEDIATE_TRANSMITTER 0x03 + + +// RegFifoThresh +#define RF_FIFOTHRESH_TXSTART_FIFOTHRESH 0x00 // Reset value +#define RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY 0x80 // Recommended default + +#define RF_FIFOTHRESH_VALUE 0x0F // Default + + +// RegPacketConfig2 +#define RF_PACKET2_RXRESTARTDELAY_1BIT 0x00 // Default +#define RF_PACKET2_RXRESTARTDELAY_2BITS 0x10 +#define RF_PACKET2_RXRESTARTDELAY_4BITS 0x20 +#define RF_PACKET2_RXRESTARTDELAY_8BITS 0x30 +#define RF_PACKET2_RXRESTARTDELAY_16BITS 0x40 +#define RF_PACKET2_RXRESTARTDELAY_32BITS 0x50 +#define RF_PACKET2_RXRESTARTDELAY_64BITS 0x60 +#define RF_PACKET2_RXRESTARTDELAY_128BITS 0x70 +#define RF_PACKET2_RXRESTARTDELAY_256BITS 0x80 +#define RF_PACKET2_RXRESTARTDELAY_512BITS 0x90 +#define RF_PACKET2_RXRESTARTDELAY_1024BITS 0xA0 +#define RF_PACKET2_RXRESTARTDELAY_2048BITS 0xB0 +#define RF_PACKET2_RXRESTARTDELAY_NONE 0xC0 +#define RF_PACKET2_RXRESTART 0x04 + +#define RF_PACKET2_AUTORXRESTART_ON 0x02 // Default +#define RF_PACKET2_AUTORXRESTART_OFF 0x00 + +#define RF_PACKET2_AES_ON 0x01 +#define RF_PACKET2_AES_OFF 0x00 // Default + + +// RegAesKey1-16 +#define RF_AESKEY1_VALUE 0x00 // Default +#define RF_AESKEY2_VALUE 0x00 // Default +#define RF_AESKEY3_VALUE 0x00 // Default +#define RF_AESKEY4_VALUE 0x00 // Default +#define RF_AESKEY5_VALUE 0x00 // Default +#define RF_AESKEY6_VALUE 0x00 // Default +#define RF_AESKEY7_VALUE 0x00 // Default +#define RF_AESKEY8_VALUE 0x00 // Default +#define RF_AESKEY9_VALUE 0x00 // Default +#define RF_AESKEY10_VALUE 0x00 // Default +#define RF_AESKEY11_VALUE 0x00 // Default +#define RF_AESKEY12_VALUE 0x00 // Default +#define RF_AESKEY13_VALUE 0x00 // Default +#define RF_AESKEY14_VALUE 0x00 // Default +#define RF_AESKEY15_VALUE 0x00 // Default +#define RF_AESKEY16_VALUE 0x00 // Default + + +// RegTemp1 +#define RF_TEMP1_MEAS_START 0x08 +#define RF_TEMP1_MEAS_RUNNING 0x04 +// not present on RFM69/SX1231 +#define RF_TEMP1_ADCLOWPOWER_ON 0x01 // Default +#define RF_TEMP1_ADCLOWPOWER_OFF 0x00 + + +// RegTestLna +#define RF_TESTLNA_NORMAL 0x1B +#define RF_TESTLNA_HIGH_SENSITIVITY 0x2D + + +// RegTestDagc +#define RF_DAGC_NORMAL 0x00 // Reset value +#define RF_DAGC_IMPROVED_LOWBETA1 0x20 +#define RF_DAGC_IMPROVED_LOWBETA0 0x30 // Recommended default diff --git a/lib-ext/rfm-69.git/keywords.txt b/lib-ext/rfm-69.git/keywords.txt new file mode 100644 index 0000000..14aff85 --- /dev/null +++ b/lib-ext/rfm-69.git/keywords.txt @@ -0,0 +1,54 @@ +####################################### +# Syntax Coloring Map for RFM69 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Instances (KEYWORD2) +####################################### +RFM69 KEYWORD2 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +initialize KEYWORD2 +setAddress KEYWORD2 +canSend KEYWORD2 +send KEYWORD2 +sendWithRetry KEYWORD2 +receiveDone KEYWORD2 +ACKReceived KEYWORD2 +sendACK KEYWORD2 +setFrequency KEYWORD2 +getFrequency KEYWORD2 +encrypt KEYWORD2 +setCS KEYWORD2 +readRSSI KEYWORD2 +promiscuous KEYWORD2 +setHighPower KEYWORD2 +CryptFunction KEYWORD2 +sleep KEYWORD2 +readReg KEYWORD2 +writeReg KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +RF69_315MHZ LITERAL1 +RF69_433MHZ LITERAL1 +RF69_868MHZ LITERAL1 +RF69_915MHZ LITERAL1 +####################################### +# Variables/Volatiles (LITERAL2) +####################################### +DATA LITERAL2 +DATALEN LITERAL2 +SENDERID LITERAL2 +TARGETID LITERAL2 +PAYLOADLEN LITERAL2 +ACK_REQUESTED LITERAL2 +ACK_RECEIVED LITERAL2 +RSSI LITERAL2 \ No newline at end of file diff --git a/lib-ext/rfm-69.git/library.json b/lib-ext/rfm-69.git/library.json new file mode 100644 index 0000000..e01526e --- /dev/null +++ b/lib-ext/rfm-69.git/library.json @@ -0,0 +1,12 @@ +{ + "name": "RFM69", + "keywords": "rf, radio, wireless, spi", + "description": "RFM69 library for RFM69W, RFM69HW, RFM69CW, RFM69HCW (semtech SX1231, SX1231H)", + "repository": + { + "type": "git", + "url": "https://github.com/LowPowerLab/RFM69.git" + }, + "frameworks": "arduino", + "platforms": "atmelavr" +} diff --git a/lib/isp-repair/MegaIspRepair.cpp b/lib/isp-repair/MegaIspRepair.cpp new file mode 100644 index 0000000..8dd2544 --- /dev/null +++ b/lib/isp-repair/MegaIspRepair.cpp @@ -0,0 +1,248 @@ +/* + * Reflash a boot loader and a sketch an a second ATmega. + * MegaIspRepair + * 2014, Jan 21 Rewrote to class and converted to boot pair with lcd. + * IspRepair + * 2010-05-29 http://opensource.org/licenses/mit-license.php + * BootCloner + * adapted from http://www.arduino.cc/playground/BootCloner/BootCloner + * original copyright notice: 2007 by Amplificar + */ + +#include +#include + +bool fastSPI = false; // don't start in fast mode right away + +// transfer a byte using software SPI, using a faster mode when possible +byte MegaIspRepair::XferByte(byte v) { + byte result = 0; + if (fastSPI) + for (byte i = 0; i < 8; ++i) { + bitWrite(PORTC, 3, v & 0x80); + v <<= 1; + bitClear(PORTC, 0); + result <<= 1; + bitSet(PORTC, 0); + result |= bitRead(PIND, 4); + } + else + for (byte i = 0; i < 8; ++i) { + digitalWrite(PIN_MOSI, v & 0x80); + digitalWrite(PIN_SCK, 0); // slow pulse, max 60KHz + digitalWrite(PIN_SCK, 1); + v <<= 1; + result = (result << 1) | digitalRead(PIN_MISO); + } + return result; +} + +// send 4 bytes to target microcontroller, returns the fourth MISO byte +byte MegaIspRepair::Send_ISP(word v01, byte v2, byte v3) { + XferByte(v01 >> 8); + XferByte(v01); + XferByte(v2); + return XferByte(v3); +} + +// send 4 bytes to target microcontroller and wait for completion +void MegaIspRepair::Send_ISP_wait(word v01, byte v2, byte v3) { + Send_ISP(v01, v2, v3); + while (Send_ISP(CMD_Poll) & 1) + ; +} + +// reset the target microcontroller +void MegaIspRepair::Reset_Target() { + digitalWrite(RESET, 1); + digitalWrite(PIN_SCK, 0); // has to be set LOW at startup, or PE fails + delay(30); + digitalWrite(RESET, 0); + delay(30); // minimum delay here is 20ms for the ATmega8 +} + +// print the 16 signature bytes (device codes) +void MegaIspRepair::Read_Signature() { + Serial.print("Signatures:"); + for (byte x = 0; x < 8; ++x) { + Serial.print(" "); + Serial.print(Send_ISP(CMD_Read_Signature, x), HEX); + } + Serial.println(""); +} + +// prints the lock and fuse bits (no leading zeros) +byte MegaIspRepair::Read_Fuses(byte flo, byte fhi) { + Serial.print("Lock Bits: "); + Serial.println(Send_ISP(CMD_Read_Lock), HEX); + Serial.print("Fuses: low "); + Serial.print(Send_ISP(CMD_Read_Fuse_Low), HEX); + Serial.print(", high "); + Serial.print(Send_ISP(CMD_Read_Fuse_High), HEX); + Serial.print(", extended "); + Serial.println(Send_ISP(CMD_Read_Fuse_Extended), HEX); + return Send_ISP(CMD_Read_Lock) == LOCK_BITS && Send_ISP(CMD_Read_Fuse_Low) == flo && Send_ISP(CMD_Read_Fuse_High) == fhi && Send_ISP(CMD_Read_Fuse_Extended) == FUSE_EXTENDED; +} + +word MegaIspRepair::addr2page(word addr) { + return (word)(addr & ~(PAGE_BYTES - 1)) >> 1; +} + +void MegaIspRepair::LoadPage(word addr, const byte* ptr) { + word cmd = addr & 1 ? CMD_Load_Page_High : CMD_Load_Page_Low; + Send_ISP(cmd | (addr >> 9), addr >> 1, pgm_read_byte(ptr)); +} + +void MegaIspRepair::WritePage(word page) { + Send_ISP_wait(CMD_Write_Page | (page >> 8), page); +} + +void MegaIspRepair::WriteData(word start, const byte* data, word count) { + word page = addr2page(start); + for (word i = 0; i < count; i += 2) { + if (page != addr2page(start)) { + WritePage(page); + Serial.print('.'); + page = addr2page(start); + } + LoadPage(start++, data + i); + LoadPage(start++, data + i + 1); + } + WritePage(page); + Serial.println(); +} + +byte MegaIspRepair::EnableProgramming() { + Reset_Target(); + if (Send_ISP(CMD_Program_Enable, 0x22, 0x22) != 0x22) { + Serial.println("Program Enable FAILED"); + return 0; + } + return 1; +} + +void MegaIspRepair::blink() { + pinMode(DONE_LED, OUTPUT); + digitalWrite(DONE_LED, 0); // inverted logic + delay(100); // blink briefly + pinMode(DONE_LED, INPUT); +} + +byte MegaIspRepair::readConfig() { + static byte pins[] = { CONFIG1, CONFIG2, CONFIG3, CONFIG4 }; + byte switches = 0; + for (byte i = 0; i < 4; ++i) { + pinMode(pins[i], INPUT); + digitalWrite(pins[i], 1); // enable pull-up + bitWrite(switches, i, digitalRead(pins[i])); + digitalWrite(pins[i], 0); // disable pull-up + } + return switches; // a 4-bit value, i.e. 0..15 +} + +byte MegaIspRepair::programSection(byte index, mega_flash_data_struct sections[]) { + Serial.print(index, DEC); + byte f = EnableProgramming(); + if (f) { + fastSPI = FAST_SPI && PIN_SCK == 14 && PIN_MISO == 4 && PIN_MOSI == 17; + WriteData(sections[index].start, sections[index].progdata + sections[index].off, sections[index].count); + fastSPI = false; + } + return f; +} + +void MegaIspRepair::run(const char* typeTitle, mega_flash_data_struct sections[]) { + Serial.begin(57600); + Serial.println(); + Serial.println("# Booting mega_isp_repair"); + Serial.println("# Version=3.0"); + Serial.print("# Type="); + Serial.print(typeTitle); + Serial.println(); + blink(); + + digitalWrite(PIN_SCK, 1); + digitalWrite(PIN_MOSI, 1); + digitalWrite(RESET, 1); + + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + pinMode(RESET, OUTPUT); + + byte config = readConfig(); + byte xspeed = 0; + + // Always burn a boot pair + byte bootld = (config * 2) + 0; + byte sketch = (config * 2) + 1; + + Serial.print("Configuration: "); + Serial.print(config, HEX); + Serial.println(xspeed ? " (resonator)" : " (crystal)"); + Serial.println(); + Serial.println(sections[sketch].title); + Serial.println(sections[bootld].title); + Serial.println(); + + if (EnableProgramming()) { + Serial.println("Erasing Flash"); + Send_ISP_wait(CMD_Erase_Flash, 0x22, 0x22); + + if (EnableProgramming()) { + byte fuseLo = xspeed ? FUSE_LOW_FAST : FUSE_LOW_XTAL; + // derive the boot size from its starting address + byte fuseHi = FUSE_HIGH_2048; + switch (sections[bootld].start & 0x0FFF) { + case 0x0E00: + fuseHi = FUSE_HIGH_512; + break; + case 0x0C00: + fuseHi = FUSE_HIGH_1024; + break; + case 0x0800: + fuseHi = FUSE_HIGH_2048; + break; + case 0x0000: + fuseHi = FUSE_HIGH_4096; + break; + } + + // set the fuses and lock bits + Serial.println("Setting Fuses"); + Send_ISP_wait(CMD_Write_Fuse_Low, 0, fuseLo); + Send_ISP_wait(CMD_Write_Fuse_High, 0, fuseHi); + Send_ISP_wait(CMD_Write_Fuse_Extended, 0, FUSE_EXTENDED); + Send_ISP_wait(CMD_Write_Lock, 0, LOCK_BITS); + + // burn the sketch and bootstrap code + if (programSection(sketch, sections) && programSection(bootld, sections)) { + Read_Signature(); + if (Read_Fuses(fuseLo, fuseHi)) { + Serial.println("\nDone."); + blink(); + } else + Serial.println("Fuses NOT OK!"); + } + } + } + + pinMode(PIN_SCK, INPUT); + pinMode(PIN_MOSI, INPUT); + pinMode(RESET, INPUT); + + digitalWrite(PIN_SCK, 0); + digitalWrite(PIN_MOSI, 0); + digitalWrite(RESET, 0); + +#if ARDUINO >= 100 + Serial.flush(); +#endif + delay(10); // let the serial port finish + cli(); // stop responding to interrupts + ADCSRA &= ~bit(ADEN); // disable the ADC + //PRR = 0xFF; // disable all subsystems + set_sleep_mode (SLEEP_MODE_PWR_DOWN); + sleep_mode(); + // total power down, can only wake up with a hardware reset +} + diff --git a/lib/isp-repair/MegaIspRepair.h b/lib/isp-repair/MegaIspRepair.h new file mode 100644 index 0000000..c415bea --- /dev/null +++ b/lib/isp-repair/MegaIspRepair.h @@ -0,0 +1,39 @@ +#ifndef IspRepair_h +#define IspRepair_h + +#include +#include +#include +#include +#include + +typedef struct { + const char* title; + const char* mdate; + const unsigned char* progdata; + unsigned start; + unsigned off; + unsigned count; +} mega_flash_data_struct; + +class MegaIspRepair { +private: + static byte XferByte(byte v); + static byte Send_ISP(word v01, byte v2 = 0, byte v3 = 0); + static void Send_ISP_wait(word v01, byte v2 = 0, byte v3 = 0); + static void Reset_Target(); + static void Read_Signature(); + static byte Read_Fuses(byte flo, byte fhi); + static word addr2page(word addr); + static void LoadPage(word addr, const byte* ptr); + static void WritePage(word page); + static void WriteData(word start, const byte* data, word count); + static byte EnableProgramming(); + static void blink(); + static byte readConfig(); + static byte programSection(byte index, mega_flash_data_struct sections[]); +public: + void run(const char* typeTitle, mega_flash_data_struct sections[]); +}; + +#endif diff --git a/lib/isp-repair/MegaIspRepairConfig.h b/lib/isp-repair/MegaIspRepairConfig.h new file mode 100644 index 0000000..3fb50ab --- /dev/null +++ b/lib/isp-repair/MegaIspRepairConfig.h @@ -0,0 +1,49 @@ +#define FAST_SPI 1 // comment out to revert to digitalWrite() calls + +// pin definitions +#define PIN_SCK 14 // PC0 - AIO1 - serial clock to target avr +#define PIN_MISO 4 // PD4 - DIO1 - input from target avr +#define PIN_MOSI 17 // PC3 - AIO4 - output to target avr +#define RESET 7 // PD7 - DIO4 - reset pin of the target avr +#define DONE_LED 9 // B1 - blue LED on JN USB, blinks on start and when ok + +// pins used for the optional config switches +#define CONFIG1 5 // DIO2 +#define CONFIG2 15 // AIO2 +#define CONFIG3 16 // AIO3 +#define CONFIG4 6 // DIO3 + +// MPU-specific values +#define PAGE_BYTES 128 // ATmega168 and ATmega328 +#define LOCK_BITS 0xCF +#define FUSE_LOW_XTAL 0xFF +#define FUSE_LOW_FAST 0xDE +#define FUSE_HIGH_512 0xDE +#define FUSE_HIGH_1024 0xDC +#define FUSE_HIGH_2048 0xDA +#define FUSE_HIGH_4096 0xD8 // not in ATmega168 +#define FUSE_EXTENDED 0xFD + +// ISP Command Words +#define CMD_Program_Enable 0xAC53 +#define CMD_Erase_Flash 0xAC80 +#define CMD_Poll 0xF000 +#define CMD_Read_Flash_Low 0x2000 +#define CMD_Read_Flash_High 0x2800 +#define CMD_Load_Page_Low 0x4000 +#define CMD_Load_Page_High 0x4800 +#define CMD_Write_Page 0x4C00 +#define CMD_Read_EEPROM 0xA000 +#define CMD_Write_EEPROM 0xC000 +#define CMD_Read_Lock 0x5800 +#define CMD_Write_Lock 0xACE0 +#define CMD_Read_Signature 0x3000 +#define CMD_Write_Fuse_Low 0xACA0 +#define CMD_Write_Fuse_High 0xACA8 +#define CMD_Write_Fuse_Extended 0xACA4 +#define CMD_Read_Fuse_Low 0x5000 +#define CMD_Read_Fuse_High 0x5808 +#define CMD_Read_Fuse_Extended 0x5008 +#define CMD_Read_Fuse_High 0x5808 +#define CMD_Read_Calibration 0x3800 + diff --git a/lib/isp-repair/readme.txt b/lib/isp-repair/readme.txt new file mode 100644 index 0000000..87ed500 --- /dev/null +++ b/lib/isp-repair/readme.txt @@ -0,0 +1,44 @@ + +// This code is adapted from isp_prepare. It omits the button and run LED, +// and starts right away. To use, open a serial console and wait until done. +// +// The 6 ISP pins of the target board need to be connected to the board running +// this sketch as follows (using Arduino pin naming): +// +// ISP pin 1 <-> digital 4 (MISO) ISP CONNECTOR +// ISP pin 2 <-> VCC +---+---+ +// ISP pin 3 <-> analog 0 (SCK) | 1 | 2 | +// ISP pin 4 <-> analog 3 (MOSI) | 3 | 4 | +// ISP pin 5 <-> digital 7 (RESET) | 5 | 6 | +// ISP pin 6 <-> ground +---+---+ +// +// The same hookup, using JeeNode port/pin names: +// +// ISP pin 1 <-> DIO1 +// ISP pin 2 <-> +3V +// ISP pin 3 <-> AIO1 +// ISP pin 4 <-> AIO4 +// ISP pin 5 <-> DIO4 +// ISP pin 6 <-> GND +// + + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +/* Include code using a file generated in isp_prepare/ dir with this cmd: + + ./hex2c.tcl Blink.cpp.hex \ + RF12demo.cpp.hex \ + optiboot_atmega328.hex \ + ATmegaBOOT_168_atmega328.hex \ + optiboot_atmega328_1s.hex \ + optiboot_atmega328.hex >../isp_repair2/data.h + + Code choices are fixed: section 0 is RF12demo, section 1 is blink + Boot choices are entries 2..5 in the sections[] array in data.h +*/ + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/lib/xnode-shared/XnodeConstants.h b/lib/xnode-shared/XnodeConstants.h new file mode 100644 index 0000000..43e79ec --- /dev/null +++ b/lib/xnode-shared/XnodeConstants.h @@ -0,0 +1,77 @@ +#ifndef XnodeBaseConstants_h +#define XnodeBaseConstants_h + +// Temp version here, todo move to makefile and use git --version +#define XNODE_VERSION "1.3" + +// Default serial baudrate for all devices +#define SERIAL_SPEED 115200 + +// Default watchdog timeout +#define WDT_TIMEOUT WDTO_8S + +// RF Settings +#define RF_BASE_NODE_ID 1 +#define RF_NETWORK_ID 98 +#define RF_FREQUENCY RF69_868MHZ +#define RF_KEY_SIZE 16 +#define RF_KEY_FETCH_TIME 1000*5 +#define RF_KEY_ENCRYPT_TIME 1000*60*2 +#define RF_NO_DATA_FAIL_TIME RF_KEY_ENCRYPT_TIME*2 + +// Needed for total magic number free code +#define ZERO 0 +#define ONE 1 + +// Net related sizes +#define NET_BYTE_IP_SIZE 4 +#define NET_BYTE_MAC_SIZE 6 +#define NET_BYTE_NET_KEY_SIZE 16 +#define NET_BYTE_NET_ID_SIZE 6 + +// Net Xensit config +//define NET_XNODE_HOST "xng.xensit.com" // XNodeGateway +#define NET_XNODE_HOST "www.forwardfire.net" +#define NET_XNODE_MAC_DEFAULT {0x74,0x69,0x69,0x4D,0x33,0xB1} +#define NET_PING_BOOT_TIME 1000*3 +#define NET_PING_HOST_TIME 1000*60*90 +#define NET_DHCP_RETRY_TIME 1000*60*3 +#define NET_DNS_LOOKUP_TIME 1000*3600*1 +// TODO: make net time to secs as 1h is ~max for dns + +// Net config for url; Input Xensit Node Version A +#define NET_URL_POST "_a" +#define NET_URL_PARA_POST_TYPE "pt=" +#define NET_URL_PARA_REQ_CNT "&rc=" +#define NET_URL_PARA_NET_ID "&ni=" +#define NET_URL_PARA_NODE_DATA "&nd=" +#define NET_URL_PARA_NODE_NUMBER "&nn=" + +// The different post types of the url +#define NET_URL_PT_PING 'p' +#define NET_URL_PT_INIT 'i' +#define NET_URL_PT_DATA 'd' +#define NET_URL_RESULT_OK 'X' + +// Some characters for printing. +#define CHAR_NEWLINE '\n' +#define CHAR_SPACE ' ' +#define CHAR_DOT '.' +#define CHAR_PROMT '$' +#define CHAR_COMMENT '#' +#define CHAR_EQUALS '=' + +// Full ascii messages +#define MSG_RF_CHIP_INIT "Init radio" +#define MSG_RF_CHIP_ERROR "ERR: No chip" +#define MSG_RF_INFO_FREQ "rf_freq" +#define MSG_RF_INFO_NETWORK "rf_network" +#define MSG_RF_INFO_NODE "rf_node" +#define MSG_RF_INFO_KEY "rf_key" +#define MSG_RF_INFO_TX "rf_tx" +#define MSG_RF_INFO_RX "rf_rx" +#define MSG_RF_INFO_TXE "rf_txe" +#define MSG_RF_INFO "rf_info" +#define MSG_RF_ENCRYPT "rf_encrypt" + +#endif diff --git a/lib/xnode-shared/XnodeProtocol.h b/lib/xnode-shared/XnodeProtocol.h new file mode 100644 index 0000000..8127f4f --- /dev/null +++ b/lib/xnode-shared/XnodeProtocol.h @@ -0,0 +1,38 @@ +#ifndef XnodeProtocol_h +#define XnodeProtocol_h + +#include +#include + +#define RF_STRUCT_SUPER_SIZE 52 +#define RF_STRUCT_FLASH_SIZE 32 +#define RF_STRUCT_CHAR_SIZE 48 + +enum RFMessageType { + RF_MSG_NODE_INIT, // sat tx+rx init_t + RF_MSG_NODE_FLASH, // sat tx+rx flash_t + RF_MSG_NODE_COMMAND, // sat rx char_t + RF_MSG_NODE_DATA // sat tx char_t +}; + +typedef struct { + byte msg_type; + byte msg_data[RF_STRUCT_SUPER_SIZE]; +} xp_super_t; + +typedef struct { + byte rf_key[RF_KEY_SIZE]; + byte node_id; +} xp_msg_init_t; + +typedef struct { + uint16_t offset; + byte flash_data[RF_STRUCT_FLASH_SIZE]; +} xp_msg_flash_t; + +typedef struct { + char char_data[RF_STRUCT_CHAR_SIZE]; +} xp_msg_char_t; + +#endif + diff --git a/lib/xnode-shared/XnodeSatelliteConfig.h b/lib/xnode-shared/XnodeSatelliteConfig.h new file mode 100644 index 0000000..70578ea --- /dev/null +++ b/lib/xnode-shared/XnodeSatelliteConfig.h @@ -0,0 +1,14 @@ +#ifndef XnodeSatelliteConfig_h +#define XnodeSatelliteConfig_h + +// Config data +typedef struct { + uint16_t eeprom_struct_size; // Config size changes it data defaults to zeros + byte rf_key[RF_KEY_SIZE]; // rf key to encrypt radio + byte node_id; // this node id to transmit to base + unsigned long sys_boot; // boot counter + +} xnode_satellite_config_t; + +#endif + diff --git a/lib/xnode-shared/XnodeSerial.cpp b/lib/xnode-shared/XnodeSerial.cpp new file mode 100644 index 0000000..c9cc949 --- /dev/null +++ b/lib/xnode-shared/XnodeSerial.cpp @@ -0,0 +1,104 @@ +#include + +char cmd_buff[CMD_BUFF_SIZE]; +volatile uint8_t cmd_process = ONE; +volatile uint8_t cmd_buff_idx = ZERO; +XnodeSerial XSerial; + +void XnodeSerial::begin() { + Serial.begin(SERIAL_SPEED); + print(CHAR_NEWLINE); +} + +void XnodeSerial::loop() { + if (cmd_process == ZERO) { + executeCommand(cmd_buff); + cmd_process = ONE; + } + while (Serial.available() > ZERO) { + processSerialByte(Serial.read()); + } +} + +// Parse the cmd from a buffer +void XnodeSerial::executeCommand(char* buff,bool echoBuff,bool echoPromt) { +#ifdef DEBUG_SERIAL + Serial.print(F("#D XSerial.processCommand buff=")); + Serial.print(buff); + Serial.print(F(",echoBuff=")); + Serial.print(echoBuff); + Serial.print(F(",echoPromt=")); + Serial.print(echoPromt); + Serial.println(); +#endif + if (echoBuff) { + printChar(buff); + print(CHAR_NEWLINE); + } + if (buff[ZERO] > ZERO) { + XSystem.executeCommand(buff); // exe cmd + printChar(XSystem.replyBuffer); // print result or error + } + if (echoPromt) { + printPromt(); + } +} + +void XnodeSerial::processSerialByte(uint8_t c) { + if (c < 0x07 || c > 0x7E) { + return; // only process ascii chars + } + if (cmd_process == ZERO) { + return; // skip serial data + } + if (cmd_buff_idx > CMD_BUFF_SIZE) { + cmd_buff_idx = ZERO; // protect against to long input + } + if (c == '\b') { + cmd_buff[cmd_buff_idx] = '\0'; // backspace + cmd_buff_idx--; + print(' '); + print(c); // reply the backspace char for console like experience + } else if (c == '\n') { + cmd_buff[cmd_buff_idx] = '\0'; // newline + cmd_buff_idx = ZERO; + cmd_process = ZERO; // Start processing line + } else { + cmd_buff[cmd_buff_idx] = c; // store in buffer + cmd_buff_idx++; + } +} + +void XnodeSerial::executeCommandP(const char* cmd) { + strcpy(cmd_buff, XUtil.UNPSTR(cmd)); // free buffer as gets used in strcmpP again.. + cmd_buff_idx = ZERO; + executeCommand(cmd_buff,false,false); +} + +void XnodeSerial::printPromt() { + printCharP(XSystem.hardware->getSystemHardwareTypeP()); + print(CHAR_PROMT); + print(CHAR_SPACE); +} + +void XnodeSerial::printCommentLineP(const char* argu) { + print(CHAR_COMMENT); + print(CHAR_SPACE); + printCharP(argu); + print(CHAR_NEWLINE); +} + +void XnodeSerial::printCharP(const char* argu) { + printChar(XUtil.UNPSTR(argu)); +} + +void XnodeSerial::printChar(char* dstring) { + while (*dstring != ZERO) { + print(*dstring); + dstring++; + } +} + +void XnodeSerial::print(char value) { + Serial.print(value); +} diff --git a/lib/xnode-shared/XnodeSerial.h b/lib/xnode-shared/XnodeSerial.h new file mode 100644 index 0000000..7f4e71f --- /dev/null +++ b/lib/xnode-shared/XnodeSerial.h @@ -0,0 +1,32 @@ +#ifndef XnodeSerial_h +#define XnodeSerial_h + +#define CMD_BUFF_SIZE 40 // max command length (40 is rf_key=9A2EE3A293486E9FE73D77EFC8087D2F) + +#include +#include +#include +#include +#include + +class XnodeSerial { +private: + void executeCommand(char* buff,bool echoBuff = true,bool echoPromt = true); + void processSerialByte(uint8_t c); + +public: + void begin(); + void loop(); + + void executeCommandP(const char* cmd); + void printPromt(); + void printCommentLineP(const char* argu); + void printCharP(const char* argu); + void printChar(char* argu); + void print(char value); +}; + +extern XnodeSerial XSerial; + +#endif + diff --git a/lib/xnode-shared/XnodeSystem.cpp b/lib/xnode-shared/XnodeSystem.cpp new file mode 100644 index 0000000..a8496fb --- /dev/null +++ b/lib/xnode-shared/XnodeSystem.cpp @@ -0,0 +1,323 @@ +#include + +#define CMD_MAX_ARGS 8 // max 8 arguments to command +#define CMD_WHITE_SPACE " \r\t\n" // All diffent white space chars to split commands on + +const char pmCmdHelp[] PROGMEM = "help"; +const char pmCmdReboot[] PROGMEM = "reboot"; +const char pmCmdSysCnfRst[] PROGMEM = "sys__cnf__rst"; // (internal) +const char pmCmdSysInfo[] PROGMEM = "sys_info"; + +const char pmSysConfigSave[] PROGMEM = "Config saved"; +const char pmSysConfigLoad[] PROGMEM = "Config loaded"; +const char pmSysConfigReset[] PROGMEM = "Config reset"; + +const char pmSysInfoVNumber[] PROGMEM = "sys_vnum"; +const char pmSysInfoVDate[] PROGMEM = "sys_vdate"; +const char pmSysInfoVDateValue[] PROGMEM = __DATE__" "__TIME__; // Print compile date like; "Apr 22 2012 16:36:10" +const char pmSysInfoType[] PROGMEM = "sys_type"; +const char pmSysInfoBoot[] PROGMEM = "sys_boot"; +const char pmSysInfoDebugLevel[] PROGMEM = "sys_debug"; +const char pmSysInfoFreeRam[] PROGMEM = "sys_sram"; + +const char pmSysBootDebugHeader[] PROGMEM = "==== DEBUGGING ENABLED ===="; +const char pmSysBootStart[] PROGMEM = "Booting "; +const char pmSysBootDone[] PROGMEM = "boot done"; +const char pmSysBootDoneHelp[] PROGMEM = "Available commands;"; + +const char pmCmdErrArgument[] PROGMEM = "#ERR Missing argument: "; +const char pmCmdErrUnknown[] PROGMEM = "#ERR Unknown command: "; + +const char pmRemoteExecutePrefix[] PROGMEM = "remote@"; + +uint8_t reboot_requested = ZERO; +uint8_t debug_level = ZERO; +uint8_t replyBufferIndex = ZERO; +uint8_t systemModuleIndex = ZERO; +XnodeSystemModule* systemModules[SYSTEM_MODULE_ARRAY_SIZE]; +XnodeSystemHardware* hardware; +XnodeSystem XSystem; + +void XnodeSystem::begin(XnodeSystemHardware* hardwareNode) { + hardware = hardwareNode; + + // Print first line of boot process + XSerial.print(CHAR_COMMENT); + XSerial.print(CHAR_SPACE); + XSerial.printCharP (pmSysBootStart); // has space + XSerial.printCharP(hardware->getSystemHardwareTypeP()); + XSerial.print(CHAR_NEWLINE); + + // Start debug asp + beginDebug(); + + // Fixup config + XSerial.printCommentLineP(pmSysConfigLoad); + if (hardware->systemHardwareConfigBegin()) { + hardware->systemHardwareConfigReset(); + XSerial.printCommentLineP(pmSysConfigReset); + } + hardware->systemHardwareConfigSave(); + + // Print system info + XSerial.executeCommandP(pmCmdSysInfo); + + // Enable the watchdog + wdt_enable(WDT_TIMEOUT); +} + +void XnodeSystem::loop() { + // Tickle the watchdog + wdt_reset(); + + // Reboot countdown and action so reply can be send. + if (reboot_requested > ONE) { + reboot_requested--; + } else if (reboot_requested > ZERO) { + wdt_enable (WDTO_15MS); // reboot in 15ms. + delay(30); + } +} + +void XnodeSystem::beginDebug() { + // Make sure human and machine are notified when debugging is turned on. +#ifdef DEBUG_NETWORK + // shift every flag on its on bit so machine can readout which flags is enabled. + debug_level+=ONE << 0; // 1 +#endif +#ifdef DEBUG_RADIO + debug_level+=ONE << 1; // 2 +#endif +#ifdef DEBUG_SYSTEM + debug_level+=ONE << 2; // 4 +#endif +#ifdef DEBUG_SERIAL + debug_level+=ONE << 3; // 8 +#endif +#ifdef DEBUG_SENSOR + debug_level+=ONE << 4; // 16, all = 31 +#endif + if (debug_level > ZERO) { + XSerial.printCommentLineP(pmSysBootDebugHeader); // print line for human,machine version is in serialPrintInfo. + } +} + +void XnodeSystem::bootDone() { + XSerial.printCommentLineP(pmSysBootDoneHelp); + XSerial.executeCommandP(pmCmdHelp); + XSerial.printCommentLineP(pmSysBootDone); + XSerial.printPromt(); +} + +void XnodeSystem::configSave() { +#ifdef DEBUG_SYSTEM + Serial.println(F("#D XSystem.configSave")); +#endif + wdt_disable(); + hardware->systemHardwareConfigSave(); + wdt_enable (WDT_TIMEOUT); +} + +void XnodeSystem::cmdSysInfo() { + buildReplyPValueP(pmSysInfoVNumber,hardware->getSystemHardwareVersionP()); + buildReplyPValueP(pmSysInfoVDate,pmSysInfoVDateValue); + buildReplyPValue(pmSysInfoBoot,hardware->getSystemHardwareRebootCount()); + buildReplyPValueP(pmSysInfoType,hardware->getSystemHardwareTypeP()); + buildReplyPValue(pmSysInfoDebugLevel,debug_level); + buildReplyPValue(pmSysInfoFreeRam,XUtil.freeRam()); +} + +void XnodeSystem::cmdHelp() { + for (uint8_t i = ZERO; i < SYSTEM_MODULE_ARRAY_SIZE; i++) { + if (systemModules[i] == ZERO) { + continue; + } + systemModules[i]->systemModuleCommandList(); + } + buildReplyCommandListP(pmCmdSysInfo); + buildReplyCommandListP(pmCmdReboot); + buildReplyCommandListP(pmCmdHelp); +} + +void XnodeSystem::registrateSystemModule(XnodeSystemModule* module) { + systemModules[systemModuleIndex++] = module; +} + +// execute cmd with the supplied argument +bool XnodeSystem::executeCommandModule(char* cmd, char** args) { + + // Check for system build in commands. + if (XUtil.strcmpP(cmd, pmCmdHelp) == ZERO) { + cmdHelp(); + return true; + } + if (XUtil.strcmpP(cmd, pmCmdReboot) == ZERO) { + buildReplyPValue(pmCmdReboot,ONE); + reboot_requested = 100; // let reply be send out/back + return true; + } + if (XUtil.strcmpP(cmd, pmCmdSysInfo) == ZERO) { + cmdSysInfo(); + return true; + } + if (XUtil.strcmpP(cmd, pmCmdSysCnfRst) == ZERO) { + hardware->systemHardwareConfigReset(); + buildReplyPValue(pmCmdSysCnfRst,ONE); + configSave(); + buildReplyPValue(pmCmdReboot,ONE); + reboot_requested = 100; + return true; + } + + // Check registated parses. + for (uint8_t i = ZERO; i < SYSTEM_MODULE_ARRAY_SIZE; i++) { + if (systemModules[i] == ZERO) { + continue; + } + if (systemModules[i]->systemModuleCommandExecute(cmd, args)) { + return true; + } + } + return false; // no command found +} + +// Parse the cmd from a buffer +void XnodeSystem::executeCommand(char* input,bool isRemote) { +#ifdef DEBUG_SYSTEM + Serial.print(F("#D XSystem.executeCommand input=")); + Serial.print(input); + Serial.println(); +#endif + if (isRemote) { + XSerial.printCharP(pmRemoteExecutePrefix); + XSerial.printPromt(); + XSerial.printChar(input); + XSerial.print(CHAR_NEWLINE); + } + replyBufferIndex = ZERO; + uint8_t idx = ZERO; + char *cmd, *ptr, *args[CMD_MAX_ARGS]; + if (strtok((char *) input, CMD_WHITE_SPACE) == NULL) { + // no command given so just print new promt. + buildReplyCharP(pmCmdErrUnknown); // TODO: replace with key+value + buildReply(CHAR_NEWLINE); + buildReply('\0'); + return; + } + cmd = (char *) input; + while ((ptr = strtok(NULL, CMD_WHITE_SPACE)) != NULL) { + args[idx] = ptr; + if (++idx == (CMD_MAX_ARGS - ONE)) { + break; + } + } + args[idx] = NULL; + bool parsed = executeCommandModule(cmd, args); + if (!parsed) { + buildReplyCharP(pmCmdErrUnknown); + buildReplyChar(cmd); // TODO: add args + buildReply(CHAR_NEWLINE); + } + buildReply('\0'); +} + +void XnodeSystem::buildReply(unsigned long value, int base) { + char buf[8 * sizeof(long) + ONE]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - ONE]; + *str = ZERO; // reverse printing so start with termination. + if (base < 2) { + base = 10;// fix base 1 or 0 default to decimals + } + do { + unsigned long m = value; + value /= base; + char c = m - base * value; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(value); + return buildReplyChar(str); +} +void XnodeSystem::buildReply(float value,int digitsFull,int digitsDot) { + dtostrf(value, digitsFull, digitsDot, (char*)replyBuffer+replyBufferIndex); + replyBufferIndex += (digitsFull + 1 + digitsDot) - 1; // "999.9" "-99.9" and remove terminating zero. +} +void XnodeSystem::buildReply(char value) { + replyBuffer[replyBufferIndex++] = value; + if (replyBufferIndex > SYSTEM_REPLY_ARRAY_SIZE) { + replyBufferIndex--; + replyBuffer[replyBufferIndex] = ZERO; // terminate last char +#ifdef DEBUG_SYSTEM + Serial.print("#D+"); + Serial.print(value); // print overflow chars + Serial.print("-"); +#endif + } +} +void XnodeSystem::buildReplyChar(char* value) { + while (*value != ZERO) { + buildReply(*value); + value++; + } +} +void XnodeSystem::buildReplyCharP(const char* value) { + buildReplyChar(XUtil.UNPSTR(value)); +} +void XnodeSystem::buildReplyCommandListP(const char* cmdName) { + buildReplyCharP(cmdName); + buildReply(CHAR_NEWLINE); +} +bool XnodeSystem::buildReplyCommandArgumentError(char* cmd, char** args) { + if (args[ZERO] != NULL) { + return false; // nothing printed + } + buildReplyCharP(pmCmdErrArgument); + buildReplyChar(cmd); + buildReply(CHAR_NEWLINE); + return true; +} +void XnodeSystem::buildReplyPValueIP(const char* valueName,uint8_t ip[4]) { + buildReplyCharP(valueName); + buildReply(CHAR_EQUALS); + buildReply(ip[0], DEC); + buildReply(CHAR_DOT); + buildReply(ip[1], DEC); + buildReply(CHAR_DOT); + buildReply(ip[2], DEC); + buildReply(CHAR_DOT); + buildReply(ip[3], DEC); + buildReply(CHAR_NEWLINE); +} + +void XnodeSystem::buildReplyPValue(const char* valueName,unsigned long value) { + buildReplyCharP(valueName); + buildReply(CHAR_EQUALS); + buildReply(value); + buildReply(CHAR_NEWLINE); +} +void XnodeSystem::buildReplyPValue(const char* valueName,int value) { + buildReplyPValue(valueName,(unsigned long)value); +} +void XnodeSystem::buildReplyPValue(const char* valueName,float value,int digitsFull,int digitsDot) { + buildReplyCharP(valueName); + buildReply(CHAR_EQUALS); + buildReply(value,digitsFull,digitsDot); + buildReply(CHAR_NEWLINE); +} +void XnodeSystem::buildReplyPValueP(const char* valueName,const char* valueP) { + buildReplyCharP(valueName); + buildReply(CHAR_EQUALS); + buildReplyCharP(valueP); + buildReply(CHAR_NEWLINE); +} +void XnodeSystem::buildReplyPValueByteA(const char* valueName,byte* value, byte data_len) { + buildReplyCharP(valueName); + buildReply(CHAR_EQUALS); + for (byte i = ZERO; i < data_len; ++i) { + byte d = value[i]; + if (d<0xF) { + buildReply('0'); // exta zero to have two chars + } + buildReply(d, HEX); + } + buildReply(CHAR_NEWLINE); +} + diff --git a/lib/xnode-shared/XnodeSystem.h b/lib/xnode-shared/XnodeSystem.h new file mode 100644 index 0000000..c24b42f --- /dev/null +++ b/lib/xnode-shared/XnodeSystem.h @@ -0,0 +1,49 @@ +#ifndef XnodeSystem_h +#define XnodeSystem_h + +#include +#include +#include +#include +#include +#include +#include + +#define SYSTEM_MODULE_ARRAY_SIZE 4 +#define SYSTEM_REPLY_ARRAY_SIZE 250 + +class XnodeSystem { +private: + void beginDebug(); + bool executeCommandModule(char* cmd, char** args); + void cmdHelp(); + void cmdSysInfo(); + void buildReply(char value); + void buildReplyChar(char* value); + void buildReply(unsigned long value, int = DEC); + void buildReply(float value,int digitsFull,int digitsDot); +public: + char replyBuffer[SYSTEM_REPLY_ARRAY_SIZE]; + XnodeSystemHardware* hardware; + void begin(XnodeSystemHardware* hardware); + void loop(); + void bootDone(); + void configSave(); + void executeCommand(char* input,bool isRemote=false); + void registrateSystemModule(XnodeSystemModule* module); + + void buildReplyCommandListP(const char* cmdName); + bool buildReplyCommandArgumentError(char* cmd, char** args); + void buildReplyCharP(const char* value); + void buildReplyPValueIP(const char* valueName,uint8_t ip[4]); + void buildReplyPValue(const char* valueName,unsigned long value); + void buildReplyPValue(const char* valueName,int value); + void buildReplyPValue(const char* valueName,float value,int digitsFull = 3,int digitsDot = 1); + void buildReplyPValueP(const char* valueName,const char* valueP); + void buildReplyPValueByteA(const char* valueName,byte* value, byte data_len); +}; + +extern XnodeSystem XSystem; + +#endif + diff --git a/lib/xnode-shared/XnodeSystemHardware.h b/lib/xnode-shared/XnodeSystemHardware.h new file mode 100644 index 0000000..c5ac290 --- /dev/null +++ b/lib/xnode-shared/XnodeSystemHardware.h @@ -0,0 +1,15 @@ +#ifndef XnodeSystemHardware_h +#define XnodeSystemHardware_h + +class XnodeSystemHardware { +public: + virtual const char* getSystemHardwareTypeP(); + virtual const char* getSystemHardwareVersionP(); + virtual unsigned long getSystemHardwareRebootCount(); + virtual bool systemHardwareConfigBegin(); + virtual void systemHardwareConfigSave(); + virtual void systemHardwareConfigReset(); +}; + +#endif + diff --git a/lib/xnode-shared/XnodeSystemModule.h b/lib/xnode-shared/XnodeSystemModule.h new file mode 100644 index 0000000..1fca715 --- /dev/null +++ b/lib/xnode-shared/XnodeSystemModule.h @@ -0,0 +1,11 @@ +#ifndef XnodeSystemModule_h +#define XnodeSystemModule_h + +class XnodeSystemModule { +public: + virtual bool systemModuleCommandExecute(char* cmd, char** args); + virtual void systemModuleCommandList(); +}; + +#endif + diff --git a/lib/xnode-shared/XnodeUtil.cpp b/lib/xnode-shared/XnodeUtil.cpp new file mode 100644 index 0000000..e3428df --- /dev/null +++ b/lib/xnode-shared/XnodeUtil.cpp @@ -0,0 +1,85 @@ +#include + +char unpstr_buff[UNPSTR_BUFF_SIZE]; // buffer to copy progmem data into + +// Uncopy from program/flash memory to sram +char* XnodeUtil::UNPSTR(const char* ptr) { + for (uint8_t i = ZERO; i < UNPSTR_BUFF_SIZE; i++) { + unpstr_buff[i] = '\0'; // clean buffer + } + uint8_t i = ZERO; + uint8_t c = ZERO; + do { + c = pgm_read_byte(ptr++); + unpstr_buff[i++] = c; + } while (c != ZERO); + return unpstr_buff; +} + +// Fill pstr_buff from pointer +char* XnodeUtil::UNPSTRA(const uint16_t* argu) { + // rm readByte use word which auto size ptr + uint8_t msb = pgm_read_byte((const char*) argu + 1); + uint8_t lsb = pgm_read_byte((const char*) argu); + const char*p = (const char*) ((msb * 256) + lsb); + return UNPSTR(p); +} + +uint8_t XnodeUtil::strcmp(char *s1, char *s2) { + while (*s1 && *s2 && *s1 == *s2) { + s1++; + s2++; + } + if (*s1 == *s2) { + return 0; + } + if (*s1 < *s2) { + return -1; + } + return 1; +} + +uint8_t XnodeUtil::strcmpP(char *s1, const char* s2) { + return strcmp(s1, UNPSTR(s2)); +} + +void XnodeUtil::charsToByteA(char* input,byte* data, byte data_len) { + for (byte i = ZERO; i < data_len; i++) { + data[i] = ZERO; // clear array + } + byte charIdx = ZERO; + for (byte i = ZERO; i < data_len; i++) { + char c1 = input[charIdx]; + char c2 = input[charIdx + ONE]; + if (c1 == ZERO || c2 == ZERO) { + break; + } + data[i] = charsToByte(c1, c2); + charIdx++; + charIdx++; + } +} + +byte XnodeUtil::charsToByte(char c1, char c2) { + byte result = ZERO; + result += charToNibble(c1) * 16; + result += charToNibble(c2); + return result; +} + +byte XnodeUtil::charToNibble(char c) { + uint8_t result = ZERO; + if (c > '0' && c <= '9') { + result = c - '0'; + } else if (c >= 'A' && c <= 'F') { + result = c - 'A' + 10; + } + return result; +} + +int XnodeUtil::freeRam() { + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} + diff --git a/lib/xnode-shared/XnodeUtil.h b/lib/xnode-shared/XnodeUtil.h new file mode 100644 index 0000000..a8ad37c --- /dev/null +++ b/lib/xnode-shared/XnodeUtil.h @@ -0,0 +1,27 @@ +#ifndef XnodeUtil_h +#define XnodeUtil_h + +#include +#include +#include + +#define UNPSTR_BUFF_SIZE 32 + +class XnodeUtil { +public: + static char* UNPSTR(const char* ptr); + static char* UNPSTRA(const uint16_t* argu); + static uint8_t strcmp(char *s1, char *s2); + static uint8_t strcmpP(char *s1, const char* s2); + + static void charsToByteA(char* input,byte* data, byte data_len); + static byte charsToByte(char c1, char c2); + static byte charToNibble(char s); + + static int freeRam(); +}; + +extern XnodeUtil XUtil; + +#endif + diff --git a/protocol-a.txt b/protocol-a.txt new file mode 100644 index 0000000..43f1192 --- /dev/null +++ b/protocol-a.txt @@ -0,0 +1,59 @@ + +Protocol description Xnode-base to Xensit-server version A. + +== Abstract + +http-host: beta.xensit.com +http-method: POST +http-uri: _a +http-param-get: none +http-param-post: pt|rc|ni|nd|nn + +== Post body description + +pt = Post Type +rc = Request Counter +ni = Network Id +nd = Node Data +nn = Node Number (id) + +== Post Type parameter description + +Post Type options: +p = Sending ping +i = Sending Init request +d = Sending Data + +== Post server reply + +- Single line +- Max 40 char (or 42 chars with XX prefix counted) +- Must ALWAYS start with X(ensit) for valid reply. +- Second char is command type in uppercase: + i = Execute next init cmd. + X = Execute next normal cmd. + +== Example: Init cycle + +10.11.12.205 Mon, 17 Feb 2014 20:10:37 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=p&rc=55&ni=000000000000} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:10:37 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=p&rc=56&ni=000000000000} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:10:39 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=i&rc=59&ni=000000000000} R{Xinet_id 1234694D33B2} +10.11.12.205 Mon, 17 Feb 2014 20:10:38 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=i&rc=57&ni=000000000000} R{Xinet_key 9A2EE3A293486E9FE73D77EFC8087D2F} +10.11.12.205 Mon, 17 Feb 2014 20:10:39 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=i&rc=58&ni=1234694D33B2} R{Xirf_key 9A2EE3A293486E9FE73D77EFC8087D2F} +10.11.12.205 Mon, 17 Feb 2014 20:10:39 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=i&rc=59&ni=1234694D33B2} R{Xinet_mac 7469694D33B2} +10.11.12.205 Mon, 17 Feb 2014 20:10:40 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=i&rc=60&ni=1234694D33B2} R{Xireboot} +10.11.12.205 Mon, 17 Feb 2014 20:11:39 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=p&rc=55&ni=1234694D33B2} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:11:39 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=p&rc=56&ni=1234694D33B2} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:16:42 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=57&ni=1234694D33B2&nn=1&nd={rf_fail=1}} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:20:41 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=58&ni=1234694D33B2&nn=1&nd={rf_fail=1}} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:24:41 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=59&ni=1234694D33B2&nn=1&nd={rf_fail=1}} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:28:41 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=60&ni=1234694D33B2&nn=1&nd={rf_fail=1}} R{X} +10.11.12.205 Mon, 17 Feb 2014 20:32:40 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=61&ni=1234694D33B2&nn=1&nd={rf_fail=1}} R{X} + +== Example: Sensor data + +10.11.12.205 Tue, 18 Feb 2014 00:12:25 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=43&ni=1234694D33B2&nn=2&nd={sd_dht_hum=34.000\nsd_dht_temp=23.000}} R{X} +10.11.12.205 Tue, 18 Feb 2014 00:12:30 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=44&ni=1234694D33B2&nn=2&nd={sd_dht_hum=33.000\nsd_dht_temp=24.000}} R{X} +10.11.12.205 Tue, 18 Feb 2014 00:12:35 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=45&ni=1234694D33B2&nn=2&nd={sd_dht_hum=33.000\nsd_dht_temp=24.000}} R{X} +10.11.12.205 Tue, 18 Feb 2014 00:12:40 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=46&ni=1234694D33B2&nn=2&nd={sd_dht_hum=34.000\nsd_dht_temp=24.000}} R{X} +10.11.12.205 Tue, 18 Feb 2014 00:12:45 +0000 URI{http://beta.xensit.com/_a} G{} P{pt=d&rc=47&ni=1234694D33B2&nn=2&nd={sd_dht_hum=33.000\nsd_dht_temp=25.000}} R{X} diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..61f4daf --- /dev/null +++ b/readme.txt @@ -0,0 +1,7 @@ + +Xensit Xnode project + +This projects contains all packages to build the +software for all the different node types of the sensor network. + + diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..5e9cb35 --- /dev/null +++ b/todo.txt @@ -0,0 +1,64 @@ + +ERR: + - delayed linkup and dhcp, will garble second packet so has wrong net_id. (1st is ok,2=err,3++ is ok,*++ some err) + +PCB: + - ftdi mask DTR is RST + - ftdi mask PWR is 5v + - int or-gate diodes + - add jt batt pulse charger ? + +CODE: + - auto mac address + - sat sleep + - sat sensors + - sat sensors more + - sat boot flash code + - base sat flash code + - base rssi data send (rf signal strength) + + + - sat radio, auto lower power level icm rssi reply server + + - xnode uuid + - base is indepent of xnode + + - rf_key = comm + - rf_key_reboot = hardcoded default for reboot secure init + - rf_key_init = requirement: walking of node into base without user action + + + - base in promise + - after knock goto rf_key_init for 1min + + + - rm net_id nodeDAta + + - sat failed base after user-ack failed. + - per 5min + - prev key_init is from prev base init + - open channel port knock for request key_init + - base rf encryt to rk_key_init + - sat ook rf_key_init + - do secure xnode sat init. + - done + + - mega-flash node-uuid api over net + - isp_repair struck uuid offset uit build. + + - example + 15 sats + 3 base + result + ~ 5 sat per base + on sat reboot init can switch base. + + - xnode sat init + - any base will do. + +BUILD: + - make: add flags per file so suppress warnings about lib-ext. + - make: fix parent Makefile to support seperate clean and all targets. + - update hex2c to use sections_struct and rm casting + + diff --git a/xnode-base/Makefile b/xnode-base/Makefile new file mode 100644 index 0000000..e07f97f --- /dev/null +++ b/xnode-base/Makefile @@ -0,0 +1,5 @@ +# Minimal makefile only includes the master and libs. +MASTER_LIBS = rfm69 spi dht ethercard xnode-shared +SKT_PDE_SRC = XnodeBase.cpp +include ../lib-build/make/Makefile.master + diff --git a/xnode-base/XnodeBase.cpp b/xnode-base/XnodeBase.cpp new file mode 100644 index 0000000..09560c8 --- /dev/null +++ b/xnode-base/XnodeBase.cpp @@ -0,0 +1,34 @@ +/* + * Xnode Base + */ + +#include +#include +#include +#include +#include + +void setup() { + // Build system modules + XSystem.registrateSystemModule(&XBNetwork); + XSystem.registrateSystemModule(&XBRadio); + + // Init system modules + XSerial.begin(); + XSystem.begin(&XBHardware); + XBHardware.begin(); + XBNetwork.begin(); + XBRadio.begin(); + + // Mark device booted + XSystem.bootDone(); +} + +void loop() { + XSerial.loop(); + XSystem.loop(); + XBHardware.loop(); + XBNetwork.loop(); + XBRadio.loop(); +} + diff --git a/xnode-base/XnodeBaseConfig.h b/xnode-base/XnodeBaseConfig.h new file mode 100644 index 0000000..0eb00c8 --- /dev/null +++ b/xnode-base/XnodeBaseConfig.h @@ -0,0 +1,32 @@ +#ifndef XnodeBaseConfig_h +#define XnodeBaseConfig_h + +#include + +union NetKey_t { + unsigned long int u32[NET_BYTE_NET_KEY_SIZE / 4]; + unsigned char u8[NET_BYTE_NET_KEY_SIZE]; +}; +typedef union NetKey_t NetKey; + +// Config data +typedef struct { + uint16_t eeprom_struct_size; // Config size changes it data defaults to zeros + + byte net_mac[NET_BYTE_MAC_SIZE]; + byte net_ip[NET_BYTE_IP_SIZE]; + byte net_mask[NET_BYTE_IP_SIZE]; + byte net_gate[NET_BYTE_IP_SIZE]; + byte net_dns[NET_BYTE_IP_SIZE]; + NetKey net_key; + byte net_id[NET_BYTE_NET_ID_SIZE]; + + byte rf_key[RF_KEY_SIZE]; + byte rf_next_node_id; + + unsigned long sys_boot; // boot counter + +} xnode_base_config_t; + +#endif + diff --git a/xnode-base/XnodeBaseHardware.cpp b/xnode-base/XnodeBaseHardware.cpp new file mode 100644 index 0000000..926a3c8 --- /dev/null +++ b/xnode-base/XnodeBaseHardware.cpp @@ -0,0 +1,172 @@ +#include + +const char pmSystemHardwareType[] PROGMEM = "xnode-base"; +const char pmSystemHardwareVersion[] PROGMEM = XNODE_VERSION; +const char pmSysTestLeds[] PROGMEM = "System leds test"; + +byte CONFIG_DEFAULT_NET_MAC[] = NET_XNODE_MAC_DEFAULT; +unsigned long blink_timer = ZERO; +uint8_t blink_led = ZERO; +uint8_t blink_status = ZERO; + +xnode_base_config_t config; +xnode_base_config_t EEMEM eeprom; +XnodeBaseHardware XBHardware; + +void XnodeBaseHardware::begin() { + pinMode(HW_PIN_ERROR_LED, OUTPUT); + pinMode(HW_PIN_RADIO_LED, OUTPUT); + pinMode(HW_PIN_NETWORK_LED, OUTPUT); + + changeLed(SYS_LED_ERROR, SYS_LED_STATUS_ON); + changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON); + changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON); + + XSerial.printCommentLineP(pmSysTestLeds); + delay(SYS_LED_TEST_TIME); // let users see all leds + + changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF); + changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF); + changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF); +} + +void XnodeBaseHardware::loop() { + loopBlink(); +} + +bool XnodeBaseHardware::systemHardwareConfigBegin() { + eeprom_read_block((void*) &config, (void*) &eeprom, sizeof(xnode_base_config_t)); + if (config.eeprom_struct_size != sizeof(xnode_base_config_t)) { + return true; + } + config.sys_boot++; + return false; +} + +void XnodeBaseHardware::systemHardwareConfigSave() { + config.eeprom_struct_size = sizeof(xnode_base_config_t); + eeprom_write_block((const void*) &config, (void*) &eeprom, sizeof(xnode_base_config_t)); +} + +void XnodeBaseHardware::systemHardwareConfigReset() { + // Temp code way + config.net_mac[0] = ZERO; + config.net_mac[1] = ZERO; + config.net_mac[2] = ZERO; + config.net_mac[3] = ZERO; + config.net_mac[4] = ZERO; + config.net_mac[5] = ZERO; + + config.net_ip[0] = ZERO; + config.net_ip[1] = ZERO; + config.net_ip[2] = ZERO; + config.net_ip[3] = ZERO; + + config.net_mask[0] = ZERO; + config.net_mask[1] = ZERO; + config.net_mask[2] = ZERO; + config.net_mask[3] = ZERO; + + config.net_gate[0] = ZERO; + config.net_gate[1] = ZERO; + config.net_gate[2] = ZERO; + config.net_gate[3] = ZERO; + + config.net_dns[0] = ZERO; + config.net_dns[1] = ZERO; + config.net_dns[2] = ZERO; + config.net_dns[3] = ZERO; + + config.sys_boot = ZERO; + // end Temp + + // TODO: Temp fix cast~~ so clear config zering all in one go. + //for (uint16_t i=ZERO;i> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]); + } + v[0]=v0; v[1]=v1; +} + +void XnodeBaseNetwork::xxteaDecrypt(unsigned long v[2]) { + unsigned int i; + uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*XXTEA_NUM_ROUNDS; + for (i=0; i < XXTEA_NUM_ROUNDS; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + XBHardware.config.net_key.u32[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + XBHardware.config.net_key.u32[sum & 3]); + } + v[0]=v0; v[1]=v1; +} + +int XnodeBaseNetwork::parseReplyData(word off) { + memset(line_buf, NULL, sizeof(line_buf)); + if (off != 0) { + uint16_t pos = off; + int line_pos = 0; + + // Skip over header until data part is found + while (Ethernet::buffer[pos]) { + if (Ethernet::buffer[pos - 1] == '\n' && Ethernet::buffer[pos] == '\r') { + break; + } + pos++; + } + pos += 2; + while (Ethernet::buffer[pos]) { + if (line_pos < 49) { + line_buf[line_pos] = Ethernet::buffer[pos]; + line_pos++; + } else { + break; + } + pos++; + } + line_buf[line_pos] = '\0'; + return line_pos; + } + return 0; +} + +void XnodeBaseNetwork::sendStart(char postType) { + if (stashSession != ZERO) { + int maxWait = 100; + while (stashSession != ZERO) { + loop(); + maxWait--; + if (maxWait == ZERO) { + break; + } + } + +#ifdef DEBUG_NETWORK + if (stashSession != ZERO) { + Serial.println(F("#D kill prev tcp req")); + } +#endif + //return; // data is already sending (TODO: move ??) + } + + stashStart = stash.create(); + stash.print(XUtil.UNPSTR(pmNetworkUrlParaPostType)); + stash.print(postType); + stash.print(XUtil.UNPSTR(pmNetworkUrlParaReqCnt)); + stash.print(net_tx++); + stash.print(XUtil.UNPSTR(pmNetworkUrlParaNetId)); + for (byte i = ZERO; i < NET_BYTE_NET_ID_SIZE; ++i) { + byte data = XBHardware.config.net_id[i]; + if (data<0xF) { + stash.print(ZERO); // extra zero to have fixed length hex string + } + stash.print(data, HEX); + } +} + +void XnodeBaseNetwork::sendPing() { + sendStart(NET_URL_PT_PING); + net_status_data = NET_URL_PT_PING; +} + +void XnodeBaseNetwork::sendInit() { +#ifdef DEBUG_NETWORK + Serial.println(F("#D req init")); +#endif + sendStart(NET_URL_PT_INIT); + net_status_data = NET_URL_PT_INIT; +} + +NetKey x_data; + +void XnodeBaseNetwork::sendNodeData(byte senderId, char* data) { + sendStart(NET_URL_PT_DATA); + stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeNumber)); + stash.print((int) senderId); + stash.print(XUtil.UNPSTR(pmNetworkUrlParaNodeData)); + + char* dstring = data; + while (*dstring != 0) { + char value = *dstring; + dstring++; + stash.print(value); + } + + /* + byte i = 0; + char* dstring = data; + while (*dstring != 0) { + x_data.u8[i] = *dstring; + dstring++; + i++; + if (i==8) { + i = 0; + xxteaEncrypt(x_data.u32); + for (byte i = 0; i < 8; ++i) { + char value = x_data.u8[i]; + if (value == 0) { + stash.print('00'); + continue; + } + if (value <= 0xF) { + stash.print('0'); + } + stash.print(value,HEX); + } + } + } + while(i < 8) { + x_data.u8[i] = 0; + i++; + } + xxteaEncrypt(x_data.u32); + for (byte i = 0; i < 8; ++i) { + char value = x_data.u8[i]; + if (value == 0) { + stash.print('00'); + continue; + } + if (value <= 0xF) { + stash.print('0'); + } + stash.print(value,HEX); + } + */ + net_status_data = NET_URL_PT_DATA; +} + +void XnodeBaseNetwork::loopDataTX() { + if (net_status_data == ZERO) { + return; // no data to send + } + if (!ether.isLinkUp()) { + if (net_status_ip == ZERO) { + XSerial.printCommentLineP(pmNetworkLinkError); + } + net_status_ip = ONE; + return; // link down; request new ip when link gets up. + } + + XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_ON); + +#ifdef DEBUG_NETWORK + Serial.print(F("#D sendHttp pt=")); + Serial.print((char)net_status_data); + Serial.print(F(" size=")); + Serial.println((char)stash.size(),DEC); +#endif + + stash.save(); + Stash::prepare(PSTR("POST http://$F/$F HTTP/1.1" "\r\n" + "Host: $F" "\r\n" + "Cache-Control: no-cache" "\r\n" + "Content-type: application/x-www-form-urlencoded;\r\n" + "Accept: application/xhtml+xml" "\r\n" + "Content-Length: $D" "\r\n" + "\r\n" + "$H"), pmNetworkServer, pmNetworkUrlPost, pmNetworkServer, stash.size(), stashStart); + net_tx_open++; + net_status_data = ZERO; + stashSession = ether.tcpSend(); // releases also stash buf + //stash.release(); +} + +void XnodeBaseNetwork::loopDataRX() { + if (stashSession == ZERO) { + return; // no reply to search for + } + const char* msgStart = ether.tcpReply(stashSession); + if (msgStart == ZERO) { +#ifdef DEBUG_NETWORK + Serial.println(F("#D wait tcpReply")); +#endif + delay(100); + return; // no reply yet + } + + net_rx++; + stashSession = ZERO; + parseReplyData((int) *msgStart); + handleServerResult(); + XBHardware.changeLed(SYS_LED_NETWORK, SYS_LED_STATUS_OFF); +} + +void XnodeBaseNetwork::handleServerResult() { + if (line_buf[ZERO] != NET_URL_RESULT_OK) { + XSerial.printCharP(pmNetworkResultError); + Serial.print(line_buf[ZERO], HEX); // TODO: check +#ifdef DEBUG_NETWORK + Serial.print(CHAR_SPACE); + for (int i=0;i<10;i++) { + if (line_buf[i] != ZERO) { + Serial.print(line_buf[i]); + } + } +#endif + XSerial.print(CHAR_NEWLINE); + return; + } + net_tx_open--; // valid result + net_status_reply = ONE; // we have reply + + if (line_buf[ONE] == ZERO) { + return; // Only X returns so nop. + } + + if (line_buf[ONE] == NET_URL_PT_INIT) { + XSystem.executeCommand(line_buf + ONE + ONE,true); // skip Xi chars + loop(); // Else we miss most of the time the second init request. + loop(); // an other extra to be sure we done miss the second request. + sendInit(); // request next init command + return; + } + if (line_buf[ONE] == NET_URL_RESULT_OK) { + XSystem.executeCommand(line_buf + ONE + ONE,true); // skip XX chars + loop(); + loop(); + sendNodeData(RF_BASE_NODE_ID,XSystem.replyBuffer); // send reply as + } +} + +bool XnodeBaseNetwork::isUp() { + return ZERO == (net_status_eth + net_status_ip + net_status_dns); +} + +void XnodeBaseNetwork::loopAutoSetup() { + unsigned long time = millis(); + // auto dhcp + if (net_status_ip == ONE) { + if (time < net_dhcp_retry_timer) { + return; // wait + } + net_dhcp_retry_timer = millis() + (unsigned long) NET_DHCP_RETRY_TIME; + setupIp(); + if (net_status_ip == ONE) { + return; // failed dhcp + } + net_status_dns = ONE; // when link plugs in later + net_dns_lookup_timer = ONE; // then do direct dns lookup + } + // auto dns + if (net_status_dns == ONE) { + if (time < net_dns_lookup_timer) { + return; // wait + } + net_dns_lookup_timer = time + (unsigned long) NET_DNS_LOOKUP_TIME; + XSerial.executeCommandP(pmNetworkServerLookup); + } + // auto dns refresh + if (net_status_dns == ZERO && time > net_dns_lookup_timer) { + net_status_dns = ONE; + } +} + +// FIXME: without chip it takes 3 watchdog reboots before no chip result ?? (prev lib version) +void XnodeBaseNetwork::setupChip() { + XSerial.printCommentLineP(pmNetworkChipBoot); + if (ether.begin(sizeof Ethernet::buffer, XBHardware.config.net_mac, HW_PIN_SPI_ETH0_CS) == ZERO) { + XSerial.printCommentLineP(pmNetworkChipError); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK); + net_status_eth = ONE; + return; + } + ether.disableBroadcast(); + ether.disableMulticast(); + delay(100); // needed for link isLinkUp to return valid value. +} + +void XnodeBaseNetwork::setupIp() { + net_status_ip = ZERO; + if (net_status_eth != ZERO) { + return; // no chip + } + if (!ether.isLinkUp()) { + net_status_ip = ONE; // do again + XSerial.printCommentLineP(pmNetworkLinkError); + return; + } + + // Setup static if ip is given. + if (XBHardware.config.net_ip[ZERO] != ZERO) { + XSerial.printCommentLineP(pmNetworkStaticBoot); + ether.staticSetup(XBHardware.config.net_ip, XBHardware.config.net_gate, XBHardware.config.net_dns); + ether.copyIp(ether.netmask, XBHardware.config.net_mask); + return; + } + XSerial.printCommentLineP(pmNetworkDhcpBoot); + wdt_disable(); + if (!ether.dhcpSetup()) { + net_status_ip = ONE; // do again + XSerial.printCommentLineP(pmNetworkDhcpError); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_ON); // TODO: fix led blinking on timer int. + } else { + XSerial.printCommentLineP(pmNetworkDhcpDone); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF); // set led off after recovery + } + wdt_enable(WDT_TIMEOUT); // no link or no dhcp will take long timeout ~30s + +#ifdef DEBUG_NET_GATE + if (net_status_ip == ZERO) { + byte debug_gate[NET_BYTE_IP_SIZE] = DEBUG_NET_GATE; // transparent http proxy network config. + ether.copyIp(ether.gwip, debug_gate); + Serial.println(F("#D Used debug gate ip")); + } +#endif +} + +void XnodeBaseNetwork::cmdDnsLookup() { + net_status_dns = ZERO; + if (net_status_eth != ZERO) { + return; // no chip + } + if (net_status_ip != ZERO) { + net_status_dns = ONE; + return; // no ip + } + +#ifdef DEBUG_NET_HISIP + byte debug_hisip[NET_BYTE_IP_SIZE] = DEBUG_NET_HISIP; + ether.copyIp(ether.hisip, debug_hisip); + Serial.println(F("#D Used debug dns ip")); + return; +#endif + + wdt_disable(); + if (!ether.dnsLookup(pmNetworkServer)) { + net_status_dns = ONE; + XSystem.buildReplyPValue(pmNetworkServerLookup,ZERO); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK); + } else { + XSystem.buildReplyPValue(pmNetworkServerLookup,ONE); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_OFF); + } + wdt_enable (WDT_TIMEOUT); +} + +void XnodeBaseNetwork::cmdInfoEth0() { + // Print currently used config + XSystem.buildReplyCharP(pmNetworkUsePrefix); + XSystem.buildReplyPValueIP(pmNetworkConfigIp, ether.myip); + XSystem.buildReplyCharP(pmNetworkUsePrefix); + XSystem.buildReplyPValueIP(pmNetworkConfigMask, ether.netmask); + XSystem.buildReplyCharP(pmNetworkUsePrefix); + XSystem.buildReplyPValueIP(pmNetworkConfigGate, ether.gwip); + XSystem.buildReplyCharP(pmNetworkUsePrefix); + XSystem.buildReplyPValueIP(pmNetworkConfigDns, ether.dnsip); + XSystem.buildReplyCharP(pmNetworkUsePrefix); + XSystem.buildReplyPValueByteA(pmNetworkConfigMac,ether.mymac, NET_BYTE_MAC_SIZE); +} + +void XnodeBaseNetwork::cmdInfo() { + // Print server value and lookup + XSystem.buildReplyPValueP(pmNetworkServerHost,pmNetworkServer); + XSystem.buildReplyPValueIP(pmNetworkServerIp, ether.hisip); + + // Print config + XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE); + XSystem.buildReplyPValueIP(pmNetworkConfigIp, XBHardware.config.net_ip); + XSystem.buildReplyPValueIP(pmNetworkConfigMask, XBHardware.config.net_mask); + XSystem.buildReplyPValueIP(pmNetworkConfigGate, XBHardware.config.net_gate); + XSystem.buildReplyPValueIP(pmNetworkConfigDns, XBHardware.config.net_dns); + XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE); + XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE); + + XSystem.buildReplyPValue(pmNetworkInfoTXOpen, (int) net_tx_open); + XSystem.buildReplyPValue(pmNetworkInfoTX, net_tx); + XSystem.buildReplyPValue(pmNetworkInfoRX, net_rx); +} + +void XnodeBaseNetwork::parseCommandIp(const char* pmName, char** args, byte* ip_conf) { + ether.parseIp(ip_conf, args[ZERO]); + XSystem.buildReplyPValueIP(pmName, ip_conf); + XSystem.configSave(); // auto save on change +} + +void XnodeBaseNetwork::systemModuleCommandList() { + XSystem.buildReplyCommandListP(pmNetworkConfigInfo); + XSystem.buildReplyCommandListP(pmNetworkConfigInfoEth0); + XSystem.buildReplyCommandListP(pmNetworkConfigMac); + XSystem.buildReplyCommandListP(pmNetworkConfigIp); + XSystem.buildReplyCommandListP(pmNetworkConfigMask); + XSystem.buildReplyCommandListP(pmNetworkConfigGate); + XSystem.buildReplyCommandListP(pmNetworkConfigDns); + XSystem.buildReplyCommandListP(pmNetworkPing); + XSystem.buildReplyCommandListP(pmNetworkServerLookup); +#ifdef DEBUG_NETWORK + XSystem.buildReplyCommandListP(pmNetworkConfigId); // keep secret that these cmd work + XSystem.buildReplyCommandListP(pmNetworkConfigKey); // for init over network with this. +#endif +} + +bool XnodeBaseNetwork::systemModuleCommandExecute(char* cmd, char** args) { + if (XUtil.strcmpP(cmd, pmNetworkConfigInfo) == ZERO) { + cmdInfo(); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigInfoEth0) == ZERO) { + cmdInfoEth0(); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigId) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + XUtil.charsToByteA(args[ZERO],XBHardware.config.net_id, NET_BYTE_NET_ID_SIZE); + XSystem.buildReplyPValueByteA(pmNetworkConfigId,XBHardware.config.net_id,NET_BYTE_NET_ID_SIZE); + XSystem.configSave(); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigKey) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + XUtil.charsToByteA(args[ZERO],XBHardware.config.net_key.u8, NET_BYTE_NET_KEY_SIZE); + XSystem.buildReplyPValueByteA(pmNetworkConfigKey,XBHardware.config.net_key.u8,NET_BYTE_NET_KEY_SIZE); + XSystem.configSave(); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigMac) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + XUtil.charsToByteA(args[ZERO],XBHardware.config.net_mac, NET_BYTE_MAC_SIZE); + XSystem.buildReplyPValueByteA(pmNetworkConfigMac,XBHardware.config.net_mac, NET_BYTE_MAC_SIZE); + XSystem.configSave(); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigIp) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + parseCommandIp(pmNetworkConfigIp, args, XBHardware.config.net_ip); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigMask) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + parseCommandIp(pmNetworkConfigMask, args, XBHardware.config.net_mask); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigGate) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + parseCommandIp(pmNetworkConfigGate, args, XBHardware.config.net_gate); + return true; + + } else if (XUtil.strcmpP(cmd, pmNetworkConfigDns) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + parseCommandIp(pmNetworkConfigDns, args, XBHardware.config.net_dns); + return true; + } else if (XUtil.strcmpP(cmd, pmNetworkPing) == ZERO) { + sendPing(); + return true; + } else if (XUtil.strcmpP(cmd, pmNetworkServerLookup) == ZERO) { + cmdDnsLookup(); + return true; + } + return false; +} diff --git a/xnode-base/XnodeBaseNetwork.h b/xnode-base/XnodeBaseNetwork.h new file mode 100644 index 0000000..ae20c3e --- /dev/null +++ b/xnode-base/XnodeBaseNetwork.h @@ -0,0 +1,53 @@ +#ifndef XnodeBaseNetwork_h +#define XnodeBaseNetwork_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XXTEA_NUM_ROUNDS 32 + +class XnodeBaseNetwork: public XnodeSystemModule { +private: + int parseReplyData(word off); + + void sendStart(char postType); + void loopAutoSetup(); + void loopDataTX(); + void loopDataRX(); + void loopPingBoot(); + void loopPingHost(); + void handleServerResult(); + void setupChip(); + void setupIp(); + void sendPing(); + void sendInit(); + void parseCommandIp(const char* pmName, char** args, byte* ip_conf); + void xxteaEncrypt(unsigned long v[2]); + void xxteaDecrypt(unsigned long v[2]); + + void cmdDnsLookup(); + void cmdInfo(); + void cmdInfoEth0(); +public: + void begin(); + void loop(); + bool isUp(); + + void sendNodeData(byte senderId, char* data); + + // from XnodeSystemModule + bool systemModuleCommandExecute(char* cmd, char** args); + void systemModuleCommandList(); +}; + +extern XnodeBaseNetwork XBNetwork; + +#endif + diff --git a/xnode-base/XnodeBaseRadio.cpp b/xnode-base/XnodeBaseRadio.cpp new file mode 100644 index 0000000..3216d1e --- /dev/null +++ b/xnode-base/XnodeBaseRadio.cpp @@ -0,0 +1,243 @@ +#include + +const char pmRadioChipInit[] PROGMEM = MSG_RF_CHIP_INIT; +const char pmRadioChipError[] PROGMEM = MSG_RF_CHIP_ERROR; + +const char pmRadioInfoFreq[] PROGMEM = MSG_RF_INFO_FREQ; +const char pmRadioInfoNetwork[] PROGMEM = MSG_RF_INFO_NETWORK; +const char pmRadioInfoNode[] PROGMEM = MSG_RF_INFO_NODE; +const char pmRadioInfoKey[] PROGMEM = MSG_RF_INFO_KEY; +const char pmRadioInfoTx[] PROGMEM = MSG_RF_INFO_TX; +const char pmRadioInfoRx[] PROGMEM = MSG_RF_INFO_RX; +const char pmRadioInfoTxe[] PROGMEM = MSG_RF_INFO_TXE; +const char pmRadioInfoNextNode[] PROGMEM = "rf_next_node"; + +//const char pmRadioInfoNextNode[] PROGMEM = "rf_sat"; + +const char pmRadioEncrypt[] PROGMEM = MSG_RF_ENCRYPT; +const char pmRadioInfo[] PROGMEM = MSG_RF_INFO; + +const char pmRadioSendFailRf[] PROGMEM = "rf_fail=1"; + +volatile unsigned long key_encrypt_timer = ZERO; +volatile unsigned long rf_no_data_timer = ZERO; + +unsigned long rf_tx = ZERO; +unsigned long rf_rx = ZERO; +unsigned long rf_txe = ZERO; + +uint16_t rf_ping_count = ZERO; +uint8_t rf_status_data = ZERO; +uint8_t rf_status_ping = ZERO; +uint8_t rf_status_chip = ZERO; + +byte rf_data_sender_id; +xp_super_t rf_data; +xp_msg_init_t* rf_msg_init; +xp_msg_flash_t* rf_msg_flash; +xp_msg_char_t* rf_msg_char; + +RFM69 radio; +XnodeBaseRadio XBRadio; + +void XnodeBaseRadio::begin() { + XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON); + + // Init radio chip + XSerial.printCommentLineP(pmRadioChipInit); + if (!radio.initialize(RF_FREQUENCY, RF_BASE_NODE_ID, RF_NETWORK_ID)) { + XSerial.printCommentLineP(pmRadioChipError); + XBHardware.changeLed(SYS_LED_ERROR, SYS_LED_STATUS_BLINK); + rf_status_chip = ONE; + return; + } + radio.promiscuous(true); + + XSerial.executeCommandP(pmRadioInfo); + + // init of time window until rf is encrypted and idle timeout + key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME; + rf_no_data_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME + (unsigned long) RF_NO_DATA_FAIL_TIME; +} + +void XnodeBaseRadio::loop() { + if (rf_status_chip != ZERO) { + return; // no chip + } + if (key_encrypt_timer != ZERO && millis() > key_encrypt_timer) { + cmdClose(); + } + checkNoDataTimeout(); + + if (!radio.receiveDone()) { + return; + } + XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_ON); + rf_no_data_timer = millis() + (unsigned long) RF_NO_DATA_FAIL_TIME; + rf_rx++; + rf_status_data = ZERO; + rf_data = *(xp_super_t*) radio.DATA; + rf_data_sender_id = radio.SENDERID; + +#ifdef DEBUG_RADIO + Serial.print(F("#D rf_rx ")); + Serial.print(rf_data_sender_id,DEC); + Serial.print(CHAR_SPACE); + Serial.print(rf_data.msg_type,DEC); + Serial.print(CHAR_NEWLINE); +#endif + // always reply ack if requested, see sendWithRetry impl (before reply with sendWithRetry) + if (radio.ACK_REQUESTED) { +#ifdef DEBUG_RADIO + Serial.println(F("#D rf_sendACK")); +#endif + radio.sendACK(); + } + + if (rf_data.msg_type == RF_MSG_NODE_DATA) { + rf_msg_char = (xp_msg_char_t*) rf_data.msg_data; + XBNetwork.sendNodeData(rf_data_sender_id, rf_msg_char->char_data); + } else if (rf_data.msg_type == RF_MSG_NODE_INIT) { + rf_msg_init = (xp_msg_init_t*) rf_data.msg_data; + handleCmdInit(); + } else if (rf_data.msg_type == RF_MSG_NODE_FLASH) { + rf_msg_flash = (xp_msg_flash_t*) rf_data.msg_data; + handleCmdFlash(); + } + checkPing(); // sets radio.SENDERID to zero because it sends data + + + XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF); +} + +void XnodeBaseRadio::checkPing() { + rf_ping_count++; + if (rf_ping_count % 10 != ZERO) { + return; + } + rf_status_ping = ZERO; // reset good +#ifdef DEBUG_RADIO + Serial.print(F("#D rf_ping ")); + Serial.print(radio.SENDERID); + Serial.print(CHAR_NEWLINE); +#endif + + delay(3); //need this when sending right after reception .. ? + rf_tx++; + if (!radio.sendWithRetry(radio.SENDERID, "ACK TEST", 8, 0)) { // 0 = only 1 attempt, no retries + rf_txe++; + rf_status_ping = ONE; // bad + } +} + +void XnodeBaseRadio::checkNoDataTimeout() { + if (millis() < rf_no_data_timer) { + return; // wait until time is passed + } + rf_no_data_timer = millis() + (unsigned long) RF_NO_DATA_FAIL_TIME; + + rf_msg_char = (xp_msg_char_t*) rf_data.msg_data; // hacky reuse sensor buffer to send data + strcpy(rf_msg_char->char_data, XUtil.UNPSTR(pmRadioSendFailRf)); // because send also used unpstr buffer + XBNetwork.sendNodeData(RF_BASE_NODE_ID, rf_msg_char->char_data); +} + +void XnodeBaseRadio::sendReply() { + rf_tx++; + if (!radio.sendWithRetry(rf_data_sender_id, (const void*) &rf_data, sizeof(xp_super_t))) { + rf_txe++; + } +} + +void XnodeBaseRadio::handleCmdFlash() { + + sendReply(); +} + +void XnodeBaseRadio::handleCmdInit() { + for (byte i = ZERO; i < RF_KEY_SIZE; ++i) { + rf_msg_init->rf_key[i] = XBHardware.config.rf_key[i]; + } +#ifdef DEBUG_RADIO + Serial.print(F("#D rf_init ")); + Serial.print(rf_msg_init->node_id); + Serial.print(CHAR_NEWLINE); +#endif + + if (rf_msg_init->node_id == ZERO) { + rf_msg_init->node_id = XBHardware.config.rf_next_node_id; + + // Save next node id + XBHardware.config.rf_next_node_id++; + XSystem.configSave(); + } + sendReply(); + + // update open encrypt timer so user can init multiple devices one at the time + key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME; +} + +void XnodeBaseRadio::cmdClose() { + XSystem.buildReplyPValue(pmRadioEncrypt, ONE); + radio.encrypt((const char*) XBHardware.config.rf_key); + key_encrypt_timer = ZERO; // flag encrypted + XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_OFF); +} + +void XnodeBaseRadio::cmdOpen() { + if (key_encrypt_timer != ZERO) { + return; // only open if it is encrypted already + } + radio.encrypt(ZERO); + key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME; + XSystem.buildReplyPValue(pmRadioEncrypt, ZERO); + XBHardware.changeLed(SYS_LED_RADIO, SYS_LED_STATUS_BLINK); // rf blink = open for key requests +} + +void XnodeBaseRadio::cmdInfo() { + // Print key + XSystem.buildReplyPValueByteA(pmRadioInfoKey,XBHardware.config.rf_key, RF_KEY_SIZE); + + // Print radio config + XSystem.buildReplyPValue(pmRadioInfoFreq,(int) RF_FREQUENCY == RF69_433MHZ ? 433 : RF_FREQUENCY == RF69_868MHZ ? 868 : 915); + XSystem.buildReplyPValue(pmRadioInfoNetwork,(int) RF_NETWORK_ID); + XSystem.buildReplyPValue(pmRadioInfoNode,(int) RF_BASE_NODE_ID); + XSystem.buildReplyPValue(pmRadioEncrypt,(int) key_encrypt_timer == ZERO ? ONE : ZERO);// if timer==0 then encrypted=1 + + // Print base radio stuff + XSystem.buildReplyPValue(pmRadioInfoRx, rf_rx); + XSystem.buildReplyPValue(pmRadioInfoTx, rf_tx); + XSystem.buildReplyPValue(pmRadioInfoTxe, rf_txe); + XSystem.buildReplyPValue(pmRadioInfoNextNode, (int) XBHardware.config.rf_next_node_id); +} + +void XnodeBaseRadio::systemModuleCommandList() { + XSystem.buildReplyCommandListP(pmRadioInfoKey); + XSystem.buildReplyCommandListP(pmRadioInfo); + XSystem.buildReplyCommandListP(pmRadioEncrypt); +} + +bool XnodeBaseRadio::systemModuleCommandExecute(char* cmd, char** args) { + if (XUtil.strcmpP(cmd, pmRadioInfo) == ZERO) { + cmdInfo(); + return true; + + } else if (XUtil.strcmpP(cmd, pmRadioInfoKey) == ZERO) { + if (XSystem.buildReplyCommandArgumentError(cmd, args)) { + return true; + } + XUtil.charsToByteA(args[ZERO],XBHardware.config.rf_key, RF_KEY_SIZE); + XSystem.buildReplyPValueByteA(pmRadioInfoKey,XBHardware.config.rf_key, RF_KEY_SIZE); + XSystem.configSave(); + return true; + + } else if (XUtil.strcmpP(cmd, pmRadioEncrypt) == ZERO) { + if (key_encrypt_timer == ZERO) { + cmdOpen(); + } else { + cmdClose(); + } + return true; + } + return false; +} + diff --git a/xnode-base/XnodeBaseRadio.h b/xnode-base/XnodeBaseRadio.h new file mode 100644 index 0000000..4a1a076 --- /dev/null +++ b/xnode-base/XnodeBaseRadio.h @@ -0,0 +1,33 @@ +#ifndef XnodeBaseRadio_h +#define XnodeBaseRadio_h + +#include +#include +#include +#include +#include +#include +#include + +class XnodeBaseRadio: public XnodeSystemModule { +private: + void checkNoDataTimeout(); + void checkPing(); + void cmdOpen(); + void cmdClose(); + void cmdInfo(); + void handleCmdInit(); + void handleCmdFlash(); + void sendReply(); +public: + void begin(); + void loop(); + + // from XnodeSystemModule + bool systemModuleCommandExecute(char* cmd, char** args); + void systemModuleCommandList(); +}; + +extern XnodeBaseRadio XBRadio; + +#endif diff --git a/xnode-mega-flash/Makefile b/xnode-mega-flash/Makefile new file mode 100644 index 0000000..05ba280 --- /dev/null +++ b/xnode-mega-flash/Makefile @@ -0,0 +1,22 @@ + +# Define out program +SKT_PDE_SRC = XnodeMegaFlash.cpp + +# This needs more flash so use mega board +BOARD = megaADK + +# Define the program to flash (needs single file) +MASTER_FLASH_PROG = ../xnode-base/build/xnode-base.hex + +# Defines extra pairs of boot+image to flash(note optiboot get replaces by optiboot hex) +MASTER_FLASH_PAIR_EXTRA = \ +optiboot \ +../xnode-satellite/build/xnode-satellite.hex \ +optiboot \ +../xnode-test-blink/build/xnode-test-blink.hex \ +optiboot \ +../xnode-satellite/build/xnode-satellite.hex + +# Include our master flash build +include ../lib-build/make/Makefile.master-flash + diff --git a/xnode-mega-flash/XnodeMegaFlash.cpp b/xnode-mega-flash/XnodeMegaFlash.cpp new file mode 100644 index 0000000..8376548 --- /dev/null +++ b/xnode-mega-flash/XnodeMegaFlash.cpp @@ -0,0 +1,17 @@ +/* + * Xnode Satellite Flash + */ + +#include +#include +#include + +MegaIspRepair megaIspRepair; + +void setup() { +} + +void loop() { + megaIspRepair.run("XnodeMegaFlash", sections); +} + diff --git a/xnode-satellite-boot/XnodeSatelliteBoot.c b/xnode-satellite-boot/XnodeSatelliteBoot.c new file mode 100644 index 0000000..369cceb --- /dev/null +++ b/xnode-satellite-boot/XnodeSatelliteBoot.c @@ -0,0 +1,2 @@ + +// todo write this up in plain C not c++ diff --git a/xnode-satellite/Makefile b/xnode-satellite/Makefile new file mode 100644 index 0000000..d5fc072 --- /dev/null +++ b/xnode-satellite/Makefile @@ -0,0 +1,4 @@ +# Minimal makefile only includes the master and libs. +MASTER_LIBS = rfm69 spi dht xnode-shared +SKT_PDE_SRC = XnodeSatellite.cpp +include ../lib-build/make/Makefile.master diff --git a/xnode-satellite/XnodeSatellite.cpp b/xnode-satellite/XnodeSatellite.cpp new file mode 100644 index 0000000..a3e8ed7 --- /dev/null +++ b/xnode-satellite/XnodeSatellite.cpp @@ -0,0 +1,31 @@ +/* + * Xnode Satellite + */ + +#include +#include +#include +#include +#include + +void setup() { + // Build system modules + XSystem.registrateSystemModule(&XSRadio); + XSystem.registrateSystemModule(&XSSensor); + + // Start system modules + XSerial.begin(); + XSystem.begin(&XSHardware); + XSRadio.begin(); + XSSensor.begin(); + + // Mark device booted + XSystem.bootDone(); +} + +void loop() { + XSerial.loop(); + XSystem.loop(); + XSRadio.loop(); + XSSensor.loop(); +} diff --git a/xnode-satellite/XnodeSatelliteHardware.cpp b/xnode-satellite/XnodeSatelliteHardware.cpp new file mode 100644 index 0000000..3f76f54 --- /dev/null +++ b/xnode-satellite/XnodeSatelliteHardware.cpp @@ -0,0 +1,42 @@ +#include + +const char pmSystemHardwareType[] PROGMEM = "xnode-satellite"; +const char pmSystemHardwareVersion[] PROGMEM = XNODE_VERSION; + +xnode_satellite_config_t config; +xnode_satellite_config_t EEMEM eeprom; +XnodeSatelliteHardware XSHardware; + +const char* XnodeSatelliteHardware::getSystemHardwareTypeP() { + return pmSystemHardwareType; +} + +const char* XnodeSatelliteHardware::getSystemHardwareVersionP() { + return pmSystemHardwareVersion; +} + +unsigned long XnodeSatelliteHardware::getSystemHardwareRebootCount() { + return config.sys_boot; +} + +bool XnodeSatelliteHardware::systemHardwareConfigBegin() { + eeprom_read_block((void*) &config, (void*) &eeprom, sizeof(xnode_satellite_config_t)); + if (config.eeprom_struct_size != sizeof(xnode_satellite_config_t)) { + return true; + } + config.sys_boot++; + return false; +} + +void XnodeSatelliteHardware::systemHardwareConfigSave() { + config.eeprom_struct_size = sizeof(xnode_satellite_config_t); + eeprom_write_block((const void*) &config, (void*) &eeprom, sizeof(xnode_satellite_config_t)); +} + +void XnodeSatelliteHardware::systemHardwareConfigReset() { + config.sys_boot = ZERO; + config.node_id = ZERO; + for (byte i = ZERO; i < RF_KEY_SIZE; ++i) { + config.rf_key[i] = ZERO; + } +} diff --git a/xnode-satellite/XnodeSatelliteHardware.h b/xnode-satellite/XnodeSatelliteHardware.h new file mode 100644 index 0000000..c64ad69 --- /dev/null +++ b/xnode-satellite/XnodeSatelliteHardware.h @@ -0,0 +1,26 @@ +#ifndef XnodeSatelliteHardware_h +#define XnodeSatelliteHardware_h + +#include +#include +#include +#include + +#define HW_PIN_DHT_WIRE 4 + +class XnodeSatelliteHardware: public XnodeSystemHardware { +public: + // from XnodeSystemHardware + xnode_satellite_config_t config; + const char* getSystemHardwareTypeP(); + const char* getSystemHardwareVersionP(); + unsigned long getSystemHardwareRebootCount(); + bool systemHardwareConfigBegin(); + void systemHardwareConfigSave(); + void systemHardwareConfigReset(); +}; + +extern XnodeSatelliteHardware XSHardware; + +#endif + diff --git a/xnode-satellite/XnodeSatelliteRadio.cpp b/xnode-satellite/XnodeSatelliteRadio.cpp new file mode 100644 index 0000000..66137fb --- /dev/null +++ b/xnode-satellite/XnodeSatelliteRadio.cpp @@ -0,0 +1,204 @@ +#include + +const char pmRadioChipInit[] PROGMEM = MSG_RF_CHIP_INIT; +const char pmRadioChipError[] PROGMEM = MSG_RF_CHIP_ERROR; +const char pmRadioExecutePrefix[] PROGMEM = "@";//MSG_REMOTE_PREFIX; // FIXME + +const char pmRadioInfoFreq[] PROGMEM = MSG_RF_INFO_FREQ; +const char pmRadioInfoNetwork[] PROGMEM = MSG_RF_INFO_NETWORK; +const char pmRadioInfoNode[] PROGMEM = MSG_RF_INFO_NODE; +const char pmRadioInfoKey[] PROGMEM = MSG_RF_INFO_KEY; +const char pmRadioEncrypt[] PROGMEM = MSG_RF_ENCRYPT; +const char pmRadioInfo[] PROGMEM = MSG_RF_INFO; + +uint8_t rf_status_chip = ZERO; +uint8_t rf_status_key = ZERO; + +volatile unsigned long key_fetch_timer = ZERO; +volatile unsigned long key_encrypt_timer = ZERO; + +xp_super_t rf_data; +xp_msg_init_t* rf_msg_init; +xp_msg_flash_t* rf_msg_flash; +xp_msg_char_t* rf_msg_char; + +RFM69 radio; +XnodeSatelliteRadio XSRadio; + +void XnodeSatelliteRadio::begin() { + XSerial.printCommentLineP(pmRadioChipInit); + if (!radio.initialize(RF_FREQUENCY, XSHardware.config.node_id, RF_NETWORK_ID)) { + XSerial.printCommentLineP(pmRadioChipError); + rf_status_chip = ONE; + return; + } + key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME; + key_fetch_timer = millis() + (unsigned long) RF_KEY_FETCH_TIME; + + // Print serial info + XSerial.executeCommandP(pmRadioInfo); +} + +void XnodeSatelliteRadio::loop() { + if (rf_status_chip != ZERO) { + return; // no chip + } + if (key_encrypt_timer != ZERO) { + initEncryptionKey(); + } + if (!radio.receiveDone()) { + return; + } + //rf_status_data = ZERO; + rf_data = *(xp_super_t*) radio.DATA; +#ifdef DEBUG_RADIO + Serial.print(F("#D rf_rx ")); + Serial.print(radio.SENDERID,DEC); + Serial.print(CHAR_SPACE); + Serial.print(rf_data.msg_type,DEC); + Serial.print(CHAR_NEWLINE); +#endif + // always reply ack if requested, see sendWithRetry impl + if (radio.ACK_REQUESTED) { +#ifdef DEBUG_RADIO + Serial.println(F("#D rf_sendACK")); +#endif + radio.sendACK(); + } + if (rf_data.msg_type == RF_MSG_NODE_INIT) { + handleNodeInit(); + } else if (rf_data.msg_type == RF_MSG_NODE_COMMAND) { + handleNodeCommand(); + } +} + +void XnodeSatelliteRadio::handleNodeInit() { + rf_msg_init = (xp_msg_init_t*) rf_data.msg_data; + if (XSHardware.config.node_id != rf_msg_init->node_id) { +#ifdef DEBUG_RADIO + Serial.print(F("#D init ")); + Serial.print(rf_msg_init->node_id,DEC); + Serial.print(CHAR_NEWLINE); +#endif + XSHardware.config.node_id = rf_msg_init->node_id; // allow new node_id + } + for (byte i = ZERO; i < RF_KEY_SIZE; ++i) { + XSHardware.config.rf_key[i] = rf_msg_init->rf_key[i]; + } + XSystem.configSave(); + key_fetch_timer = ZERO; // stop sending because we have reply + if (XSHardware.config.node_id != rf_msg_init->node_id) { + radio.initialize(RF_FREQUENCY, XSHardware.config.node_id, RF_NETWORK_ID); // re-init + } +} + +void XnodeSatelliteRadio::handleNodeCommand() { + rf_msg_char = (xp_msg_char_t*) rf_data.msg_data; + XSerial.print(CHAR_NEWLINE); + XSerial.printCharP(pmRadioExecutePrefix); + //XSerial.printPromtLine(); + //XSerial.processCommand(rf_msg_char->char_data); +} + +void XnodeSatelliteRadio::initEncryptionKey() { + if (millis() > key_encrypt_timer) { + cmdClose(); // do once after timeout + return; + } + if (key_fetch_timer==ZERO) { + return; // we are done + } + if (millis() < key_fetch_timer) { + return; // wait until next fetch + } + key_fetch_timer = millis() + (unsigned long) RF_KEY_FETCH_TIME; + + // Setup first data package for fetching key rf_keys. + rf_data.msg_type = RF_MSG_NODE_INIT; + rf_msg_init = (xp_msg_init_t*) rf_data.msg_data; + rf_msg_init->node_id = XSHardware.config.node_id; // send our id, so we fetch only once new id. + send(); +} + +byte XnodeSatelliteRadio::readTemperature() { + return radio.readTemperature(); +} + +bool XnodeSatelliteRadio::isSecure() { + return key_encrypt_timer == ZERO; +} + +void XnodeSatelliteRadio::cmdClose() { + XSystem.buildReplyPValue(pmRadioEncrypt, ONE); + radio.encrypt((const char*) XSHardware.config.rf_key); + key_encrypt_timer = ZERO; // disable calling initEncrytion and this +} + +void XnodeSatelliteRadio::cmdOpen() { + if (key_encrypt_timer != ZERO) { + return; // only open if it is encrypted already + } + radio.encrypt(ZERO); + key_encrypt_timer = millis() + (unsigned long) RF_KEY_ENCRYPT_TIME; + XSystem.buildReplyPValue(pmRadioEncrypt, ZERO); +} + +void XnodeSatelliteRadio::send() { + //rf_tx++; + if (radio.sendWithRetry(RF_BASE_NODE_ID, (const void*) &rf_data, sizeof(xp_super_t)), 5, 100) { + // TODO make cnt + Serial.println("# send ok"); + } else { + Serial.println("# ERR: send failed"); + } +} + +void XnodeSatelliteRadio::sendNodeData(char* data) { + rf_data.msg_type = RF_MSG_NODE_DATA; + rf_msg_char = (xp_msg_char_t*) rf_data.msg_data; + + // TODO: add loop + cnt over data + strcpy(rf_msg_char->char_data, data); + send(); +} + +void XnodeSatelliteRadio::sendCommandP(const char* cmdName) { + if (!isSecure()) { + return; // wait until line is secure + } + char sendCommandBuff[32]; + strcpy(sendCommandBuff, XUtil.UNPSTR(cmdName)); // free buffer as gets used in strcmpP again.. + XSystem.executeCommand(sendCommandBuff); + sendNodeData(XSystem.replyBuffer); // print result or error +} + +void XnodeSatelliteRadio::cmdInfo() { + // Print key + XSystem.buildReplyPValueByteA(pmRadioInfoKey,XSHardware.config.rf_key,RF_KEY_SIZE); + + // Print radio config + XSystem.buildReplyPValue(pmRadioInfoFreq,(int) RF_FREQUENCY == RF69_433MHZ ? 433 : RF_FREQUENCY == RF69_868MHZ ? 868 : 915); + XSystem.buildReplyPValue(pmRadioInfoNetwork,(int) RF_NETWORK_ID); + XSystem.buildReplyPValue(pmRadioInfoNode,(int) XSHardware.config.node_id); + XSystem.buildReplyPValue(pmRadioEncrypt,(int) key_encrypt_timer == ZERO ? ONE : ZERO);// if timer==0 then encrypted=1 +} + +void XnodeSatelliteRadio::systemModuleCommandList() { + XSystem.buildReplyCommandListP(pmRadioInfo); + XSystem.buildReplyCommandListP(pmRadioEncrypt); +} + +bool XnodeSatelliteRadio::systemModuleCommandExecute(char* cmd, char** args) { + if (XUtil.strcmpP(cmd, pmRadioInfo) == ZERO) { + cmdInfo(); + return true; + } else if (XUtil.strcmpP(cmd, pmRadioEncrypt) == ZERO) { + if (key_encrypt_timer == ZERO) { + cmdOpen(); + } else { + cmdClose(); + } + return true; + } + return false; +} diff --git a/xnode-satellite/XnodeSatelliteRadio.h b/xnode-satellite/XnodeSatelliteRadio.h new file mode 100644 index 0000000..36c5d37 --- /dev/null +++ b/xnode-satellite/XnodeSatelliteRadio.h @@ -0,0 +1,34 @@ +#ifndef XnodeSatelliteRadio_h +#define XnodeSatelliteRadio_h + +#include +#include +#include +#include +#include + +class XnodeSatelliteRadio: public XnodeSystemModule { +public: + void begin(); + void loop(); + void sendCommandP(const char* cmdName); + void sendNodeData(char* data); + byte readTemperature(); +private: + bool isSecure(); + void cmdClose(); + void cmdOpen(); + void initEncryptionKey(); + void send(); + void handleNodeInit(); + void handleNodeCommand(); + void cmdInfo(); + + // from XnodeSystemModule + virtual bool systemModuleCommandExecute(char* cmd, char** args); + virtual void systemModuleCommandList(); +}; + +extern XnodeSatelliteRadio XSRadio; + +#endif diff --git a/xnode-satellite/XnodeSatelliteSensor.cpp b/xnode-satellite/XnodeSatelliteSensor.cpp new file mode 100644 index 0000000..4cf20bf --- /dev/null +++ b/xnode-satellite/XnodeSatelliteSensor.cpp @@ -0,0 +1,117 @@ +#include + +const char pmSensorInit[] PROGMEM = "Init sensors"; + +const char pmSensorRadioTemp[] PROGMEM = "s_rt"; +const char pmSensorDHTTemp[] PROGMEM = "s_dt"; +const char pmSensorDHTWater[] PROGMEM = "s_dh"; +const char pmSensorSolarVoltage[] PROGMEM = "s_sv"; +const char pmSensorRotoCupsPPM[] PROGMEM = "s_rp"; + +#define READ_SENSOR_TIME 15000 +unsigned long read_sensor_timerA = ZERO; +unsigned long read_sensor_timerB = ZERO; +unsigned long read_sensor_timerC = ZERO; +unsigned long read_sensor_timerD = ZERO; +DHT dht(HW_PIN_DHT_WIRE,DHT22,6); +XnodeSatelliteSensor XSSensor; + +/* +int valueRadioTemp = ZERO; +int valueDHTTemp = ZERO; +int valueDHTWater = ZERO; +int valueSolarVoltage = ZERO; +int rotoCupsPPM = ZERO; + +byte valueRadioTemp = ZERO; +float valueDHTTemp = ZEROf; +float valueDHTWater = ZEROf; +int valueSolarVoltage = ZERO; +int rotoCupsPPM = ZERO; +*/ +void XnodeSatelliteSensor::begin() { + XSerial.printCommentLineP(pmSensorInit); + + + //delay(1100); // chip needs 1 sec init time, else we get NAN returned. + read_sensor_timerA = millis() + (unsigned long) READ_SENSOR_TIME; // temp redo with deep sleep + read_sensor_timerB = millis() + (unsigned long) READ_SENSOR_TIME + 2000; + read_sensor_timerC = millis() + (unsigned long) READ_SENSOR_TIME + 3000; + read_sensor_timerD = millis() + (unsigned long) READ_SENSOR_TIME + 4000; + XSerial.executeCommandP(pmSensorRadioTemp); + XSerial.executeCommandP(pmSensorDHTTemp); + XSerial.executeCommandP(pmSensorSolarVoltage); + XSerial.executeCommandP(pmSensorDHTWater); +} + +void XnodeSatelliteSensor::loop() { + loopA(); + loopB(); + loopC(); + loopD(); +} + +void XnodeSatelliteSensor::loopA() { + if (millis() < read_sensor_timerA) { + return; + } + read_sensor_timerA = millis() + (unsigned long) READ_SENSOR_TIME; + XSRadio.sendCommandP(pmSensorDHTTemp); +} + +void XnodeSatelliteSensor::loopB() { + if (millis() < read_sensor_timerB) { + return; + } + read_sensor_timerB = millis() + (unsigned long) READ_SENSOR_TIME; + XSRadio.sendCommandP(pmSensorDHTWater); +} + +void XnodeSatelliteSensor::loopC() { + if (millis() < read_sensor_timerC) { + return; + } + read_sensor_timerC = millis() + (unsigned long) READ_SENSOR_TIME; + XSRadio.sendCommandP(pmSensorSolarVoltage); +} + +void XnodeSatelliteSensor::loopD() { + if (millis() < read_sensor_timerD) { + return; + } + read_sensor_timerD = millis() + (unsigned long) READ_SENSOR_TIME; + XSRadio.sendCommandP(pmSensorRadioTemp); +} + +void XnodeSatelliteSensor::systemModuleCommandList() { + XSystem.buildReplyCommandListP(pmSensorRadioTemp); + XSystem.buildReplyCommandListP(pmSensorDHTTemp); + XSystem.buildReplyCommandListP(pmSensorDHTWater); + XSystem.buildReplyCommandListP(pmSensorSolarVoltage); + //XSystem.buildReplyCommandListP(pmSensorRotoCupsPPM); +} + +bool XnodeSatelliteSensor::systemModuleCommandExecute(char* cmd, char** args) { + if (XUtil.strcmpP(cmd, pmSensorRadioTemp) == ZERO) { + XSystem.buildReplyPValue(pmSensorRadioTemp,XSRadio.readTemperature()); + return true; + } + if (XUtil.strcmpP(cmd, pmSensorDHTTemp) == ZERO) { + XSystem.buildReplyPValue(pmSensorDHTTemp,dht.readTemperature());// TODO: fixme + return true; + } + if (XUtil.strcmpP(cmd, pmSensorDHTWater) == ZERO) { + XSystem.buildReplyPValue(pmSensorDHTWater,dht.readHumidity()); + return true; + } + if (XUtil.strcmpP(cmd, pmSensorSolarVoltage) == ZERO) { + XSystem.buildReplyPValue(pmSensorSolarVoltage,analogRead(A1)); + return true; + } + if (XUtil.strcmpP(cmd, pmSensorRotoCupsPPM) == ZERO) { + //XSystem.buildReplyPValue(pmSensorRotoCupsPPM,readAnalog(0)); + return true; + } + return false; +} + diff --git a/xnode-satellite/XnodeSatelliteSensor.h b/xnode-satellite/XnodeSatelliteSensor.h new file mode 100644 index 0000000..7984245 --- /dev/null +++ b/xnode-satellite/XnodeSatelliteSensor.h @@ -0,0 +1,28 @@ +#ifndef XnodeSatelliteSensor_h +#define XnodeSatelliteSensor_h + +#include +#include +#include +#include +#include + +class XnodeSatelliteSensor: public XnodeSystemModule { +private: + void loopA(); + void loopB(); + void loopC(); + void loopD(); +public: + void begin(); + void loop(); + + // from XnodeSystemModule + virtual bool systemModuleCommandExecute(char* cmd, char** args); + virtual void systemModuleCommandList(); +}; + +extern XnodeSatelliteSensor XSSensor; + +#endif + diff --git a/xnode-test-blink/Makefile b/xnode-test-blink/Makefile new file mode 100644 index 0000000..cf0aa32 --- /dev/null +++ b/xnode-test-blink/Makefile @@ -0,0 +1,3 @@ +# Minimal makefile +SKT_PDE_SRC = XnodeTestBlink.cpp +include ../lib-build/make/Makefile.master diff --git a/xnode-test-blink/XnodeTestBlink.cpp b/xnode-test-blink/XnodeTestBlink.cpp new file mode 100644 index 0000000..5ba4748 --- /dev/null +++ b/xnode-test-blink/XnodeTestBlink.cpp @@ -0,0 +1,43 @@ +/* + * Xnode Test Blink + */ + +#include + +#define DELAY_TIME 100 +#define ERROR_LED A2 // 15 +#define RADIO_LED A3 // 14 +#define NETWORK_LED 7 + + + +void setup(void) { + Serial.begin(115200); + Serial.println("[XnodeTestBlink]"); + pinMode(ERROR_LED, OUTPUT); + pinMode(RADIO_LED, OUTPUT); + pinMode(NETWORK_LED, OUTPUT); +} + +void loop(void) { + Serial.print("OUTPUT: "); + Serial.println(ERROR_LED); + digitalWrite(ERROR_LED, HIGH); + delay(DELAY_TIME * 1); + digitalWrite(ERROR_LED, LOW); + delay(DELAY_TIME); + + Serial.print("OUTPUT: "); + Serial.println(RADIO_LED); + digitalWrite(RADIO_LED, HIGH); + delay(DELAY_TIME * 3); + digitalWrite(RADIO_LED, LOW); + delay(DELAY_TIME); + + Serial.print("OUTPUT: "); + Serial.println(NETWORK_LED); + digitalWrite(NETWORK_LED, HIGH); + delay(DELAY_TIME * 9); + digitalWrite(NETWORK_LED, LOW); + delay(DELAY_TIME); +}