diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d1617fd..ca7cd16 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1 +1 @@
-To get started, sign the Contributor License Agreement.
\ No newline at end of file
+To get started, sign the Contributor License Agreement.
diff --git a/Documentation/Doxyfile b/Documentation/Doxyfile
index 55bb410..d9b76af 100644
--- a/Documentation/Doxyfile
+++ b/Documentation/Doxyfile
@@ -743,7 +743,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
-INPUT = libraries/MySensors Documentation/mainpage.dox
+INPUT = . Documentation/mainpage.dox
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -811,7 +811,7 @@ EXCLUDE_SYMBOLS =
# that contain example code fragments that are included (see the \include
# command).
-EXAMPLE_PATH = libraries/MySensors/examples libraries/MySensors/drivers/AES
+EXAMPLE_PATH = examples drivers/AES
# 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
diff --git a/libraries/MySensors/MyConfig.h b/MyConfig.h
similarity index 83%
rename from libraries/MySensors/MyConfig.h
rename to MyConfig.h
index d25a65b..cb775ce 100644
--- a/libraries/MySensors/MyConfig.h
+++ b/MyConfig.h
@@ -31,14 +31,18 @@
* Serial and debug options
***********************************/
-// Enables this in sketch to show debug prints. This option will add a lot to the size of the
+// Enable MY_DEBUG in sketch to show debug prints. This option will add a lot to the size of the
// final sketch but is helpful to see what is actually is happening during development
//#define MY_DEBUG
-// Enable MY_DEBUG_VERBOSE flag for verbose debug prints related to RF24 radio.
-// Requires DEBUG to be enabled.
-// This will add even more to the size of the final sketch!
-//#define MY_DEBUG_VERBOSE
+// Enable MY_SPECIAL_DEBUG in sketch to activate I_DEBUG messages if MY_DEBUG is disabled.
+// I_DEBUG requests are:
+// R: routing info (only repeaters): received msg XXYY (as stream), where XX is the node and YY the routing node
+// V: CPU voltage
+// F: CPU frequency
+// M: free memory
+// E: clear MySensors EEPROM area and reboot (i.e. "factory" reset)
+//#define MY_SPECIAL_DEBUG
// Enable MY_DEBUG_VERBOSE_SIGNING flag for verbose debug prints related to signing.
// Requires DEBUG to be enabled.
@@ -77,6 +81,52 @@
//#define MY_RADIO_RFM69
//#define MY_RS485
+/**
+* @def MY_TRANSPORT_SANITY_CHECK
+* @brief If enabled, node will check transport in regular intervals to detect HW issues and re-initialize in case of failure. This feature is enabled for all repeater nodes (incl. GW)
+*/
+//#define MY_TRANSPORT_SANITY_CHECK
+/**
+* @def MY_TRANSPORT_SANITY_CHECK_INTERVAL
+* @brief Interval (in ms) of transport sanity checks
+*/
+#ifndef MY_TRANSPORT_SANITY_CHECK_INTERVAL
+#define MY_TRANSPORT_SANITY_CHECK_INTERVAL ((uint32_t)60000)
+#endif
+/**
+ * @def MY_REGISTRATION_FEATURE
+ * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data.
+ */
+#define MY_REGISTRATION_FEATURE
+
+ /**
+ * @def MY_REGISTRATION_RETRIES
+ * @brief Number of registration retries if no reply received from GW/controller
+ */
+
+#ifndef MY_REGISTRATION_RETRIES
+#define MY_REGISTRATION_RETRIES 3
+#endif
+
+ /**
+ * @def MY_REGISTRATION_DEFAULT
+ * @brief Node registration default - this applies if no registration response is recieved from controller
+ */
+
+#define MY_REGISTRATION_DEFAULT true
+
+ /**
+ * @def MY_REGISTRATION_CONTROLLER
+ * @brief If enabled, node registration request has to be handled by controller
+ */
+ // #define MY_REGISTRATION_CONTROLLER
+
+ /**
+ * @def MY_CORE_COMPATIBILITY_CHECK
+ * @brief If enabled, library compatibility is checked during node registration. Incompatible libraries are unable to send sensor data.
+ */
+#define MY_CORE_COMPATIBILITY_CHECK
+
/**
* @def MY_NODE_ID
* @brief Node id defaults to AUTO (tries to fetch id from controller).
@@ -93,6 +143,12 @@
#define MY_PARENT_NODE_ID AUTO
#endif
+/**
+ * @def MY_PARENT_NODE_IS_STATIC
+ * @brief Enable MY_PARENT_NODE_IS_STATIC to disable fall back if parent node fails
+ */
+//#define MY_PARENT_NODE_IS_STATIC
+
// Enables repeater functionality (relays messages from other nodes)
// #define MY_REPEATER_FEATURE
@@ -183,9 +239,9 @@
// The following defines can be used to set the port pin, that the LED is connected to
// If one of the following is defined here, or in the sketch, MY_LEDS_BLINKING_FEATURE will be
// enabled by default. (Replace x with the pin number you have the LED on)
-//#define MY_DEFAULT_ERR_LED x
-//#define MY_DEFAULT_TX_LED x
-//#define MY_DEFAULT_RX_LED x
+//#define MY_DEFAULT_ERR_LED_PIN x
+//#define MY_DEFAULT_TX_LED_PIN x
+//#define MY_DEFAULT_RX_LED_PIN x
/**********************************************
* Gateway inclusion button/mode configuration
@@ -327,12 +383,24 @@
#endif
/**********************************
-* NRF24L01 Driver Defaults
+* NRF24L01P Driver Defaults
***********************************/
// Enables RF24 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key)
//#define MY_RF24_ENABLE_ENCRYPTION
+/**
+ * @def MY_DEBUG_VERBOSE_RF24
+ * @brief Enable MY_DEBUG_VERBOSE_RF24 flag for verbose debug prints related to the RF24 driver. Requires DEBUG to be enabled.
+ */
+//#define MY_DEBUG_VERBOSE_RF24
+
+/**
+ * @def MY_RF24_SPI_MAX_SPEED
+ * @brief MY_RF24_SPI_MAX_SPEED to overrule default nRF24L01+ SPI speed.
+ */
+//#define MY_RF24_SPI_MAX_SPEED 4000000
+
/**
* @def MY_RF24_CE_PIN
* @brief Default RF24 chip enable pin setting. Override in sketch if needed.
@@ -372,6 +440,22 @@
#endif
#endif
+/**
+ * @def MY_RF24_IRQ_PIN
+ * @brief Disable RF24 interrupt pin usage by default. Override in sketch if needed.
+ */
+//#define MY_RF24_IRQ_PIN
+
+/**
+ * @def MY_RX_MESSAGE_BUFFER_SIZE
+ * @brief Declare the amount of incoming messages that can be buffered. Requires MY_RADIO_NRF24 and MY_RF24_IRQ_PIN. Override in sketch if needed.
+ */
+#ifdef MY_RF24_IRQ_PIN
+ #ifndef MY_RX_MESSAGE_BUFFER_SIZE
+ #define MY_RX_MESSAGE_BUFFER_SIZE (20)
+ #endif
+#endif
+
/**
* @def MY_RF24_PA_LEVEL
* @brief Default RF24 PA level. Override in sketch if needed.
@@ -410,10 +494,20 @@
* @def MY_RF24_BASE_RADIO_ID
* @brief RF24 radio network identifier.
*
- * This is also act as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network.
+ * This acts as base value for sensor nodeId addresses. Change this (or channel) if you have more than one sensor network.
*/
#ifndef MY_RF24_BASE_RADIO_ID
-#define MY_RF24_BASE_RADIO_ID ((uint64_t)0xA8A8E1FC00LL)
+#define MY_RF24_BASE_RADIO_ID 0x00,0xFC,0xE1,0xA8,0xA8
+#endif
+
+/**
+ * @def MY_RF24_ADDR_WIDTH
+ * @brief RF24 address width.
+ *
+ * This defines the width of the base address.
+ */
+#ifndef MY_RF24_ADDR_WIDTH
+#define MY_RF24_ADDR_WIDTH 5
#endif
// Enable SOFTSPI for NRF24L01, useful for the W5100 Ethernet module
@@ -602,7 +696,7 @@
*
* If using a secure bootloader, grounding the pin is the only option to reactivate the node.
* If using stock Android bootloader or a DualOptiBoot it is also possible to download a sketch
- * using serial protocol to erase EEPROM to unlock the node.
+ * using serial protocol to erase EEPROM to unlock the node.
*/
#ifndef MY_NODE_UNLOCK_PIN
#define MY_NODE_UNLOCK_PIN 14
@@ -650,4 +744,11 @@
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}}
#define MY_IS_RFM69HW
+#define MY_PARENT_NODE_IS_STATIC
+#define MY_REGISTRATION_CONTROLLER
+#define MY_DEBUG_VERBOSE_RF24
+#define MY_TRANSPORT_SANITY_CHECK
+#define MY_RF24_IRQ_PIN
+#define MY_RX_MESSAGE_BUFFER_SIZE
+#define MY_NODE_LOCK_FEATURE
#endif
diff --git a/libraries/MySensors/MySensor.h b/MySensors.h
similarity index 81%
rename from libraries/MySensors/MySensor.h
rename to MySensors.h
index e073a46..d849874 100644
--- a/libraries/MySensors/MySensor.h
+++ b/MySensors.h
@@ -18,14 +18,14 @@
*/
/**
- * @file MySensor.h
+ * @file MySensors.h
*
* MySensors main interface (includes all necessary code for the library)
*/
-#ifndef MySensor_h
-#define MySensor_h
+#ifndef MySensors_h
+#define MySensors_h
-#include "core/MySensorCore.h"
+#include "core/MySensorsCore.h"
// Detect node type
/**
@@ -43,13 +43,13 @@
#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_RASPBERRYPI) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT)
#define MY_GATEWAY_FEATURE
#define MY_IS_GATEWAY (true)
- #define MY_NODE_TYPE "gateway"
+ #define MY_NODE_TYPE "GW"
#elif defined(MY_REPEATER_FEATURE)
#define MY_IS_GATEWAY (false)
- #define MY_NODE_TYPE "repeater"
+ #define MY_NODE_TYPE "REPEATER"
#else
#define MY_IS_GATEWAY (false)
- #define MY_NODE_TYPE "sensor"
+ #define MY_NODE_TYPE "NODE"
#endif
// Enable radio "feature" if one of the radio types was enabled
@@ -154,6 +154,8 @@
#include "core/MyLeds.h"
#endif
+#include "core/MyIndication.cpp"
+
// INCLUSION MODE
#if defined(MY_INCLUSION_MODE_FEATURE)
@@ -181,7 +183,39 @@
#endif
#endif
-#if defined(MY_GATEWAY_FEATURE)
+
+// FLASH
+#if defined(MY_OTA_FIRMWARE_FEATURE)
+ #include "drivers/SPIFlash/SPIFlash.cpp"
+ #include "core/MyOTAFirmwareUpdate.cpp"
+#endif
+
+// GATEWAY - TRANSPORT
+#if defined(MY_GATEWAY_MQTT_CLIENT)
+ #if defined(MY_RADIO_FEATURE)
+ // We assume that a gateway having a radio also should act as repeater
+ #define MY_REPEATER_FEATURE
+ #endif
+ // GATEWAY - COMMON FUNCTIONS
+ // We only support MQTT Client using W5100 and ESP8266 at the moment
+ #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS))
+ #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS
+ #endif
+
+ #if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX)
+ #error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client
+ #endif
+ #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)
+ #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client
+ #endif
+ #if !defined(MY_MQTT_CLIENT_ID)
+ #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client
+ #endif
+
+ #include "drivers/PubSubClient/PubSubClient.cpp"
+ #include "core/MyGatewayTransport.cpp"
+ #include "core/MyGatewayTransportMQTTClient.cpp"
+#elif defined(MY_GATEWAY_FEATURE)
// GATEWAY - COMMON FUNCTIONS
#include "core/MyGatewayTransport.cpp"
@@ -264,19 +298,31 @@
#if defined(ARDUINO_ARCH_ESP8266)
#error Soft SPI is not available on ESP8266
#endif
- #include "drivers/AVR/DigitalIO/SoftI2cMaster.cpp"
- #include "drivers/AVR/DigitalIO/PinIO.cpp"
+ #include "drivers/AVR/DigitalIO/DigitalIO.h"
#endif
- // FLASH
- #ifdef MY_OTA_FIRMWARE_FEATURE
- #include "drivers/SPIFlash/SPIFlash.cpp"
- #endif
#include "core/MyTransport.cpp"
#if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485))
#error Only one forward link driver can be activated
#endif
#if defined(MY_RADIO_NRF24)
+ #ifdef MY_RF24_IRQ_PIN
+ // SoftSPI does not support usingInterrupt()
+ #ifdef MY_SOFTSPI
+ #error RF24 IRQ usage cannot be used with Soft SPI
+ #endif
+ // ESP8266 does not support usingInterrupt()
+ #ifdef ESP8266
+ #error RF24 IRQ usage cannot be used with ESP8266
+ #endif
+ #ifndef SPI_HAS_TRANSACTION
+ #error RF24 IRQ usage requires transactional SPI support
+ #endif
+ #else
+ #ifdef MY_RX_MESSAGE_BUFFER_SIZE
+ #error Receive message buffering requires RF24 IRQ usage
+ #endif
+ #endif
#if defined(MY_RF24_ENABLE_ENCRYPTION)
#include "drivers/AES/AES.cpp"
#endif
@@ -293,6 +339,10 @@
#endif
#endif
+#if defined(MY_PARENT_NODE_IS_STATIC) && (MY_PARENT_NODE_ID == AUTO)
+ #error Parent is static but no parent ID defined.
+#endif
+
// Make sure to disable child features when parent feature is disabled
#if !defined(MY_RADIO_FEATURE)
#undef MY_OTA_FIRMWARE_FEATURE
@@ -314,7 +364,7 @@
#include "core/MyCapabilities.h"
#include "core/MyMessage.cpp"
-#include "core/MySensorCore.cpp"
+#include "core/MySensorsCore.cpp"
#include
diff --git a/README.md b/README.md
index 2f8ce14..db75a27 100644
--- a/README.md
+++ b/README.md
@@ -5,14 +5,20 @@ MySensors Arduino Library v2.0.0-beta
Please visit www.mysensors.org for more information
-Current build status of master branch: [](http://ci.mysensors.org/job/MySensorsArduino/branch/master/)
+Doxygen
+-------
+[master](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/development/Doxygen_HTML/index.html)
-Current build status of development branch: [](http://ci.mysensors.org/job/MySensorsArduino/branch/development/)
+CI statuses
+-----------
+Current build status of master branch: [](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/master/)
-Current build status of master branch (nightly build): [](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/)
+Current build status of development branch: [](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/development/)
-Current build status of development branch (nightly build): [](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/)
+Current build status of master branch (nightly build): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/master/)
-Current build status of master branch (nightly build of Arduino IDE): [](http://ci.mysensors.org/job/MySensorsArduinoNightlyIDE/branch/master/)
+Current build status of development branch (nightly build): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/development/)
-Current build status of development branch (nightly build of Arduino IDE): [](http://ci.mysensors.org/job/MySensorsArduinoNightlyIDE/branch/development/)
+Current build status of master branch (nightly build of Arduino IDE): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/master/)
+
+Current build status of development branch (nightly build of Arduino IDE): [](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/development/)
diff --git a/libraries/MySensors/core/MyCapabilities.h b/core/MyCapabilities.h
similarity index 89%
rename from libraries/MySensors/core/MyCapabilities.h
rename to core/MyCapabilities.h
index 6910d3b..735ec32 100644
--- a/libraries/MySensors/core/MyCapabilities.h
+++ b/core/MyCapabilities.h
@@ -70,7 +70,13 @@
#define MY_CAP_SIGN "-"
#endif
+#if defined(MY_RX_MESSAGE_BUFFER_SIZE)
+ #define MY_CAP_RXBUF "Q"
+#else
+ #define MY_CAP_RXBUF "-"
+#endif
-#define MY_CAPABILIIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN
+
+#define MY_CAPABILITIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN MY_CAP_RXBUF
#endif /* MyGatewayTransportEthernet_h */
diff --git a/libraries/MySensors/core/MyEepromAddresses.h b/core/MyEepromAddresses.h
similarity index 100%
rename from libraries/MySensors/core/MyEepromAddresses.h
rename to core/MyEepromAddresses.h
diff --git a/libraries/MySensors/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp
similarity index 93%
rename from libraries/MySensors/core/MyGatewayTransport.cpp
rename to core/MyGatewayTransport.cpp
index 26d9818..beb16d2 100644
--- a/libraries/MySensors/core/MyGatewayTransport.cpp
+++ b/core/MyGatewayTransport.cpp
@@ -19,9 +19,10 @@
#include "MyGatewayTransport.h"
-extern boolean transportSendRoute(MyMessage &message);
+extern bool transportSendRoute(MyMessage &message);
extern MyMessage _msg;
+
inline void gatewayTransportProcess() {
if (gatewayTransportAvailable()) {
_msg = gatewayTransportReceive();
@@ -40,7 +41,7 @@ inline void gatewayTransportProcess() {
if (mGetCommand(_msg) == C_INTERNAL) {
if (_msg.type == I_VERSION) {
// Request for version. Create the response
- gatewayTransportSend(buildGw(_msg, I_VERSION).set(LIBRARY_VERSION));
+ gatewayTransportSend(buildGw(_msg, I_VERSION).set(MYSENSORS_LIBRARY_VERSION));
#ifdef MY_INCLUSION_MODE_FEATURE
} else if (_msg.type == I_INCLUSION_MODE) {
// Request to change inclusion mode
diff --git a/libraries/MySensors/core/MyGatewayTransport.h b/core/MyGatewayTransport.h
similarity index 98%
rename from libraries/MySensors/core/MyGatewayTransport.h
rename to core/MyGatewayTransport.h
index d34bd31..8df4b59 100644
--- a/libraries/MySensors/core/MyGatewayTransport.h
+++ b/core/MyGatewayTransport.h
@@ -21,6 +21,7 @@
#define MyGatewayTransport_h
#include "MyProtocol.h"
+#include "MySensorsCore.h"
// Common gateway functions
diff --git a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp
similarity index 85%
rename from libraries/MySensors/core/MyGatewayTransportEthernet.cpp
rename to core/MyGatewayTransportEthernet.cpp
index d04c7d8..6c930e7 100644
--- a/libraries/MySensors/core/MyGatewayTransportEthernet.cpp
+++ b/core/MyGatewayTransportEthernet.cpp
@@ -1,4 +1,4 @@
-/**
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
@@ -47,8 +47,8 @@ typedef struct
#define EthernetUDP WiFiUDP
#if defined(MY_IP_ADDRESS)
- IPAddress gateway(MY_IP_GATEWAY_ADDRESS);
- IPAddress subnet(MY_IP_SUBNET_ADDRESS);
+ IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
+ IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
#endif
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
#endif
@@ -76,7 +76,7 @@ typedef struct
// On W5100 boards with SPI_EN exposed we can use the real SPI bus together with radio
// (if we enable it during usage)
#ifdef MY_W5100_SPI_EN
- void _w5100_spi_en(boolean enable)
+ void _w5100_spi_en(bool enable)
{
if (enable)
{
@@ -100,32 +100,40 @@ typedef struct
bool gatewayTransportInit() {
_w5100_spi_en(true);
#if defined(MY_GATEWAY_ESP8266)
- (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD);
- #ifdef MY_IP_ADDRESS
- WiFi.config(_ethernetGatewayIP, gateway, subnet);
+ #if defined(MY_ESP8266_SSID)
+ // Turn off access point
+ WiFi.mode (WIFI_STA);
+ #if defined(MY_ESP8266_HOSTNAME)
+ WiFi.hostname(MY_ESP8266_HOSTNAME);
+ #endif
+ #ifdef MY_IP_ADDRESS
+ WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp);
+ #endif
+ (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ {
+ delay(500);
+ MY_SERIALDEVICE.print(".");
+ yield();
+ }
+ MY_SERIALDEVICE.print(F("IP: "));
+ MY_SERIALDEVICE.println(WiFi.localIP());
#endif
- while (WiFi.status() != WL_CONNECTED)
- {
- delay(500);
- MY_SERIALDEVICE.print(".");
- yield();
- }
- MY_SERIALDEVICE.print(F("IP: "));
- MY_SERIALDEVICE.println(WiFi.localIP());
#else
#ifdef MY_IP_ADDRESS
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP);
- MY_SERIALDEVICE.print(F("IP: "));
- MY_SERIALDEVICE.println(Ethernet.localIP());
#else
// Get IP address from DHCP
- Ethernet.begin(_ethernetGatewayMAC);
- MY_SERIALDEVICE.print(F("IP: "));
- MY_SERIALDEVICE.println(Ethernet.localIP());
- #endif /* IP_ADDRESS_DHCP */
+ if (!Ethernet.begin(_ethernetGatewayMAC)) {
+ MY_SERIALDEVICE.print("DHCP FAILURE...");
+ _w5100_spi_en(false);
+ return false;
+ }
+ #endif
+ MY_SERIALDEVICE.print(F("IP: "));
+ MY_SERIALDEVICE.println(Ethernet.localIP());
// give the Ethernet interface a second to initialize
- // TODO: use HW delay
delay(1000);
#endif
@@ -134,9 +142,6 @@ bool gatewayTransportInit() {
#else
// we have to use pointers due to the constructor of EthernetServer
_ethernetServer.begin();
- #if defined(MY_GATEWAY_ESP8266)
- _ethernetServer.setNoDelay(true);
- #endif
#endif /* USE_UDP */
_w5100_spi_en(false);
return true;
@@ -147,6 +152,8 @@ bool gatewayTransportSend(MyMessage &message)
bool ret = true;
char *_ethernetMsg = protocolFormat(message);
+ setIndication(INDICATION_GW_TX);
+
_w5100_spi_en(true);
#if defined(MY_CONTROLLER_IP_ADDRESS)
#if defined(MY_USE_UDP)
@@ -157,17 +164,16 @@ bool gatewayTransportSend(MyMessage &message)
#else
EthernetClient client;
#if defined(MY_CONTROLLER_URL_ADDRESS)
- if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
- #else
- if (client.connect(_ethernetControllerIP, MY_PORT)) {
- #endif
- client.write(_ethernetMsg, strlen(_ethernetMsg));
- client.stop();
- }
- else {
- // connecting to the server failed!
- ret = false;
- }
+ if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
+ #else
+ if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) {
+ #endif
+ client.write(_ethernetMsg, strlen(_ethernetMsg));
+ }
+ else {
+ // connecting to the server failed!
+ ret = false;
+ }
#endif
#else
// Send message to connected clients
@@ -264,14 +270,17 @@ bool gatewayTransportAvailable()
if (packet_size) {
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
+ setIndication(INDICATION_GW_RX);
#if defined(MY_GATEWAY_ESP8266)
_ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
+ inputString[0].string[packet_size] = 0;
debug(PSTR("UDP packet received: %s\n"), inputString[0].string);
return protocolParse(_ethernetMsg, inputString[0].string);
#else
_ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
- _w5100_spi_en(false);
+ inputString.string[packet_size] = 0;
debug(PSTR("UDP packet received: %s\n"), inputString.string);
+ _w5100_spi_en(false);
return protocolParse(_ethernetMsg, inputString.string);
#endif
}
@@ -291,11 +300,9 @@ bool gatewayTransportAvailable()
clients[i] = _ethernetServer.available();
inputString[i].idx = 0;
debug(PSTR("Client %d connected\n"), i);
- _w5100_spi_en(false);
gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete."));
- _w5100_spi_en(true);
- if (presentation)
- presentation();
+ // Send presentation of locally attached sensors (and node if applicable)
+ presentNode();
}
}
bool connected = clients[i].connected();
@@ -311,6 +318,7 @@ bool gatewayTransportAvailable()
// Loop over clients connect and read available data
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
if (_readFromClient(i)) {
+ setIndication(INDICATION_GW_RX);
_w5100_spi_en(false);
return true;
}
@@ -326,8 +334,8 @@ bool gatewayTransportAvailable()
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete."));
- if (presentation)
- presentation();
+ _w5100_spi_en(true);
+ presentNode();
}
}
if (client) {
@@ -336,6 +344,7 @@ bool gatewayTransportAvailable()
client.stop();
} else {
if (_readFromClient()) {
+ setIndication(INDICATION_GW_RX);
_w5100_spi_en(false);
return true;
}
diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp
new file mode 100644
index 0000000..b6ca377
--- /dev/null
+++ b/core/MyGatewayTransportMQTTClient.cpp
@@ -0,0 +1,244 @@
+/*
+* The MySensors Arduino library handles the wireless radio link and protocol
+* between your home built sensors/actuators and HA controller of choice.
+* The sensors forms a self healing radio network with optional repeaters. Each
+* repeater and gateway builds a routing tables in EEPROM which keeps track of the
+* network topology allowing messages to be routed to nodes.
+*
+* Created by Henrik Ekblad
+* Copyright (C) 2013-2015 Sensnology AB
+* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+*
+* Documentation: http://www.mysensors.org
+* Support Forum: http://forum.mysensors.org
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*/
+
+
+// Topic structure: MY_MQTT_PUBLISH_TOPIC_PREFIX/NODE-ID/SENSOR-ID/CMD-TYPE/ACK-FLAG/SUB-TYPE
+
+#include "MyGatewayTransport.h"
+
+#if defined MY_CONTROLLER_IP_ADDRESS
+ IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS);
+#endif
+
+#if defined(MY_GATEWAY_ESP8266)
+ #define EthernetClient WiFiClient
+ #if defined(MY_IP_ADDRESS)
+ IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
+ IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
+ #endif
+#else
+ byte _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
+#endif
+
+#if defined(MY_IP_ADDRESS)
+ IPAddress _MQTT_clientIp(MY_IP_ADDRESS);
+#endif
+
+static EthernetClient _MQTT_ethClient;
+static PubSubClient _MQTT_client(_MQTT_ethClient);
+static bool _MQTT_connecting = true;
+static bool _MQTT_available = false;
+static MyMessage _MQTT_msg;
+
+uint8_t protocolH2i(char c) {
+ uint8_t i = 0;
+ if (c <= '9')
+ i += c - '0';
+ else if (c >= 'a')
+ i += c - 'a' + 10;
+ else
+ i += c - 'A' + 10;
+ return i;
+}
+
+
+bool gatewayTransportSend(MyMessage &message) {
+ if (!_MQTT_client.connected())
+ return false;
+ setIndication(INDICATION_GW_TX);
+ char _fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH];
+ char _convBuffer[MAX_PAYLOAD * 2 + 1];
+ snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
+ debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer);
+ return _MQTT_client.publish(_fmtBuffer, message.getString(_convBuffer));
+}
+
+void incomingMQTT(char* topic, byte* payload, unsigned int length) {
+ debug(PSTR("Message arrived on topic: %s\n"), topic);
+ char *str, *p;
+ uint8_t i = 0;
+ uint8_t bvalue[MAX_PAYLOAD];
+ uint8_t blen = 0;
+ uint8_t command = 0;
+ for (str = strtok_r(topic, "/", &p); str && i <= 5;
+ str = strtok_r(NULL, "/", &p)) {
+ switch (i) {
+ case 0: {
+ // Topic prefix
+ if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) {
+ // Message not for us or malformed!
+ return;
+ }
+ break;
+ }
+ case 1: {
+ // Node id
+ _MQTT_msg.destination = atoi(str);
+ break;
+ }
+ case 2: {
+ // Sensor id
+ _MQTT_msg.sensor = atoi(str);
+ break;
+ }
+ case 3: {
+ // Command type
+ command = atoi(str);
+ mSetCommand(_MQTT_msg, command);
+ break;
+ }
+ case 4: {
+ // Ack flag
+ mSetRequestAck(_MQTT_msg, atoi(str) ? 1 : 0);
+ break;
+ }
+ case 5: {
+ // Sub type
+ _MQTT_msg.type = atoi(str);
+ // Add payload
+ if (command == C_STREAM) {
+ blen = 0;
+ uint8_t val;
+ while (*payload) {
+ val = protocolH2i(*payload++) << 4;
+ val += protocolH2i(*payload++);
+ bvalue[blen] = val;
+ blen++;
+ }
+ _MQTT_msg.set(bvalue, blen);
+ }
+ else {
+ char* ca;
+ ca = (char *)payload;
+ ca += length;
+ *ca = '\0';
+ _MQTT_msg.set((const char*)payload);
+ }
+ _MQTT_available = true;
+ }
+ }
+ i++;
+ }
+}
+
+
+bool reconnectMQTT() {
+ debug(PSTR("Attempting MQTT connection...\n"));
+ // Attempt to connect
+ if (_MQTT_client.connect(MY_MQTT_CLIENT_ID
+#if defined(MY_MQTT_USER) && defined(MY_MQTT_PASSWORD)
+ , MY_MQTT_USER, MY_MQTT_PASSWORD
+#endif
+ )) {
+ debug(PSTR("MQTT connected\n"));
+
+ // Send presentation of locally attached sensors (and node if applicable)
+ presentNode();
+
+ // Once connected, publish an announcement...
+ //_MQTT_client.publish("outTopic","hello world");
+ // ... and resubscribe
+ _MQTT_client.subscribe(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "/+/+/+/+/+");
+ return true;
+ }
+ return false;
+}
+
+bool gatewayTransportConnect() {
+ #if defined(MY_GATEWAY_ESP8266)
+ while (WiFi.status() != WL_CONNECTED) {
+ delay(500); // delay calls yield
+ MY_SERIALDEVICE.print(".");
+ }
+ MY_SERIALDEVICE.print("IP: ");
+ MY_SERIALDEVICE.println(WiFi.localIP());
+ #else
+ #ifdef MY_IP_ADDRESS
+ Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp);
+ #else
+ // Get IP address from DHCP
+ if (!Ethernet.begin(_MQTT_clientMAC)) {
+ MY_SERIALDEVICE.print("DHCP FAILURE...");
+ _MQTT_connecting = false;
+ return false;
+ }
+ #endif
+ MY_SERIALDEVICE.print("IP: ");
+ MY_SERIALDEVICE.println(Ethernet.localIP());
+ // give the Ethernet interface a second to initialize
+ delay(1000);
+ #endif
+ return true;
+}
+
+bool gatewayTransportInit() {
+ _MQTT_connecting = true;
+ #if defined(MY_CONTROLLER_IP_ADDRESS)
+ _MQTT_client.setServer(_brokerIp, MY_PORT);
+ #else
+ _MQTT_client.setServer(MY_CONTROLLER_URL_ADDRESS, MY_PORT);
+ #endif
+
+ _MQTT_client.setCallback(incomingMQTT);
+
+ #if defined(MY_GATEWAY_ESP8266)
+ // Turn off access point
+ WiFi.mode(WIFI_STA);
+ #if defined(MY_ESP8266_HOSTNAME)
+ WiFi.hostname(MY_ESP8266_HOSTNAME);
+ #endif
+ (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD);
+ #ifdef MY_IP_ADDRESS
+ WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp);
+ #endif
+ #endif
+
+ gatewayTransportConnect();
+
+ _MQTT_connecting = false;
+ return true;
+}
+
+
+
+bool gatewayTransportAvailable() {
+
+ if (_MQTT_connecting)
+ return false;
+
+ //keep lease on dhcp address
+ //Ethernet.maintain();
+ if (!_MQTT_client.connected()) {
+ //reinitialise client
+ if (gatewayTransportConnect())
+ reconnectMQTT();
+ return false;
+ }
+ _MQTT_client.loop();
+ return _MQTT_available;
+}
+
+MyMessage & gatewayTransportReceive() {
+ // Return the last parsed message
+ _MQTT_available = false;
+ return _MQTT_msg;
+}
+
+
+
diff --git a/libraries/MySensors/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp
similarity index 93%
rename from libraries/MySensors/core/MyGatewayTransportSerial.cpp
rename to core/MyGatewayTransportSerial.cpp
index c67f1a9..f7c35c8 100644
--- a/libraries/MySensors/core/MyGatewayTransportSerial.cpp
+++ b/core/MyGatewayTransportSerial.cpp
@@ -31,6 +31,7 @@ MyMessage _serialMsg;
bool gatewayTransportSend(MyMessage &message) {
+ setIndication(INDICATION_GW_TX);
MY_SERIALDEVICE.print(protocolFormat(message));
// Serial print is always successful
return true;
@@ -38,6 +39,9 @@ bool gatewayTransportSend(MyMessage &message) {
bool gatewayTransportInit() {
gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete."));
+ // Send presentation of locally attached sensors (and node if applicable)
+ presentNode();
+
return true;
}
@@ -52,8 +56,7 @@ bool gatewayTransportAvailable() {
if (inChar == '\n') {
_serialInputString[_serialInputPos] = 0;
bool ok = protocolParse(_serialMsg, _serialInputString);
- if (ok)
- _serialInputPos = 0;
+ _serialInputPos = 0;
return ok;
} else {
// add it to the inputString:
diff --git a/core/MyHw.h b/core/MyHw.h
new file mode 100644
index 0000000..f2b29c3
--- /dev/null
+++ b/core/MyHw.h
@@ -0,0 +1,114 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+ /**
+ * @file MyHw.h
+ *
+ * MySensors hardware abstraction layer
+ */
+
+#ifndef MyHw_h
+#define MyHw_h
+
+#include "MyConfig.h"
+#include "MyMessage.h"
+
+
+#ifdef __cplusplus
+#include
+#endif
+
+// Implement these as functions or macros
+/*
+#define hwDigitalWrite(__pin, __value)
+#define hwInit() MY_SERIALDEVICE.begin(BAUD_RATE)
+#define hwWatchdogReset() wdt_reset()
+#define hwReboot() wdt_enable(WDTO_15MS); while (1)
+#define hwMillis() millis()
+
+void hwReadConfigBlock(void* buf, void* adr, size_t length);
+void hwWriteConfigBlock(void* buf, void* adr, size_t length);
+void hwWriteConfig(int adr, uint8_t value);
+uint8_t hwReadConfig(int adr);
+*/
+
+/**
+ * Sleep for a defined time, using minimum power.
+ * @param ms Time to sleep, in [ms].
+ * @return Nonsense, please ignore.
+ */
+int8_t hwSleep(unsigned long ms);
+
+/**
+ * Sleep for a defined time, using minimum power, or until woken by interrupt.
+ * @param interrupt Interrupt number, which can wake the mcu from sleep.
+ * @param mode Interrupt mode, as passed to attachInterrupt.
+ * @param ms Time to sleep, in [ms].
+ * @return -1 when woken by timer, or interrupt number when woken by interrupt.
+ */
+int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms);
+
+/**
+ * Sleep for a defined time, using minimum power, or until woken by one of the interrupts.
+ * @param interrupt1 Interrupt1 number, which can wake the mcu from sleep.
+ * @param mode1 Interrupt1 mode, as passed to attachInterrupt.
+ * @param interrupt2 Interrupt2 number, which can wake the mcu from sleep.
+ * @param mode2 Interrupt2 mode, as passed to attachInterrupt.
+ * @param ms Time to sleep, in [ms].
+ * @return -1 when woken by timer, or interrupt number when woken by interrupt.
+ */
+int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms);
+
+#ifdef MY_DEBUG
+ void hwDebugPrint(const char *fmt, ... );
+#endif
+
+/**
+ * @def MY_CRITICAL_SECTION
+ * @brief Creates a block of code that is guaranteed to be executed atomically.
+ * Upon entering the block all interrupts are disabled, and re-enabled upon
+ * exiting the block from any exit path.
+ * A typical example that requires atomic access is a 16 (or more) bit variable
+ * that is shared between the main execution path and an ISR, on an 8-bit
+ * platform (e.g AVR):
+ * @code
+ * volatile uint16_t val = 0;
+ *
+ * void interrupHandler()
+ * {
+ * val = ~val;
+ * }
+ *
+ * void loop()
+ * {
+ * uint16_t copy_val;
+ * MY_CRITICAL_SECTION
+ * {
+ * copy_val = val;
+ * }
+ * }
+ * @endcode
+ * All code within the MY_CRITICAL_SECTION block will be protected from being
+ * interrupted during execution.
+ */
+#ifdef DOXYGEN
+ #define MY_CRITICAL_SECTION
+#endif /* DOXYGEN */
+
+#endif // #ifdef MyHw_h
diff --git a/libraries/MySensors/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp
similarity index 59%
rename from libraries/MySensors/core/MyHwATMega328.cpp
rename to core/MyHwATMega328.cpp
index 0a0bcc9..349e775 100644
--- a/libraries/MySensors/core/MyHwATMega328.cpp
+++ b/core/MyHwATMega328.cpp
@@ -21,15 +21,26 @@
#include "MyHwATMega328.h"
-int8_t pinIntTrigger = 0;
+#define INVALID_INTERRUPT_NUM (0xFFu)
-void wakeUp() //place to send the interrupts
+volatile uint8_t _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu.
+volatile uint8_t _wakeUp1Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback.
+volatile uint8_t _wakeUp2Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback.
+
+void wakeUp1() //place to send the interrupts
{
- pinIntTrigger = 1;
+ detachInterrupt(_wakeUp1Interrupt);
+ _wokeUpByInterrupt = _wakeUp1Interrupt;
}
void wakeUp2() //place to send the second interrupts
{
- pinIntTrigger = 2;
+ detachInterrupt(_wakeUp2Interrupt);
+ _wokeUpByInterrupt = _wakeUp2Interrupt;
+}
+
+bool interruptWakeUp()
+{
+ return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
}
// Watchdog Timer interrupt service routine. This routine is required
@@ -39,7 +50,6 @@ ISR (WDT_vect)
}
void hwPowerDown(period_t period) {
-
// disable ADC for power saving
ADCSRA &= ~(1 << ADEN);
// save WDT settings
@@ -56,11 +66,12 @@ void hwPowerDown(period_t period) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_enable();
-#if defined __AVR_ATmega328P__
- sleep_bod_disable();
-#endif
+ #if defined __AVR_ATmega328P__
+ sleep_bod_disable();
+ #endif
+ // Enable interrupts & sleep until WDT or ext. interrupt
sei();
- // sleep until WDT or ext. interrupt
+ // Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet)
sleep_cpu();
sleep_disable();
// restore previous WDT settings
@@ -77,21 +88,19 @@ void hwPowerDown(period_t period) {
void hwInternalSleep(unsigned long ms) {
// Let serial prints finish (debug, log etc)
- #ifndef MY_DISABLED_SERIAL
- Serial.flush();
- #endif
- // reset interrupt trigger var
- pinIntTrigger = 0;
- while (!pinIntTrigger && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; }
- if (!pinIntTrigger && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; }
- if (!pinIntTrigger && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; }
- if (!pinIntTrigger && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; }
- if (!pinIntTrigger && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; }
- if (!pinIntTrigger && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; }
- if (!pinIntTrigger && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; }
- if (!pinIntTrigger && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; }
- if (!pinIntTrigger && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; }
- if (!pinIntTrigger && ms >= 16) { hwPowerDown(SLEEP_15MS); ms -= 15; }
+ #ifndef MY_DISABLED_SERIAL
+ MY_SERIALDEVICE.flush();
+ #endif
+ while (!interruptWakeUp() && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; }
+ if (!interruptWakeUp() && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; }
+ if (!interruptWakeUp() && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; }
+ if (!interruptWakeUp() && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; }
+ if (!interruptWakeUp() && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; }
+ if (!interruptWakeUp() && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; }
+ if (!interruptWakeUp() && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; }
+ if (!interruptWakeUp() && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; }
+ if (!interruptWakeUp() && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; }
+ if (!interruptWakeUp() && ms >= 16) { hwPowerDown(SLEEP_15MS); ms -= 15; }
}
int8_t hwSleep(unsigned long ms) {
@@ -100,15 +109,18 @@ int8_t hwSleep(unsigned long ms) {
}
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
- return hwSleep(interrupt,mode,0xFF,0x00,ms);
+ return hwSleep(interrupt,mode,INVALID_INTERRUPT_NUM,0u,ms);
}
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
- // reset interrupt trigger var
- pinIntTrigger = 0;
+ // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt()
+ // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled!
+ cli();
// attach interrupts
- attachInterrupt(interrupt1, wakeUp, mode1);
- if (interrupt2!=0xFF) attachInterrupt(interrupt2, wakeUp2, mode2);
+ _wakeUp1Interrupt = interrupt1;
+ _wakeUp2Interrupt = interrupt2;
+ if (interrupt1 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt1, wakeUp1, mode1);
+ if (interrupt2 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt2, wakeUp2, mode2);
if (ms>0) {
// sleep for defined time
@@ -118,18 +130,14 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo
hwPowerDown(SLEEP_FOREVER);
}
- detachInterrupt(interrupt1);
- if (interrupt2!=0xFF) detachInterrupt(interrupt2);
-
- // default: no interrupt triggered, timer wake up
- int8_t retVal = -1;
+ // Return what woke the mcu.
+ int ret = -1; // default: no interrupt triggered, timer wake up
+ if (interruptWakeUp()) ret = static_cast(_wokeUpByInterrupt);
- if (pinIntTrigger == 1) {
- retVal = (int8_t)interrupt1;
- } else if (pinIntTrigger == 2) {
- retVal = (int8_t)interrupt2;
- }
- return retVal;
+ // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
+ _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
+
+ return ret;
}
uint16_t hwCPUVoltage() {
@@ -152,8 +160,8 @@ uint16_t hwCPUVoltage() {
return (1125300UL) / ADC;
}
-uint8_t hwCPUFrequency() {
- noInterrupts();
+uint16_t hwCPUFrequency() {
+ cli();
// setup timer1
TIFR1 = 0xFF;
TCNT1 = 0;
@@ -175,11 +183,17 @@ uint8_t hwCPUFrequency() {
wdt_reset();
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = WDTsave;
- interrupts();
+ sei();
// return frequency in 1/10MHz (accuracy +- 10%)
return TCNT1 * 2048UL / 100000UL;
}
+uint16_t hwFreeMem() {
+ extern int __heap_start, *__brkval;
+ int v;
+ return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
+}
+
#ifdef MY_DEBUG
@@ -188,7 +202,7 @@ void hwDebugPrint(const char *fmt, ... ) {
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
- Serial.print(fmtBuffer);
+ MY_SERIALDEVICE.print(fmtBuffer);
#endif
va_list args;
va_start (args, fmt );
@@ -202,10 +216,10 @@ void hwDebugPrint(const char *fmt, ... ) {
vsnprintf_P(fmtBuffer, 299, fmt, args);
#endif
va_end (args);
- Serial.print(fmtBuffer);
- Serial.flush();
+ MY_SERIALDEVICE.print(fmtBuffer);
+ MY_SERIALDEVICE.flush();
- //Serial.write(freeRam());
+ //MY_SERIALDEVICE.write(freeRam());
}
#endif
diff --git a/libraries/MySensors/core/MyHwATMega328.h b/core/MyHwATMega328.h
similarity index 94%
rename from libraries/MySensors/core/MyHwATMega328.h
rename to core/MyHwATMega328.h
index 9b9a487..157ecb1 100644
--- a/libraries/MySensors/core/MyHwATMega328.h
+++ b/core/MyHwATMega328.h
@@ -27,7 +27,7 @@
#include
#include
#include
-
+#include
#ifdef __cplusplus
@@ -57,7 +57,7 @@ do { \
// Define these as macros to save valuable space
#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value))
-#define hwInit() Serial.begin(MY_BAUD_RATE)
+#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE)
#define hwWatchdogReset() wdt_reset()
#define hwReboot() wdt_enable(WDTO_15MS); while (1)
#define hwMillis() millis()
@@ -92,4 +92,8 @@ enum period_t
void hwInternalSleep(unsigned long ms);
+#ifndef DOXYGEN
+ #define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+#endif /* DOXYGEN */
+
#endif
diff --git a/libraries/MySensors/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp
similarity index 90%
rename from libraries/MySensors/core/MyHwESP8266.cpp
rename to core/MyHwESP8266.cpp
index cec567f..1e50156 100644
--- a/libraries/MySensors/core/MyHwESP8266.cpp
+++ b/core/MyHwESP8266.cpp
@@ -90,20 +90,27 @@ void hwWriteConfig(int adr, uint8_t value)
}
-
-
int8_t hwSleep(unsigned long ms) {
// TODO: Not supported!
+ (void)ms;
return -2;
}
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
// TODO: Not supported!
+ (void)interrupt;
+ (void)mode;
+ (void)ms;
return -2;
}
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
- // TODO: Not supported!
+ // TODO: Not supported!
+ (void)interrupt1;
+ (void)mode1;
+ (void)interrupt2;
+ (void)mode2;
+ (void)ms;
return -2;
}
@@ -119,13 +126,17 @@ uint16_t hwCPUFrequency() {
return ESP.getCpuFreqMHz()*10;
}
+uint16_t hwFreeMem() {
+ return ESP.getFreeHeap();
+}
+
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) {
char fmtBuffer[300];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
- Serial.print(fmtBuffer);
+ MY_SERIALDEVICE.print(fmtBuffer);
#endif
va_list args;
va_start (args, fmt );
@@ -139,9 +150,9 @@ void hwDebugPrint(const char *fmt, ... ) {
vsnprintf_P(fmtBuffer, 299, fmt, args);
#endif
va_end (args);
- Serial.print(fmtBuffer);
- Serial.flush();
+ MY_SERIALDEVICE.print(fmtBuffer);
+ MY_SERIALDEVICE.flush();
- //Serial.write(freeRam());
+ //MY_SERIALDEVICE.write(freeRam());
}
#endif
diff --git a/libraries/MySensors/core/MyHwESP8266.h b/core/MyHwESP8266.h
similarity index 75%
rename from libraries/MySensors/core/MyHwESP8266.h
rename to core/MyHwESP8266.h
index bd958cb..1495e69 100644
--- a/libraries/MySensors/core/MyHwESP8266.h
+++ b/core/MyHwESP8266.h
@@ -23,7 +23,6 @@
#ifdef __cplusplus
#include
-//#include
#endif
#define MY_SERIALDEVICE Serial
@@ -34,9 +33,9 @@
// Define these as macros to save valuable space
#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value))
-#define hwInit() Serial.begin(MY_BAUD_RATE); Serial.setDebugOutput(true)
+#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true)
#define hwWatchdogReset() wdt_reset()
-#define hwReboot() wdt_enable(WDTO_15MS); while (1)
+#define hwReboot() ESP.restart();
#define hwMillis() millis()
void hwReadConfigBlock(void* buf, void* adr, size_t length);
@@ -44,5 +43,17 @@ void hwWriteConfigBlock(void* buf, void* adr, size_t length);
void hwWriteConfig(int adr, uint8_t value);
uint8_t hwReadConfig(int adr);
+/**
+ * Restore interrupt state.
+ * Helper function for MY_CRITICAL_SECTION.
+ */
+static __inline__ void __psRestore(const uint32_t *__s)
+{
+ xt_wsr_ps( *__s );
+}
+
+#ifndef DOXYGEN
+ #define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = xt_rsil(15), __ToDo = 1; __ToDo ; __ToDo = 0 )
+#endif /* DOXYGEN */
#endif // #ifdef ARDUINO_ARCH_ESP8266
diff --git a/libraries/MySensors/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp
similarity index 92%
rename from libraries/MySensors/core/MyHwSAMD.cpp
rename to core/MyHwSAMD.cpp
index 017fc7a..264da9c 100644
--- a/libraries/MySensors/core/MyHwSAMD.cpp
+++ b/core/MyHwSAMD.cpp
@@ -68,7 +68,7 @@ void hwReadConfigBlock(void* buf, void* adr, size_t length)
int offs = reinterpret_cast(adr);
while (length-- > 0)
{
- *dst++ = i2c_eeprom_read_byte(offs++);
+ *dst++ = i2c_eeprom_read_byte(offs++);
}
}
@@ -100,7 +100,7 @@ void hwWriteConfig(int adr, uint8_t value)
void hwInit() {
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
- #ifndef MY_GATEWAY_W5100
+ #if defined(MY_GATEWAY_SERIAL)
while (!MY_SERIALDEVICE) {}
#endif
Wire.begin();
@@ -138,6 +138,21 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo
return -2;
}
+uint16_t hwCPUVoltage() {
+ // TODO: Not supported!
+ return 0;
+}
+
+uint16_t hwCPUFrequency() {
+ // TODO: Not supported!
+ return 0;
+}
+
+uint16_t hwFreeMem() {
+ // TODO: Not supported!
+ return 0;
+}
+
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) {
if (MY_SERIALDEVICE) {
@@ -162,7 +177,7 @@ void hwDebugPrint(const char *fmt, ... ) {
MY_SERIALDEVICE.print(fmtBuffer);
// MY_SERIALDEVICE.flush();
- //Serial.write(freeRam());
+ //MY_SERIALDEVICE.write(freeRam());
}
}
#endif
diff --git a/libraries/MySensors/core/MyHwSAMD.h b/core/MyHwSAMD.h
similarity index 76%
rename from libraries/MySensors/core/MyHwSAMD.h
rename to core/MyHwSAMD.h
index fcc5a9d..dcb783c 100644
--- a/libraries/MySensors/core/MyHwSAMD.h
+++ b/core/MyHwSAMD.h
@@ -58,4 +58,28 @@ uint8_t hwReadConfig(int adr);
#define hwWriteConfig(__adr, __value) ( __value = __value)
#define hwReadConfig(__adr) (0)
*/
+
+/**
+ * Disable all interrupts.
+ * Helper function for MY_CRITICAL_SECTION.
+ */
+static __inline__ uint8_t __disableIntsRetVal(void)
+{
+ __disable_irq();
+ return 1;
+}
+
+/**
+ * Restore priority mask register.
+ * Helper function for MY_CRITICAL_SECTION.
+ */
+static __inline__ void __priMaskRestore(const uint32_t *priMask)
+{
+ __set_PRIMASK(*priMask);
+}
+
+#ifndef DOXYGEN
+ #define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 )
+#endif /* DOXYGEN */
+
#endif // #ifdef ARDUINO_ARCH_SAMD
diff --git a/libraries/MySensors/core/MyInclusionMode.cpp b/core/MyInclusionMode.cpp
similarity index 97%
rename from libraries/MySensors/core/MyInclusionMode.cpp
rename to core/MyInclusionMode.cpp
index b66be24..e55612f 100644
--- a/libraries/MySensors/core/MyInclusionMode.cpp
+++ b/core/MyInclusionMode.cpp
@@ -33,7 +33,7 @@ inline void inclusionInit() {
}
-void inclusionModeSet(boolean newMode) {
+void inclusionModeSet(bool newMode) {
if (newMode != _inclusionMode) {
_inclusionMode = newMode;
// Send back mode change to controller
diff --git a/libraries/MySensors/core/MyInclusionMode.h b/core/MyInclusionMode.h
similarity index 93%
rename from libraries/MySensors/core/MyInclusionMode.h
rename to core/MyInclusionMode.h
index dfa0936..9c58c82 100644
--- a/libraries/MySensors/core/MyInclusionMode.h
+++ b/core/MyInclusionMode.h
@@ -1,4 +1,4 @@
-/**
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
@@ -20,13 +20,13 @@
#ifndef MyInclusionMode_h
#define MyInclusionMode_h
-#include "MySensorCore.h"
+#include "MySensorsCore.h"
extern bool gatewayTransportSend(MyMessage &message);
void inclusionInit();
-void inclusionModeSet(boolean newMode);
+void inclusionModeSet(bool newMode);
void inclusionProcess();
diff --git a/core/MyIndication.cpp b/core/MyIndication.cpp
new file mode 100644
index 0000000..8e5e65b
--- /dev/null
+++ b/core/MyIndication.cpp
@@ -0,0 +1,42 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2016 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyIndication.h"
+#ifdef MY_LEDS_BLINKING_FEATURE
+#include "MyLeds.h"
+#endif
+
+void setIndication( const indication_t ind )
+{
+#ifdef MY_LEDS_BLINKING_FEATURE
+ if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind))
+ {
+ ledsBlinkTx(1);
+ } else if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind))
+ {
+ ledsBlinkRx(1);
+ } else if (ind > INDICATION_ERR_START)
+ {
+ // Number of blinks indicates which error occurred.
+ ledsBlinkErr(ind-INDICATION_ERR_START);
+ }
+#endif
+ if (indication)
+ indication(ind);
+}
diff --git a/core/MyIndication.h b/core/MyIndication.h
new file mode 100644
index 0000000..ab2bbbc
--- /dev/null
+++ b/core/MyIndication.h
@@ -0,0 +1,75 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2016 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef MyIndication_h
+#define MyIndication_h
+
+/**
+ * Indication type
+ */
+typedef enum {
+ INDICATION_TX = 0, //!< Sent a message.
+ INDICATION_RX, //!< Received a message.
+
+ INDICATION_GW_TX, //!< Gateway transmit message.
+ INDICATION_GW_RX, //!< Gateway receive message.
+
+ INDICATION_FIND_PARENT, //!< Start finding parent node.
+ INDICATION_GOT_PARENT, //!< Found parent node.
+ INDICATION_REQ_NODEID, //!< Request node ID.
+ INDICATION_GOT_NODEID, //!< Got a node ID.
+ INDICATION_REQ_REGISTRATION, //!< Request node registration.
+ INDICATION_GOT_REGISTRATION, //!< Got registration reponse.
+ INDICATION_REBOOT, //!< Rebooting node.
+ INDICATION_PRESENT, //!< Presenting node to gateway.
+ INDICATION_CLEAR_ROUTING, //!< Clear rrouting table requested.
+ INDICATION_SLEEP, //!< Node goes to sleep.
+ INDICATION_WAKEUP, //!< Node just woke from sleep.
+ INDICATION_FW_UPDATE_START, //!< Start of OTA firmware update process.
+ INDICATION_FW_UPDATE_RX, //!< Received a piece of firmware data.
+
+ INDICATION_ERR_START = 100,
+ INDICATION_ERR_TX, //!< Failed to transmit message.
+ INDICATION_ERR_TRANSPORT_FAILURE, //!< Transport failure.
+ INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure.
+ INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node.
+ INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID.
+ INDICATION_ERR_SIGN, //!< Error signing.
+ INDICATION_ERR_VERSION, //!< Protocol version mismatch.
+ INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken.
+ INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure.
+ INDICATION_ERR_LOCKED, //!< Node is locked.
+ INDICATION_ERR_FW_FLASH_INIT, //!< Firmware update flash initialisation failure.
+ INDICATION_ERR_FW_TIMEOUT, //!< Firmware update timeout.
+ INDICATION_ERR_FW_CHECKSUM, //!< Firmware update checksum mismatch.
+ INDICATION_ERR_END
+} indication_t;
+
+/**
+ * Function which is called when something changes about the internal state of MySensors.
+ * @param ind Event indication of what happened.
+ */
+void setIndication( const indication_t ind );
+
+/**
+ * Allow user to define their own indication handler.
+ */
+void indication( const indication_t ) __attribute__((weak));
+
+#endif
diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp
new file mode 100644
index 0000000..2974c18
--- /dev/null
+++ b/core/MyLeds.cpp
@@ -0,0 +1,82 @@
+/**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyLeds.h"
+
+#define LED_ON_OFF_RATIO (4) // Power of 2 please
+#define LED_PROCESS_INTERVAL_MS (MY_DEFAULT_LED_BLINK_PERIOD/LED_ON_OFF_RATIO)
+
+// these variables don't need to be volatile, since we are not using interrupts
+static uint8_t countRx;
+static uint8_t countTx;
+static uint8_t countErr;
+static unsigned long prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run.
+
+
+inline void ledsInit()
+{
+ // initialize counters
+ countRx = 0;
+ countTx = 0;
+ countErr = 0;
+
+ // Setup led pins
+ pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
+ pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
+ pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT);
+
+ ledsProcess();
+}
+
+void ledsProcess() {
+ // Just return if it is not the time...
+ if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS)
+ return;
+
+ prevTime += LED_PROCESS_INTERVAL_MS;
+
+ uint8_t state;
+
+ // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off]
+ // until the counter becomes 0.
+ state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state);
+ if (countRx) --countRx;
+
+ state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state);
+ if (countTx) --countTx;
+
+ state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
+ hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state);
+ if (countErr) --countErr;
+}
+
+void ledsBlinkRx(uint8_t cnt) {
+ if (!countRx) { countRx = cnt*LED_ON_OFF_RATIO; }
+}
+
+void ledsBlinkTx(uint8_t cnt) {
+ if(!countTx) { countTx = cnt*LED_ON_OFF_RATIO; }
+}
+
+void ledsBlinkErr(uint8_t cnt) {
+ if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; }
+}
+
diff --git a/libraries/MySensors/core/MyLeds.h b/core/MyLeds.h
similarity index 100%
rename from libraries/MySensors/core/MyLeds.h
rename to core/MyLeds.h
diff --git a/libraries/MySensors/core/MyMainDefault.cpp b/core/MyMainDefault.cpp
similarity index 100%
rename from libraries/MySensors/core/MyMainDefault.cpp
rename to core/MyMainDefault.cpp
diff --git a/core/MyMainESP8266.cpp b/core/MyMainESP8266.cpp
new file mode 100644
index 0000000..ee800a0
--- /dev/null
+++ b/core/MyMainESP8266.cpp
@@ -0,0 +1,147 @@
+
+//This may be used to change user task stack size:
+//#define CONT_STACKSIZE 4096
+#include "Schedule.h"
+extern "C" {
+#include "ets_sys.h"
+#include "os_type.h"
+#include "osapi.h"
+#include "mem.h"
+#include "user_interface.h"
+#include "cont.h"
+}
+#include
+
+#define LOOP_TASK_PRIORITY 1
+#define LOOP_QUEUE_SIZE 1
+
+#define OPTIMISTIC_YIELD_TIME_US 16000
+
+struct rst_info resetInfo;
+
+extern "C" {
+ extern const uint32_t __attribute__((section(".ver_number"))) core_version = ARDUINO_ESP8266_GIT_VER;
+ const char* core_release =
+#ifdef ARDUINO_ESP8266_RELEASE
+ ARDUINO_ESP8266_RELEASE;
+#else
+ NULL;
+#endif
+} // extern "C"
+
+int atexit(void(*func)()) {
+ (void)func;
+ return 0;
+}
+
+extern "C" void ets_update_cpu_frequency(int freqmhz);
+void initVariant() __attribute__((weak));
+void initVariant() {
+}
+
+void preloop_update_frequency() __attribute__((weak));
+void preloop_update_frequency() {
+#if defined(F_CPU) && (F_CPU == 160000000L)
+ REG_SET_BIT(0x3ff00014, BIT(0));
+ ets_update_cpu_frequency(160);
+#endif
+}
+
+extern void(*__init_array_start)(void);
+extern void(*__init_array_end)(void);
+
+cont_t g_cont __attribute__((aligned(16)));
+static os_event_t g_loop_queue[LOOP_QUEUE_SIZE];
+
+static uint32_t g_micros_at_task_start;
+
+extern "C" void esp_yield() {
+ if (cont_can_yield(&g_cont)) {
+ cont_yield(&g_cont);
+ }
+}
+
+extern "C" void esp_schedule() {
+ ets_post(LOOP_TASK_PRIORITY, 0, 0);
+}
+
+extern "C" void __yield() {
+ if (cont_can_yield(&g_cont)) {
+ esp_schedule();
+ esp_yield();
+ }
+ else {
+ panic();
+ }
+}
+
+extern "C" void yield(void) __attribute__((weak, alias("__yield")));
+
+extern "C" void optimistic_yield(uint32_t interval_us) {
+ if (cont_can_yield(&g_cont) &&
+ (system_get_time() - g_micros_at_task_start) > interval_us)
+ {
+ yield();
+ }
+}
+
+static void loop_wrapper() {
+ static bool setup_done = false;
+ preloop_update_frequency();
+ if (!setup_done) {
+ _begin(); // Startup MySensors library
+ setup_done = true;
+ }
+ _process(); // Process incoming data
+ loop();
+ run_scheduled_functions();
+ esp_schedule();
+}
+
+static void loop_task(os_event_t *events) {
+ (void)events;
+ g_micros_at_task_start = system_get_time();
+ cont_run(&g_cont, &loop_wrapper);
+ if (cont_check(&g_cont) != 0) {
+ panic();
+ }
+}
+
+static void do_global_ctors(void) {
+ void(**p)(void) = &__init_array_end;
+ while (p != &__init_array_start)
+ (*--p)();
+}
+
+extern "C" void __gdb_init() {}
+extern "C" void gdb_init(void) __attribute__((weak, alias("__gdb_init")));
+
+extern "C" void __gdb_do_break() {}
+extern "C" void gdb_do_break(void) __attribute__((weak, alias("__gdb_do_break")));
+
+void init_done() {
+ system_set_os_print(1);
+ gdb_init();
+ do_global_ctors();
+ esp_schedule();
+}
+
+
+extern "C" void user_init(void) {
+ struct rst_info *rtc_info_ptr = system_get_rst_info();
+ memcpy((void *)&resetInfo, (void *)rtc_info_ptr, sizeof(resetInfo));
+
+ uart_div_modify(0, UART_CLK_FREQ / (115200));
+
+ init();
+
+ initVariant();
+
+ cont_init(&g_cont);
+
+ ets_task(loop_task,
+ LOOP_TASK_PRIORITY, g_loop_queue,
+ LOOP_QUEUE_SIZE);
+
+ system_init_done_cb(&init_done);
+}
\ No newline at end of file
diff --git a/libraries/MySensors/core/MyMessage.cpp b/core/MyMessage.cpp
similarity index 92%
rename from libraries/MySensors/core/MyMessage.cpp
rename to core/MyMessage.cpp
index 117dfe3..027b273 100644
--- a/libraries/MySensors/core/MyMessage.cpp
+++ b/core/MyMessage.cpp
@@ -23,14 +23,28 @@
#include
-MyMessage::MyMessage() {
- destination = 0; // Gateway is default destination
+MyMessage::MyMessage()
+{
+ clear();
}
-MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) {
- destination = 0; // Gateway is default destination
+MyMessage::MyMessage(uint8_t _sensor, uint8_t _type)
+{
+ clear();
sensor = _sensor;
- type = _type;
+ type = _type;
+}
+
+void MyMessage::clear()
+{
+ last = 0u;
+ sender = 0u;
+ destination = 0u; // Gateway is default destination
+ version_length = 0u;
+ command_ack_payload = 0u;
+ type = 0u;
+ sensor = 0u;
+ (void)memset(data, 0u, sizeof(data));
}
bool MyMessage::isAck() const {
diff --git a/core/MyMessage.h b/core/MyMessage.h
new file mode 100644
index 0000000..aa84b49
--- /dev/null
+++ b/core/MyMessage.h
@@ -0,0 +1,379 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+/**
+ * @file MyMessage.h
+ *
+ * @brief API and type declarations for MySensors messages
+ * @defgroup MyMessagegrp MyMessage
+ * @{
+ *
+ * @brief Here you can find all message types used by the MySensors protocol as well as macros for
+ * parsing and manipulating messages.
+ */
+#ifndef MyMessage_h
+#define MyMessage_h
+
+#ifdef __cplusplus
+#include
+#include
+#include
+#endif
+
+#define PROTOCOL_VERSION 2 //!< The version of the protocol
+#define MAX_MESSAGE_LENGTH 32 //!< The maximum size of a message (including header)
+#define HEADER_SIZE 7 //!< The size of the header
+#define MAX_PAYLOAD (MAX_MESSAGE_LENGTH - HEADER_SIZE) //!< The maximum size of a payload depends on #MAX_MESSAGE_LENGTH and #HEADER_SIZE
+
+/// @brief The command field (message-type) defines the overall properties of a message
+typedef enum {
+ C_PRESENTATION = 0, //!< Sent by a node when they present attached sensors. This is usually done in presentation() at startup.
+ C_SET = 1, //!< This message is sent from or to a sensor when a sensor value should be updated.
+ C_REQ = 2, //!< Requests a variable value (usually from an actuator destined for controller).
+ C_INTERNAL = 3, //!< Internal MySensors messages (also include common messages provided/generated by the library).
+ C_STREAM = 4 //!< For firmware and other larger chunks of data that need to be divided into pieces.
+} mysensor_command;
+
+/// @brief Type of sensor (used when presenting sensors)
+typedef enum {
+ S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED
+ S_MOTION = 1, //!< Motion sensor, V_TRIPPED, V_ARMED
+ S_SMOKE = 2, //!< Smoke sensor, V_TRIPPED, V_ARMED
+ S_BINARY = 3, //!< Binary light or relay, V_STATUS, V_WATT
+ S_LIGHT = 3, //!< \deprecated Same as S_BINARY, **** DEPRECATED, DO NOT USE ****
+ S_DIMMER = 4, //!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT
+ S_COVER = 5, //!< Blinds or window cover, V_UP, V_DOWN, V_STOP, V_PERCENTAGE (open/close to a percentage)
+ S_TEMP = 6, //!< Temperature sensor, V_TEMP
+ S_HUM = 7, //!< Humidity sensor, V_HUM
+ S_BARO = 8, //!< Barometer sensor, V_PRESSURE, V_FORECAST
+ S_WIND = 9, //!< Wind sensor, V_WIND, V_GUST
+ S_RAIN = 10, //!< Rain sensor, V_RAIN, V_RAINRATE
+ S_UV = 11, //!< Uv sensor, V_UV
+ S_WEIGHT = 12, //!< Personal scale sensor, V_WEIGHT, V_IMPEDANCE
+ S_POWER = 13, //!< Power meter, V_WATT, V_KWH, V_VAR, V_VA, V_POWER_FACTOR
+ S_HEATER = 14, //!< Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP
+ S_DISTANCE = 15, //!< Distance sensor, V_DISTANCE
+ S_LIGHT_LEVEL = 16, //!< Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux)
+ S_ARDUINO_NODE = 17, //!< Used (internally) for presenting a non-repeating Arduino node
+ S_ARDUINO_REPEATER_NODE = 18, //!< Used (internally) for presenting a repeating Arduino node
+ S_LOCK = 19, //!< Lock device, V_LOCK_STATUS
+ S_IR = 20, //!< IR device, V_IR_SEND, V_IR_RECEIVE
+ S_WATER = 21, //!< Water meter, V_FLOW, V_VOLUME
+ S_AIR_QUALITY = 22, //!< Air quality sensor, V_LEVEL
+ S_CUSTOM = 23, //!< Custom sensor
+ S_DUST = 24, //!< Dust sensor, V_LEVEL
+ S_SCENE_CONTROLLER = 25, //!< Scene controller device, V_SCENE_ON, V_SCENE_OFF.
+ S_RGB_LIGHT = 26, //!< RGB light. Send color component data using V_RGB. Also supports V_WATT
+ S_RGBW_LIGHT = 27, //!< RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT
+ S_COLOR_SENSOR = 28, //!< Color sensor, send color information using V_RGB
+ S_HVAC = 29, //!< Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP
+ S_MULTIMETER = 30, //!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE
+ S_SPRINKLER = 31, //!< Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
+ S_WATER_LEAK = 32, //!< Water leak sensor, V_TRIPPED, V_ARMED
+ S_SOUND = 33, //!< Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB)
+ S_VIBRATION = 34, //!< Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz)
+ S_MOISTURE = 35, //!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?)
+ S_INFO = 36, //!< LCD text device / Simple information device on controller, V_TEXT
+ S_GAS = 37, //!< Gas meter, V_FLOW, V_VOLUME
+ S_GPS = 38, //!< GPS Sensor, V_POSITION
+ S_WATER_QUALITY = 39 //!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS
+} mysensor_sensor;
+
+/// @brief Type of sensor data (for set/req/ack messages)
+typedef enum {
+ V_TEMP = 0, //!< S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC
+ V_HUM = 1, //!< S_HUM. Humidity
+ V_STATUS = 2, //!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off
+ V_LIGHT = 2, //!< \deprecated Same as V_STATUS, **** DEPRECATED, DO NOT USE ****
+ V_PERCENTAGE = 3, //!< S_DIMMER. Used for sending a percentage value 0-100 (%).
+ V_DIMMER = 3, //!< \deprecated Same as V_PERCENTAGE, **** DEPRECATED, DO NOT USE ****
+ V_PRESSURE = 4, //!< S_BARO. Atmospheric Pressure
+ V_FORECAST = 5, //!< S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
+ V_RAIN = 6, //!< S_RAIN. Amount of rain
+ V_RAINRATE = 7, //!< S_RAIN. Rate of rain
+ V_WIND = 8, //!< S_WIND. Wind speed
+ V_GUST = 9, //!< S_WIND. Gust
+ V_DIRECTION = 10, //!< S_WIND. Wind direction 0-360 (degrees)
+ V_UV = 11, //!< S_UV. UV light level
+ V_WEIGHT = 12, //!< S_WEIGHT. Weight(for scales etc)
+ V_DISTANCE = 13, //!< S_DISTANCE. Distance
+ V_IMPEDANCE = 14, //!< S_MULTIMETER, S_WEIGHT. Impedance value
+ V_ARMED = 15, //!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed
+ V_TRIPPED = 16, //!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0
+ V_WATT = 17, //!< S_POWER, S_BINARY, S_DIMMER, S_RGB_LIGHT, S_RGBW_LIGHT. Watt value for power meters
+ V_KWH = 18, //!< S_POWER. Accumulated number of KWH for a power meter
+ V_SCENE_ON = 19, //!< S_SCENE_CONTROLLER. Turn on a scene
+ V_SCENE_OFF = 20, //!< S_SCENE_CONTROLLER. Turn of a scene
+ V_HVAC_FLOW_STATE = 21, //!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver")
+ V_HEATER = 21, //!< \deprecated Same as V_HVAC_FLOW_STATE, **** DEPRECATED, DO NOT USE ****
+ V_HVAC_SPEED = 22, //!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
+ V_LIGHT_LEVEL = 23, //!< S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux
+ V_VAR1 = 24, //!< VAR1
+ V_VAR2 = 25, //!< VAR2
+ V_VAR3 = 26, //!< VAR3
+ V_VAR4 = 27, //!< VAR4
+ V_VAR5 = 28, //!< VAR5
+ V_UP = 29, //!< S_COVER. Window covering. Up
+ V_DOWN = 30, //!< S_COVER. Window covering. Down
+ V_STOP = 31, //!< S_COVER. Window covering. Stop
+ V_IR_SEND = 32, //!< S_IR. Send out an IR-command
+ V_IR_RECEIVE = 33, //!< S_IR. This message contains a received IR-command
+ V_FLOW = 34, //!< S_WATER. Flow of water (in meter)
+ V_VOLUME = 35, //!< S_WATER. Water volume
+ V_LOCK_STATUS = 36, //!< S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked
+ V_LEVEL = 37, //!< S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux)
+ V_VOLTAGE = 38, //!< S_MULTIMETER
+ V_CURRENT = 39, //!< S_MULTIMETER
+ V_RGB = 40, //!< S_RGB_LIGHT, S_COLOR_SENSOR. Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component)
+ V_RGBW = 41, //!< S_RGBW_LIGHT. Sent as ASCII hex: RRGGBBWW (WW=white component)
+ V_ID = 42, //!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b).
+ V_UNIT_PREFIX = 43, //!< Allows sensors to send in a string representing the unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
+ V_HVAC_SETPOINT_COOL = 44, //!< S_HVAC. HVAC cool setpoint (Integer between 0-100)
+ V_HVAC_SETPOINT_HEAT = 45, //!< S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100)
+ V_HVAC_FLOW_MODE = 46, //!< S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
+ V_TEXT = 47, //!< S_INFO. Text message to display on LCD or controller device
+ V_CUSTOM = 48, //!< Custom messages used for controller/inter node specific commands, preferably using S_CUSTOM device type.
+ V_POSITION = 49, //!< GPS position and altitude. Payload: latitude;longitude;altitude(m). E.g. "55.722526;13.017972;18"
+ V_IR_RECORD = 50, //!< Record IR codes S_IR for playback
+ V_PH = 51, //!< S_WATER_QUALITY, water PH
+ V_ORP = 52, //!< S_WATER_QUALITY, water ORP : redox potential in mV
+ V_EC = 53, //!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm)
+ V_VAR = 54, //!< S_POWER, Reactive power: volt-ampere reactive (var)
+ V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA)
+ V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
+} mysensor_data;
+
+
+/// @brief Type of internal messages (for internal messages)
+typedef enum {
+ I_BATTERY_LEVEL = 0, //!< Battery level
+ I_TIME = 1, //!< Time
+ I_VERSION = 2, //!< Version
+ I_ID_REQUEST = 3, //!< ID request
+ I_ID_RESPONSE = 4, //!< ID response
+ I_INCLUSION_MODE = 5, //!< Inclusion mode
+ I_CONFIG = 6, //!< Config
+ I_FIND_PARENT = 7, //!< Find parent
+ I_FIND_PARENT_RESPONSE = 8, //!< Find parent response
+ I_LOG_MESSAGE = 9, //!< Log message
+ I_CHILDREN = 10, //!< Children
+ I_SKETCH_NAME = 11, //!< Sketch name
+ I_SKETCH_VERSION = 12, //!< Sketch version
+ I_REBOOT = 13, //!< Reboot request
+ I_GATEWAY_READY = 14, //!< Gateway ready
+ I_SIGNING_PRESENTATION = 15, //!< Provides signing related preferences (first byte is preference version)
+ I_NONCE_REQUEST = 16, //!< Request for a nonce
+ I_NONCE_RESPONSE = 17, //!< Payload is nonce data
+ I_HEARTBEAT = 18, //!< Heartbeat request
+ I_PRESENTATION = 19, //!< Presentation message
+ I_DISCOVER = 20, //!< Discover request
+ I_DISCOVER_RESPONSE = 21, //!< Discover response
+ I_HEARTBEAT_RESPONSE = 22, //!< Heartbeat response
+ I_LOCKED = 23, //!< Node is locked (reason in string-payload)
+ I_PING = 24, //!< Ping sent to node, payload incremental hop counter
+ I_PONG = 25, //!< In return to ping, sent back to sender, payload incremental hop counter
+ I_REGISTRATION_REQUEST = 26, //!< Register request to GW
+ I_REGISTRATION_RESPONSE = 27, //!< Register response from GW
+ I_DEBUG = 28 //!< Debug message
+} mysensor_internal;
+
+
+/// @brief Type of data stream (for streamed message)
+typedef enum {
+ ST_FIRMWARE_CONFIG_REQUEST = 0, //!< Request new FW, payload contains current FW details
+ ST_FIRMWARE_CONFIG_RESPONSE = 1, //!< New FW details to initiate OTA FW update
+ ST_FIRMWARE_REQUEST = 2, //!< Request FW block
+ ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
+ ST_SOUND = 4, //!< Sound
+ ST_IMAGE = 5 //!< Image
+} mysensor_stream;
+
+/// @brief Type of payload
+typedef enum {
+ P_STRING = 0, //!< Payload type is string
+ P_BYTE = 1, //!< Payload type is byte
+ P_INT16 = 2, //!< Payload type is INT16
+ P_UINT16 = 3, //!< Payload type is UINT16
+ P_LONG32 = 4, //!< Payload type is INT32
+ P_ULONG32 = 5, //!< Payload type is UINT32
+ P_CUSTOM = 6, //!< Payload type is binary
+ P_FLOAT32 = 7 //!< Payload type is float32
+} mysensor_payload;
+
+
+
+#ifndef BIT
+#define BIT(n) ( 1<<(n) ) //!< Bit indexing macro
+#endif
+#define BIT_MASK(len) ( BIT(len)-1 ) //!< Create a bitmask of length 'len'
+#define BF_MASK(start, len) ( BIT_MASK(len)<<(start) ) //!< Create a bitfield mask of length starting at bit 'start'
+
+#define BF_PREP(x, start, len) ( ((x)&BIT_MASK(len)) << (start) ) //!< Prepare a bitmask for insertion or combining
+#define BF_GET(y, start, len) ( ((y)>>(start)) & BIT_MASK(len) ) //!< Extract a bitfield of length 'len' starting at bit 'start' from 'y'
+#define BF_SET(y, x, start, len) ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) //!< Insert a new bitfield value 'x' into 'y'
+
+// Getters/setters for special bit fields in header
+#define mSetVersion(_msg,_version) BF_SET(_msg.version_length, _version, 0, 2) //!< Set version field
+#define mGetVersion(_msg) ((uint8_t)BF_GET(_msg.version_length, 0, 2)) //!< Get version field
+
+#define mSetSigned(_msg,_signed) BF_SET(_msg.version_length, _signed, 2, 1) //!< Set signed field
+#define mGetSigned(_msg) ((bool)BF_GET(_msg.version_length, 2, 1)) //!< Get versignedsion field
+
+#define mSetLength(_msg,_length) BF_SET(_msg.version_length, _length, 3, 5) //!< Set length field
+#define mGetLength(_msg) ((uint8_t)BF_GET(_msg.version_length, 3, 5)) //!< Get length field
+
+#define mSetCommand(_msg,_command) BF_SET(_msg.command_ack_payload, _command, 0, 3) //!< Set command field
+#define mGetCommand(_msg) ((uint8_t)BF_GET(_msg.command_ack_payload, 0, 3)) //!< Get command field
+
+#define mSetRequestAck(_msg,_rack) BF_SET(_msg.command_ack_payload, _rack, 3, 1) //!< Set ack-request field
+#define mGetRequestAck(_msg) ((bool)BF_GET(_msg.command_ack_payload, 3, 1)) //!< Get ack-request field
+
+#define mSetAck(_msg,_ackMsg) BF_SET(_msg.command_ack_payload, _ackMsg, 4, 1) //!< Set ack field
+#define mGetAck(_msg) ((bool)BF_GET(_msg.command_ack_payload, 4, 1)) //!< Get ack field
+
+#define mSetPayloadType(_msg, _pt) BF_SET(_msg.command_ack_payload, _pt, 5, 3) //!< Set payload type field
+#define mGetPayloadType(_msg) ((uint8_t)BF_GET(_msg.command_ack_payload, 5, 3)) //!< Get payload type field
+
+
+// internal access for special fields
+#define miGetCommand() ((uint8_t)BF_GET(command_ack_payload, 0, 3)) //!< Internal getter for command field
+
+#define miSetLength(_length) BF_SET(version_length, _length, 3, 5) //!< Internal setter for length field
+#define miGetLength() ((uint8_t)BF_GET(version_length, 3, 5)) //!< Internal getter for length field
+
+#define miSetRequestAck(_rack) BF_SET(command_ack_payload, _rack, 3, 1) //!< Internal setter for ack-request field
+#define miGetRequestAck() ((bool)BF_GET(command_ack_payload, 3, 1)) //!< Internal getter for ack-request field
+
+#define miSetAck(_ack) BF_SET(command_ack_payload, _ack, 4, 1) //!< Internal setter for ack field
+#define miGetAck() ((bool)BF_GET(command_ack_payload, 4, 1)) //!< Internal getter for ack field
+
+#define miSetPayloadType(_pt) BF_SET(command_ack_payload, _pt, 5, 3) //!< Internal setter for payload type field
+#define miGetPayloadType() (uint8_t)BF_GET(command_ack_payload, 5, 3) //!< Internal getter for payload type field
+
+
+#if !DOXYGEN
+#ifdef __cplusplus
+class MyMessage
+{
+private:
+ char* getCustomString(char *buffer) const;
+
+public:
+ // Constructors
+ MyMessage();
+
+ MyMessage(uint8_t sensor, uint8_t type);
+
+ char i2h(uint8_t i) const;
+
+ /**
+ * Clear message contents.
+ */
+ void clear();
+
+ /**
+ * If payload is something else than P_STRING you can have the payload value converted
+ * into string representation by supplying a buffer with the minimum size of
+ * 2*MAX_PAYLOAD+1. This is to be able to fit hex-conversion of a full binary payload.
+ */
+ char* getStream(char *buffer) const;
+ char* getString(char *buffer) const;
+ const char* getString() const;
+ void* getCustom() const;
+ bool getBool() const;
+ uint8_t getByte() const;
+ float getFloat() const;
+ int16_t getInt() const;
+ uint16_t getUInt() const;
+ int32_t getLong() const;
+ uint32_t getULong() const;
+
+ // Getter for command type
+ uint8_t getCommand() const;
+
+ // Getter for ack-flag. True if this is an ack message.
+ bool isAck() const;
+
+ // Setters for building message "on the fly"
+ MyMessage& setType(uint8_t type);
+ MyMessage& setSensor(uint8_t sensor);
+ MyMessage& setDestination(uint8_t destination);
+
+ // Setters for payload
+ MyMessage& set(void* payload, uint8_t length);
+ MyMessage& set(const char* value);
+ MyMessage& set(float value, uint8_t decimals);
+ MyMessage& set(bool value);
+ MyMessage& set(uint8_t value);
+ MyMessage& set(uint32_t value);
+ MyMessage& set(int32_t value);
+ MyMessage& set(uint16_t value);
+ MyMessage& set(int16_t value);
+
+#else
+
+typedef union {
+struct
+{
+
+#endif
+ uint8_t last; // 8 bit - Id of last node this message passed
+ uint8_t sender; // 8 bit - Id of sender node (origin)
+ uint8_t destination; // 8 bit - Id of destination node
+
+ uint8_t version_length; // 2 bit - Protocol version
+ // 1 bit - Signed flag
+ // 5 bit - Length of payload
+ uint8_t command_ack_payload; // 3 bit - Command type
+ // 1 bit - Request an ack - Indicator that receiver should send an ack back.
+ // 1 bit - Is ack messsage - Indicator that this is the actual ack message.
+ // 3 bit - Payload data type
+ uint8_t type; // 8 bit - Type varies depending on command
+ uint8_t sensor; // 8 bit - Id of sensor that this message concerns.
+
+ // Each message can transfer a payload. We add one extra byte for string
+ // terminator \0 to be "printable" this is not transferred OTA
+ // This union is used to simplify the construction of the binary data types transferred.
+ union {
+ uint8_t bValue;
+ uint16_t uiValue;
+ int16_t iValue;
+ uint32_t ulValue;
+ int32_t lValue;
+ struct { // Float messages
+ float fValue;
+ uint8_t fPrecision; // Number of decimals when serializing
+ };
+ struct { // Presentation messages
+ uint8_t version; // Library version
+ uint8_t sensorType; // Sensor type hint for controller, see table above
+ };
+ char data[MAX_PAYLOAD + 1];
+ } __attribute__((packed));
+#ifdef __cplusplus
+} __attribute__((packed));
+#else
+};
+uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
+} __attribute__((packed)) MyMessage;
+#endif
+#endif
+
+#endif
+/** @}*/
diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp
new file mode 100644
index 0000000..73f7488
--- /dev/null
+++ b/core/MyOTAFirmwareUpdate.cpp
@@ -0,0 +1,149 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2016 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyOTAFirmwareUpdate.h"
+
+SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
+NodeFirmwareConfig _fc;
+bool _fwUpdateOngoing;
+unsigned long _fwLastRequestTime;
+uint16_t _fwBlock;
+uint8_t _fwRetry;
+
+inline void readFirmwareSettings() {
+ hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
+}
+
+inline void firmwareOTAUpdateRequest() {
+ unsigned long enter = hwMillis();
+ if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) {
+ if (!_fwRetry) {
+ setIndication(INDICATION_ERR_FW_TIMEOUT);
+ debug(PSTR("fw upd fail\n"));
+ // Give up. We have requested MY_OTA_RETRY times without any packet in return.
+ _fwUpdateOngoing = false;
+ return;
+ }
+ _fwRetry--;
+ _fwLastRequestTime = enter;
+ // Time to (re-)request firmware block from controller
+ RequestFWBlock firmwareRequest;
+ firmwareRequest.type = _fc.type;
+ firmwareRequest.version = _fc.version;
+ firmwareRequest.block = (_fwBlock - 1);
+ debug(PSTR("req FW: T=%02X, V=%02X, B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1);
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock)));
+ }
+}
+
+inline bool firmwareOTAUpdateProcess() {
+ if (_msg.type == ST_FIRMWARE_CONFIG_RESPONSE) {
+ NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data;
+ // compare with current node configuration, if they differ, start fw fetch process
+ if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
+ setIndication(INDICATION_FW_UPDATE_START);
+ debug(PSTR("fw update\n"));
+ // copy new FW config
+ memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
+ // Init flash
+ if (!_flash.initialize()) {
+ setIndication(INDICATION_ERR_FW_FLASH_INIT);
+ debug(PSTR("flash init fail\n"));
+ _fwUpdateOngoing = false;
+ } else {
+ // erase lower 32K -> max flash size for ATMEGA328
+ _flash.blockErase32K(0);
+ // wait until flash erased
+ while ( _flash.busy() );
+ _fwBlock = _fc.blocks;
+ _fwUpdateOngoing = true;
+ // reset flags
+ _fwRetry = MY_OTA_RETRY+1;
+ _fwLastRequestTime = 0;
+ }
+ return true;
+ }
+ debug(PSTR("fw update skipped\n"));
+ } else if (_msg.type == ST_FIRMWARE_RESPONSE) {
+ if (_fwUpdateOngoing) {
+ // Save block to flash
+ setIndication(INDICATION_FW_UPDATE_RX);
+ debug(PSTR("fw block %d\n"), _fwBlock);
+ // extract FW block
+ ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data;
+ // write to flash
+ _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
+ // wait until flash written
+ while ( _flash.busy() );
+ _fwBlock--;
+ if (!_fwBlock) {
+ // We're finished! Do a checksum and reboot.
+ _fwUpdateOngoing = false;
+ if (transportIsValidFirmware()) {
+ debug(PSTR("fw checksum ok\n"));
+ // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
+ uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks;
+ uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(uint8_t)(fwsize >> 8),(uint8_t)(fwsize & 0xff),':'};
+ _flash.writeBytes(0, OTAbuffer, 10);
+ // Write the new firmware config to eeprom
+ hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
+ hwReboot();
+ } else {
+ setIndication(INDICATION_ERR_FW_CHECKSUM);
+ debug(PSTR("fw checksum fail\n"));
+ }
+ }
+ // reset flags
+ _fwRetry = MY_OTA_RETRY+1;
+ _fwLastRequestTime = 0;
+ } else {
+ debug(PSTR("No fw update ongoing\n"));
+ }
+ return true;
+ }
+ return false;
+}
+
+inline void presentBootloaderInformation(){
+ RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msgTmp.data;
+ mSetLength(_msgTmp, sizeof(RequestFirmwareConfig));
+ mSetCommand(_msgTmp, C_STREAM);
+ mSetPayloadType(_msgTmp,P_CUSTOM);
+ // copy node settings to reqFWConfig
+ memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig));
+ // add bootloader information
+ reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
+ _fwUpdateOngoing = false;
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false));
+}
+// do a crc16 on the whole received firmware
+inline bool transportIsValidFirmware() {
+ // init crc
+ uint16_t crc = ~0;
+ for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
+ crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET);
+ for (int8_t j = 0; j < 8; ++j) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0xA001;
+ else
+ crc = (crc >> 1);
+ }
+ }
+ return crc == _fc.crc;
+}
diff --git a/libraries/MySensors/core/MyTransport.h b/core/MyOTAFirmwareUpdate.h
similarity index 69%
rename from libraries/MySensors/core/MyTransport.h
rename to core/MyOTAFirmwareUpdate.h
index d0d8bc7..3c3921d 100644
--- a/libraries/MySensors/core/MyTransport.h
+++ b/core/MyOTAFirmwareUpdate.h
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad
- * Copyright (C) 2013-2015 Sensnology AB
+ * Copyright (C) 2013-2016 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
@@ -17,11 +17,10 @@
* version 2 as published by the Free Software Foundation.
*/
-#ifndef MyTransport_h
-#define MyTransport_h
+#ifndef MyOTAFirmwareUpdate_h
+#define MyOTAFirmwareUpdate_h
-#include
-#include "MySensorCore.h"
+#include "MySensorsCore.h"
// Size of each firmware block
#define FIRMWARE_BLOCK_SIZE 16
@@ -38,9 +37,6 @@
#define MY_OTA_BOOTLOADER_MINOR_VERSION 0
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION)
-// Search for a new parent node after this many transmission failures
-#define SEARCH_FAILURES 5
-
/// @brief FW config structure, stored in eeprom
typedef struct {
@@ -75,35 +71,31 @@ typedef struct {
} __attribute__((packed)) ReplyFWBlock;
+/**
+ * @brief Read firmware settings from EEPROM
+ *
+ * Current firmware settings (type, version, crc, blocks) are read into _fc
+ */
+void readFirmwareSettings();
+/**
+ * @brief Handle OTA FW update requests
+ */
+ void firmwareOTAUpdateRequest();
+/**
+ * @brief Handle OTA FW update responses
+ *
+ * This function handles incoming OTA FW packets and stores them to external flash (Sensebender)
+ */
+bool firmwareOTAUpdateProcess();
+/**
+ * @brief Validate uploaded FW CRC
+ *
+ * This function verifies if uploaded FW CRC is valid
+ */
+bool transportIsValidFirmware();
+/**
+ * @brief Present bootloader/FW information upon startup
+ */
+void presentBootloaderInformation();
-#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId.
-
-#define BROADCAST_ADDRESS ((uint8_t)0xFF)
-
-// invalid distance when searching for parent
-#define DISTANCE_INVALID (0xFF)
-
-// Common functions in all radio drivers
-#ifdef MY_OTA_FIRMWARE_FEATURE
- // do a crc16 on the whole received firmware
- bool transportIsValidFirmware();
-#endif
-
-
-void transportProcess();
-void transportRequestNodeId();
-void transportPresentNode();
-void transportFindParentNode();
-boolean transportSendRoute(MyMessage &message);
-boolean transportSendWrite(uint8_t to, MyMessage &message);
-
-// "Interface" functions for radio driver
-bool transportInit();
-void transportSetAddress(uint8_t address);
-uint8_t transportGetAddress();
-bool transportSend(uint8_t to, const void* data, uint8_t len);
-bool transportAvailable(uint8_t *to);
-uint8_t transportReceive(void* data);
-void transportPowerDown();
-
-#endif
+#endif
\ No newline at end of file
diff --git a/libraries/MySensors/core/MyPrivateConfig.h.sample b/core/MyPrivateConfig.h.sample
similarity index 98%
rename from libraries/MySensors/core/MyPrivateConfig.h.sample
rename to core/MyPrivateConfig.h.sample
index 099fd36..5dace60 100644
--- a/libraries/MySensors/core/MyPrivateConfig.h.sample
+++ b/core/MyPrivateConfig.h.sample
@@ -22,7 +22,7 @@
* it in the sketch:
* #include "MyPrivateConfig.h"
* Make sure to include it before
- * #include
+ * #include
* Then adapt the contents to your personal preference.
*/
diff --git a/libraries/MySensors/core/MyProtocol.h b/core/MyProtocol.h
similarity index 97%
rename from libraries/MySensors/core/MyProtocol.h
rename to core/MyProtocol.h
index 766abfc..d22f71d 100644
--- a/libraries/MySensors/core/MyProtocol.h
+++ b/core/MyProtocol.h
@@ -20,7 +20,7 @@
#ifndef MyProtocol_h
#define MyProtocol_h
-#include "MySensorCore.h"
+#include "MySensorsCore.h"
// parse(message, inputString)
diff --git a/libraries/MySensors/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp
similarity index 96%
rename from libraries/MySensors/core/MyProtocolMySensors.cpp
rename to core/MyProtocolMySensors.cpp
index 68810b3..18fdbd5 100644
--- a/libraries/MySensors/core/MyProtocolMySensors.cpp
+++ b/core/MyProtocolMySensors.cpp
@@ -96,7 +96,7 @@ bool protocolParse(MyMessage &message, char *inputString) {
}
char * protocolFormat(MyMessage &message) {
- snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(_convBuffer));
+ snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, (uint8_t)mGetCommand(message), (uint8_t)mGetAck(message), message.type, message.getString(_convBuffer));
return _fmtBuffer;
}
diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp
new file mode 100644
index 0000000..0be5781
--- /dev/null
+++ b/core/MySensorsCore.cpp
@@ -0,0 +1,561 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MySensorsCore.h"
+
+ControllerConfig _cc; // Configuration coming from controller
+NodeConfig _nc; // Essential settings for node to work
+MyMessage _msg; // Buffer for incoming messages.
+MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others).
+
+bool _nodeRegistered = false;
+
+#if defined(MY_DEBUG)
+ char _convBuf[MAX_PAYLOAD*2+1];
+#endif
+
+void (*_timeCallback)(unsigned long); // Callback for requested time messages
+
+void _process() {
+ hwWatchdogReset();
+
+ #if defined (MY_LEDS_BLINKING_FEATURE)
+ ledsProcess();
+ #endif
+
+ #if defined(MY_INCLUSION_MODE_FEATURE)
+ inclusionProcess();
+ #endif
+
+ #if defined(MY_GATEWAY_FEATURE)
+ gatewayTransportProcess();
+ #endif
+
+ #if defined(MY_RADIO_FEATURE)
+ transportProcess();
+ #endif
+
+}
+
+void _infiniteLoop() {
+ while(1) {
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ #if defined (MY_LEDS_BLINKING_FEATURE)
+ ledsProcess();
+ #endif
+ }
+}
+
+void _begin() {
+
+ if (preHwInit)
+ preHwInit();
+
+ #if !defined(MY_DISABLED_SERIAL)
+ hwInit();
+ #endif
+
+ debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n"));
+
+ // Call before() in sketch (if it exists)
+ if (before)
+ before();
+
+ #if defined(MY_LEDS_BLINKING_FEATURE)
+ ledsInit();
+ #endif
+
+ signerInit();
+
+ // Read latest received controller configuration from EEPROM
+ // Note: _cc.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default)
+ hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig));
+
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ // Read firmware config from EEPROM, i.e. type, version, CRC, blocks
+ readFirmwareSettings();
+ #endif
+
+ #if defined(MY_RADIO_FEATURE)
+ // Save static parent id in eeprom (used by bootloader)
+ hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
+ transportInitialize();
+ while (!isTransportReady()) {
+ hwWatchdogReset();
+ transportProcess();
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ }
+ #endif
+
+
+
+ #ifdef MY_NODE_LOCK_FEATURE
+ // Check if node has been locked down
+ if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) {
+ // Node is locked, check if unlock pin is asserted, else hang the node
+ pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP);
+ // Make a short delay so we are sure any large external nets are fully pulled
+ unsigned long enter = hwMillis();
+ while (hwMillis() - enter < 2);
+ if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) {
+ // Pin is grounded, reset lock counter
+ hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX);
+ // Disable pullup
+ pinMode(MY_NODE_UNLOCK_PIN, INPUT);
+ setIndication(INDICATION_ERR_LOCKED);
+ debug(PSTR("MCO:BGN:NODE UNLOCKED\n"));
+ } else {
+ // Disable pullup
+ pinMode(MY_NODE_UNLOCK_PIN, INPUT);
+ nodeLock("LDB"); //Locked during boot
+ }
+ } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) {
+ // Reset walue
+ hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX);
+ }
+ #endif
+
+ #if defined(MY_GATEWAY_FEATURE)
+ #if defined(MY_INCLUSION_BUTTON_FEATURE)
+ inclusionInit();
+ #endif
+
+ // initialize the transport driver
+ if (!gatewayTransportInit()) {
+ setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
+ debug(PSTR("!MCO:BGN:TSP FAIL\n"));
+ // Nothing more we can do
+ _infiniteLoop();
+ }
+ #endif
+
+ #if !defined(MY_GATEWAY_FEATURE)
+ presentNode();
+ #endif
+
+ // register node
+ _registerNode();
+
+ // Call sketch setup
+ if (setup) {
+ setup();
+ }
+
+ debug(PSTR("MCO:BGN:INIT OK,ID=%d,PAR=%d,DIS=%d,REG=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered);
+}
+
+
+void _registerNode() {
+ #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
+ debug(PSTR("MCO:REG:REQ\n")); // registration request
+ setIndication(INDICATION_REQ_REGISTRATION);
+ _nodeRegistered = MY_REGISTRATION_DEFAULT;
+ uint8_t counter = MY_REGISTRATION_RETRIES;
+ // only proceed if register response received or retries exceeded
+ do {
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION));
+ } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--);
+
+ #else
+ _nodeRegistered = true;
+ debug(PSTR("MCO:REG:NOT NEEDED\n"));
+ #endif
+}
+
+void presentNode() {
+ setIndication(INDICATION_PRESENT);
+ // Present node and request config
+ #if defined(MY_GATEWAY_FEATURE)
+ // Send presentation for this gateway device
+ #if defined(MY_REPEATER_FEATURE)
+ present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
+ #else
+ present(NODE_SENSOR_ID, S_ARDUINO_NODE);
+ #endif
+ #else
+
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ presentBootloaderInformation();
+ #endif
+
+ // Send signing preferences for this node to the GW
+ signerPresentation(_msgTmp, GATEWAY_ADDRESS);
+
+ // Send presentation for this radio node
+ #if defined(MY_REPEATER_FEATURE)
+ present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
+ #else
+ present(NODE_SENSOR_ID, S_ARDUINO_NODE);
+ #endif
+
+ // Send a configuration exchange request to controller
+ // Node sends parent node. Controller answers with latest node configuration
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId));
+
+ // Wait configuration reply.
+ wait(2000, C_INTERNAL, I_CONFIG);
+
+ #endif
+
+ if (presentation)
+ presentation();
+
+}
+
+
+uint8_t getNodeId() {
+ return _nc.nodeId;
+}
+
+uint8_t getParentNodeId() {
+ return _nc.parentNodeId;
+}
+
+ControllerConfig getConfig() {
+ return _cc;
+}
+
+
+bool _sendRoute(MyMessage &message) {
+ #if defined(MY_CORE_ONLY)
+ (void)message;
+ #endif
+ #if defined(MY_GATEWAY_FEATURE)
+ if (message.destination == _nc.nodeId) {
+ // This is a message sent from a sensor attached on the gateway node.
+ // Pass it directly to the gateway transport layer.
+ return gatewayTransportSend(message);
+ }
+ #endif
+ #if defined(MY_RADIO_FEATURE)
+ return transportSendRoute(message);
+ #else
+ return false;
+ #endif
+}
+
+bool send(MyMessage &message, bool enableAck) {
+ message.sender = _nc.nodeId;
+ mSetCommand(message, C_SET);
+ mSetRequestAck(message, enableAck);
+
+ #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
+ if (_nodeRegistered) {
+ return _sendRoute(message);
+ }
+ else {
+ debug(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered
+ return false;
+ }
+ #else
+ return _sendRoute(message);
+ #endif
+ }
+
+void sendBatteryLevel(uint8_t value, bool enableAck) {
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value));
+}
+
+void sendHeartbeat(void) {
+ #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485)
+ uint32_t heartbeat = transportGetHeartbeat();
+ #else
+ uint32_t heartbeat = hwMillis();
+ #endif
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat));
+}
+
+void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) {
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description));
+}
+
+void sendSketchInfo(const char *name, const char *version, bool enableAck) {
+ if (name) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name));
+ if (version) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version));
+}
+
+void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) {
+ _sendRoute(build(_msgTmp, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set(""));
+}
+
+void requestTime() {
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set(""));
+}
+
+// Message delivered through _msg
+bool _processInternalMessages() {
+ uint8_t type = _msg.type;
+
+ if (_msg.sender == GATEWAY_ADDRESS) {
+ if (type == I_REBOOT) {
+ #if !defined(MY_DISABLE_REMOTE_RESET)
+ // Requires MySensors or other bootloader with watchdogs enabled
+ setIndication(INDICATION_REBOOT);
+ hwReboot();
+ #endif
+ }
+ else if (type == I_REGISTRATION_RESPONSE) {
+ #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
+ _nodeRegistered = _msg.getBool();
+ setIndication(INDICATION_GOT_REGISTRATION);
+ debug(PSTR("MCO:PIM:NODE REG=%d\n"), _nodeRegistered); // node registration
+ #endif
+ }
+ else if (type == I_CONFIG) {
+ // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed
+ _cc.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M
+ hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, _cc.isMetric);
+ }
+ else if (type == I_PRESENTATION) {
+ // Re-send node presentation to controller
+ presentNode();
+ }
+ else if (type == I_HEARTBEAT) {
+ sendHeartbeat();
+ }
+ else if (type == I_TIME) {
+ // Deliver time to callback
+ if (receiveTime)
+ receiveTime(_msg.getULong());
+ }
+ else if (type == I_CHILDREN) {
+ #if defined(MY_REPEATER_FEATURE)
+ if (_msg.data[0] == 'C') {
+ // Clears child relay data for this node
+ setIndication(INDICATION_CLEAR_ROUTING);
+ transportClearRoutingTable();
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN, false).set("ok"));
+ }
+ #endif
+ }
+ else if (type == I_DEBUG) {
+ #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
+ char debug_msg = _msg.data[0];
+ if (debug_msg == 'R') { // routing table
+ #if defined(MY_REPEATER_FEATURE)
+ for (uint8_t cnt = 0; cnt != 255; cnt++) {
+ uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS + cnt);
+ if (route != BROADCAST_ADDRESS) {
+ debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route);
+ uint8_t OutBuf[2] = { cnt,route };
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(OutBuf, 2));
+ wait(200);
+ }
+ }
+ #endif
+ }
+ else if (debug_msg == 'V') { // CPU voltage
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUVoltage()));
+ }
+ else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUFrequency()));
+ }
+ else if (debug_msg == 'M') { // free memory
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwFreeMem()));
+ }
+ else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set("ok"));
+ for (int i = EEPROM_START; i= MY_CORE_MIN_VERSION);
+ #endif
+ _sendRoute(build(_msgTmp, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_RESPONSE, false).set(approveRegistration));
+ #else
+ return false; // processing of this request via controller
+ #endif
+ #endif
+ }
+ else return false;
+ }
+ return true;
+}
+
+
+void saveState(uint8_t pos, uint8_t value) {
+ hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value);
+}
+uint8_t loadState(uint8_t pos) {
+ return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos);
+}
+
+
+void wait(unsigned long ms) {
+ unsigned long enter = hwMillis();
+ while (hwMillis() - enter < ms) {
+ _process();
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ }
+}
+
+bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype) {
+ unsigned long enter = hwMillis();
+ // invalidate msg type
+ _msg.type = !msgtype;
+ bool expectedResponse = false;
+ while ( (hwMillis() - enter < ms) && !expectedResponse ) {
+ _process();
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype);
+ }
+ return expectedResponse;
+}
+
+
+int8_t sleep(unsigned long ms) {
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ if (_fwUpdateOngoing) {
+ // Do not sleep node while fw update is ongoing
+ wait(ms);
+ return -1;
+ }
+ #endif
+ // if repeater, do not sleep
+ #if defined(MY_REPEATER_FEATURE)
+ wait(ms);
+ return -1;
+ #else
+ #if defined(MY_RADIO_FEATURE)
+ transportPowerDown();
+ #endif
+ setIndication(INDICATION_SLEEP);
+ const int8_t res = hwSleep(ms);
+ setIndication(INDICATION_WAKEUP);
+ return res;
+ #endif
+}
+
+int8_t smartSleep(unsigned long ms) {
+ // notify controller about going to sleep
+ sendHeartbeat();
+ // listen for incoming messages
+ wait(MY_SMART_SLEEP_WAIT_DURATION);
+ return sleep(ms);
+}
+
+int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ if (_fwUpdateOngoing) {
+ // not supported
+ return -2;
+ }
+ #endif
+ #if defined(MY_REPEATER_FEATURE)
+ // not supported
+ (void)interrupt;
+ (void)mode;
+ (void)ms;
+ return -2;
+ #else
+ #if defined(MY_RADIO_FEATURE)
+ transportPowerDown();
+ #endif
+ setIndication(INDICATION_SLEEP);
+ const int8_t res = hwSleep(interrupt, mode, ms);
+ setIndication(INDICATION_WAKEUP);
+ return res;
+ #endif
+}
+
+int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
+ // notify controller about going to sleep
+ sendHeartbeat();
+ // listen for incoming messages
+ wait(MY_SMART_SLEEP_WAIT_DURATION);
+ return sleep(interrupt, mode, ms);
+}
+
+int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ if (_fwUpdateOngoing) {
+ // not supported
+ return -2;
+ }
+ #endif
+ #if defined(MY_REPEATER_FEATURE)
+ // not supported
+ (void)interrupt1;
+ (void)mode1;
+ (void)interrupt2;
+ (void)mode2;
+ (void)ms;
+ return -2;
+ #else
+ #if defined(MY_RADIO_FEATURE)
+ transportPowerDown();
+ #endif
+ setIndication(INDICATION_SLEEP);
+ const int8_t res = hwSleep(interrupt1, mode1, interrupt2, mode2, ms);
+ setIndication(INDICATION_WAKEUP);
+ return res;
+ #endif
+}
+
+int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
+ // notify controller about going to sleep
+ sendHeartbeat();
+ // listen for incoming messages
+ wait(MY_SMART_SLEEP_WAIT_DURATION);
+ return sleep(interrupt1, mode1, interrupt2, mode2, ms);
+}
+
+#ifdef MY_NODE_LOCK_FEATURE
+void nodeLock(const char* str) {
+ // Make sure EEPROM is updated to locked status
+ hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0);
+ while (1) {
+ setIndication(INDICATION_ERR_LOCKED);
+ debug(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN);
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED, false).set(str));
+ #if defined(MY_RADIO_FEATURE)
+ transportPowerDown();
+ #endif
+ setIndication(INDICATION_SLEEP);
+ (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message
+ setIndication(INDICATION_WAKEUP);
+ }
+}
+#endif
diff --git a/libraries/MySensors/core/MySensorCore.h b/core/MySensorsCore.h
similarity index 60%
rename from libraries/MySensors/core/MySensorCore.h
rename to core/MySensorsCore.h
index d8cac58..5d52a8b 100644
--- a/libraries/MySensors/core/MySensorCore.h
+++ b/core/MySensorsCore.h
@@ -17,42 +17,74 @@
* version 2 as published by the Free Software Foundation.
*/
+ /**
+ * @file MySensorsCore.h
+ *
+ * @defgroup MySensorsCoregrp MySensorsCore
+ * @ingroup internals
+ * @{
+ *
+ * MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
+ * - [!] Exclamation mark is prepended in case of error
+ * - SYSTEM:
+ * - MCO messages emitted by MySensorsCore
+ * - SUB SYSTEMS:
+ * - MCO:BGN from @ref _begin()
+ * - MCO:REG from @ref _registerNode()
+ * - MCO:SND from @ref send()
+ * - MCO:PIM from @ref _processInternalMessages()
+ * - MCO:NLK from @ref nodeLock()
+ *
+ * MySensorsCore debug log messages:
+ *
+ * |E| SYS | SUB | Message | Comment
+ * |-|------|-------|-------------------------------------------|----------------------------------------------------------------------------
+ * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER)
+ * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG)
+ * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter)
+ * |!| MCO | BGN | TSP FAIL | Transport initialization failed
+ * | | MCO | REG | REQ | Registration request
+ * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW)
+ * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message
+ * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG)
+ * | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R)
+ * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET| Node locked during booting, see signing chapter for additional information
+ *
+ *
+ * @brief API declaration for MySensorsCore
+ */
-#ifndef MySensorCore_h
-#define MySensorCore_h
+
+#ifndef MySensorsCore_h
+#define MySensorsCore_h
#include "Version.h" // Auto generated by bot
#include "MyConfig.h"
#include "MyEepromAddresses.h"
#include "MyMessage.h"
-#ifdef MY_OTA_FIRMWARE_FEATURE
-#include "drivers/SPIFlash/SPIFlash.h"
-#endif
-
#include
#include
+#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch
+#define NODE_SENSOR_ID 0xFF //!< Node child is always created/presented when a node is started
+#define MY_CORE_VERSION ((uint8_t)2) //!< core version
+#define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility
+
#ifdef MY_DEBUG
-#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__)
+ #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
#else
-#define debug(x,...)
+ #define debug(x,...) //!< debug NULL
#endif
-// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data).
-#define GATEWAY_ADDRESS ((uint8_t)0)
-// Node child is always created/presented when a node is started
-#define NODE_SENSOR_ID 0xFF
-
-
/**
* @brief Node configuration
*
* This structure stores node-related configurations
*/
struct NodeConfig {
- uint8_t nodeId; //!< Current node id
- uint8_t parentNodeId; //!< Where this node sends its messages
- uint8_t distance; //!< This nodes distance to sensor net gateway (number of hops)
+ uint8_t nodeId; //!< Current node id
+ uint8_t parentNodeId; //!< Where this node sends its messages
+ uint8_t distance; //!< This nodes distance to sensor net gateway (number of hops)
};
/**
@@ -61,16 +93,33 @@ struct NodeConfig {
* This structure stores controllerrelated configurations
*/
struct ControllerConfig {
- uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used
+ uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used
};
+extern NodeConfig _nc; //!< Node config
+extern MyMessage _msg; //!< Buffer for incoming messages
+extern MyMessage _msgTmp; //!< Buffer for temporary messages (acks and nonces among others)
+#ifdef MY_DEBUG
+ extern char _convBuf[MAX_PAYLOAD * 2 + 1];
+#endif
+// **** public functions ********
/**
* Return this nodes id.
*/
uint8_t getNodeId();
+/**
+ * Return the parent node id.
+ */
+uint8_t getParentNodeId();
+
+/**
+* Sends node information to the gateway.
+*/
+void presentNode();
+
/**
* Each node must present all attached sensors before any values can be handled correctly by the controller.
* It is usually good to present all attached sensors after power-up in setup().
@@ -132,8 +181,6 @@ void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GA
*/
void requestTime();
-
-
/**
* Returns the most recent node configuration received from controller
*/
@@ -168,12 +215,29 @@ uint8_t loadState(uint8_t pos);
*/
void wait(unsigned long ms);
+/**
+ * Wait for a specified amount of time to pass or until specified message received. Keeps process()ing.
+ * This does not power-down the radio nor the Arduino.
+ * Because this calls process() in a loop, it is a good way to wait
+ * in your loop() on a repeater node or sensor that listens to messages.
+ * @param ms Number of milliseconds to sleep.
+ * @param cmd Command of incoming message.
+ * @param msgtype Message type.
+ * @return True if specified message received
+ */
+bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype);
+
/**
* Sleep (PowerDownMode) the MCU and radio. Wake up on timer.
* @param ms Number of milliseconds to sleep.
* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
*/
int8_t sleep(unsigned long ms);
+/**
+* Same as sleep(), send heartbeat upon wakeup and process incoming messages
+* @param ms Number of milliseconds to sleep.
+* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
+*/
int8_t smartSleep(unsigned long ms);
/**
@@ -186,6 +250,13 @@ int8_t smartSleep(unsigned long ms);
* @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
*/
int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0);
+/**
+* Same as sleep(), send heartbeat upon wakeup and process incoming messages
+* @param interrupt Interrupt that should trigger the wakeup
+* @param mode RISING, FALLING, CHANGE
+* @param ms Number of milliseconds to sleep.
+* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
+*/
int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0);
/**
@@ -200,6 +271,15 @@ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0);
* @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
*/
int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0);
+/**
+* Same as sleep(), send heartbeat upon wakeup and process incoming messages
+* @param interrupt1 First interrupt that should trigger the wakeup
+* @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE)
+* @param interrupt2 Second interrupt that should trigger the wakeup
+* @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE)
+* @param ms Number of milliseconds to sleep or 0 to sleep forever
+* @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update)
+*/
int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0);
#ifdef MY_NODE_LOCK_FEATURE
@@ -217,27 +297,64 @@ int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t
void nodeLock(const char* str);
#endif
-/****** PRIVATE ********/
+// **** private functions ********
+/**
+* @brief Node initialisation
+*/
void _begin();
-
+/**
+* @brief Main framework process
+*/
void _process(void);
+/**
+* @brief Processes internal messages
+* @return True if received message requires further processing
+*/
+bool _processInternalMessages();
+/**
+* @brief Puts node to a infinite loop if unrecoverable situation detected
+*/
+void _infiniteLoop();
+/**
+* @brief Handles registration request
+*/
+void _registerNode();
+/**
+* @brief Sends message according to routing table
+* @param message
+* @return True if message successfully sent to next node
+*/
+bool _sendRoute(MyMessage &message);
-void _processInternalMessages();
-
-boolean _sendRoute(MyMessage &message);
-
-extern NodeConfig _nc;
-extern MyMessage _msg; // Buffer for incoming messages.
-extern MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others).
-#ifdef MY_DEBUG
- extern char _convBuf[MAX_PAYLOAD*2+1];
-#endif
+/**
+* @brief Callback for incoming messages
+* @param message
+*/
void receive(const MyMessage &message) __attribute__((weak));
+/**
+* @brief Callback for incoming time messages
+*/
void receiveTime(unsigned long) __attribute__((weak));
+/**
+* @brief Node presenation
+*/
void presentation() __attribute__((weak));
+/**
+* @brief Called before node initialises
+*/
void before() __attribute__((weak));
+/**
+* @brief Called before any hwInitialization is done
+*/
+void preHwInit() __attribute__((weak));
+/**
+* @brief Called after node initialises but before main loop
+*/
void setup() __attribute__((weak));
+/**
+* @brief Main loop
+*/
void loop() __attribute__((weak));
@@ -256,7 +373,7 @@ static inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destinati
static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) {
msg.sender = GATEWAY_ADDRESS;
msg.destination = GATEWAY_ADDRESS;
- msg.sensor = 255;
+ msg.sensor = NODE_SENSOR_ID;
msg.type = type;
mSetCommand(msg, C_INTERNAL);
mSetRequestAck(msg, false);
@@ -266,3 +383,5 @@ static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) {
#endif
+
+/** @}*/
diff --git a/libraries/MySensors/core/MySigning.cpp b/core/MySigning.cpp
similarity index 89%
rename from libraries/MySensors/core/MySigning.cpp
rename to core/MySigning.cpp
index 09de114..a1081a4 100644
--- a/libraries/MySensors/core/MySigning.cpp
+++ b/core/MySigning.cpp
@@ -84,10 +84,12 @@ static bool skipSign(MyMessage &msg) {
SIGN_DEBUG(PSTR("Skipping security for ACK on command %d type %d\n"), mGetCommand(msg), msg.type);
return true;
} else if (mGetCommand(msg) == C_INTERNAL &&
- (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION ||
- msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE ||
- msg.type == I_FIND_PARENT || msg.type == I_FIND_PARENT_RESPONSE ||
- msg.type == I_HEARTBEAT || msg.type == I_HEARTBEAT_RESPONSE)) {
+ (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION ||
+ msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE ||
+ msg.type == I_FIND_PARENT || msg.type == I_FIND_PARENT_RESPONSE ||
+ msg.type == I_HEARTBEAT || msg.type == I_HEARTBEAT_RESPONSE ||
+ msg.type == I_PING || msg.type == I_PONG ||
+ msg.type == I_REGISTRATION_REQUEST )) {
SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type);
return true;
} else if (mGetCommand(msg) == C_STREAM &&
@@ -106,6 +108,7 @@ static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) {
// Only supports version 1 for now
build(msg, _nc.nodeId, destination, NODE_SENSOR_ID, C_INTERNAL, I_SIGNING_PRESENTATION, false).set("");
mSetLength(msg, 2);
+ mSetPayloadType(msg, P_CUSTOM); // displayed as hex
msg.data[0] = SIGNING_PRESENTATION_VERSION_1;
msg.data[1] = 0;
}
@@ -129,8 +132,8 @@ void signerInit(void) {
#endif
}
-void signerPresentation(MyMessage &msg) {
- prepareSigningPresentation(msg, GATEWAY_ADDRESS);
+void signerPresentation(MyMessage &msg, uint8_t destination) {
+ prepareSigningPresentation(msg, destination);
#if defined(MY_SIGNING_REQUEST_SIGNATURES)
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES;
@@ -141,12 +144,16 @@ void signerPresentation(MyMessage &msg) {
SIGN_DEBUG(PSTR("Whitelisting required\n"));
#endif
- _sendRoute(msg);
+ if (!_sendRoute(msg)) {
+ SIGN_DEBUG(PSTR("Failed to transmit signing presentation!"));
+ }
#if defined(MY_SIGNING_FEATURE)
// If we do support signing, wait for the gateway to tell us how it prefer us to transmit our messages
- SIGN_DEBUG(PSTR("Waiting for GW to send signing preferences...\n"));
- wait(2000);
+ if (destination == GATEWAY_ADDRESS) {
+ SIGN_DEBUG(PSTR("Waiting for GW to send signing preferences...\n"));
+ wait(2000, C_INTERNAL, I_SIGNING_PRESENTATION);
+ }
#endif
}
@@ -161,7 +168,9 @@ bool signerProcessInternal(MyMessage &msg) {
prepareSigningPresentation(msg, sender);
SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"),
sender);
- _sendRoute(msg);
+ if (!_sendRoute(msg)) {
+ SIGN_DEBUG(PSTR("Failed to transmit signing presentation!"));
+ }
return true; // No need to further process I_SIGNING_PRESENTATION in this case
}
#elif defined(MY_SIGNING_FEATURE)
@@ -179,9 +188,12 @@ bool signerProcessInternal(MyMessage &msg) {
#if defined(MY_SIGNING_ATSHA204)
if (signerAtsha204GetNonce(msg)) {
#endif
- SIGN_DEBUG(PSTR("Transmittng nonce\n"));
- _sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID,
- C_INTERNAL, I_NONCE_RESPONSE, false));
+ if (!_sendRoute(build(msg, _nc.nodeId, msg.sender, NODE_SENSOR_ID,
+ C_INTERNAL, I_NONCE_RESPONSE, false))) {
+ SIGN_DEBUG(PSTR("Failed to transmit nonce!\n"));
+ } else {
+ SIGN_DEBUG(PSTR("Transmitted nonce\n"));
+ }
} else {
SIGN_DEBUG(PSTR("Failed to generate nonce!\n"));
}
@@ -245,7 +257,9 @@ bool signerProcessInternal(MyMessage &msg) {
} else {
SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), sender);
}
- _sendRoute(msg);
+ if (!_sendRoute(msg)) {
+ SIGN_DEBUG(PSTR("Failed to transmit signing presentation!"));
+ }
#endif // MY_GATEWAY_FEATURE
return true; // No need to further process I_SIGNING_PRESENTATION
} else if (msg.type == I_NONCE_RESPONSE) {
@@ -301,7 +315,7 @@ bool signerSignMsg(MyMessage &msg) {
} else {
// Send nonce-request
_signingNonceStatus=SIGN_WAITING_FOR_NONCE;
- if (!_sendRoute(build(_msgTmp, _nc.nodeId, msg.destination, msg.sensor,
+ if (!_sendRoute(build(_msgSign, _nc.nodeId, msg.destination, msg.sensor,
C_INTERNAL, I_NONCE_REQUEST, false).set(""))) {
SIGN_DEBUG(PSTR("Failed to transmit nonce request!\n"));
return false;
@@ -405,3 +419,32 @@ uint8_t* signerSha256Final(void) {
memcpy(sha256_hash, _soft_sha256.result(), 32);
return sha256_hash;
}
+
+int signerMemcmp(const void* a, const void* b, size_t sz) {
+ int retVal;
+ size_t i;
+ int done = 0;
+ const uint8_t* ptrA = (const uint8_t*)a;
+ const uint8_t* ptrB = (const uint8_t*)b;
+ for (i=0; i < sz; i++) {
+ if (ptrA[i] == ptrB[i]) {
+ if (done > 0) {
+ done = 1;
+ } else {
+ done = 0;
+ }
+ } else {
+ if (done > 0) {
+ done = 2;
+ } else {
+ done = 3;
+ }
+ }
+ }
+ if (done > 0) {
+ retVal = -1;
+ } else {
+ retVal = 0;
+ }
+ return retVal;
+}
diff --git a/libraries/MySensors/core/MySigning.h b/core/MySigning.h
similarity index 86%
rename from libraries/MySensors/core/MySigning.h
rename to core/MySigning.h
index 8677151..1353353 100644
--- a/libraries/MySensors/core/MySigning.h
+++ b/core/MySigning.h
@@ -146,10 +146,10 @@
* @code{.cpp}
* //#define MY_SIGNING_SOFT
* #define MY_SIGNING_ATSHA204
- * #include
+ * #include
* ...
* @endcode
- * Make sure to set the define before the inclusion of MySensor.h.
+ * Make sure to set the define before the inclusion of MySensors.h.
* It is legal to mix hardware- and software-based backends in a network. They work together.
*
* You also need to decide if the node (or gateway) in question require and verify signatures in addition to calculating them.
@@ -157,6 +157,8 @@
* Just set the flag @ref MY_SIGNING_REQUEST_SIGNATURES and the node will inform the gateway that it expects the gateway to sign all
* messages sent to the node. If this is set in a gateway, it will @b NOT force all nodes to sign messages to it. It will only require
* signatures from nodes that in turn require signatures.
+ * If you want to have two nodes communicate securely directly with each other, the nodes that require signatures must send a presentation
+ * message to all nodes it expect signed messages from (only the gateway is informed automatically). See @ref signerPresentation().
* A node can have three "states" with respect to signing:
* 1. Node does not support signing in any way (neither @ref MY_SIGNING_ATSHA204 nor @ref MY_SIGNING_SOFT is set)
* 2. Node does support signing but don't require messages sent to it to be signed (@ref MY_SIGNING_REQUEST_SIGNATURES is not set)
@@ -170,7 +172,7 @@
* #define MY_SIGNING_ATSHA204
* #define MY_SIGNING_ATSHA204_PIN 4
* #define MY_SIGNING_REQUEST_SIGNATURES
- * #include
+ * #include
* ...
* @endcode
* For the software backed signingbackend, an unconnected analog pin is required to set a random seed for the pseudo-random generator.
@@ -178,18 +180,18 @@
* signatures. The setting is defined using @ref MY_SIGNING_SOFT_RANDOMSEED_PIN and the default is to use pin A7. The same configuration
* possibilities exist as with the other configuration options.
*
- * Thirdly, if you use the software backend, you need to personalize the node (see @ref perzonalization).
+ * Thirdly, if you use the software backend, you need to personalize the node (see @ref personalization).
* @code{.cpp}
* #define MY_SIGNING_SOFT
* #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
* #define MY_SIGNING_REQUEST_SIGNATURES
- * #include
+ * #include
* ...
* @endcode
*
* An example of a node that require signatures is available in @ref SecureActuator.ino.
*
- * @anchor perzonalization If you use the “real” ATSHA204A, before any signing operations can be done, the device needs to be personalized.
+ * @anchor personalization If you use the “real” ATSHA204A, before any signing operations can be done, the device needs to be personalized.
* This can be a daunting process as it involves irreversibly writing configurations to the device, which cannot be undone. I have however tried
* to simplify the process as much as possibly by creating a helper-sketch specifically for this purpose in @ref SecurityPersonalizer.ino
* Note that you also need to do personalization for software signing, but then the values are stored in EEPROM (described below).
@@ -324,7 +326,7 @@
* #define MY_SIGNING_ATSHA204
* #define MY_SIGNING_REQUEST_SIGNATURES
* #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}},{.nodeId = 2,.serial = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}}}
- * #include
+ * #include
* ...
* @endcode
* In this example, there are two nodes in the whitelist; the gateway, and a separate node that communicates directly with this node (with signed
@@ -336,7 +338,7 @@
* #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
* #define MY_SIGNING_REQUEST_SIGNATURES
* #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}},{.nodeId = 2,.serial = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}}}
- * #include
+ * #include
* ...
* @endcode
*
@@ -403,7 +405,7 @@
* @code{.cpp}
* #define MY_SIGNING_ATSHA204
* #define MY_SIGNING_REQUEST_SIGNATURES
- * #include
+ * #include
* ...
* @endcode
* If you do also want your gateway to require signatures from your lock you just enable the same (or similar if using software signing) settings
@@ -423,7 +425,7 @@
* #define MY_SIGNING_SOFT
* #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
* #define MY_SIGNING_REQUEST_SIGNATURES
- * #include
+ * #include
* ...
* @endcode
*
@@ -433,7 +435,7 @@
* #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
* #define MY_SIGNING_REQUEST_SIGNATURES
* #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = MOTION_SENSOR_ID,.serial = {0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78}}}
- * #include
+ * #include
* ...
* @endcode
@@ -445,7 +447,7 @@
* Configuration example for the keyfob (keyfob will only transmit to another node and not receive anything):
* @code{.cpp}
* #define MY_SIGNING_ATSHA204
- * #include
+ * #include
* ...
* @endcode
*
@@ -455,7 +457,7 @@
* #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
* #define MY_SIGNING_REQUEST_SIGNATURES
* #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}},{.nodeId = KEYFOB_ID,.serial = {}}}
- * #include
+ * #include
* ...
* @endcode
*
@@ -473,7 +475,7 @@
#ifndef MySigning_h
#define MySigning_h
-#include "MySensorCore.h"
+#include "MySensorsCore.h"
#include "drivers/ATSHA204/ATSHA204.h"
#ifdef MY_SIGNING_NODE_WHITELISTING
@@ -506,14 +508,19 @@ void signerInit(void);
/**
* @brief Does signing specific presentation for a node.
*
- * This function makes sure any signing related presentation info is shared with the gateway.
+ * This function makes sure any signing related presentation info is shared with the other part.
* The presentation of the gateways signing preferences is done in @ref signerProcessInternal().
* \n@b Usage: This function should be called by the presentation routine of the mysensors library.
- * There is no need to call this directly from a sketch.
+ * You only need to call this directly from a sketch to set up a node to node signed message exchange.
+ * If you do call this directly from a sketch, and you at some point change your sketch to go from
+ * requireing signing to not requireing signatures, you need to present this change to the node at least
+ * once, so it can update its requirements tables accordingly. Or it will keep believing that this node
+ * require signatures and attempt to send signed messages to it.
*
* @param msg Message buffer to use.
+ * @param destination Node ID of the destination.
*/
-void signerPresentation(MyMessage &msg);
+void signerPresentation(MyMessage &msg, uint8_t destination);
/**
* @brief Manages internal signing message handshaking.
@@ -615,5 +622,94 @@ void signerSha256Update(const uint8_t* data, size_t sz);
*/
uint8_t* signerSha256Final(void);
+/**
+ * @brief Do a timing neutral memory comparison.
+ *
+ * The function behaves similar to memcmp with the difference that it will
+ * always use the same number of instructions for a given number of bytes,
+ * no matter how the two buffers differ and the response is either 0 or -1.
+ *
+ * @param a First buffer for comparison.
+ * @param b Second buffer for comparison.
+ * @param sz The number of bytes to compare.
+ * @returns 0 if buffers match, -1 if they do not.
+ */
+int signerMemcmp(const void* a, const void* b, size_t sz);
+
#endif
-/** @}*/
\ No newline at end of file
+/** @}*/
+/**
+ * @defgroup MySigningTroubleshootinggrp Troubleshooting
+ * @ingroup MySigninggrp
+ * @{
+ *
+ * @section MySigningTroubleshootingSymptoms Symptoms and solutions
+ *
+ * The first thing to do if you suspect signing is causing problems, is to enable the verbose debug
+ * flag for the signing backend. @see MY_DEBUG_VERBOSE_SIGNING
+ *
+ * If you are having trouble getting signing to work, please see the following troubleshooting tips.
+ *
+ * @subsection MySigningTroubleshootingSymptomStFail Signing fails and logs show st=fail on transmissions
+ *
+ * This is actually not a signing problem, although ofthen st=fail becomes st=ok when signing is disabled.
+ * This is by far the most commonly reported problem with signing, but the problems is not with signing,
+ * it is with radio performence.
+ * This is a typical log which might look like a signing related issue but isn't:
+ * @code{.unparsed}
+ * 0;255;3;0;9;Skipping security for command 3 type 16
+ * 0;255;3;0;9;read: 3-3-0 s=255,c=3,t=16,pt=0,l=0,sg=0:
+ * 0;255;3;0;9;Signing backend: ATSHA204Soft
+ * 0;255;3;0;9;SHA256: 86DEAE1DAF50D577A4E2262B33ABF9DEE05DD8FAF84F94F50900000000000000
+ * 0;255;3;0;9;Skipping security for command 3 type 17
+ * 0;255;3;0;9;send: 0-0-3-3 s=255,c=3,t=17,pt=6,l=25,sg=0,st=fail:86DEAE1DAF50D577A4E2262B33ABF9DEE05DD8FAF84F94F509
+ * 0;255;3;0;9;Failed to transmit nonce!
+ * 0;255;3;0;9;Message is not signed, but it should have been!
+ * 0;255;3;0;9;verify fail
+ * @endcode
+ *
+ * The reason for this is that when signing is used, the messages transmitted become relatively large.
+ * Because of this, the message is more sensitive to noise, and the chance for a message to get scrambled
+ * increase with the message size. Please refer to the troubleshooting section at the MySensors forum for
+ * information on how to improve radio performence.
+ * This is a good place to start: https://forum.mysensors.org/topic/666/debug-faq-and-how-ask-for-help
+ *
+ * @subsection MySigningTroubleshootingSymptomNonce Failed to generate nonce
+ *
+ * The signing backend failed to generate the nonce needed to sign a message. This indicate a hardware
+ * problem. Please post the debug info on the forum together with a description of your hardware setup.
+ *
+ * @subsection MySigningTroubleshootingSymptomSign Failed to sign message
+ *
+ * The signing backend failed to sign the message. Typically this happens if your message is so large,
+ * that there is no room left in the buffer to store a signature.
+ *
+ * @subsection MySigningTroubleshootingSymptomWrongSource Nonce did not come from the destination (XX) of the message to be signed! It came from YY
+ *
+ * This should not really happen. The reason for this message is that the signing backend is only capable
+ * of handling one signed message session at any time. If for some reason multiple nodes send a nonce message to
+ * the same node, only the nonce from a node that is the destination of the current message signing session will be
+ * accepted. Any other nonces will be dropped. This should not happen as no node should send a nonce unless asked to,
+ * and a node will only ask for a nonce to one destination for every signing session.
+ * If you see this message, please post the debugging details on the MySensors forum so it can be investigated further
+ * together with a description of your setup.
+ *
+ * @subsection MySigningTroubleshootingSymptomNotSigned Message is not signed, but it should have been
+ *
+ * A node has failed to comply with the signing preferences of this node. Check that the node has received a
+ * signing presentation message from this node. This is automatically transmitted to gateways. For other nodes,
+ * you need to transmit the presentation from the sketch. @see signerPresentation
+ *
+ * @subsection MySigningTroubleshootingSymptomNotSignedGeneral "Messages do not appear to be signed but I think they should be..."
+ *
+ * Make sure you have enabled the flag to require signatures to require signatures and have enabled one of the signing
+ * backends. @see MY_SIGNING_REQUEST_SIGNATURES @see MY_SIGNING_ATSHA204 @see MY_SIGNING_SOFT
+ *
+ * @subsection MySigningTroubleshootingSymptomNotWorkingWhitelisting Signature verification failed!
+ *
+ * Make sure both source and destination of the signed message has undergone @ref personalization with the same HMAC key.
+ * Also, if whitelisting is used, make sure the proper serial is paired with the proper node ID at the destination.
+ * Whitelisting preferences are communicated with the signing presentation (done automatically from nodes to gateway but
+ * has to be explicitly done by sketch for node to node communication). @see signerPresentation
+ */
+/** @}*/
diff --git a/libraries/MySensors/core/MySigningAtsha204.cpp b/core/MySigningAtsha204.cpp
similarity index 59%
rename from libraries/MySensors/core/MySigningAtsha204.cpp
rename to core/MySigningAtsha204.cpp
index 61a1293..94dd91a 100644
--- a/libraries/MySensors/core/MySigningAtsha204.cpp
+++ b/core/MySigningAtsha204.cpp
@@ -31,20 +31,20 @@
// Define MY_DEBUG_VERBOSE_SIGNING in your sketch to enable signing backend debugprints
-ATSHA204Class atsha204(MY_SIGNING_ATSHA204_PIN);
unsigned long _signing_timestamp;
bool _signing_verification_ongoing = false;
-uint8_t _signing_current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1];
+uint8_t _signing_verifying_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1];
+uint8_t _signing_signing_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH+SHA204_SERIAL_SZ+1];
uint8_t _signing_temp_message[SHA_MSG_SIZE];
-uint8_t _singning_rx_buffer[SHA204_RSP_SIZE_MAX];
-uint8_t _singning_tx_buffer[SHA204_CMD_SIZE_MAX];
+uint8_t _signing_rx_buffer[SHA204_RSP_SIZE_MAX];
+uint8_t _signing_tx_buffer[SHA204_CMD_SIZE_MAX];
extern uint8_t _doWhitelist[32];
#ifdef MY_SIGNING_NODE_WHITELISTING
const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING;
#endif
-static void signerCalculateSignature(MyMessage &msg);
+static void signerCalculateSignature(MyMessage &msg, bool signing);
static uint8_t* signerSha256(const uint8_t* data, size_t sz);
@@ -87,14 +87,16 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf,
#endif
void signerAtsha204Init(void) {
+ atsha204_init(MY_SIGNING_ATSHA204_PIN);
}
bool signerAtsha204CheckTimer(void) {
if (_signing_verification_ongoing) {
- if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) {
+ if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) {
DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0);
// Purge nonce
- memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
+ memset(_signing_signing_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
+ memset(_signing_verifying_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
_signing_verification_ongoing = false;
return false;
}
@@ -105,38 +107,41 @@ bool signerAtsha204CheckTimer(void) {
bool signerAtsha204GetNonce(MyMessage &msg) {
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0);
// Generate random number for use as nonce
- // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value
+ // We used a basic whitening technique that XORs each byte in a 32byte random value with current hwMillis() counter
// This 32-byte random value is then hashed (SHA256) to produce the resulting nonce
- for (int i = 0; i < 32; i++) {
- if (atsha204.sha204m_execute(SHA204_RANDOM, RANDOM_NO_SEED_UPDATE, 0, 0, NULL,
- RANDOM_COUNT, _singning_tx_buffer, RANDOM_RSP_SIZE, _singning_rx_buffer) != SHA204_SUCCESS) {
- DEBUG_SIGNING_PRINTBUF(F("Failed to generate nonce"), NULL, 0);
- return false;
- }
- _signing_current_nonce[i] = _singning_rx_buffer[SHA204_BUFFER_POS_DATA];
+ (void)atsha204_wakeup(_signing_temp_message);
+ if (atsha204_execute(SHA204_RANDOM, RANDOM_SEED_UPDATE, 0, 0, NULL,
+ RANDOM_COUNT, _signing_tx_buffer, RANDOM_RSP_SIZE, _signing_rx_buffer) != SHA204_SUCCESS) {
+ DEBUG_SIGNING_PRINTBUF(F("Failed to generate nonce"), NULL, 0);
+ return false;
}
- memcpy(_signing_current_nonce, signerSha256(_signing_current_nonce, 32), MAX_PAYLOAD);
+ for (int i = 0; i < 32; i++) {
+ _signing_verifying_nonce[i] = _signing_rx_buffer[SHA204_BUFFER_POS_DATA+i] ^ (hwMillis()&0xFF);
+ }
+ memcpy(_signing_verifying_nonce, signerSha256(_signing_verifying_nonce, 32), MAX_PAYLOAD);
+
+ atsha204_idle(); // We just idle the chip now since we expect to use it soon when the signed message arrives
// We set the part of the 32-byte nonce that does not fit into a message to 0xAA
- memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD);
+ memset(&_signing_verifying_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_verifying_nonce)-MAX_PAYLOAD);
// Transfer the first part of the nonce to the message
- msg.set(_signing_current_nonce, MAX_PAYLOAD);
+ msg.set(_signing_verifying_nonce, MAX_PAYLOAD);
_signing_verification_ongoing = true;
- _signing_timestamp = millis(); // Set timestamp to determine when to purge nonce
+ _signing_timestamp = hwMillis(); // Set timestamp to determine when to purge nonce
// Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover)
// Note that if message is "too" quick, and arrives before turnover, it will be rejected
// but this is consider such a rare case that it is accepted and rejects are 'safe'
- if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) _signing_timestamp = 0;
+ if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) _signing_timestamp = 0;
return true;
}
void signerAtsha204PutNonce(MyMessage &msg) {
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0);
- memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
+ memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
// We set the part of the 32-byte nonce that does not fit into a message to 0xAA
- memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD);
+ memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD);
}
bool signerAtsha204SignMsg(MyMessage &msg) {
@@ -148,22 +153,25 @@ bool signerAtsha204SignMsg(MyMessage &msg) {
// Calculate signature of message
mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated
- signerCalculateSignature(msg);
+ signerCalculateSignature(msg, true);
if (DO_WHITELIST(msg.destination)) {
// Salt the signature with the senders nodeId and the unique serial of the ATSHA device
- memcpy(_signing_current_nonce, &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed
- _signing_current_nonce[32] = msg.sender;
- atsha204.getSerialNumber(&_signing_current_nonce[33]);
- (void)signerSha256(_signing_current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place
+ memcpy(_signing_signing_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed
+ _signing_signing_nonce[32] = msg.sender;
+ atsha204_getSerialNumber(&_signing_signing_nonce[33]);
+ (void)signerSha256(_signing_signing_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place
DEBUG_SIGNING_PRINTBUF(F("Signature salted with serial"), NULL, 0);
}
+ // Put device back to sleep
+ atsha204_sleep();
+
// Overwrite the first byte in the signature with the signing identifier
- _singning_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER;
+ _signing_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER;
// Transfer as much signature data as the remaining space in the message permits
- memcpy(&msg.data[mGetLength(msg)], &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg));
+ memcpy(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg));
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg));
return true;
@@ -187,7 +195,7 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
}
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg));
- signerCalculateSignature(msg); // Get signature of message
+ signerCalculateSignature(msg, false); // Get signature of message
#ifdef MY_SIGNING_NODE_WHITELISTING
// Look up the senders nodeId in our whitelist and salt the signature with that data
@@ -195,25 +203,30 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
for (j=0; j < NUM_OF(_signing_whitelist); j++) {
if (_signing_whitelist[j].nodeId == msg.sender) {
DEBUG_SIGNING_PRINTBUF(F("Sender found in whitelist"), NULL, 0);
- memcpy(_signing_current_nonce, &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed
- _signing_current_nonce[32] = msg.sender;
- memcpy(&_signing_current_nonce[33], _signing_whitelist[j].serial, SHA204_SERIAL_SZ);
- (void)signerSha256(_signing_current_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place
+ memcpy(_signing_verifying_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed
+ _signing_verifying_nonce[32] = msg.sender;
+ memcpy(&_signing_verifying_nonce[33], _signing_whitelist[j].serial, SHA204_SERIAL_SZ);
+ (void)signerSha256(_signing_verifying_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place
break;
}
}
if (j == NUM_OF(_signing_whitelist)) {
DEBUG_SIGNING_PRINTBUF(F("Sender not found in whitelist, message rejected!"), NULL, 0);
+ // Put device back to sleep
+ atsha204_sleep();
return false;
}
#endif
+ // Put device back to sleep
+ atsha204_sleep();
+
// Overwrite the first byte in the signature with the signing identifier
- _singning_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER;
+ _signing_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER;
// Compare the caluclated signature with the provided signature
- if (memcmp(&msg.data[mGetLength(msg)], &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) {
- DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg));
+ if (signerMemcmp(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) {
+ DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg));
#ifdef MY_SIGNING_NODE_WHITELISTING
DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0);
#endif
@@ -225,44 +238,43 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
}
}
-// Helper to calculate signature of msg (returned in _singning_rx_buffer[SHA204_BUFFER_POS_DATA])
-static void signerCalculateSignature(MyMessage &msg) {
+// Helper to calculate signature of msg (returned in _signing_rx_buffer[SHA204_BUFFER_POS_DATA])
+static void signerCalculateSignature(MyMessage &msg, bool signing) {
+ (void)atsha204_wakeup(_signing_temp_message);
memset(_signing_temp_message, 0, 32);
memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg)));
// Program the data to sign into the ATSHA204
DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg)));
- DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), _signing_current_nonce, 32);
- (void)atsha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, _signing_temp_message,
- WRITE_COUNT_LONG, _singning_tx_buffer, WRITE_RSP_SIZE, _singning_rx_buffer);
+ DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), signing ? _signing_signing_nonce : _signing_verifying_nonce, 32);
+ (void)atsha204_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, _signing_temp_message,
+ WRITE_COUNT_LONG, _signing_tx_buffer, WRITE_RSP_SIZE, _signing_rx_buffer);
// Program the nonce to use for the signature (has to be done just before GENDIG due to chip limitations)
- (void)atsha204.sha204m_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, _signing_current_nonce,
- NONCE_COUNT_LONG, _singning_tx_buffer, NONCE_RSP_SIZE_SHORT, _singning_rx_buffer);
+ (void)atsha204_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH,
+ signing ? _signing_signing_nonce : _signing_verifying_nonce,
+ NONCE_COUNT_LONG, _signing_tx_buffer, NONCE_RSP_SIZE_SHORT, _signing_rx_buffer);
// Purge nonce when used
- memset(_signing_current_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
+ memset(signing ? _signing_signing_nonce : _signing_verifying_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
// Generate digest of data and nonce
- (void)atsha204.sha204m_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL,
- GENDIG_COUNT_DATA, _singning_tx_buffer, GENDIG_RSP_SIZE, _singning_rx_buffer);
+ (void)atsha204_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL,
+ GENDIG_COUNT_DATA, _signing_tx_buffer, GENDIG_RSP_SIZE, _signing_rx_buffer);
// Calculate HMAC of message+nonce digest and secret key
- (void)atsha204.sha204m_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL,
- HMAC_COUNT, _singning_tx_buffer, HMAC_RSP_SIZE, _singning_rx_buffer);
+ (void)atsha204_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL,
+ HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer);
- // Put device back to sleep
- atsha204.sha204c_sleep();
-
- DEBUG_SIGNING_PRINTBUF(F("HMAC: "), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32);
+ DEBUG_SIGNING_PRINTBUF(F("HMAC: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32);
}
// Helper to calculate a generic SHA256 digest of provided buffer (only supports one block)
-// The pointer to the hash is returned, but the hash is also stored in _singning_rx_buffer[SHA204_BUFFER_POS_DATA])
+// The pointer to the hash is returned, but the hash is also stored in _signing_rx_buffer[SHA204_BUFFER_POS_DATA])
static uint8_t* signerSha256(const uint8_t* data, size_t sz) {
// Initiate SHA256 calculator
- (void)atsha204.sha204m_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL,
- SHA_COUNT_SHORT, _singning_tx_buffer, SHA_RSP_SIZE_SHORT, _singning_rx_buffer);
+ (void)atsha204_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL,
+ SHA_COUNT_SHORT, _signing_tx_buffer, SHA_RSP_SIZE_SHORT, _signing_rx_buffer);
// Calculate a hash
memset(_signing_temp_message, 0x00, SHA_MSG_SIZE);
@@ -271,12 +283,9 @@ static uint8_t* signerSha256(const uint8_t* data, size_t sz) {
// Write length data to the last bytes
_signing_temp_message[SHA_MSG_SIZE-2] = (sz >> 5);
_signing_temp_message[SHA_MSG_SIZE-1] = (sz << 3);
- (void)atsha204.sha204m_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, _signing_temp_message,
- SHA_COUNT_LONG, _singning_tx_buffer, SHA_RSP_SIZE_LONG, _singning_rx_buffer);
+ (void)atsha204_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, _signing_temp_message,
+ SHA_COUNT_LONG, _signing_tx_buffer, SHA_RSP_SIZE_LONG, _signing_rx_buffer);
- // Put device back to sleep
- atsha204.sha204c_sleep();
-
- DEBUG_SIGNING_PRINTBUF(F("SHA256: "), &_singning_rx_buffer[SHA204_BUFFER_POS_DATA], 32);
- return &_singning_rx_buffer[SHA204_BUFFER_POS_DATA];
+ DEBUG_SIGNING_PRINTBUF(F("SHA256: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32);
+ return &_signing_rx_buffer[SHA204_BUFFER_POS_DATA];
}
diff --git a/libraries/MySensors/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp
similarity index 85%
rename from libraries/MySensors/core/MySigningAtsha204Soft.cpp
rename to core/MySigningAtsha204Soft.cpp
index 037905a..400895f 100644
--- a/libraries/MySensors/core/MySigningAtsha204Soft.cpp
+++ b/core/MySigningAtsha204Soft.cpp
@@ -38,7 +38,8 @@
Sha256Class _signing_sha256;
unsigned long _signing_timestamp;
bool _signing_verification_ongoing = false;
-uint8_t _signing_current_nonce[NONCE_NUMIN_SIZE_PASSTHROUGH];
+uint8_t _signing_verifying_nonce[32];
+uint8_t _signing_signing_nonce[32];
uint8_t _signing_temp_message[32];
static uint8_t _signing_hmac_key[32];
uint8_t _signing_hmac[32];
@@ -49,7 +50,7 @@ static uint8_t _signing_node_serial_info[9];
const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING;
#endif
-static void signerCalculateSignature(MyMessage &msg);
+static void signerCalculateSignature(MyMessage &msg, bool signing);
#ifdef MY_DEBUG_VERBOSE_SIGNING
static char i2h(uint8_t i)
@@ -99,10 +100,11 @@ void signerAtsha204SoftInit(void) {
bool signerAtsha204SoftCheckTimer(void) {
if (_signing_verification_ongoing) {
- if (millis() < _signing_timestamp || millis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) {
+ if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) {
DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0);
// Purge nonce
- memset(_signing_current_nonce, 0xAA, 32);
+ memset(_signing_signing_nonce, 0xAA, 32);
+ memset(_signing_verifying_nonce, 0xAA, 32);
_signing_verification_ongoing = false;
return false;
}
@@ -113,35 +115,35 @@ bool signerAtsha204SoftCheckTimer(void) {
bool signerAtsha204SoftGetNonce(MyMessage &msg) {
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0);
- // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value
- // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce
+ // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is
+ // hashed (SHA256) to produce the resulting nonce
_signing_sha256.init();
for (int i = 0; i < 32; i++) {
- _signing_sha256.write(random(256));
+ _signing_sha256.write(random(256) ^ (hwMillis()&0xFF));
}
- memcpy(_signing_current_nonce, _signing_sha256.result(), MAX_PAYLOAD);
- DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_current_nonce, 32);
+ memcpy(_signing_verifying_nonce, _signing_sha256.result(), MAX_PAYLOAD);
+ DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_verifying_nonce, 32);
// We set the part of the 32-byte nonce that does not fit into a message to 0xAA
- memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD);
+ memset(&_signing_verifying_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_verifying_nonce)-MAX_PAYLOAD);
// Transfer the first part of the nonce to the message
- msg.set(_signing_current_nonce, MAX_PAYLOAD);
+ msg.set(_signing_verifying_nonce, MAX_PAYLOAD);
_signing_verification_ongoing = true;
- _signing_timestamp = millis(); // Set timestamp to determine when to purge nonce
+ _signing_timestamp = hwMillis(); // Set timestamp to determine when to purge nonce
// Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover)
// Note that if message is "too" quick, and arrives before turnover, it will be rejected
// but this is consider such a rare case that it is accepted and rejects are 'safe'
- if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) _signing_timestamp = 0;
+ if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) _signing_timestamp = 0;
return true;
}
void signerAtsha204SoftPutNonce(MyMessage &msg) {
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0);
- memcpy(_signing_current_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
+ memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
// We set the part of the 32-byte nonce that does not fit into a message to 0xAA
- memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD);
+ memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD);
}
bool signerAtsha204SoftSignMsg(MyMessage &msg) {
@@ -153,7 +155,7 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) {
// Calculate signature of message
mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated
- signerCalculateSignature(msg);
+ signerCalculateSignature(msg, true);
if (DO_WHITELIST(msg.destination)) {
// Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided
@@ -195,7 +197,7 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) {
// Get signature of message
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg));
- signerCalculateSignature(msg);
+ signerCalculateSignature(msg, false);
#ifdef MY_SIGNING_NODE_WHITELISTING
// Look up the senders nodeId in our whitelist and salt the signature with that data
@@ -222,7 +224,7 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) {
_signing_hmac[0] = SIGNING_IDENTIFIER;
// Compare the caluclated signature with the provided signature
- if (memcmp(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg))) {
+ if (signerMemcmp(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg))) {
DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), _signing_hmac, MAX_PAYLOAD-mGetLength(msg));
#ifdef MY_SIGNING_NODE_WHITELISTING
DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0);
@@ -236,11 +238,11 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) {
}
// Helper to calculate signature of msg (returned in hmac)
-static void signerCalculateSignature(MyMessage &msg) {
+static void signerCalculateSignature(MyMessage &msg, bool signing) {
memset(_signing_temp_message, 0, 32);
memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg)));
DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg)));
- DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), _signing_current_nonce, 32);
+ DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), signing ? _signing_signing_nonce : _signing_verifying_nonce, 32);
// ATSHA204 calculates the HMAC with a PSK and a SHA256 digest of the following data:
// 32 bytes zeroes
@@ -275,9 +277,9 @@ static void signerCalculateSignature(MyMessage &msg) {
_signing_sha256.write(0x01); // SN[0]
_signing_sha256.write(0x23); // SN[1]
for (int i=0; i<25; i++) _signing_sha256.write(0x00);
- for (int i=0; i<32; i++) _signing_sha256.write(_signing_current_nonce[i]);
+ for (int i=0; i<32; i++) _signing_sha256.write(signing ? _signing_signing_nonce[i] : _signing_verifying_nonce[i]);
// Purge nonce when used
- memset(_signing_current_nonce, 0xAA, 32);
+ memset(signing ? _signing_signing_nonce : _signing_verifying_nonce, 0xAA, 32);
memcpy(_signing_temp_message, _signing_sha256.result(), 32);
// Feed "message" to HMAC calculator
diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp
new file mode 100644
index 0000000..a54c34d
--- /dev/null
+++ b/core/MyTransport.cpp
@@ -0,0 +1,720 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyTransport.h"
+
+// SM: transitions and update states
+static transportState stInit = { stInitTransition, NULL };
+static transportState stParent = { stParentTransition, stParentUpdate };
+static transportState stID = { stIDTransition, stIDUpdate };
+static transportState stUplink = { stUplinkTransition, NULL };
+static transportState stReady = { stReadyTransition, stReadyUpdate };
+static transportState stFailure = { stFailureTransition, stFailureUpdate };
+
+// transport SM variables
+static transportSM _transportSM;
+
+// stInit: initialize transport HW
+void stInitTransition() {
+ TRANSPORT_DEBUG(PSTR("TSM:INIT\n"));
+ // initialize status variables
+ _transportSM.pingActive = false;
+ _transportSM.transportActive = false;
+ #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE)
+ _transportSM.lastSanityCheck = hwMillis();
+ #endif
+ _transportSM.lastUplinkCheck = 0;
+ // Read node settings (ID, parentId, GW distance) from EEPROM
+ hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig));
+
+ // initialize radio
+ if (!transportInit()) {
+ TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n"));
+ setIndication(INDICATION_ERR_INIT_TRANSPORT);
+ transportSwitchSM(stFailure);
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("TSM:INIT:TSP OK\n"));
+ _transportSM.transportActive = true;
+ #if defined(MY_GATEWAY_FEATURE)
+ // Set configuration for gateway
+ TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n"));
+ _nc.parentNodeId = GATEWAY_ADDRESS;
+ _nc.distance = 0;
+ _nc.nodeId = GATEWAY_ADDRESS;
+ transportSetAddress(GATEWAY_ADDRESS);
+ // GW mode: skip FPAR,ID,UPL states
+ transportSwitchSM(stReady);
+ #else
+ if ((uint8_t)MY_NODE_ID != AUTO) {
+ TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID,ID=%d\n"),MY_NODE_ID);
+ // Set static id
+ _nc.nodeId = MY_NODE_ID;
+ // Save static id in eeprom
+ hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID);
+ }
+ // set ID if static or set in EEPROM
+ if (_nc.nodeId == AUTO || transportAssignNodeID(_nc.nodeId)) {
+ // if node ID > 0, proceed to next state
+ transportSwitchSM(stParent);
+ }
+ else {
+ // ID invalid (=0), nothing we can do
+ transportSwitchSM(stFailure);
+ }
+ #endif
+ }
+}
+
+// stParent: find parent
+void stParentTransition() {
+ TRANSPORT_DEBUG(PSTR("TSM:FPAR\n")); // find parent
+ setIndication(INDICATION_FIND_PARENT);
+ _transportSM.uplinkOk = false;
+ _transportSM.preferredParentFound = false;
+ #if defined(MY_PARENT_NODE_IS_STATIC)
+ TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"),MY_PARENT_NODE_ID); // static parent
+ _transportSM.findingParentNode = false;
+ _nc.distance = 1; // assumption, CHKUPL:GWDC will update this variable
+ _nc.parentNodeId = MY_PARENT_NODE_ID;
+ // skipping find parent
+ setIndication(INDICATION_GOT_PARENT);
+ transportSwitchSM(stID);
+ #else
+ _transportSM.findingParentNode = true;
+ _nc.distance = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID
+ _nc.parentNodeId = AUTO;
+ // Broadcast find parent request
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""));
+ #endif
+}
+
+// stParentUpdate
+void stParentUpdate() {
+ #if !defined(MY_PARENT_NODE_IS_STATIC)
+ if (transportTimeInState() > STATE_TIMEOUT || _transportSM.preferredParentFound) {
+ // timeout or preferred parent found
+ if (_nc.parentNodeId != AUTO) {
+ // parent assigned
+ TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok
+ _transportSM.findingParentNode = false;
+ setIndication(INDICATION_GOT_PARENT);
+ // go to next state
+ transportSwitchSM(stID);
+ }
+ else if (transportTimeInState() > STATE_TIMEOUT) {
+ // timeout w/o reply or valid parent
+ if (_transportSM.retries < STATE_RETRIES) {
+ // retries left
+ TRANSPORT_DEBUG(PSTR("!TSM:FPAR:NO REPLY\n")); // find parent, no reply
+ // reenter state
+ transportSwitchSM(stParent);
+ }
+ else {
+ // no retries left, finding parent failed
+ TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); // find parent fail
+ setIndication(INDICATION_ERR_FIND_PARENT);
+ transportSwitchSM(stFailure);
+ }
+ }
+ }
+ #endif
+}
+
+// stID: verify and request ID if necessary
+void stIDTransition() {
+ TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID
+ if (_nc.nodeId == AUTO) {
+ // send ID request
+ setIndication(INDICATION_REQ_NODEID);
+ TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""));
+ }
+}
+
+void stIDUpdate() {
+ if (_nc.nodeId != AUTO) {
+ // current node ID is valid
+ TRANSPORT_DEBUG(PSTR("TSM:ID:OK,ID=%d\n"), _nc.nodeId);
+ setIndication(INDICATION_GOT_NODEID);
+ // proceed to next state
+ transportSwitchSM(stUplink);
+ }
+ else if (transportTimeInState() > STATE_TIMEOUT) {
+ // timeout
+ if (_transportSM.retries < STATE_RETRIES) {
+ // reenter
+ transportSwitchSM(stID);
+ }
+ else {
+ // no retries left
+ TRANSPORT_DEBUG(PSTR("!TSM:ID:FAIL,ID=%d\n"), _nc.nodeId);
+ setIndication(INDICATION_ERR_GET_NODEID);
+ transportSwitchSM(stFailure);
+ }
+ }
+}
+
+void stUplinkTransition() {
+ TRANSPORT_DEBUG(PSTR("TSM:UPL\n"));
+ // check uplink
+ if(transportCheckUplink(true)) {
+ // uplink ok, i.e. GW replied
+ TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok
+ // proceed to next state
+ transportSwitchSM(stReady);
+ }
+ else {
+ // uplink failed, at this point, no retries or timeout
+ TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink failed
+ // go back to stParent
+ transportSwitchSM(stParent);
+ }
+}
+
+void stReadyTransition() {
+ // transport is ready and fully operational
+ TRANSPORT_DEBUG(PSTR("TSM:READY\n")); // transport is ready
+ _transportSM.uplinkOk = true;
+ _transportSM.failedUplinkTransmissions = 0; // reset counter
+}
+
+// stReadyUpdate: monitors uplink failures
+void stReadyUpdate() {
+ #if !defined(MY_GATEWAY_FEATURE)
+ if (_transportSM.failedUplinkTransmissions > TRANSMISSION_FAILURES) {
+ // too many uplink transmissions failed, find new parent (if non-static)
+ #if !defined(MY_PARENT_NODE_IS_STATIC)
+ TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,SNP\n")); // uplink failed, search new parent
+ transportSwitchSM(stParent);
+ #else
+ TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,STATP\n")); // uplink failed, static parent
+ // reset counter
+ _transportSM.failedUplinkTransmissions = 0;
+ #endif
+ }
+ #endif
+}
+
+// stFailure: entered upon HW init failure or max retries exceeded
+void stFailureTransition() {
+ TRANSPORT_DEBUG(PSTR("TSM:FAILURE\n"));
+ _transportSM.uplinkOk = false; // uplink nok
+ _transportSM.transportActive = false; // transport inactive
+ setIndication(INDICATION_ERR_INIT_TRANSPORT);
+ // power down transport, no need until re-init
+ TRANSPORT_DEBUG(PSTR("TSM:FAILURE:PDT\n")); // power down transport
+ transportPowerDown();
+}
+
+void stFailureUpdate() {
+ if (transportTimeInState()> TIMEOUT_FAILURE_STATE) {
+ TRANSPORT_DEBUG(PSTR("TSM:FAILURE:RE-INIT\n")); // attempt to re-initialize transport
+ transportSwitchSM(stInit);
+ }
+}
+
+void transportSwitchSM(transportState& newState) {
+ if (_transportSM.currentState != &newState) {
+ // state change, reset retry counter
+ _transportSM.retries = 0;
+ // change state
+ _transportSM.currentState = &newState;
+ }
+ else {
+ _transportSM.retries++; // increment retries
+ }
+ // Transition event
+ if (_transportSM.currentState->Transition) _transportSM.currentState->Transition();
+ // save time
+ _transportSM.stateEnter = hwMillis();
+}
+
+uint32_t transportTimeInState() {
+ return hwMillis() - _transportSM.stateEnter;
+}
+
+void transportUpdateSM(){
+ if (_transportSM.currentState->Update) _transportSM.currentState->Update();
+}
+
+bool isTransportReady() {
+ return _transportSM.uplinkOk;
+}
+
+bool isTransportSearchingParent() {
+ return _transportSM.findingParentNode;
+}
+
+void transportInitialize() {
+ // intial state
+ _transportSM.currentState = &stFailure;
+ transportSwitchSM(stInit);
+}
+
+// update TSM and process incoming messages
+void transportProcess() {
+ // update state machine
+ transportUpdateSM();
+ // process transport FIFO
+ transportProcessFIFO();
+}
+
+
+bool transportCheckUplink(bool force) {
+ if (!force && (hwMillis() - _transportSM.lastUplinkCheck) < CHKUPL_INTERVAL) {
+ TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK,FCTRL\n")); // flood control
+ return true;
+ }
+ // ping GW
+ uint8_t hopsCount = transportPingNode(GATEWAY_ADDRESS);
+ // verify hops
+ if (hopsCount != INVALID_HOPS) {
+ // update
+ _transportSM.lastUplinkCheck = hwMillis();
+ TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK\n"));
+ // did distance to GW change upstream, eg. re-routing of uplink nodes
+ if (hopsCount != _nc.distance) {
+ TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:DGWC,O=%d,N=%d\n"), _nc.distance, hopsCount); // distance to GW changed
+ _nc.distance = hopsCount;
+ }
+ return true;
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:FAIL\n"));
+ return false;
+ }
+}
+
+bool transportAssignNodeID(uint8_t newNodeId) {
+ // verify if ID valid
+ if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) {
+ _nc.nodeId = newNodeId;
+ transportSetAddress(newNodeId);
+ // Write ID to EEPROM
+ hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId);
+ TRANSPORT_DEBUG(PSTR("TSF:ASID:OK,ID=%d\n"),newNodeId);
+ return true;
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("!TSF:ASID:FAIL,ID=%d\n"),newNodeId);
+ setIndication(INDICATION_ERR_NET_FULL);
+ return false;
+ }
+}
+
+bool transportRouteMessage(MyMessage &message) {
+ uint8_t destination = message.destination;
+ uint8_t route;
+
+ if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) {
+ TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:FPAR ACTIVE\n")); // find parent active, message not sent
+ // request to send a non-BC message while finding parent active, abort
+ return false;
+ }
+
+ if (destination == GATEWAY_ADDRESS) {
+ route = _nc.parentNodeId; // message to GW always routes via parent
+ }
+ else if (destination == BROADCAST_ADDRESS) {
+ route = BROADCAST_ADDRESS; // message to BC does not require routing
+ }
+ else {
+ #if defined(MY_REPEATER_FEATURE)
+ // destination not GW & not BC, get route
+ route = hwReadConfig(EEPROM_ROUTES_ADDRESS + destination);
+ if (route == AUTO) {
+ // route unknown
+ if (message.last != _nc.parentNodeId) {
+ // message not from parent, i.e. child node - route it to parent
+ TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:%d UNKNOWN\n"), destination);
+ route = _nc.parentNodeId;
+ }
+ else {
+ // route unknown and msg received from parent, send it to destination assuming in rx radius
+ route = destination;
+ }
+ }
+ #else
+ route = _nc.parentNodeId; // not a repeater, all traffic routed via parent
+ #endif
+ }
+ // send message
+ bool ok = transportSendWrite(route, message);
+ #if !defined(MY_GATEWAY_FEATURE)
+ // update counter
+ if (route == _nc.parentNodeId) {
+ if (!ok) {
+ setIndication(INDICATION_ERR_TX);
+ _transportSM.failedUplinkTransmissions++;
+ }
+ else _transportSM.failedUplinkTransmissions = 0;
+ }
+ #else
+ if(!ok) setIndication(INDICATION_ERR_TX);
+ #endif
+
+ return ok;
+}
+
+bool transportSendRoute(MyMessage &message) {
+ if (isTransportReady()) {
+ return transportRouteMessage(message);
+ }
+ else {
+ // TNR: transport not ready
+ TRANSPORT_DEBUG(PSTR("!TSF:SEND:TNR\n"));
+ return false;
+ }
+}
+
+// only be used inside transport
+bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype){
+ uint32_t enter = hwMillis();
+ // invalidate msg type
+ _msg.type = !msgtype;
+ bool expectedResponse = false;
+ while ((hwMillis() - enter < ms) && !expectedResponse) {
+ // process incoming messages
+ transportProcessFIFO();
+ #if defined(ARDUINO_ARCH_ESP8266)
+ yield();
+ #endif
+ expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype);
+ }
+ return expectedResponse;
+}
+
+uint8_t transportPingNode(uint8_t targetId) {
+ if(!_transportSM.pingActive){
+ if(targetId == _nc.nodeId) {
+ // ping to ourself, pingActive remains false
+ return 0;
+ }
+ _transportSM.pingActive = true;
+ _transportSM.pingResponse = INVALID_HOPS;
+ TRANSPORT_DEBUG(PSTR("TSF:PING:SEND,TO=%d\n"), targetId);
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)0x01));
+ // Wait for ping reply or timeout
+ transportWait(2000, C_INTERNAL, I_PONG);
+ // make sure missing I_PONG msg does not block pinging function by leaving pignActive=true
+ _transportSM.pingActive = false;
+ return _transportSM.pingResponse;
+ }
+ else {
+ return INVALID_HOPS;
+ }
+}
+
+void transportClearRoutingTable() {
+ for (uint8_t i = 0; i != 255; i++) {
+ hwWriteConfig(EEPROM_ROUTES_ADDRESS + i, BROADCAST_ADDRESS);
+ }
+ TRANSPORT_DEBUG(PSTR("TSF:CRT:OK\n")); // clear routing table
+}
+
+uint32_t transportGetHeartbeat() {
+ return transportTimeInState();
+}
+
+void transportProcessMessage() {
+ (void)signerCheckTimer(); // Manage signing timeout
+
+ uint8_t payloadLength = transportReceive((uint8_t *)&_msg);
+ (void)payloadLength; // currently not used
+
+ setIndication(INDICATION_RX);
+
+ uint8_t command = mGetCommand(_msg);
+ uint8_t type = _msg.type;
+ uint8_t sender = _msg.sender;
+ uint8_t last = _msg.last;
+ uint8_t destination = _msg.destination;
+
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:READ,%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"),
+ sender, last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf));
+
+ // verify protocol version
+ if(mGetVersion(_msg) != PROTOCOL_VERSION) {
+ setIndication(INDICATION_ERR_VERSION);
+ TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d!=%d\n"), mGetVersion(_msg),PROTOCOL_VERSION); // protocol version mismatch
+ return;
+ }
+
+ // Reject messages that do not pass verification
+ if (!signerVerifyMsg(_msg)) {
+ setIndication(INDICATION_ERR_SIGN);
+ TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN VERIFY FAIL\n"));
+ return;
+ }
+
+ // Is message addressed to this node?
+ if (destination == _nc.nodeId) {
+ // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes)
+ mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD));
+ // null terminate data
+ _msg.data[mGetLength(_msg)] = 0x00;
+
+ // update routing table if msg not from parent
+ #if defined(MY_REPEATER_FEATURE)
+ if (last != _nc.parentNodeId) {
+ // Message is from one of the child nodes. Add it to routing table.
+ hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last);
+ }
+ #endif
+
+ // Check if sender requests an ack back.
+ if (mGetRequestAck(_msg)) {
+ _msgTmp = _msg; // Copy message
+ mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop)
+ mSetAck(_msgTmp, true); // set ACK flag
+ _msgTmp.sender = _nc.nodeId;
+ _msgTmp.destination = sender;
+ // send ACK
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested
+ // use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply
+ transportSendRoute(_msgTmp);
+ }
+ if(!mGetAck(_msg)) {
+ // only process if not ACK
+ if (command == C_INTERNAL) {
+ // Process signing related internal messages
+ if (signerProcessInternal(_msg)) {
+ return; // Signer processing indicated no further action needed
+ }
+ #if !defined(MY_GATEWAY_FEATURE)
+ if (type == I_ID_RESPONSE) {
+ #if (MY_NODE_ID == AUTO)
+ // only active if node ID dynamic
+ transportAssignNodeID(_msg.getByte());
+ #endif
+ return; // no further processing required
+ }
+ if (type == I_FIND_PARENT_RESPONSE) {
+ #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC)
+ if (_transportSM.findingParentNode) { // only process if find parent active
+ // Reply to a I_FIND_PARENT message. Check if the distance is shorter than we already have.
+ uint8_t distance = _msg.getByte();
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR RES,ID=%d,D=%d\n"), sender, distance); // find parent response
+ if (isValidDistance(distance)) {
+ // Distance to gateway is one more for us w.r.t. parent
+ distance++;
+ // update settings if distance shorter or preferred parent found
+ if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) {
+ // Found a neighbor closer to GW than previously found
+ if (!_autoFindParent && sender == MY_PARENT_NODE_ID) {
+ _transportSM.preferredParentFound = true;
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF FOUND\n")); // find parent, preferred parent found
+ }
+ _nc.distance = distance;
+ _nc.parentNodeId = sender;
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _nc.parentNodeId, _nc.distance);
+ }
+ }
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive
+ }
+ return;
+ #endif
+ }
+ #endif
+ // general
+ if (type == I_PING) {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:PINGED,ID=%d,HP=%d\n"), sender, _msg.getByte()); // node pinged
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)0x01));
+ return; // no further processing required
+ }
+ if (type == I_PONG) {
+ if (_transportSM.pingActive) {
+ _transportSM.pingActive = false;
+ _transportSM.pingResponse = _msg.getByte();
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:PONG RECV,HP=%d\n"), _transportSM.pingResponse); // pong received
+ }
+ return; // no further processing required
+ }
+
+ if (_processInternalMessages()) {
+ return; // no further processing required
+ }
+ } else if (command == C_STREAM) {
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ if(firmwareOTAUpdateProcess()){
+ return; // OTA FW update processing indicated no further action needed
+ }
+ #endif
+ }
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK\n")); // received message is ACK, no internal processing, handover to msg callback
+ }
+ #if defined(MY_GATEWAY_FEATURE)
+ // Hand over message to controller
+ gatewayTransportSend(_msg);
+ #endif
+ // Call incoming message callback if available
+ if (receive) {
+ receive(_msg);
+ }
+ return;
+ }
+ else if (destination == BROADCAST_ADDRESS) {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:BC\n")); // broadcast msg
+ if (command == C_INTERNAL) {
+ if (isTransportReady()) {
+ // only reply if node is fully operational
+ if (type == I_FIND_PARENT) {
+ #if defined(MY_REPEATER_FEATURE)
+ if (sender != _nc.parentNodeId) { // no circular reference
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPR: find parent request
+ // node is in our range, update routing table - important if node has new repeater as parent
+ hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, sender);
+ // check if uplink functional - node can only be parent node if link to GW functional
+ // this also prevents circular references in case GW ooo
+ if(transportCheckUplink(false)){
+ _transportSM.lastUplinkCheck = hwMillis();
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok
+ // delay minimizes collisions
+ delay(hwMillis() & 0x3ff);
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance));
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request
+ }
+ }
+
+ #endif
+ return; // no further processing required
+ }
+ }
+ if (type == I_DISCOVER) {
+ if (last == _nc.parentNodeId) {
+ // random wait to minimize collisions
+ delay(hwMillis() & 0x3ff);
+ transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId));
+ // no return here (for fwd if repeater)
+ }
+ }
+ }
+ // controlled BC relay
+ #if defined(MY_REPEATER_FEATURE)
+ // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds
+ if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportReady()){
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding
+ transportRouteMessage(_msg);
+ }
+ #endif
+
+ // Call incoming message callback if available, but only if message received from parent
+ if (command != C_INTERNAL && last == _nc.parentNodeId && receive) {
+ receive(_msg);
+ }
+
+ }
+ else {
+ // msg not to us and not BC, relay msg
+ #if defined(MY_REPEATER_FEATURE)
+ if (isTransportReady()) {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:REL MSG\n")); // relay msg
+ // update routing table if message not received from parent
+ if (last != _nc.parentNodeId) {
+ hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, last);
+ }
+ if (command == C_INTERNAL) {
+ if (type == I_PING || type == I_PONG) {
+ uint8_t hopsCnt = _msg.getByte();
+ if (hopsCnt != MAX_HOPS) {
+ TRANSPORT_DEBUG(PSTR("TSF:MSG:REL PxNG,HP=%d\n"), hopsCnt);
+ _msg.set((uint8_t)(hopsCnt + 1));
+ }
+ }
+ }
+ // Relay this message to another node
+ transportRouteMessage(_msg);
+ }
+ #else
+ TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NORP\n")); // message relaying request, but not a repeater
+ #endif
+ }
+}
+
+void transportInvokeSanityCheck() {
+ if (!transportSanityCheck()) {
+ TRANSPORT_DEBUG(PSTR("!TSF:SANCHK:FAIL\n")); // sanity check fail
+ transportSwitchSM(stFailure);
+ return;
+ }
+ else {
+ TRANSPORT_DEBUG(PSTR("TSF:SANCHK:OK\n")); // sanity check ok
+ }
+}
+
+inline void transportProcessFIFO() {
+ if (_transportSM.transportActive) {
+ #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE)
+ if (hwMillis() - _transportSM.lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL) {
+ _transportSM.lastSanityCheck = hwMillis();
+ transportInvokeSanityCheck();
+ }
+ #endif
+ }
+ else {
+ // transport not active, nothing to be done
+ return;
+ }
+ uint8_t _processedMessages = MAX_SUBSEQ_MSGS;
+ // process all msgs in FIFO or counter exit
+ while (transportAvailable() && _processedMessages--) {
+ transportProcessMessage();
+ }
+ #if defined(MY_OTA_FIRMWARE_FEATURE)
+ if (isTransportReady()) {
+ // only process if transport ok
+ firmwareOTAUpdateRequest();
+ }
+ #endif
+}
+
+bool transportSendWrite(uint8_t to, MyMessage &message) {
+ // set protocol version and update last
+ mSetVersion(message, PROTOCOL_VERSION);
+ message.last = _nc.nodeId;
+
+ // sign message if required
+ if (!signerSignMsg(message)) {
+ TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN FAIL\n"));
+ setIndication(INDICATION_ERR_SIGN);
+ return false;
+ }
+
+ // msg length changes if signed
+ uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message);
+
+ // send
+ setIndication(INDICATION_TX);
+ bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length));
+
+ TRANSPORT_DEBUG(PSTR("%sTSF:MSG:SEND,%d-%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s\n"),
+ (ok || to == BROADCAST_ADDRESS ? "" : "!"),message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type,
+ mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, to==BROADCAST_ADDRESS ? "bc" : (ok ? "OK":"NACK"), message.getString(_convBuf));
+
+ return (ok || to==BROADCAST_ADDRESS);
+}
+
+// EOF MyTransport.cpp
\ No newline at end of file
diff --git a/core/MyTransport.h b/core/MyTransport.h
new file mode 100644
index 0000000..0b5a5c7
--- /dev/null
+++ b/core/MyTransport.h
@@ -0,0 +1,391 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+ /**
+ * @file MyTransport.h
+ *
+ * @defgroup MyTransportgrp MyTransport
+ * @ingroup internals
+ * @{
+ *
+ * Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
+ * - [!] Exclamation mark is prepended in case of error
+ * - SYSTEM:
+ * - TSM: messages emitted by the transport state machine
+ * - TSF: messages emitted by transport support functions
+ * - SUB SYSTEMS:
+ * - Transport state machine (TSM)
+ * - TSM:INIT from stInit Initialize transport and radio
+ * - TSM:FPAR from stParent Find parent
+ * - TSM:ID from stID Check/request node ID, if dynamic node ID set
+ * - TSM:UPL from stUplink Verify uplink connection by pinging GW
+ * - TSM:READY from stReady Transport is ready and fully operational
+ * - TSM:FAILURE from stFailure Failure in transport link or transport HW
+ * - Transport support function (TSF)
+ * - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW
+ * - TSF:ASID from @ref transportAssignNodeID(), assigns node ID
+ * - TSF:PING from @ref transportPingNode(), pings a node
+ * - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM
+ * - TSF:MSG from @ref transportProcessMessage(), processes incoming message
+ * - TSF:SANCHK from @ref transportInvokeSanityCheck(), calls transport-specific sanity check
+ * - TSF:ROUTE from @ref transportRouteMessage(), sends message
+ * - TSF:SEND from @ref transportSendRoute(), sends message if transport is ready (exposed)
+ *
+ * Transport debug log messages:
+ *
+ * |E| SYS | SUB | Message | Comment
+ * |-|------|-----------|-----------------------|---------------------------------------------------------------------
+ * | | TSM | INIT | | Transition to stInit state
+ * | | TSM | INIT | STATID,ID=%%d | Node ID is static
+ * | | TSM | INIT | TSP OK | Transport device configured and fully operational
+ * | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states
+ * |!| TSM | INIT | TSP FAIL | Transport device initialization failed
+ * | | TSM | FPAR | | Transition to stParent state
+ * | | TSM | FPAR | STATP=%%d | Static parent set, skip finding parent
+ * | | TSM | FPAR | OK | Parent node identified
+ * |!| TSM | FPAR | NO REPLY | No potential parents replied to find parent request
+ * |!| TSM | FPAR | FAIL | Finding parent failed
+ * | | TSM | ID | | Transition to stID state
+ * | | TSM | ID | OK,ID=%%d | Node ID is valid
+ * | | TSM | ID | REQ | Request node ID from controller
+ * |!| TSM | ID | FAIL,ID=%%d | ID verification failed, ID invalid
+ * | | TSM | UPL | | Transition to stUplink state
+ * | | TSM | UPL | OK | Uplink OK, GW returned ping
+ * |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged
+ * | | TSM | READY | | Transition to stReady, i.e. transport is ready and fully operational
+ * |!| TSM | READY | UPL FAIL,SNP | Too many failed uplink transmissions, search new parent
+ * |!| TSM | READY | FAIL,STATP | Too many failed uplink transmissions, static parent enforced
+ * | | TSM | FAILURE | | Transition to stFailure state
+ * | | TSM | FAILURE | PDT | Power-down transport
+ * | | TSM | FAILURE | RE-INIT | Attempt to re-initialize transport
+ * | | TSF | CHKUPL | OK | Uplink OK
+ * | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals
+ * | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N)
+ * | | TSF | CHKUPL | FAIL | No reply received when checking uplink
+ * | | TSF | ASID | OK,ID=%%d | Node ID assigned
+ * |!| TSF | ASID | FAIL,ID=%%d | Assigned ID is invalid
+ * | | TSF | PING | SEND,TO=%%d | Send ping to destination (TO)
+ * | | TSF | MSG | ACK REQ | ACK message requested
+ * | | TSF | MSG | ACK | ACK message, do not proceed but forward to callback
+ * | | TSF | MSG | FPAR RES,ID=%%d,D=%%d | Response to find parent received from node (ID) with distance (D) to GW
+ * | | TSF | MSG | FPAR PREF FOUND | Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID
+ * | | TSF | MSG | FPAR OK,ID=%%d,D=%%d | Find parent response from node (ID) is valid, distance (D) to GW
+ * | | TSF | MSG | FPAR INACTIVE | Find parent response received, but no find parent request active, skip response
+ * | | TSF | MSG | FPAR REQ,ID=%%d | Find parent request from node (ID)
+ * | | TSF | MSG | PINGED,ID=%%d,HP=%%d | Node pinged by node (ID) with (HP) hops
+ * | | TSF | MSG | PONG RECV,HP=%%d | Pinged node replied with (HP) hops
+ * | | TSF | MSG | BC | Broadcast message received
+ * | | TSF | MSG | GWL OK | Link to GW ok
+ * | | TSF | MSG | FWD BC MSG | Controlled broadcast message forwarding
+ * | | TSF | MSG | REL MSG | Relay message
+ * | | TSF | MSG | REL PxNG,HP=%%d | Relay PING/PONG message, increment hop counter (HP)
+ * |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch
+ * |!| TSF | MSG | SIGN VERIFY FAIL | Signing verification failed
+ * |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped
+ * |!| TSF | MSG | SIGN FAIL | Signing message failed
+ * |!| TSF | MSG | GWL FAIL | GW uplink failed
+ * | | TSF | SANCHK | OK | Sanity check passed
+ * |!| TSF | SANCHK | FAIL | Sanity check failed, attempt to re-initialize radio
+ * | | TSF | CRT | OK | Clearing routing table successful
+ * |!| TSF | ROUTE | FPAR ACTIVE | Finding parent active, message not sent
+ * |!| TSF | ROUTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent
+ * |!| TSF | SEND | TNR | Transport not ready, message cannot be sent
+ *
+ * Incoming / outgoing messages:
+ *
+ * See here for more detail on the format and definitons.
+ *
+ * Receiving a message
+ * - TSF:MSG:READ,sender-last-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d:%%s
+ *
+ * Sending a message
+ * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d,ft=%%d,st=%%s:%%s
+ *
+ * Message fields:
+ * - s=sensor ID
+ * - c=command
+ * - t=msg type
+ * - pt=payload type
+ * - l=length
+ * - ft=failed uplink transmission counter
+ * - sg=signing flag
+ *
+ * @brief API declaration for MyTransport
+ *
+ */
+
+#ifndef MyTransport_h
+#define MyTransport_h
+
+#include "MySensorsCore.h"
+
+ // debug
+#if defined(MY_DEBUG)
+ #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug
+#else
+ #define TRANSPORT_DEBUG(x,...) //!< debug NULL
+#endif
+
+#if defined(MY_REPEATER_FEATURE)
+ #define TRANSMISSION_FAILURES 10 //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes
+#else
+ #define TRANSMISSION_FAILURES 5 //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes
+#endif
+#define TIMEOUT_FAILURE_STATE 10000 //!< duration failure state
+#define STATE_TIMEOUT 2000 //!< general state timeout
+#define STATE_RETRIES 3 //!< retries before switching to FAILURE
+#define AUTO 255 //!< ID 255 is reserved for auto initialization of nodeId.
+#define BROADCAST_ADDRESS ((uint8_t)255) //!< broadcasts are addressed to ID 255
+#define DISTANCE_INVALID ((uint8_t)255) //!< invalid distance when searching for parent
+#define MAX_HOPS ((uint8_t)254) //!< maximal mumber of hops for ping/pong
+#define INVALID_HOPS ((uint8_t)255) //!< invalid hops
+#define MAX_SUBSEQ_MSGS 5 //!< Maximum number of subsequentially processed messages in FIFO (to prevent transport deadlock if HW issue)
+#define CHKUPL_INTERVAL ((uint32_t)10000) //!< Minimum time interval to re-check uplink
+
+#define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined
+#define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid
+#define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid
+
+ /**
+ * @brief SM state
+ *
+ * This structure stores SM state definitions
+ */
+struct transportState {
+ void(*Transition)(); //!< state transition function
+ void(*Update)(); //!< state update function
+};
+
+/**
+* @brief Status variables and SM state
+*
+* This structure stores transport status and SM variables
+*/
+typedef struct {
+ transportState* currentState; //!< pointer to current fsm state
+ uint32_t stateEnter; //!< state enter timepoint
+ uint32_t lastUplinkCheck; //!< last uplink check, required to prevent GW flooding
+ uint32_t lastSanityCheck; //!< last sanity check
+ // 8 bits
+ bool findingParentNode : 1; //!< flag finding parent node is active
+ bool preferredParentFound : 1; //!< flag preferred parent found
+ bool uplinkOk : 1; //!< flag uplink ok
+ bool pingActive : 1; //!< flag ping active
+ bool transportActive : 1; //!< flag transport active
+ uint8_t reserved : 3; //!< reserved
+ // 8 bits
+ uint8_t retries : 4; //!< retries / state re-enter
+ uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions
+ // 8 bits
+ uint8_t pingResponse; //!< stores hops received in I_PONG
+} __attribute__((packed)) transportSM;
+
+
+// PRIVATE functions
+
+/**
+* @brief Initialize SM variables and transport HW
+*/
+void stInitTransition();
+/**
+* @brief Find parent
+*/
+void stParentTransition();
+/**
+* @brief Verify find parent responses
+*/
+void stParentUpdate();
+/**
+* @brief Send ID request
+*/
+void stIDTransition();
+/**
+* @brief Verify ID response and GW link
+*/
+void stIDUpdate();
+/**
+* @brief Send uplink ping request
+*/
+void stUplinkTransition();
+/**
+* @brief Set transport OK
+*/
+void stReadyTransition();
+/**
+* @brief Monitor transport link
+*/
+void stReadyUpdate();
+/**
+* @brief Transport failure and power down radio
+*/
+void stFailureTransition();
+/**
+* @brief Re-initialize transport after timeout
+*/
+void stFailureUpdate();
+/**
+* @brief Switch SM state
+* @param newState New state to switch SM to
+*/
+void transportSwitchSM(transportState& newState);
+/**
+* @brief Update SM state
+*/
+void transportUpdateSM();
+/**
+* @brief Request time in current SM state
+* @return ms in current state
+*/
+uint32_t transportTimeInState();
+/**
+* @brief Call transport driver sanity check
+*/
+void transportInvokeSanityCheck();
+/**
+* @brief Process all pending messages in RX FIFO
+*/
+void transportProcessFIFO();
+/**
+* @brief Receive message from RX FIFO and process
+*/
+void transportProcessMessage();
+/**
+* @brief Assign node ID
+* @param newNodeId New node ID
+* @return true if node ID valid and successfully assigned
+*/
+bool transportAssignNodeID(uint8_t newNodeId);
+/**
+* @brief Wait and process messages for a defined amount of time until specified message received
+* @param ms Time to wait and process incoming messages in ms
+* @param cmd Specific command
+* @param msgtype Specific message type
+* @return true if specified command received within waiting time
+*/
+bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype);
+/**
+* @brief Ping node
+* @param targetId Node to be pinged
+* @return hops from pinged node or 255 if no answer received within 2000ms
+*/
+uint8_t transportPingNode(uint8_t targetId);
+/**
+* @brief Send and route message according to destination
+*
+* This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is not ready
+*
+* @param message
+* @return true if message sent successfully
+*/
+bool transportRouteMessage(MyMessage &message);
+/**
+* @brief Send and route message according to destination with transport state check
+* @param message
+* @return true if message sent successfully and false if sending error or transport !OK
+*/
+bool transportSendRoute(MyMessage &message);
+/**
+* @brief Send message to recipient
+* @param to Recipient of message
+* @param message
+* @return true if message sent successfully
+*/
+bool transportSendWrite(uint8_t to, MyMessage &message);
+/**
+* @brief Check uplink to GW, includes flooding control
+* @param force to override flood control timer
+* @return true if uplink ok
+*/
+bool transportCheckUplink(bool force);
+
+// PUBLIC functions
+
+/**
+* @brief Initialize transport and SM
+*/
+void transportInitialize();
+/**
+* @brief Process FIFO msg and update SM
+*/
+void transportProcess();
+/**
+* @brief Flag transport ready
+* @return true if transport is initialize and ready
+*/
+bool isTransportReady();
+/**
+* @brief Flag searching parent ongoing
+* @return true if transport is searching for parent
+*/
+bool isTransportSearchingParent();
+/**
+* @brief Clear routing table
+*/
+void transportClearRoutingTable();
+/**
+* @brief Return heart beat, i.e. ms in current state
+*/
+uint32_t transportGetHeartbeat();
+
+// interface functions for radio driver
+
+/**
+* @brief Initialize transport HW
+* @return true if initialization successful
+*/
+bool transportInit();
+/**
+* @brief Set node address
+*/
+void transportSetAddress(uint8_t address);
+/**
+* @brief Retrieve node address
+*/
+uint8_t transportGetAddress();
+/**
+* @brief Send message
+* @param to recipient
+* @param data message to be sent
+* @param len length of message (header + payload)
+* @return true if message sent successfully
+*/
+bool transportSend(uint8_t to, const void* data, uint8_t len);
+/**
+* @brief Verify if RX FIFO has pending messages
+* @return true if message available in RX FIFO
+*/
+bool transportAvailable();
+/**
+* @brief Sanity check for transport: is transport still responsive?
+* @return true transport ok
+*/
+bool transportSanityCheck();
+/**
+* @brief Receive message from FIFO
+* @return length of recevied message (header + payload)
+*/
+uint8_t transportReceive(void* data);
+/**
+* @brief Power down transport HW
+*/
+void transportPowerDown();
+
+
+#endif // MyTransport_h
+/** @}*/
diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp
new file mode 100644
index 0000000..6d7f407
--- /dev/null
+++ b/core/MyTransportNRF24.cpp
@@ -0,0 +1,148 @@
+/*
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "MyConfig.h"
+#include "MyTransport.h"
+#include "drivers/RF24/RF24.h"
+#include "drivers/CircularBuffer/CircularBuffer.h"
+
+#if defined(MY_RF24_ENABLE_ENCRYPTION)
+ #include "drivers/AES/AES.h"
+#endif
+
+#ifdef MY_RF24_IRQ_PIN
+typedef struct _transportQueuedMessage
+{
+ uint8_t m_len; // Length of the data
+ uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data
+} transportQueuedMessage;
+
+/** Buffer to store queued messages in. */
+static transportQueuedMessage transportRxQueueStorage[MY_RX_MESSAGE_BUFFER_SIZE];
+/** Circular buffer, which uses the transportRxQueueStorage and administers stored messages. */
+static CircularBuffer transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE);
+
+static volatile uint8_t transportLostMessageCount = 0;
+
+static void transportRxCallback(void)
+{
+ // Called for each message received by radio, from interrupt context.
+ // This function _must_ call RF24_readMessage() to de-assert interrupt line!
+ if (!transportRxQueue.full())
+ {
+ transportQueuedMessage* msg = transportRxQueue.getFront();
+ msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR
+ (void)transportRxQueue.pushFront(msg);
+ } else {
+ // Queue is full. Discard message.
+ (void)RF24_readMessage(NULL); // Read payload & clear RX_DR
+ // Keep track of messages lost. Max 255, prevent wrapping.
+ if (transportLostMessageCount < 255)
+ {
+ ++transportLostMessageCount;
+ }
+ }
+}
+#endif
+
+#if defined(MY_RF24_ENABLE_ENCRYPTION)
+ AES _aes;
+ uint8_t _dataenc[32] = {0};
+ uint8_t _psk[16];
+#endif
+
+bool transportInit() {
+ #if defined(MY_RF24_ENABLE_ENCRYPTION)
+ hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
+ //set up AES-key
+ _aes.set_key(_psk, 16);
+ // Make sure it is purged from memory when set
+ memset(_psk, 0, 16);
+ #endif
+
+ #ifdef MY_RF24_IRQ_PIN
+ RF24_registerReceiveCallback( transportRxCallback );
+ #endif
+ return RF24_initialize();
+}
+
+void transportSetAddress(uint8_t address) {
+ RF24_setNodeAddress(address);
+ RF24_startListening();
+}
+
+uint8_t transportGetAddress() {
+ return RF24_getNodeID();
+}
+
+bool transportSend(uint8_t recipient, const void* data, uint8_t len) {
+ #if defined(MY_RF24_ENABLE_ENCRYPTION)
+ // copy input data because it is read-only
+ memcpy(_dataenc,data,len);
+ // has to be adjusted, WIP!
+ _aes.set_IV(0);
+ len = len > 16 ? 32 : 16;
+ //encrypt data
+ _aes.cbc_encrypt(_dataenc, _dataenc, len/16);
+ bool status = RF24_sendMessage( recipient, _dataenc, len );
+ #else
+ bool status = RF24_sendMessage( recipient, data, len );
+ #endif
+
+ return status;
+}
+
+bool transportAvailable() {
+ #ifdef MY_RF24_IRQ_PIN
+ (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning
+ return !transportRxQueue.empty();
+ #else
+ return RF24_isDataAvailable();
+ #endif
+}
+
+bool transportSanityCheck() {
+ return RF24_sanityCheck();
+}
+
+uint8_t transportReceive(void* data) {
+ uint8_t len = 0;
+ #ifdef MY_RF24_IRQ_PIN
+ transportQueuedMessage* msg = transportRxQueue.getBack();
+ if (msg)
+ {
+ len = msg->m_len;
+ (void)memcpy(data, msg->m_data, len);
+ (void)transportRxQueue.popBack();
+ }
+ #else
+ len = RF24_readMessage(data);
+ #endif
+ #if defined(MY_RF24_ENABLE_ENCRYPTION)
+ // has to be adjusted, WIP!
+ _aes.set_IV(0);
+ // decrypt data
+ _aes.cbc_decrypt((byte*)(data), (byte*)(data), len>16?2:1);
+ #endif
+ return len;
+}
+
+void transportPowerDown() {
+ RF24_powerDown();
+}
diff --git a/libraries/MySensors/core/MyTransportRFM69.cpp b/core/MyTransportRFM69.cpp
similarity index 92%
rename from libraries/MySensors/core/MyTransportRFM69.cpp
rename to core/MyTransportRFM69.cpp
index 35305ce..b5aec33 100644
--- a/libraries/MySensors/core/MyTransportRFM69.cpp
+++ b/core/MyTransportRFM69.cpp
@@ -1,4 +1,4 @@
-/**
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
@@ -32,7 +32,7 @@ bool transportInit() {
#ifdef MY_RFM69_ENABLE_ENCRYPTION
uint8_t _psk[16];
hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
- _radio.encrypt(_psk);
+ _radio.encrypt((const char*)_psk);
memset(_psk, 0, 16); // Make sure it is purged from memory when set
#endif
return true;
@@ -53,14 +53,15 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) {
return _radio.sendWithRetry(to,data,len);
}
-bool transportAvailable(uint8_t *to) {
- if (_radio.TARGETID == BROADCAST_ADDRESS)
- *to = BROADCAST_ADDRESS;
- else
- *to = _address;
+bool transportAvailable() {
return _radio.receiveDone();
}
+bool transportSanityCheck() {
+ // not implemented yet
+ return true;
+}
+
uint8_t transportReceive(void* data) {
memcpy(data,(const void *)_radio.DATA, _radio.DATALEN);
// Send ack back if this message wasn't a broadcast
diff --git a/libraries/MySensors/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp
similarity index 98%
rename from libraries/MySensors/core/MyTransportRS485.cpp
rename to core/MyTransportRS485.cpp
index dff19b2..814f721 100644
--- a/libraries/MySensors/core/MyTransportRS485.cpp
+++ b/core/MyTransportRS485.cpp
@@ -1,4 +1,4 @@
-/**
+/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
@@ -126,7 +126,7 @@ void _serialReset(){
// our station ID, then look for a registered command that matches the
// command code. If all the above is true, execute the command's
// function.
-boolean _serialProcess()
+bool _serialProcess()
{
char inch;
unsigned char i;
@@ -332,17 +332,16 @@ uint8_t transportGetAddress() {
}
-bool transportAvailable(uint8_t *to) {
+bool transportAvailable() {
_serialProcess();
- if (_packet_received == true) {
- if (_recStation==BROADCAST_ADDRESS) {
- *to = BROADCAST_ADDRESS;
- }
- else { *to = _nodeId; }
- }
return _packet_received;
}
+bool transportSanityCheck() {
+ // not implemented yet
+ return true;
+}
+
uint8_t transportReceive(void* data) {
if (_packet_received) {
memcpy(data,_data,_packet_len);
diff --git a/libraries/MySensors/core/Version.h b/core/Version.h
similarity index 60%
rename from libraries/MySensors/core/Version.h
rename to core/Version.h
index fce3bc7..e91949f 100644
--- a/libraries/MySensors/core/Version.h
+++ b/core/Version.h
@@ -1,11 +1,11 @@
/***
- * This file defines the Sensor library version number
+ * This file defines the Sensor library version number
* Normally, contributors should not modify this directly
* as it is managed by the MySensors Bot.
*/
#ifndef Version_h
#define Version_h
-#define LIBRARY_VERSION "2.0.0-beta"
+#define MYSENSORS_LIBRARY_VERSION "2.0.1-beta"
#endif
diff --git a/libraries/MySensors/drivers/AES/AES.cpp b/drivers/AES/AES.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AES/AES.cpp
rename to drivers/AES/AES.cpp
diff --git a/libraries/MySensors/drivers/AES/AES.h b/drivers/AES/AES.h
similarity index 100%
rename from libraries/MySensors/drivers/AES/AES.h
rename to drivers/AES/AES.h
diff --git a/libraries/MySensors/drivers/AES/AES_config.h b/drivers/AES/AES_config.h
similarity index 94%
rename from libraries/MySensors/drivers/AES/AES_config.h
rename to drivers/AES/AES_config.h
index 62eb13b..d0ae828 100644
--- a/libraries/MySensors/drivers/AES/AES_config.h
+++ b/drivers/AES/AES_config.h
@@ -31,6 +31,8 @@
#define PSTR(x) (x)
#elif defined(ARDUINO_ARCH_ESP8266)
#include
+#elif defined(ARDUINO_ARCH_SAMD)
+ #define printf_P printf
#else
#include
#endif
diff --git a/libraries/MySensors/drivers/AES/Doxyfile b/drivers/AES/Doxyfile
similarity index 100%
rename from libraries/MySensors/drivers/AES/Doxyfile
rename to drivers/AES/Doxyfile
diff --git a/libraries/MySensors/drivers/AES/Makefile b/drivers/AES/Makefile
similarity index 100%
rename from libraries/MySensors/drivers/AES/Makefile
rename to drivers/AES/Makefile
diff --git a/libraries/MySensors/drivers/AES/README.MD b/drivers/AES/README.MD
similarity index 100%
rename from libraries/MySensors/drivers/AES/README.MD
rename to drivers/AES/README.MD
diff --git a/libraries/MySensors/drivers/AES/examples/aes/aes.pde b/drivers/AES/examples/aes/aes.pde
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples/aes/aes.pde
rename to drivers/AES/examples/aes/aes.pde
diff --git a/libraries/MySensors/drivers/AES/examples/test_vectors/RESOURCES b/drivers/AES/examples/test_vectors/RESOURCES
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples/test_vectors/RESOURCES
rename to drivers/AES/examples/test_vectors/RESOURCES
diff --git a/libraries/MySensors/drivers/AES/examples/test_vectors/known_answers.txt b/drivers/AES/examples/test_vectors/known_answers.txt
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples/test_vectors/known_answers.txt
rename to drivers/AES/examples/test_vectors/known_answers.txt
diff --git a/libraries/MySensors/drivers/AES/examples/test_vectors/test_vectors.pde b/drivers/AES/examples/test_vectors/test_vectors.pde
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples/test_vectors/test_vectors.pde
rename to drivers/AES/examples/test_vectors/test_vectors.pde
diff --git a/libraries/MySensors/drivers/AES/examples_Rpi/Makefile b/drivers/AES/examples_Rpi/Makefile
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples_Rpi/Makefile
rename to drivers/AES/examples_Rpi/Makefile
diff --git a/libraries/MySensors/drivers/AES/examples_Rpi/RESOURCES b/drivers/AES/examples_Rpi/RESOURCES
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples_Rpi/RESOURCES
rename to drivers/AES/examples_Rpi/RESOURCES
diff --git a/libraries/MySensors/drivers/AES/examples_Rpi/aes.cpp b/drivers/AES/examples_Rpi/aes.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples_Rpi/aes.cpp
rename to drivers/AES/examples_Rpi/aes.cpp
diff --git a/libraries/MySensors/drivers/AES/examples_Rpi/known_answers.txt b/drivers/AES/examples_Rpi/known_answers.txt
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples_Rpi/known_answers.txt
rename to drivers/AES/examples_Rpi/known_answers.txt
diff --git a/libraries/MySensors/drivers/AES/examples_Rpi/test_vectors.cpp b/drivers/AES/examples_Rpi/test_vectors.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AES/examples_Rpi/test_vectors.cpp
rename to drivers/AES/examples_Rpi/test_vectors.cpp
diff --git a/libraries/MySensors/drivers/AES/keywords.txt b/drivers/AES/keywords.txt
similarity index 100%
rename from libraries/MySensors/drivers/AES/keywords.txt
rename to drivers/AES/keywords.txt
diff --git a/libraries/MySensors/drivers/AES/printf.h b/drivers/AES/printf.h
similarity index 100%
rename from libraries/MySensors/drivers/AES/printf.h
rename to drivers/AES/printf.h
diff --git a/libraries/MySensors/drivers/ATSHA204/ATSHA204.cpp b/drivers/ATSHA204/ATSHA204.cpp
similarity index 81%
rename from libraries/MySensors/drivers/ATSHA204/ATSHA204.cpp
rename to drivers/ATSHA204/ATSHA204.cpp
index 16b82c3..0c7de23 100644
--- a/libraries/MySensors/drivers/ATSHA204/ATSHA204.cpp
+++ b/drivers/ATSHA204/ATSHA204.cpp
@@ -1,58 +1,26 @@
#include "Arduino.h"
#include "ATSHA204.h"
-// atsha204Class Constructor
-// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin
-// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin
-// As well as the bit value for each of those registers
-ATSHA204Class::ATSHA204Class(uint8_t pin)
-{
-#if defined(ARDUINO_ARCH_AVR)
- device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin
- uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers
-
- // Point to data direction register port of pin
- device_port_DDR = portModeRegister(port);
- // Point to output register of pin
- device_port_OUT = portOutputRegister(port);
- // Point to input register of pin
- device_port_IN = portInputRegister(port);
-#else
- device_pin = pin;
+/* Local data and function prototypes */
+
+static uint8_t device_pin;
+#ifdef ARDUINO_ARCH_AVR
+static volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN;
#endif
-}
-
-void ATSHA204Class::getSerialNumber(uint8_t * response)
-{
- uint8_t readCommand[READ_COUNT];
- uint8_t readResponse[READ_4_RSP_SIZE];
-
- /* read from bytes 0->3 of config zone */
- uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03);
- if (!returnCode)
- {
- for (int i=0; i<4; i++) // store bytes 0-3 into respones array
- response[i] = readResponse[SHA204_BUFFER_POS_DATA+i];
-
- /* read from bytes 8->11 of config zone */
- returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47);
-
- for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array
- response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)];
-
- if (!returnCode)
- { /* Finally if last two reads were successful, read byte 8 of the SN */
- returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8);
- response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE
- }
- }
-
- return;
-}
+static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc);
+static uint8_t sha204c_check_crc(uint8_t *response);
+static void swi_set_signal_pin(uint8_t is_high);
+static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer);
+static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer);
+static uint8_t swi_send_byte(uint8_t value);
+static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response);
+static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address);
+static uint8_t sha204c_resync(uint8_t size, uint8_t *response);
+static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout);
/* SWI bit bang functions */
-void ATSHA204Class::swi_set_signal_pin(uint8_t is_high)
+static void swi_set_signal_pin(uint8_t is_high)
{
SHA204_SET_OUTPUT();
@@ -62,7 +30,7 @@ void ATSHA204Class::swi_set_signal_pin(uint8_t is_high)
SHA204_POUT_LOW();
}
-uint8_t ATSHA204Class::swi_send_bytes(uint8_t count, uint8_t *buffer)
+static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer)
{
uint8_t i, bit_mask;
@@ -72,23 +40,23 @@ uint8_t ATSHA204Class::swi_send_bytes(uint8_t count, uint8_t *buffer)
// Set signal pin as output.
SHA204_POUT_HIGH();
SHA204_SET_OUTPUT();
-
+
// Wait turn around time.
delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY;
- for (i = 0; i < count; i++)
+ for (i = 0; i < count; i++)
{
- for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
+ for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
{
- if (bit_mask & buffer[i])
+ if (bit_mask & buffer[i])
{
SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin;
delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin;
delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7;
}
- else
+ else
{
// Send a zero bit.
SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin;
@@ -106,12 +74,12 @@ uint8_t ATSHA204Class::swi_send_bytes(uint8_t count, uint8_t *buffer)
return SWI_FUNCTION_RETCODE_SUCCESS;
}
-uint8_t ATSHA204Class::swi_send_byte(uint8_t value)
+static uint8_t swi_send_byte(uint8_t value)
{
return swi_send_bytes(1, &value);
}
-uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
+static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer)
{
uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS;
uint8_t i;
@@ -124,11 +92,11 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
// Configure signal pin as input.
SHA204_SET_INPUT();
-
+
// Receive bits and store in buffer.
for (i = 0; i < count; i++)
{
- for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
+ for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
{
pulse_count = 0;
@@ -138,23 +106,23 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
timeout_count = START_PULSE_TIME_OUT;
// Detect start bit.
- while (--timeout_count > 0)
+ while (--timeout_count > 0)
{
// Wait for falling edge.
if (SHA204_PIN_READ() == 0)
break;
}
- if (timeout_count == 0)
+ if (timeout_count == 0)
{
status = SWI_FUNCTION_RETCODE_TIMEOUT;
break;
}
- do
+ do
{
// Wait for rising edge.
- if (SHA204_PIN_READ() != 0)
+ if (SHA204_PIN_READ() != 0)
{
// For an Atmel microcontroller this might be faster than "pulse_count++".
pulse_count = 1;
@@ -162,7 +130,7 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
}
} while (--timeout_count > 0);
- if (pulse_count == 0)
+ if (pulse_count == 0)
{
status = SWI_FUNCTION_RETCODE_TIMEOUT;
break;
@@ -175,9 +143,9 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
timeout_count = ZERO_PULSE_TIME_OUT;
// Detect possible edge indicating zero bit.
- do
+ do
{
- if (SHA204_PIN_READ() == 0)
+ if (SHA204_PIN_READ() == 0)
{
// For an Atmel microcontroller this might be faster than "pulse_count++".
pulse_count = 2;
@@ -187,9 +155,9 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
// Wait for rising edge of zero pulse before returning. Otherwise we might interpret
// its rising edge as the next start pulse.
- if (pulse_count == 2)
+ if (pulse_count == 2)
{
- do
+ do
{
if (SHA204_PIN_READ() != 0)
break;
@@ -206,7 +174,7 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
}
interrupts(); //swi_enable_interrupts();
- if (status == SWI_FUNCTION_RETCODE_TIMEOUT)
+ if (status == SWI_FUNCTION_RETCODE_TIMEOUT)
{
if (i > 0)
// Indicate that we timed out after having received at least one byte.
@@ -217,12 +185,7 @@ uint8_t ATSHA204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
/* Physical functions */
-void ATSHA204Class::sha204c_sleep()
-{
- swi_send_byte(SHA204_SWI_FLAG_SLEEP);
-}
-
-uint8_t ATSHA204Class::sha204p_receive_response(uint8_t size, uint8_t *response)
+static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response)
{
uint8_t count_byte;
uint8_t i;
@@ -234,7 +197,7 @@ uint8_t ATSHA204Class::sha204p_receive_response(uint8_t size, uint8_t *response)
(void) swi_send_byte(SHA204_SWI_FLAG_TX);
ret_code = swi_receive_bytes(size, response);
- if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL)
+ if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL)
{
count_byte = response[SHA204_BUFFER_POS_COUNT];
if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size))
@@ -254,35 +217,7 @@ uint8_t ATSHA204Class::sha204p_receive_response(uint8_t size, uint8_t *response)
/* Communication functions */
-uint8_t ATSHA204Class::sha204c_wakeup(uint8_t *response)
-{
- swi_set_signal_pin(0);
- delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH);
- swi_set_signal_pin(1);
- delay(SHA204_WAKEUP_DELAY);
-
- uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response);
- if (ret_code != SHA204_SUCCESS)
- return ret_code;
-
- // Verify status response.
- if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN)
- ret_code = SHA204_INVALID_SIZE;
- else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP)
- ret_code = SHA204_COMM_FAIL;
- else
- {
- if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33)
- || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43))
- ret_code = SHA204_BAD_CRC;
- }
- if (ret_code != SHA204_SUCCESS)
- delay(SHA204_COMMAND_EXEC_MAX);
-
- return ret_code;
-}
-
-uint8_t ATSHA204Class::sha204c_resync(uint8_t size, uint8_t *response)
+static uint8_t sha204c_resync(uint8_t size, uint8_t *response)
{
// Try to re-synchronize without sending a Wake token
// (step 1 of the re-synchronization process).
@@ -294,8 +229,8 @@ uint8_t ATSHA204Class::sha204c_resync(uint8_t size, uint8_t *response)
// We lost communication. Send a Wake pulse and try
// to receive a response (steps 2 and 3 of the
// re-synchronization process).
- sha204c_sleep();
- ret_code = sha204c_wakeup(response);
+ atsha204_sleep();
+ ret_code = atsha204_wakeup(response);
// Translate a return value of success into one
// that indicates that the device had to be woken up
@@ -303,7 +238,7 @@ uint8_t ATSHA204Class::sha204c_resync(uint8_t size, uint8_t *response)
return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code);
}
-uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout)
+static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout)
{
uint8_t ret_code = SHA204_FUNC_FAIL;
uint8_t ret_code_resync;
@@ -322,7 +257,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
// Retry loop for sending a command and receiving a response.
n_retries_send = SHA204_RETRY_COUNT + 1;
- while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS))
+ while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS))
{
// Send command.
ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD);
@@ -331,7 +266,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
else
ret_code = swi_send_bytes(count, tx_buffer);
- if (ret_code != SHA204_SUCCESS)
+ if (ret_code != SHA204_SUCCESS)
{
if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
return ret_code; // The device seems to be dead in the water.
@@ -344,7 +279,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
// Retry loop for receiving a response.
n_retries_receive = SHA204_RETRY_COUNT + 1;
- while (n_retries_receive-- > 0)
+ while (n_retries_receive-- > 0)
{
// Reset response buffer.
for (i = 0; i < rx_size; i++)
@@ -352,14 +287,14 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
// Poll for response.
timeout_countdown = execution_timeout_us;
- do
+ do
{
ret_code = sha204p_receive_response(rx_size, rx_buffer);
timeout_countdown -= SHA204_RESPONSE_TIMEOUT;
- }
+ }
while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE));
- if (ret_code == SHA204_RX_NO_RESPONSE)
+ if (ret_code == SHA204_RX_NO_RESPONSE)
{
// We did not receive a response. Re-synchronize and send command again.
if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
@@ -389,7 +324,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
// We received a response of valid size.
// Check the consistency of the response.
ret_code = sha204c_check_crc(rx_buffer);
- if (ret_code == SHA204_SUCCESS)
+ if (ret_code == SHA204_SUCCESS)
{
// Received valid response.
if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN)
@@ -405,7 +340,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
return SHA204_PARSE_ERROR;
if (status_byte == SHA204_STATUS_BYTE_EXEC)
return SHA204_CMD_FAIL;
- if (status_byte == SHA204_STATUS_BYTE_COMM)
+ if (status_byte == SHA204_STATUS_BYTE_COMM)
{
// In case of the device status byte indicating a communication
// error this function exits the retry loop for receiving a response
@@ -420,7 +355,7 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
return ret_code;
}
- else
+ else
{
// Received response with incorrect CRC.
ret_code_resync = sha204c_resync(rx_size, rx_buffer);
@@ -445,7 +380,8 @@ uint8_t ATSHA204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s
/* Marshaling functions */
-uint8_t ATSHA204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address)
+
+static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address)
{
uint8_t rx_size;
@@ -462,16 +398,113 @@ uint8_t ATSHA204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint
return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY);
}
-uint8_t ATSHA204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
+/* CRC Calculator and Checker */
+
+static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc)
+{
+ uint8_t counter;
+ uint16_t crc_register = 0;
+ uint16_t polynom = 0x8005;
+ uint8_t shift_register;
+ uint8_t data_bit, crc_bit;
+
+ for (counter = 0; counter < length; counter++)
+ {
+ for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1)
+ {
+ data_bit = (data[counter] & shift_register) ? 1 : 0;
+ crc_bit = crc_register >> 15;
+
+ // Shift CRC to the left by 1.
+ crc_register <<= 1;
+
+ if ((data_bit ^ crc_bit) != 0)
+ crc_register ^= polynom;
+ }
+ }
+ crc[0] = (uint8_t) (crc_register & 0x00FF);
+ crc[1] = (uint8_t) (crc_register >> 8);
+}
+
+static uint8_t sha204c_check_crc(uint8_t *response)
+{
+ uint8_t crc[SHA204_CRC_SIZE];
+ uint8_t count = response[SHA204_BUFFER_POS_COUNT];
+
+ count -= SHA204_CRC_SIZE;
+ sha204c_calculate_crc(count, response, crc);
+
+ return (crc[0] == response[count] && crc[1] == response[count + 1])
+ ? SHA204_SUCCESS : SHA204_BAD_CRC;
+}
+
+/* Public functions */
+
+void atsha204_init(uint8_t pin)
+{
+#if defined(ARDUINO_ARCH_AVR)
+ device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin
+ uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers
+
+ // Point to data direction register port of pin
+ device_port_DDR = portModeRegister(port);
+ // Point to output register of pin
+ device_port_OUT = portOutputRegister(port);
+ // Point to input register of pin
+ device_port_IN = portInputRegister(port);
+#else
+ device_pin = pin;
+#endif
+}
+
+void atsha204_idle(void)
+{
+ swi_send_byte(SHA204_SWI_FLAG_IDLE);
+}
+
+void atsha204_sleep(void)
+{
+ swi_send_byte(SHA204_SWI_FLAG_SLEEP);
+}
+
+uint8_t atsha204_wakeup(uint8_t *response)
+{
+ swi_set_signal_pin(0);
+ delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH);
+ swi_set_signal_pin(1);
+ delay(SHA204_WAKEUP_DELAY);
+
+ uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response);
+ if (ret_code != SHA204_SUCCESS)
+ return ret_code;
+
+ // Verify status response.
+ if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN)
+ ret_code = SHA204_INVALID_SIZE;
+ else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP)
+ ret_code = SHA204_COMM_FAIL;
+ else
+ {
+ if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33)
+ || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43))
+ ret_code = SHA204_BAD_CRC;
+ }
+ if (ret_code != SHA204_SUCCESS)
+ delay(SHA204_COMMAND_EXEC_MAX);
+
+ return ret_code;
+}
+
+uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer)
{
uint8_t poll_delay, poll_timeout, response_size;
uint8_t *p_buffer;
uint8_t len;
(void)tx_size;
-
+
// Supply delays and response size.
- switch (op_code)
+ switch (op_code)
{
case SHA204_GENDIG:
poll_delay = GENDIG_DELAY;
@@ -538,43 +571,30 @@ uint8_t ATSHA204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t
&rx_buffer[0], poll_delay, poll_timeout);
}
-/* CRC Calculator and Checker */
-
-void ATSHA204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc)
+uint8_t atsha204_getSerialNumber(uint8_t * response)
{
- uint8_t counter;
- uint16_t crc_register = 0;
- uint16_t polynom = 0x8005;
- uint8_t shift_register;
- uint8_t data_bit, crc_bit;
+ uint8_t readCommand[READ_COUNT];
+ uint8_t readResponse[READ_4_RSP_SIZE];
- for (counter = 0; counter < length; counter++)
+ /* read from bytes 0->3 of config zone */
+ uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03);
+ if (!returnCode)
{
- for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1)
- {
- data_bit = (data[counter] & shift_register) ? 1 : 0;
- crc_bit = crc_register >> 15;
+ for (int i=0; i<4; i++) // store bytes 0-3 into respones array
+ response[i] = readResponse[SHA204_BUFFER_POS_DATA+i];
- // Shift CRC to the left by 1.
- crc_register <<= 1;
+ /* read from bytes 8->11 of config zone */
+ returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47);
- if ((data_bit ^ crc_bit) != 0)
- crc_register ^= polynom;
+ for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array
+ response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)];
+
+ if (!returnCode)
+ { /* Finally if last two reads were successful, read byte 8 of the SN */
+ returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8);
+ response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE
}
}
- crc[0] = (uint8_t) (crc_register & 0x00FF);
- crc[1] = (uint8_t) (crc_register >> 8);
+
+ return returnCode;
}
-
-uint8_t ATSHA204Class::sha204c_check_crc(uint8_t *response)
-{
- uint8_t crc[SHA204_CRC_SIZE];
- uint8_t count = response[SHA204_BUFFER_POS_COUNT];
-
- count -= SHA204_CRC_SIZE;
- sha204c_calculate_crc(count, response, crc);
-
- return (crc[0] == response[count] && crc[1] == response[count + 1])
- ? SHA204_SUCCESS : SHA204_BAD_CRC;
-}
-
diff --git a/libraries/MySensors/drivers/ATSHA204/ATSHA204.h b/drivers/ATSHA204/ATSHA204.h
similarity index 93%
rename from libraries/MySensors/drivers/ATSHA204/ATSHA204.h
rename to drivers/ATSHA204/ATSHA204.h
index c7034bf..aefa644 100644
--- a/libraries/MySensors/drivers/ATSHA204/ATSHA204.h
+++ b/drivers/ATSHA204/ATSHA204.h
@@ -3,7 +3,7 @@
#if !DOXYGEN
#include "Arduino.h"
-/* This is a scaled down variant of the ATSHA204 library, tweaked to meet the specific needs of MySensors. */
+/* This is a scaled down variant of the ATSHA204 library, tweaked to meet the specific needs of the MySensors library. */
/* Library return codes */
#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded.
@@ -239,31 +239,14 @@
#define SHA204_PIN_READ() (*device_port_IN & device_pin)
#endif
-class ATSHA204Class
-{
-private:
- uint8_t device_pin;
- #ifdef ARDUINO_ARCH_AVR
- volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN;
- #endif
- void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc);
- uint8_t sha204c_check_crc(uint8_t *response);
- void swi_set_signal_pin(uint8_t is_high);
- uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer);
- uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer);
- uint8_t swi_send_byte(uint8_t value);
- uint8_t sha204p_receive_response(uint8_t size, uint8_t *response);
- uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address);
- uint8_t sha204c_wakeup(uint8_t *response);
- uint8_t sha204c_resync(uint8_t size, uint8_t *response);
- uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout);
-public:
- ATSHA204Class(uint8_t pin); // Constructor
- void sha204c_sleep();
- uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
- uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
- void getSerialNumber(uint8_t *response);
-};
+void atsha204_init(uint8_t pin);
+void atsha204_idle(void);
+void atsha204_sleep(void);
+uint8_t atsha204_wakeup(uint8_t *response);
+uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
+ uint8_t datalen1, uint8_t *data1, uint8_t tx_size,
+ uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
+uint8_t atsha204_getSerialNumber(uint8_t *response);
#endif
#endif
diff --git a/libraries/MySensors/drivers/ATSHA204/sha256.cpp b/drivers/ATSHA204/sha256.cpp
similarity index 100%
rename from libraries/MySensors/drivers/ATSHA204/sha256.cpp
rename to drivers/ATSHA204/sha256.cpp
diff --git a/libraries/MySensors/drivers/ATSHA204/sha256.h b/drivers/ATSHA204/sha256.h
similarity index 100%
rename from libraries/MySensors/drivers/ATSHA204/sha256.h
rename to drivers/ATSHA204/sha256.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/DigitalIO.h b/drivers/AVR/DigitalIO/DigitalIO.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/DigitalIO.h
rename to drivers/AVR/DigitalIO/DigitalIO.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/DigitalPin.h b/drivers/AVR/DigitalIO/DigitalPin.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/DigitalPin.h
rename to drivers/AVR/DigitalIO/DigitalPin.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/I2cConstants.h b/drivers/AVR/DigitalIO/I2cConstants.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/I2cConstants.h
rename to drivers/AVR/DigitalIO/I2cConstants.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/PinIO.cpp b/drivers/AVR/DigitalIO/PinIO.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/PinIO.cpp
rename to drivers/AVR/DigitalIO/PinIO.cpp
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/PinIO.h b/drivers/AVR/DigitalIO/PinIO.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/PinIO.h
rename to drivers/AVR/DigitalIO/PinIO.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.cpp b/drivers/AVR/DigitalIO/SoftI2cMaster.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.cpp
rename to drivers/AVR/DigitalIO/SoftI2cMaster.cpp
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.h b/drivers/AVR/DigitalIO/SoftI2cMaster.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/SoftI2cMaster.h
rename to drivers/AVR/DigitalIO/SoftI2cMaster.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/SoftSPI.h b/drivers/AVR/DigitalIO/SoftSPI.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/SoftSPI.h
rename to drivers/AVR/DigitalIO/SoftSPI.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/attic/ADS7818.h b/drivers/AVR/DigitalIO/attic/ADS7818.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/attic/ADS7818.h
rename to drivers/AVR/DigitalIO/attic/ADS7818.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP320X.h b/drivers/AVR/DigitalIO/attic/MCP320X.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP320X.h
rename to drivers/AVR/DigitalIO/attic/MCP320X.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP355X.h b/drivers/AVR/DigitalIO/attic/MCP355X.h
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/attic/MCP355X.h
rename to drivers/AVR/DigitalIO/attic/MCP355X.h
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino b/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino
rename to drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino b/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino
rename to drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino b/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino
rename to drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino b/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino
rename to drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino b/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino
rename to drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino b/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino
rename to drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino b/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino
rename to drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino b/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino
rename to drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino b/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino
rename to drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino b/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino
rename to drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino b/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino
rename to drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino b/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino
rename to drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino b/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino
rename to drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino
diff --git a/libraries/MySensors/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino b/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino
similarity index 100%
rename from libraries/MySensors/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino
rename to drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino
diff --git a/libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.cpp b/drivers/AltSoftSerial/AltSoftSerial.cpp
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.cpp
rename to drivers/AltSoftSerial/AltSoftSerial.cpp
diff --git a/libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h b/drivers/AltSoftSerial/AltSoftSerial.h
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/AltSoftSerial.h
rename to drivers/AltSoftSerial/AltSoftSerial.h
diff --git a/libraries/MySensors/drivers/AltSoftSerial/README.md b/drivers/AltSoftSerial/README.md
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/README.md
rename to drivers/AltSoftSerial/README.md
diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h b/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h
rename to drivers/AltSoftSerial/config/AltSoftSerial_Boards.h
diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h b/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h
rename to drivers/AltSoftSerial/config/AltSoftSerial_Timers.h
diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/known_boards.h b/drivers/AltSoftSerial/config/known_boards.h
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/config/known_boards.h
rename to drivers/AltSoftSerial/config/known_boards.h
diff --git a/libraries/MySensors/drivers/AltSoftSerial/config/known_timers.h b/drivers/AltSoftSerial/config/known_timers.h
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/config/known_timers.h
rename to drivers/AltSoftSerial/config/known_timers.h
diff --git a/libraries/MySensors/drivers/AltSoftSerial/examples/Test/Test.pde b/drivers/AltSoftSerial/examples/Test/Test.pde
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/examples/Test/Test.pde
rename to drivers/AltSoftSerial/examples/Test/Test.pde
diff --git a/libraries/MySensors/drivers/AltSoftSerial/keywords.txt b/drivers/AltSoftSerial/keywords.txt
similarity index 100%
rename from libraries/MySensors/drivers/AltSoftSerial/keywords.txt
rename to drivers/AltSoftSerial/keywords.txt
diff --git a/drivers/CircularBuffer/CircularBuffer.h b/drivers/CircularBuffer/CircularBuffer.h
new file mode 100644
index 0000000..c3362d9
--- /dev/null
+++ b/drivers/CircularBuffer/CircularBuffer.h
@@ -0,0 +1,196 @@
+/*
+ CircularBuffer - An Arduino circular buffering library for arbitrary types.
+
+ Created by Ivo Pullens, Emmission, 2014-2016 -- www.emmission.nl
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+ /**
+ * @file CircularBuffer.h
+ *
+ * Circular buffering for arbitrary types.
+ */
+
+#ifndef CircularBuffer_h
+#define CircularBuffer_h
+
+/**
+ * The circular buffer class.
+ * Pass the datatype to be stored in the buffer as template parameter.
+ */
+template class CircularBuffer
+{
+ public:
+ /**
+ * Constructor
+ * @param buffer Preallocated buffer of at least size records.
+ * @param size Number of records available in the buffer.
+ */
+ CircularBuffer(T* buffer, const uint8_t size )
+ : m_size(size), m_buff(buffer)
+ {
+ clear();
+ }
+
+ /**
+ * Clear all entries in the circular buffer.
+ */
+ void clear(void)
+ {
+ MY_CRITICAL_SECTION
+ {
+ m_front = 0;
+ m_fill = 0;
+ }
+ }
+
+ /**
+ * Test if the circular buffer is empty.
+ * @return True, when empty.
+ */
+ inline bool empty(void) const
+ {
+ bool empty;
+ MY_CRITICAL_SECTION
+ {
+ empty = !m_fill;
+ }
+ return empty;
+ }
+
+ /**
+ * Test if the circular buffer is full.
+ * @return True, when full.
+ */
+ inline bool full(void) const
+ {
+ bool full;
+ MY_CRITICAL_SECTION
+ {
+ full = m_fill == m_size;
+ }
+ return full;
+ }
+
+ /**
+ * Return the number of records stored in the buffer.
+ * @return number of records.
+ */
+ inline uint8_t available(void) const
+ {
+ MY_CRITICAL_SECTION
+ {
+ return m_fill;
+ }
+ }
+
+ /**
+ * Aquire unused record on front of the buffer, for writing.
+ * After filling the record, it has to be pushed to actually
+ * add it to the buffer.
+ * @return Pointer to record, or NULL when buffer is full.
+ */
+ T* getFront(void) const
+ {
+ MY_CRITICAL_SECTION
+ {
+ if (!full()) return get(m_front);
+ }
+ return static_cast(NULL);
+ }
+
+ /**
+ * Push record to front of the buffer.
+ * @param record Record to push. If record was aquired previously (using getFront) its
+ * data will not be copied as it is already present in the buffer.
+ * @return True, when record was pushed successfully.
+ */
+ bool pushFront(T* record)
+ {
+ MY_CRITICAL_SECTION
+ {
+ if (!full())
+ {
+ T* f = get(m_front);
+ if (f != record)
+ *f = *record;
+ m_front = (m_front+1) % m_size;
+ m_fill++;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Aquire record on back of the buffer, for reading.
+ * After reading the record, it has to be pop'ed to actually
+ * remove it from the buffer.
+ * @return Pointer to record, or NULL when buffer is empty.
+ */
+ T* getBack(void) const
+ {
+ MY_CRITICAL_SECTION
+ {
+ if (!empty()) return get(back());
+ }
+ return static_cast(NULL);
+ }
+
+ /**
+ * Remove record from back of the buffer.
+ * @return True, when record was pop'ed successfully.
+ */
+ bool popBack(void)
+ {
+ MY_CRITICAL_SECTION
+ {
+ if (!empty())
+ {
+ m_fill--;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ /**
+ * Internal getter for records.
+ * @param idx Record index in buffer.
+ * @return Ptr to record.
+ */
+ inline T * get(const uint8_t idx) const
+ {
+ return &(m_buff[idx]);
+ }
+
+ /**
+ * Internal getter for index of last used record in buffer.
+ * @return Index of last record.
+ */
+ inline uint8_t back(void) const
+ {
+ return (m_front - m_fill + m_size) % m_size;
+ }
+
+ const uint8_t m_size; //!< Total number of records that can be stored in the buffer.
+ T* const m_buff; //!< Ptr to buffer holding all records.
+ volatile uint8_t m_front; //!< Index of front element (not pushed yet).
+ volatile uint8_t m_fill; //!< Amount of records currently pushed.
+};
+
+#endif // CircularBuffer_h
diff --git a/libraries/MySensors/drivers/pubsubclient/src/PubSubClient.cpp b/drivers/PubSubClient/PubSubClient.cpp
similarity index 92%
rename from libraries/MySensors/drivers/pubsubclient/src/PubSubClient.cpp
rename to drivers/PubSubClient/PubSubClient.cpp
index 29f70fc..e66c9e0 100644
--- a/libraries/MySensors/drivers/pubsubclient/src/PubSubClient.cpp
+++ b/drivers/PubSubClient/PubSubClient.cpp
@@ -122,7 +122,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
} else {
result = _client->connect(this->ip, this->port);
}
- if (result) {
+ if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
@@ -177,7 +177,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
while (!_client->available()) {
unsigned long t = millis();
- if (t-lastInActivity > MQTT_KEEPALIVE*1000UL) {
+ if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
_state = MQTT_CONNECTION_TIMEOUT;
_client->stop();
return false;
@@ -205,14 +205,33 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
return true;
}
-uint8_t PubSubClient::readByte() {
- while(!_client->available()) {}
- return _client->read();
+// reads a byte into result
+boolean PubSubClient::readByte(uint8_t * result) {
+ uint32_t previousMillis = millis();
+ while(!_client->available()) {
+ uint32_t currentMillis = millis();
+ if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
+ return false;
+ }
+ }
+ *result = _client->read();
+ return true;
+}
+
+// reads a byte into result[*index] and increments index
+boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){
+ uint16_t current_index = *index;
+ uint8_t * write_address = &(result[current_index]);
+ if(readByte(write_address)){
+ *index = current_index + 1;
+ return true;
+ }
+ return false;
}
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint16_t len = 0;
- buffer[len++] = readByte();
+ if(!readByte(buffer, &len)) return 0;
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
uint32_t multiplier = 1;
uint16_t length = 0;
@@ -221,7 +240,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint8_t start = 0;
do {
- digit = readByte();
+ if(!readByte(&digit)) return 0;
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
@@ -230,8 +249,8 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
- buffer[len++] = readByte();
- buffer[len++] = readByte();
+ if(!readByte(buffer, &len)) return 0;
+ if(!readByte(buffer, &len)) return 0;
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
@@ -241,7 +260,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
}
for (uint16_t i = start;istream) {
if (isPublish && len-*lengthLength-2>skip) {
this->stream->write(digit);
@@ -409,7 +428,7 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
- uint8_t rc;
+ uint16_t rc;
uint16_t len = length;
do {
digit = len % 128;
@@ -428,7 +447,7 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
#ifdef MQTT_MAX_TRANSFER_SIZE
uint8_t* writeBuf = buf+(4-llen);
- uint8_t bytesRemaining = length+1+llen;
+ uint16_t bytesRemaining = length+1+llen; //Match the length type
uint8_t bytesToWrite;
boolean result = true;
while((bytesRemaining > 0) && result) {
@@ -451,7 +470,8 @@ boolean PubSubClient::subscribe(const char* topic) {
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
- if (qos > 1) {
+ // original: if (qos < 0 || qos > 1) { (qos is uint8_t, hence qos < 0 impossible, tekka)
+ if (qos > 1) {
return false;
}
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
@@ -551,7 +571,7 @@ PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
return *this;
}
-PubSubClient& PubSubClient::setCallback(void(*callback)(char*,uint8_t*,unsigned int)){
+PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) {
this->callback = callback;
return *this;
}
diff --git a/libraries/MySensors/drivers/pubsubclient/src/PubSubClient.h b/drivers/PubSubClient/PubSubClient.h
similarity index 91%
rename from libraries/MySensors/drivers/pubsubclient/src/PubSubClient.h
rename to drivers/PubSubClient/PubSubClient.h
index 76d76cc..90ad8ae 100644
--- a/libraries/MySensors/drivers/pubsubclient/src/PubSubClient.h
+++ b/drivers/PubSubClient/PubSubClient.h
@@ -17,13 +17,24 @@
// MQTT_VERSION : Pick the version
//#define MQTT_VERSION MQTT_VERSION_3_1
+#ifndef MQTT_VERSION
#define MQTT_VERSION MQTT_VERSION_3_1_1
+#endif
// MQTT_MAX_PACKET_SIZE : Maximum packet size
+#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 128
+#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
+#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 15
+#endif
+
+// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
+#ifndef MQTT_SOCKET_TIMEOUT
+#define MQTT_SOCKET_TIMEOUT 15
+#endif
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to
@@ -62,7 +73,12 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
-#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*,uint8_t*,unsigned int)
+#ifdef ESP8266
+#include
+#define MQTT_CALLBACK_SIGNATURE std::function callback
+#else
+#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
+#endif
/** PubSubClient class */
class PubSubClient {
@@ -75,7 +91,8 @@ private:
bool pingOutstanding;
MQTT_CALLBACK_SIGNATURE;
uint16_t readPacket(uint8_t*);
- uint8_t readByte();
+ boolean readByte(uint8_t * result);
+ boolean readByte(uint8_t * result, uint16_t * index);
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
IPAddress ip;
diff --git a/libraries/MySensors/drivers/pubsubclient/README.md b/drivers/PubSubClient/README.md
similarity index 100%
rename from libraries/MySensors/drivers/pubsubclient/README.md
rename to drivers/PubSubClient/README.md
diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp
new file mode 100644
index 0000000..d263c1f
--- /dev/null
+++ b/drivers/RF24/RF24.cpp
@@ -0,0 +1,367 @@
+/*
+* The MySensors Arduino library handles the wireless radio link and protocol
+* between your home built sensors/actuators and HA controller of choice.
+* The sensors forms a self healing radio network with optional repeaters. Each
+* repeater and gateway builds a routing tables in EEPROM which keeps track of the
+* network topology allowing messages to be routed to nodes.
+*
+* Created by Henrik Ekblad
+* Copyright (C) 2013-2015 Sensnology AB
+* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+*
+* Documentation: http://www.mysensors.org
+* Support Forum: http://forum.mysensors.org
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* Based on maniacbug's RF24 library, copyright (C) 2011 J. Coliz
+* RF24 driver refactored and optimized for speed and size, copyright (C) 2016 Olivier Mauti
+*/
+
+#include "RF24.h"
+
+LOCAL uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
+LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO;
+
+#ifdef MY_RF24_IRQ_PIN
+ LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL;
+#endif
+
+LOCAL void RF24_csn(bool level) {
+ digitalWrite(MY_RF24_CS_PIN, level);
+}
+
+LOCAL void RF24_ce(bool level) {
+ digitalWrite(MY_RF24_CE_PIN, level);
+}
+
+LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) {
+ uint8_t* current = buf;
+ #if !defined(MY_SOFTSPI)
+ _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE));
+ #endif
+ RF24_csn(LOW);
+ // timing
+ delayMicroseconds(10);
+ uint8_t status = _SPI.transfer( cmd );
+ while ( len-- ) {
+ if (aReadMode) {
+ status = _SPI.transfer( NOP );
+ if(buf != NULL) *current++ = status;
+ } else status = _SPI.transfer(*current++);
+ }
+ RF24_csn(HIGH);
+ #if !defined(MY_SOFTSPI)
+ _SPI.endTransaction();
+ #endif
+ // timing
+ delayMicroseconds(10);
+ return status;
+}
+
+LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd) {
+ return RF24_spiMultiByteTransfer( cmd, NULL, 0, false);
+}
+
+LOCAL uint8_t RF24_RAW_readByteRegister(uint8_t cmd) {
+ uint8_t value = RF24_spiMultiByteTransfer( cmd, NULL, 1, true);
+ RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & (R_REGISTER ^ 0xFF), value);
+ return value;
+}
+
+LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value) {
+ RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & (W_REGISTER ^ 0xFF), value);
+ return RF24_spiMultiByteTransfer( cmd , &value, 1, false);
+}
+
+LOCAL void RF24_flushRX(void) {
+ RF24_DEBUG(PSTR("RF24:flushRX\n"));
+ RF24_spiByteTransfer( FLUSH_RX );
+}
+
+LOCAL void RF24_flushTX(void) {
+ RF24_DEBUG(PSTR("RF24:flushTX\n"));
+ RF24_spiByteTransfer( FLUSH_TX );
+}
+
+LOCAL uint8_t RF24_getStatus(void) {
+ return RF24_spiByteTransfer( NOP );
+}
+
+LOCAL uint8_t RF24_getFifoStatus(void) {
+ return RF24_readByteRegister(FIFO_STATUS);
+}
+
+LOCAL void RF24_setChannel(uint8_t channel) {
+ RF24_writeByteRegister(RF_CH, channel);
+}
+
+LOCAL void RF24_setRetries(uint8_t retransmitDelay, uint8_t retransmitCount) {
+ RF24_writeByteRegister(SETUP_RETR, retransmitDelay << ARD | retransmitCount << ARC);
+}
+
+LOCAL void RF24_setAddressWidth(uint8_t width) {
+ RF24_writeByteRegister(SETUP_AW, width - 2);
+}
+
+LOCAL void RF24_setRFSetup(uint8_t RFsetup) {
+ RF24_writeByteRegister(RF_SETUP, RFsetup);
+}
+
+LOCAL void RF24_setFeature(uint8_t feature) {
+ RF24_writeByteRegister(FEATURE, feature);
+}
+
+LOCAL void RF24_setPipe(uint8_t pipe) {
+ RF24_writeByteRegister(EN_RXADDR, pipe);
+}
+
+LOCAL void RF24_setAutoACK(uint8_t pipe) {
+ RF24_writeByteRegister(EN_AA, pipe);
+}
+
+LOCAL void RF24_setDynamicPayload(uint8_t pipe) {
+ RF24_writeByteRegister(DYNPD, pipe);
+}
+
+LOCAL void RF24_setRFConfiguration(uint8_t configuration) {
+ RF24_writeByteRegister(NRF_CONFIG, configuration);
+}
+
+LOCAL void RF24_setPipeAddress(uint8_t pipe, uint8_t* address, uint8_t width) {
+ RF24_writeMultiByteRegister(pipe, address, width);
+}
+
+LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB) {
+ RF24_writeByteRegister(pipe, LSB);
+}
+
+LOCAL void RF24_setStatus(uint8_t status) {
+ RF24_writeByteRegister(RF24_STATUS, status);
+}
+LOCAL void RF24_enableFeatures(void) {
+ RF24_RAW_writeByteRegister(ACTIVATE, 0x73);
+}
+
+LOCAL void RF24_openWritingPipe(uint8_t recipient) {
+ RF24_DEBUG(PSTR("RF24:open writing pipe, recipient=%d\n"), recipient);
+ // only write LSB of RX0 and TX pipe
+ RF24_setPipeLSB(RX_ADDR_P0, recipient);
+ RF24_setPipeLSB(TX_ADDR, recipient);
+}
+
+LOCAL void RF24_startListening(void) {
+ RF24_DEBUG(PSTR("RF24:start listening\n"));
+ // toggle PRX
+ RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) | _BV(PRIM_RX) );
+ // all RX pipe addresses must be unique, therefore skip if node ID is 0xFF
+ if(MY_RF24_NODE_ADDRESS!=AUTO) RF24_setPipeLSB(RX_ADDR_P0, MY_RF24_NODE_ADDRESS);
+ // start listening
+ RF24_ce(HIGH);
+}
+
+LOCAL void RF24_stopListening(void) {
+ RF24_DEBUG(PSTR("RF24:stop listening\n"));
+ RF24_ce(LOW);
+ // timing
+ delayMicroseconds(130);
+ RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) );
+ // timing
+ delayMicroseconds(100);
+}
+
+LOCAL void RF24_powerDown(void) {
+ RF24_ce(LOW);
+ RF24_setRFConfiguration(MY_RF24_CONFIGURATION);
+ RF24_DEBUG(PSTR("RF24:power down\n"));
+}
+
+LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) {
+ uint8_t status;
+
+ RF24_stopListening();
+ RF24_openWritingPipe( recipient );
+ RF24_DEBUG(PSTR("RF24:send message to %d, len=%d\n"),recipient,len);
+ // flush TX FIFO
+ RF24_flushTX();
+ // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD
+ // RF24_spiMultiByteTransfer( recipient==BROADCAST_ADDRESS ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, (uint8_t*)buf, len, false );
+ // we are safe by disabling AutoACK on the broadcasting pipe
+ RF24_spiMultiByteTransfer( W_TX_PAYLOAD, (uint8_t*)buf, len, false );
+ // go, TX starts after ~10us
+ RF24_ce(HIGH);
+ // timeout counter to detect HW issues
+ uint16_t timeout = 0xFFFF;
+ do {
+ status = RF24_getStatus();
+ } while (!(status & ( _BV(MAX_RT) | _BV(TX_DS) )) && timeout--);
+ // timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles
+ RF24_ce(LOW);
+ // reset interrupts
+ RF24_setStatus(_BV(TX_DS) | _BV(MAX_RT) );
+ // Max retries exceeded
+ if( status & _BV(MAX_RT)){
+ // flush packet
+ RF24_DEBUG(PSTR("RF24:MAX_RT\n"));
+ RF24_flushTX();
+ }
+
+ RF24_startListening();
+ // true if message sent and not timeout
+ return (status & _BV(TX_DS) && timeout);
+}
+
+LOCAL uint8_t RF24_getDynamicPayloadSize(void) {
+ uint8_t result = RF24_spiMultiByteTransfer(R_RX_PL_WID, NULL, 1, true);
+ // check if payload size invalid
+ if(result > 32) {
+ RF24_DEBUG(PSTR("RF24:invalid payload length = %d\n"),result);
+ RF24_flushRX();
+ result = 0;
+ }
+ return result;
+}
+
+
+LOCAL bool RF24_isDataAvailable() {
+ uint8_t status = RF24_getStatus();
+ return (((status >> RX_P_NO) & 0b0111) <= 5);
+}
+
+
+LOCAL uint8_t RF24_readMessage( void* buf) {
+ uint8_t len = RF24_getDynamicPayloadSize();
+ RF24_DEBUG(PSTR("RF24:read message, len=%d\n"), len);
+ RF24_spiMultiByteTransfer( R_RX_PAYLOAD , (uint8_t*)buf, len, true );
+ // clear RX interrupt
+ RF24_setStatus(_BV(RX_DR) );
+ return len;
+}
+
+LOCAL void RF24_setNodeAddress(uint8_t address) {
+ if(address!=AUTO){
+ MY_RF24_NODE_ADDRESS = address;
+ // enable node pipe
+ RF24_setPipe(_BV(ERX_P0 + BROADCAST_PIPE) | _BV(ERX_P0) );
+ // enable autoACK on pipe 0
+ RF24_setAutoACK(_BV(ENAA_P0) );
+ }
+}
+
+LOCAL uint8_t RF24_getNodeID(void) {
+ return MY_RF24_NODE_ADDRESS;
+}
+
+LOCAL bool RF24_sanityCheck(void) {
+ // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected
+ bool status = RF24_readByteRegister(RF_SETUP) == MY_RF24_RF_SETUP;
+ status &= RF24_readByteRegister(RF_CH) == MY_RF24_CHANNEL;
+ return status;
+}
+
+#ifdef MY_RF24_IRQ_PIN
+LOCAL void RF24_irqHandler( void )
+{
+ if (RF24_receiveCallback)
+ {
+ // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial
+ // rx coming in during our stay will not be handled and will cause characters to be lost.
+ // As a workaround we re-enable interrupts to allow nested processing of other interrupts.
+ // Our own handler is disconnected to prevent recursive calling of this handler.
+ #ifdef MY_GATEWAY_SERIAL
+ detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
+ interrupts();
+ #endif
+ // Read FIFO until empty.
+ // Procedure acc. to datasheet (pg. 63):
+ // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available.
+ // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS.
+
+ // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt
+ // for a message we've already read.
+ while (!(RF24_getFifoStatus() & _BV(0))) {
+ RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ !
+ }
+ // Restore our interrupt handler.
+ #ifdef MY_GATEWAY_SERIAL
+ noInterrupts();
+ attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
+ #endif
+ } else {
+ // clear RX interrupt
+ RF24_setStatus(_BV(RX_DR));
+ }
+}
+
+LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb )
+{
+ MY_CRITICAL_SECTION {
+ RF24_receiveCallback = cb;
+ }
+}
+#endif
+
+LOCAL bool RF24_initialize(void) {
+ // Initialize pins
+ pinMode(MY_RF24_CE_PIN,OUTPUT);
+ pinMode(MY_RF24_CS_PIN,OUTPUT);
+ #ifdef MY_RF24_IRQ_PIN
+ pinMode(MY_RF24_IRQ_PIN,INPUT);
+ #endif
+ // Initialize SPI
+ _SPI.begin();
+ RF24_ce(LOW);
+ RF24_csn(HIGH);
+ #ifdef MY_RF24_IRQ_PIN
+ // assure SPI can be used from interrupt context
+ // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI,
+ // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI!
+ _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
+ // attach interrupt
+ attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING);
+ #else
+ (void)RF24_getFifoStatus; // prevent 'defined but not used' warning
+ #endif
+ // CRC and power up
+ RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ;
+ // settle >2ms
+ delay(5);
+ // set address width
+ RF24_setAddressWidth(MY_RF24_ADDR_WIDTH);
+ // auto retransmit delay 1500us, auto retransmit count 15
+ RF24_setRetries(RF24_ARD, RF24_ARC);
+ // set channel
+ RF24_setChannel(MY_RF24_CHANNEL);
+ // set data rate and pa level
+ RF24_setRFSetup(MY_RF24_RF_SETUP);
+ // toggle features (necessary on some clones and non-P versions)
+ RF24_enableFeatures();
+ // enable ACK payload and dynamic payload
+ RF24_setFeature(MY_RF24_FEATURE);
+ // sanity check (this function is P/non-P independent)
+ if (!RF24_sanityCheck()) {
+ RF24_DEBUG(PSTR("!RF24:Sanity check failed: configuration mismatch! Check wiring or replace module\n"));
+ return false;
+ }
+ // enable broadcasting pipe
+ RF24_setPipe(_BV(ERX_P0 + BROADCAST_PIPE));
+ // disable AA on all pipes, activate when node pipe set
+ RF24_setAutoACK(0x00);
+ // enable dynamic payloads on used pipes
+ RF24_setDynamicPayload(_BV(DPL_P0 + BROADCAST_PIPE) | _BV(DPL_P0));
+ // listen to broadcast pipe
+ MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
+ RF24_setPipeAddress(RX_ADDR_P0 + BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH);
+ // pipe 0, set full address, later only LSB is updated
+ RF24_setPipeAddress(RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
+ RF24_setPipeAddress(TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH);
+ // reset FIFO
+ RF24_flushRX();
+ RF24_flushTX();
+ // reset interrupts
+ RF24_setStatus(_BV(TX_DS) | _BV(MAX_RT) | _BV(RX_DR));
+ return true;
+}
+
diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h
new file mode 100644
index 0000000..765a434
--- /dev/null
+++ b/drivers/RF24/RF24.h
@@ -0,0 +1,267 @@
+/*
+* The MySensors Arduino library handles the wireless radio link and protocol
+* between your home built sensors/actuators and HA controller of choice.
+* The sensors forms a self healing radio network with optional repeaters. Each
+* repeater and gateway builds a routing tables in EEPROM which keeps track of the
+* network topology allowing messages to be routed to nodes.
+*
+* Created by Henrik Ekblad
+* Copyright (C) 2013-2015 Sensnology AB
+* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+*
+* Documentation: http://www.mysensors.org
+* Support Forum: http://forum.mysensors.org
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* Based on maniacbug's RF24 library, copyright (C) 2011 J. Coliz
+* RF24 driver refactored and optimized for speed and size, copyright (C) 2016 Olivier Mauti
+*/
+
+#ifndef __RF24_H__
+#define __RF24_H__
+
+#define LOCAL static
+
+// SPI settings
+#if !defined(MY_RF24_SPI_MAX_SPEED)
+ // default 2Mhz - safe for nRF24L01+ clones
+ #define MY_RF24_SPI_MAX_SPEED 2000000
+#endif
+#define MY_RF24_SPI_DATA_ORDER MSBFIRST
+#define MY_RF24_SPI_DATA_MODE SPI_MODE0
+
+#if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI)
+ #if defined(MY_SOFTSPI)
+ SoftSPI _SPI;
+ #elif defined(ARDUINO_ARCH_SAMD)
+ #include
+ #define _SPI SPI1
+ #else
+ #include
+ #define _SPI SPI
+ #endif
+#else
+ #include
+ #include
+ #include
+
+ #define _BV(x) (1<<(x))
+
+ #if defined(__arm__)
+ #include
+ #else
+ extern HardwareSPI SPI;
+ #endif
+
+ #if !defined(_SPI)
+ #define _SPI SPI
+ #endif
+#endif
+
+// RF24 settings
+#ifdef MY_RF24_IRQ_PIN
+ #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT))
+#else
+ #define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2)
+#endif
+#define MY_RF24_FEATURE (uint8_t)( _BV(EN_DPL) | _BV(EN_ACK_PAY) )
+#define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1
+
+// pipes
+#define BROADCAST_PIPE 1
+#define NODE_PIPE 0
+
+// debug
+#if defined(MY_DEBUG_VERBOSE_RF24)
+ #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
+#else
+ #define RF24_DEBUG(x,...)
+#endif
+
+// PA levels
+#define RF24_PA_MIN 0
+#define RF24_PA_LOW 1
+#define RF24_PA_HIGH 2
+#define RF24_PA_MAX 3
+
+// data rate
+#define RF24_1MBPS 0
+#define RF24_2MBPS 1
+#define RF24_250KBPS 2
+
+// CRC
+#define RF24_CRC_DISABLED 0
+#define RF24_CRC_8 2
+#define RF24_CRC_16 3
+
+// ARD, auto retry delay
+#define RF24_ARD 5 //=1500us
+
+// ARD, auto retry count
+#define RF24_ARC 15
+
+// nRF24L01(+) register definitions
+#define NRF_CONFIG 0x00
+#define EN_AA 0x01
+#define EN_RXADDR 0x02
+#define SETUP_AW 0x03
+#define SETUP_RETR 0x04
+#define RF_CH 0x05
+#define RF_SETUP 0x06
+#define RF24_STATUS 0x07
+#define OBSERVE_TX 0x08
+#define CD 0x09
+#define RX_ADDR_P0 0x0A
+#define RX_ADDR_P1 0x0B
+#define RX_ADDR_P2 0x0C
+#define RX_ADDR_P3 0x0D
+#define RX_ADDR_P4 0x0E
+#define RX_ADDR_P5 0x0F
+#define TX_ADDR 0x10
+#define RX_PW_P0 0x11
+#define RX_PW_P1 0x12
+#define RX_PW_P2 0x13
+#define RX_PW_P3 0x14
+#define RX_PW_P4 0x15
+#define RX_PW_P5 0x16
+#define FIFO_STATUS 0x17
+#define DYNPD 0x1C
+#define FEATURE 0x1D
+
+// instructions
+#define R_REGISTER 0x00
+#define RPD 0x09
+#define W_REGISTER 0x20
+#define REGISTER_MASK 0x1F
+#define ACTIVATE 0x50
+#define R_RX_PL_WID 0x60
+#define R_RX_PAYLOAD 0x61
+#define W_TX_PAYLOAD 0xA0
+#define W_ACK_PAYLOAD 0xA8
+#define W_TX_PAYLOAD_NO_ACK 0xB0
+#define FLUSH_TX 0xE1
+#define FLUSH_RX 0xE2
+#define REUSE_TX_PL 0xE3
+#define NOP 0xFF
+
+// bit mnemonics
+#define MASK_RX_DR 6
+#define MASK_TX_DS 5
+#define MASK_MAX_RT 4
+#define EN_CRC 3
+#define CRCO 2
+#define PWR_UP 1
+#define PRIM_RX 0
+
+// auto ACK
+#define ENAA_P5 5
+#define ENAA_P4 4
+#define ENAA_P3 3
+#define ENAA_P2 2
+#define ENAA_P1 1
+#define ENAA_P0 0
+
+// rx pipe
+#define ERX_P5 5
+#define ERX_P4 4
+#define ERX_P3 3
+#define ERX_P2 2
+#define ERX_P1 1
+#define ERX_P0 0
+
+// dynamic payload
+#define DPL_P5 5
+#define DPL_P4 4
+#define DPL_P3 3
+#define DPL_P2 2
+#define DPL_P1 1
+#define DPL_P0 0
+
+#define AW 0
+#define ARD 4
+#define ARC 0
+#define PLL_LOCK 4
+#define RF_DR 3
+#define RF_PWR 6
+#define RX_DR 6
+#define TX_DS 5
+#define MAX_RT 4
+#define RX_P_NO 1
+#define TX_FULL 0
+#define PLOS_CNT 4
+#define ARC_CNT 0
+#define TX_REUSE 6
+#define FIFO_FULL 5
+#define TX_EMPTY 4
+#define RX_FULL 1
+#define RX_EMPTY 0
+
+// features
+#define EN_DPL 2
+#define EN_ACK_PAY 1
+#define EN_DYN_ACK 0
+
+#define LNA_HCURR 0
+#define RF_DR_LOW 5
+#define RF_DR_HIGH 3
+#define RF_PWR_LOW 1
+#define RF_PWR_HIGH 2
+
+// functions
+
+LOCAL void RF24_csn(bool level);
+LOCAL void RF24_ce(bool level);
+LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode);
+LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd);
+LOCAL uint8_t RF24_RAW_readByteRegister(uint8_t cmd);
+LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value);
+
+#define RF24_readByteRegister(reg) RF24_RAW_readByteRegister( R_REGISTER | ( REGISTER_MASK & (reg) ) )
+#define RF24_writeByteRegister(reg, value) RF24_RAW_writeByteRegister( W_REGISTER | ( REGISTER_MASK & (reg) ), value )
+#define RF24_writeMultiByteRegister(reg, buf, len) RF24_spiMultiByteTransfer( W_REGISTER | ( REGISTER_MASK & (reg) ), (uint8_t*)buf, len, false )
+
+LOCAL void RF24_flushRX(void);
+LOCAL void RF24_flushTX(void);
+LOCAL uint8_t RF24_getStatus(void);
+LOCAL uint8_t RF24_getFifoStatus(void);
+LOCAL void RF24_openWritingPipe(uint8_t recipient);
+LOCAL void RF24_startListening(void);
+LOCAL void RF24_stopListening(void);
+LOCAL void RF24_powerDown(void);
+LOCAL bool RF24_sendMessage(uint8_t recipient, const void* buf, uint8_t len);
+LOCAL uint8_t RF24_getDynamicPayloadSize(void);
+LOCAL bool RF24_isDataAvailable();
+LOCAL uint8_t RF24_readMessage(void* buf);
+LOCAL void RF24_setNodeAddress(uint8_t address);
+LOCAL uint8_t RF24_getNodeID(void);
+LOCAL bool RF24_sanityCheck(void);
+LOCAL bool RF24_initialize(void);
+LOCAL void RF24_setChannel(uint8_t channel);
+LOCAL void RF24_setRetries(uint8_t retransmitDelay, uint8_t retransmitCount);
+LOCAL void RF24_setAddressWidth(uint8_t width);
+LOCAL void RF24_setRFSetup(uint8_t RFsetup);
+LOCAL void RF24_setFeature(uint8_t feature);
+LOCAL void RF24_setPipe(uint8_t pipe);
+LOCAL void RF24_setAutoACK(uint8_t pipe);
+LOCAL void RF24_setDynamicPayload(uint8_t pipe);
+LOCAL void RF24_setRFConfiguration(uint8_t configuration);
+LOCAL void RF24_setPipeAddress(uint8_t pipe, uint8_t* address, uint8_t width);
+LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB);
+LOCAL void RF24_setStatus(uint8_t status);
+LOCAL void RF24_enableFeatures(void);
+
+#ifdef MY_RF24_IRQ_PIN
+ typedef void (*RF24_receiveCallbackType)(void);
+ /**
+ * Register a callback, which will be called (from interrupt context) for every message received.
+ * @note When a callback is registered, it _must_ retrieve the message from the nRF24
+ * by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted
+ * and message reception will stop.
+ */
+ LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb );
+#endif
+
+#endif // __RF24_H__
\ No newline at end of file
diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp
new file mode 100644
index 0000000..a8edbab
--- /dev/null
+++ b/drivers/RFM69/RFM69.cpp
@@ -0,0 +1,805 @@
+// **********************************************************************************
+// 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 "RFM69.h"
+#include "RFM69registers.h"
+#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();
+ unsigned long start = millis();
+ uint8_t timeout = 50;
+ do {
+ writeReg(REG_SYNCVALUE1, 0xAA);
+ yield();
+ } while (readReg(REG_SYNCVALUE1) != 0xaa && millis()-start < timeout);
+ start = millis();
+ do {
+ writeReg(REG_SYNCVALUE1, 0x55);
+ yield();
+ } while (readReg(REG_SYNCVALUE1) != 0x55 && millis()-start < timeout);
+
+ 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);
+ start = millis();
+ while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout) {
+ yield();
+ } // wait for ModeReady
+ if (millis()-start >= timeout)
+ return false;
+ 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;
+}
+
+//put transceiver in sleep mode to save battery - to wake or resume receiving just call receiveDone()
+void RFM69::sleep() {
+ setMode(RF69_MODE_SLEEP);
+}
+
+//set this node's address
+void RFM69::setAddress(uint8_t addr)
+{
+ _address = addr;
+ writeReg(REG_NODEADRS, _address);
+}
+
+//set this node's network id
+void RFM69::setNetwork(uint8_t networkID)
+{
+ writeReg(REG_SYNCVALUE2, networkID);
+}
+
+// set *transmit/TX* output power: 0=min, 31=max
+// this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
+// the power configurations are explained in the SX1231H datasheet (Table 10 on p21; RegPaLevel p66): http://www.semtech.com/images/datasheet/sx1231h.pdf
+// valid powerLevel parameter values are 0-31 and result in a directly proportional effect on the output/transmission power
+// this function implements 2 modes as follows:
+// - for RFM69W the range is from 0-31 [-18dBm to 13dBm] (PA0 only on RFIO pin)
+// - for RFM69HW the range is from 0-31 [5dBm to 20dBm] (PA1 & PA2 on PA_BOOST pin & high Power PA settings - see section 3.3.7 in datasheet, p22)
+void RFM69::setPowerLevel(uint8_t powerLevel)
+{
+ _powerLevel = (powerLevel > 31 ? 31 : powerLevel);
+ if (_isRFM69HW) _powerLevel /= 2;
+ writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | _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) {
+ ACK_REQUESTED = 0; // TWS added to make sure we don't end up in a timing race and infinite loop sending Acks
+ 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();
+ yield();
+ }
+ SENDERID = sender; // TWS: Restore SenderID after it gets wiped out by receiveDone()
+ sendFrame(sender, buffer, bufferSize, false, true);
+ RSSI = _RSSI; // restore payload RSSI
+}
+
+void RFM69::interruptHook(uint8_t CTLbyte) {
+ (void)CTLbyte;
+};
+
+// internal function
+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 = RFM69_CTL_SENDACK;
+ else if (requestACK)
+ CTLbyte = RFM69_CTL_REQACK;
+
+ // 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);
+}
+
+// internal function - interrupt gets called when a packet is received
+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 & RFM69_CTL_SENDACK; // extract ACK-received flag
+ ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK; // extract ACK-requested flag
+
+ interruptHook(CTLbyte); // TWS: hook to derived class interrupt function
+
+ 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);
+}
+
+// internal function
+void RFM69::isr0() { selfPointer->interruptHandler(); }
+
+// internal function
+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);
+}
+
+// checks if a packet was received and/or puts transceiver in receive (ie RX or listen) mode
+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));
+}
+
+// get the received signal strength indicator (RSSI)
+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 RFM69 transceiver (save SPI settings, set CS low)
+void RFM69::select() {
+ noInterrupts();
+#if defined (SPCR) && defined (SPSR)
+ // save current SPI settings
+ _SPCR = SPCR;
+ _SPSR = SPSR;
+#endif
+ // 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 RFM69 transceiver (set CS high, restore SPI settings)
+void RFM69::unselect() {
+ digitalWrite(_slaveSelectPin, HIGH);
+ // restore SPI settings to what they were before talking to RFM69
+#if defined (SPCR) && defined (SPSR)
+ SPCR = _SPCR;
+ SPSR = _SPSR;
+#endif
+ interrupts();
+}
+
+// true = disable filtering to capture all frames on network
+// false = 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));
+}
+
+// for RFM69HW only: you must call setHighPower(true) after initialize() or else transmission won't work
+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
+}
+
+// internal function
+void RFM69::setHighPowerRegs(bool onOff) {
+ writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55);
+ writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70);
+}
+
+// set the slave select (CS) pin
+void RFM69::setCS(uint8_t newSPISlaveSelect) {
+ _slaveSelectPin = newSPISlaveSelect;
+ digitalWrite(_slaveSelectPin, HIGH);
+ pinMode(_slaveSelectPin, OUTPUT);
+}
+
+//for debugging
+#define REGISTER_DETAIL 0
+#if REGISTER_DETAIL
+// SERIAL PRINT
+// replace Serial.print("string") with SerialPrint("string")
+#define SerialPrint(x) SerialPrint_P(PSTR(x))
+void SerialWrite ( uint8_t c ) {
+ Serial.write ( c );
+}
+
+void SerialPrint_P(PGM_P str, void (*f)(uint8_t) = SerialWrite ) {
+ for (uint8_t c; (c = pgm_read_byte(str)); str++) (*f)(c);
+}
+#endif
+
+void RFM69::readAllRegs()
+{
+ uint8_t regVal;
+
+#if REGISTER_DETAIL
+ int capVal;
+
+ //... State Variables for intelligent decoding
+ uint8_t modeFSK = 0;
+ int bitRate = 0;
+ int freqDev = 0;
+ long freqCenter = 0;
+#endif
+
+ Serial.println("Address - HEX - BIN");
+ 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);
+
+#if REGISTER_DETAIL
+ switch ( regAddr )
+ {
+ case 0x1 : {
+ SerialPrint ( "Controls the automatic Sequencer ( see section 4.2 )\nSequencerOff : " );
+ if ( 0x80 & regVal ) {
+ SerialPrint ( "1 -> Mode is forced by the user\n" );
+ } else {
+ SerialPrint ( "0 -> Operating mode as selected with Mode bits in RegOpMode is automatically reached with the Sequencer\n" );
+ }
+
+ SerialPrint( "\nEnables Listen mode, should be enabled whilst in Standby mode:\nListenOn : " );
+ if ( 0x40 & regVal ) {
+ SerialPrint ( "1 -> On\n" );
+ } else {
+ SerialPrint ( "0 -> Off ( see section 4.3)\n" );
+ }
+
+ SerialPrint( "\nAborts Listen mode when set together with ListenOn=0 See section 4.3.4 for details (Always reads 0.)\n" );
+ if ( 0x20 & regVal ) {
+ SerialPrint ( "ERROR - ListenAbort should NEVER return 1 this is a write only register\n" );
+ }
+
+ SerialPrint("\nTransceiver's operating modes:\nMode : ");
+ capVal = (regVal >> 2) & 0x7;
+ if ( capVal == 0b000 ) {
+ SerialPrint ( "000 -> Sleep mode (SLEEP)\n" );
+ } else if ( capVal = 0b001 ) {
+ SerialPrint ( "001 -> Standby mode (STDBY)\n" );
+ } else if ( capVal = 0b010 ) {
+ SerialPrint ( "010 -> Frequency Synthesizer mode (FS)\n" );
+ } else if ( capVal = 0b011 ) {
+ SerialPrint ( "011 -> Transmitter mode (TX)\n" );
+ } else if ( capVal = 0b100 ) {
+ SerialPrint ( "100 -> Receiver Mode (RX)\n" );
+ } else {
+ Serial.print( capVal, BIN );
+ SerialPrint ( " -> RESERVED\n" );
+ }
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ case 0x2 : {
+
+ SerialPrint("Data Processing mode:\nDataMode : ");
+ capVal = (regVal >> 5) & 0x3;
+ if ( capVal == 0b00 ) {
+ SerialPrint ( "00 -> Packet mode\n" );
+ } else if ( capVal == 0b01 ) {
+ SerialPrint ( "01 -> reserved\n" );
+ } else if ( capVal == 0b10 ) {
+ SerialPrint ( "10 -> Continuous mode with bit synchronizer\n" );
+ } else if ( capVal == 0b11 ) {
+ SerialPrint ( "11 -> Continuous mode without bit synchronizer\n" );
+ }
+
+ SerialPrint("\nModulation scheme:\nModulation Type : ");
+ capVal = (regVal >> 3) & 0x3;
+ if ( capVal == 0b00 ) {
+ SerialPrint ( "00 -> FSK\n" );
+ modeFSK = 1;
+ } else if ( capVal == 0b01 ) {
+ SerialPrint ( "01 -> OOK\n" );
+ } else if ( capVal == 0b10 ) {
+ SerialPrint ( "10 -> reserved\n" );
+ } else if ( capVal == 0b11 ) {
+ SerialPrint ( "11 -> reserved\n" );
+ }
+
+ SerialPrint("\nData shaping: ");
+ if ( modeFSK ) {
+ SerialPrint( "in FSK:\n" );
+ } else {
+ SerialPrint( "in OOK:\n" );
+ }
+ SerialPrint ("ModulationShaping : ");
+ capVal = regVal & 0x3;
+ if ( modeFSK ) {
+ if ( capVal == 0b00 ) {
+ SerialPrint ( "00 -> no shaping\n" );
+ } else if ( capVal == 0b01 ) {
+ SerialPrint ( "01 -> Gaussian filter, BT = 1.0\n" );
+ } else if ( capVal == 0b10 ) {
+ SerialPrint ( "10 -> Gaussian filter, BT = 0.5\n" );
+ } else if ( capVal == 0b11 ) {
+ SerialPrint ( "11 -> Gaussian filter, BT = 0.3\n" );
+ }
+ } else {
+ if ( capVal == 0b00 ) {
+ SerialPrint ( "00 -> no shaping\n" );
+ } else if ( capVal == 0b01 ) {
+ SerialPrint ( "01 -> filtering with f(cutoff) = BR\n" );
+ } else if ( capVal == 0b10 ) {
+ SerialPrint ( "10 -> filtering with f(cutoff) = 2*BR\n" );
+ } else if ( capVal == 0b11 ) {
+ SerialPrint ( "ERROR - 11 is reserved\n" );
+ }
+ }
+
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ case 0x3 : {
+ bitRate = (regVal << 8);
+ break;
+ }
+
+ case 0x4 : {
+ bitRate |= regVal;
+ SerialPrint ( "Bit Rate (Chip Rate when Manchester encoding is enabled)\nBitRate : ");
+ unsigned long val = 32UL * 1000UL * 1000UL / bitRate;
+ Serial.println( val );
+ SerialPrint( "\n" );
+ break;
+ }
+
+ case 0x5 : {
+ freqDev = ( (regVal & 0x3f) << 8 );
+ break;
+ }
+
+ case 0x6 : {
+ freqDev |= regVal;
+ SerialPrint( "Frequency deviation\nFdev : " );
+ unsigned long val = 61UL * freqDev;
+ Serial.println( val );
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ case 0x7 : {
+ unsigned long tempVal = regVal;
+ freqCenter = ( tempVal << 16 );
+ break;
+ }
+
+ case 0x8 : {
+ unsigned long tempVal = regVal;
+ freqCenter = freqCenter | ( tempVal << 8 );
+ break;
+ }
+
+ case 0x9 : {
+ freqCenter = freqCenter | regVal;
+ SerialPrint ( "RF Carrier frequency\nFRF : " );
+ unsigned long val = 61UL * freqCenter;
+ Serial.println( val );
+ SerialPrint( "\n" );
+ break;
+ }
+
+ case 0xa : {
+ SerialPrint ( "RC calibration control & status\nRcCalDone : " );
+ if ( 0x40 & regVal ) {
+ SerialPrint ( "1 -> RC calibration is over\n" );
+ } else {
+ SerialPrint ( "0 -> RC calibration is in progress\n" );
+ }
+
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ case 0xb : {
+ SerialPrint ( "Improved AFC routine for signals with modulation index lower than 2. Refer to section 3.4.16 for details\nAfcLowBetaOn : " );
+ if ( 0x20 & regVal ) {
+ SerialPrint ( "1 -> Improved AFC routine\n" );
+ } else {
+ SerialPrint ( "0 -> Standard AFC routine\n" );
+ }
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ case 0xc : {
+ SerialPrint ( "Reserved\n\n" );
+ break;
+ }
+
+ case 0xd : {
+ byte val;
+ SerialPrint ( "Resolution of Listen mode Idle time (calibrated RC osc):\nListenResolIdle : " );
+ val = regVal >> 6;
+ if ( val == 0b00 ) {
+ SerialPrint ( "00 -> reserved\n" );
+ } else if ( val == 0b01 ) {
+ SerialPrint ( "01 -> 64 us\n" );
+ } else if ( val == 0b10 ) {
+ SerialPrint ( "10 -> 4.1 ms\n" );
+ } else if ( val == 0b11 ) {
+ SerialPrint ( "11 -> 262 ms\n" );
+ }
+
+ SerialPrint ( "\nResolution of Listen mode Rx time (calibrated RC osc):\nListenResolRx : " );
+ val = (regVal >> 4) & 0x3;
+ if ( val == 0b00 ) {
+ SerialPrint ( "00 -> reserved\n" );
+ } else if ( val == 0b01 ) {
+ SerialPrint ( "01 -> 64 us\n" );
+ } else if ( val == 0b10 ) {
+ SerialPrint ( "10 -> 4.1 ms\n" );
+ } else if ( val == 0b11 ) {
+ SerialPrint ( "11 -> 262 ms\n" );
+ }
+
+ SerialPrint ( "\nCriteria for packet acceptance in Listen mode:\nListenCriteria : " );
+ if ( 0x8 & regVal ) {
+ SerialPrint ( "1 -> signal strength is above RssiThreshold and SyncAddress matched\n" );
+ } else {
+ SerialPrint ( "0 -> signal strength is above RssiThreshold\n" );
+ }
+
+ SerialPrint ( "\nAction taken after acceptance of a packet in Listen mode:\nListenEnd : " );
+ val = (regVal >> 1 ) & 0x3;
+ if ( val == 0b00 ) {
+ SerialPrint ( "00 -> chip stays in Rx mode. Listen mode stops and must be disabled (see section 4.3)\n" );
+ } else if ( val == 0b01 ) {
+ SerialPrint ( "01 -> chip stays in Rx mode until PayloadReady or Timeout interrupt occurs. It then goes to the mode defined by Mode. Listen mode stops and must be disabled (see section 4.3)\n" );
+ } else if ( val == 0b10 ) {
+ SerialPrint ( "10 -> chip stays in Rx mode until PayloadReady or Timeout occurs. Listen mode then resumes in Idle state. FIFO content is lost at next Rx wakeup.\n" );
+ } else if ( val == 0b11 ) {
+ SerialPrint ( "11 -> Reserved\n" );
+ }
+
+
+ SerialPrint ( "\n" );
+ break;
+ }
+
+ default : {
+ }
+ }
+#endif
+ }
+ 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);
+}
\ No newline at end of file
diff --git a/drivers/RFM69/RFM69.h b/drivers/RFM69/RFM69.h
new file mode 100644
index 0000000..d8eb7aa
--- /dev/null
+++ b/drivers/RFM69/RFM69.h
@@ -0,0 +1,157 @@
+// **********************************************************************************
+// 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
+#elif defined(__arm__)//Use pin 10 or any pin you want
+ #define RF69_IRQ_PIN 10
+ #define RF69_IRQ_NUM 10
+#else
+ #define RF69_IRQ_PIN 2
+ #define RF69_IRQ_NUM 0
+#endif
+
+
+#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access
+#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)
+
+// TWS: define CTLbyte bits
+#define RFM69_CTL_SENDACK 0x80
+#define RFM69_CTL_REQACK 0x40
+
+/** RFM69 class */
+class RFM69 {
+ public:
+ static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes
+ static volatile uint8_t DATALEN; //!< DATALEN
+ static volatile uint8_t SENDERID; //!< SENDERID
+ static volatile uint8_t TARGETID; //!< should match _address
+ static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN
+ static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED
+ static volatile uint8_t ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith 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) { //!< Constructor
+ _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); //!< initialize
+ void setAddress(uint8_t addr); //!< setAddress
+ void setNetwork(uint8_t networkID); //!< setNetwork
+ bool canSend(); //!< canSend
+ virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false); //!< send
+ virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); //!< sendWithRetry (40ms roundtrip req for 61byte packets)
+ virtual bool receiveDone(); //!< receiveDone
+ bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived
+ bool ACKRequested(); //!< ACKRequested
+ virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK
+ uint32_t getFrequency(); //!< getFrequency
+ void setFrequency(uint32_t freqHz); //!< setFrequency
+ void encrypt(const char* key); //!< encrypt
+ void setCS(uint8_t newSPISlaveSelect); //!< setCS
+ int16_t readRSSI(bool forceTrigger=false); //!< readRSSI
+ void promiscuous(bool onOff=true); //!< promiscuous
+ virtual void setHighPower(bool onOFF=true); //!< setHighPower (have to call it after initialize for RFM69HW)
+ virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level)
+ void sleep(); //!< sleep
+ uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit))
+ void rcCalibration(); //!< 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); //!< readReg
+ void writeReg(uint8_t addr, uint8_t val); //!< writeReg
+ void readAllRegs(); //!< readAllRegs
+
+ protected:
+ static void isr0(); //!< isr0
+ void virtual interruptHandler(); //!< interruptHandler
+ virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook
+ virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); //!< sendFrame
+
+ static RFM69* selfPointer; //!< selfPointer
+ uint8_t _slaveSelectPin; //!< _slaveSelectPin
+ uint8_t _interruptPin; //!< _interruptPin
+ uint8_t _interruptNum; //!< _interruptNum
+ uint8_t _address; //!< _address
+ bool _promiscuousMode; //!< _promiscuousMode
+ uint8_t _powerLevel; //!< _powerLevel
+ bool _isRFM69HW; //!< _isRFM69HW
+#if defined (SPCR) && defined (SPSR)
+ uint8_t _SPCR; //!< _SPCR
+ uint8_t _SPSR; //!< _SPSR
+#endif
+
+ virtual void receiveBegin(); //!< receiveBegin
+ virtual void setMode(uint8_t mode); //!< setMode
+ virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs
+ virtual void select(); //!< select
+ virtual void unselect(); //!< unselect
+};
+
+#endif
diff --git a/drivers/RFM69/RFM69registers.h b/drivers/RFM69/RFM69registers.h
new file mode 100644
index 0000000..2d815ec
--- /dev/null
+++ b/drivers/RFM69/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/libraries/MySensors/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp
similarity index 84%
rename from libraries/MySensors/drivers/SPIFlash/SPIFlash.cpp
rename to drivers/SPIFlash/SPIFlash.cpp
index 9fa26ad..1d4205c 100644
--- a/libraries/MySensors/drivers/SPIFlash/SPIFlash.cpp
+++ b/drivers/SPIFlash/SPIFlash.cpp
@@ -7,6 +7,8 @@
// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4
+// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02,
+// > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory
// **********************************************************************************
// License
// **********************************************************************************
@@ -230,8 +232,48 @@ void SPIFlash::writeByte(uint32_t addr, uint8_t byt) {
/// WARNING: you can only write to previously erased memory locations (see datasheet)
/// use the block erase commands to first clear memory (write 0xFFs)
/// This version handles both page alignment and data blocks larger than 256 bytes.
-///
+/// See documentation of #MY_SPIFLASH_SST25TYPE define for more information
void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
+#ifdef MY_SPIFLASH_SST25TYPE
+ //SST25 Type of Flash does not support Page Programming but AAI Word Programming
+ uint16_t i=0;
+ uint8_t oddAdr=0;
+ char s[5];
+
+ command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program
+ SPI.transfer(addr >> 16);
+ SPI.transfer(addr >> 8);
+ SPI.transfer(addr);
+
+ if (addr%2){
+ //start address is not even, i.e. first byte of word must be 0xff
+ SPI.transfer(0xff);
+ SPI.transfer(((uint8_t*) buf)[0]);
+ unselect();
+ oddAdr=1; //following addresses must all be shifted one off
+ len--;
+ if (len > 0) command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command
+ }
+
+ for (i=0;i<(len/2);i++){
+ //AAI command must be set before every new word
+ if (i>0) command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before
+ SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
+ SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]);
+ unselect();
+ }
+
+ if (len-i*2 == 1){
+ //There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd)
+ if (i>0) command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid
+ SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
+ SPI.transfer(0xff);
+ unselect();
+ }
+
+ command(SPIFLASH_WRITEDISABLE); //end AAI programming
+ unselect();
+#else
uint16_t n;
uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
uint16_t offset = 0;
@@ -244,7 +286,7 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
SPI.transfer(addr);
for (uint16_t i = 0; i < n; i++)
- SPI.transfer(((uint8_t*) buf)[offset + i]);
+ SPI.transfer(((uint8_t*) buf)[offset + i]);
unselect();
addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
@@ -252,6 +294,7 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
len -= n;
maxBytes = 256; // now we can do up to 256 bytes per loop
}
+#endif
}
/// erase entire flash memory array
diff --git a/drivers/SPIFlash/SPIFlash.h b/drivers/SPIFlash/SPIFlash.h
new file mode 100644
index 0000000..e08b6d5
--- /dev/null
+++ b/drivers/SPIFlash/SPIFlash.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2013-2015 by Felix Rusu, LowPowerLab.com
+// SPI Flash memory library for arduino/moteino.
+// This works with 256byte/page SPI flash memory
+// For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes)
+// Minimal modifications should allow chips that have different page size but modifications
+// DEPENDS ON: Arduino SPI library
+// > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
+// > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
+// > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4
+// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02,
+// > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory. Added / changed comments to better suit doxygen
+// **********************************************************************************
+// 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
+
+///
+/// @file SPIFlash.h
+///
+/// @brief SPIFlash provides access to a SPI Flash IC for OTA update or storing data
+///
+/// IMPORTANT: NAND FLASH memory requires erase before write, because
+/// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
+/// See http://en.wikipedia.org/wiki/Flash_memory
+/// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command
+///
+/// Standard SPI flash commands
+/// Assuming the WP pin is pulled up (to disable hardware write protection).
+/// To use any write commands the WEL bit in the status register must be set to 1.
+/// This is accomplished by sending a 0x06 command before any such write/erase command.
+/// The WEL bit in the status register resets to the logical ?0? state after a device power-up or reset.
+/// In addition, the WEL bit will be reset to the logical ?0? state automatically under the following conditions:
+/// - Write Disable operation completes successfully
+/// - Write Status Register operation completes successfully or aborts
+/// - Protect Sector operation completes successfully or aborts
+/// - Unprotect Sector operation completes successfully or aborts
+/// - Byte/Page Program operation completes successfully or aborts
+/// - Sequential Program Mode reaches highest unprotected memory location
+/// - Sequential Program Mode reaches the end of the memory array
+/// - Sequential Program Mode aborts
+/// - Block Erase operation completes successfully or aborts
+/// - Chip Erase operation completes successfully or aborts
+/// - Hold condition aborts
+///
+
+#ifndef _SPIFLASH_H_
+#define _SPIFLASH_H_
+
+#if ARDUINO >= 100
+#include
+#else
+#include
+#include "pins_arduino.h"
+#endif
+
+#include
+
+#define SPIFLASH_WRITEENABLE 0x06 //!< write enable
+#define SPIFLASH_WRITEDISABLE 0x04 //!< write disable
+
+#define SPIFLASH_BLOCKERASE_4K 0x20 //!< erase one 4K block of flash memory
+#define SPIFLASH_BLOCKERASE_32K 0x52 //!< erase one 32K block of flash memory
+#define SPIFLASH_BLOCKERASE_64K 0xD8 //!< erase one 64K block of flash memory
+#define SPIFLASH_CHIPERASE 0x60 //!< @brief chip erase (may take several seconds depending on size)
+ //!< Chip is erased but not actually waited for completion (instead need to check the status register BUSY bit)
+#define SPIFLASH_STATUSREAD 0x05 //!< read status register
+#define SPIFLASH_STATUSWRITE 0x01 //!< write status register
+#define SPIFLASH_ARRAYREAD 0x0B //!< read array (fast, need to add 1 dummy byte after 3 address bytes)
+#define SPIFLASH_ARRAYREADLOWFREQ 0x03 //!< read array (low frequency)
+
+#define SPIFLASH_SLEEP 0xB9 //!< deep power down
+#define SPIFLASH_WAKE 0xAB //!< deep power wake up
+#define SPIFLASH_BYTEPAGEPROGRAM 0x02 //!< write (1 to 256bytes). Writing more than one Byte is not supported on all devices (e.g. SST25 Series)
+#define SPIFLASH_AAIWORDPROGRAM 0xAD //!< @brief Auto Address Increment Programming on Microchip SST Family Devices which do not support page program.
+ //!< Use define #MY_SPIFLASH_SST25TYPE to use AAI prog instead of Bytepageprogram which does not work on SST Family Chips
+ //!< tested with SST25PF020B80 http://ww1.microchip.com/downloads/en/DeviceDoc/20005135B.pdf
+#define SPIFLASH_IDREAD 0x9F //!< @brief read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device)
+ //!< Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
+ //!< Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
+#define SPIFLASH_MACREAD 0x4B //!< read unique ID number (MAC)
+
+///
+/// @def MY_SPIFLASH_SST25TYPE
+/// @brief If set AAI Word Programming is used to support SST25 Family SPI Flash.
+///
+/// SST25 Family Flash does not support programming multiple Bytes with opcode 0x02 #SPIFLASH_BYTEPAGEPROGRAM.
+/// If SPIFLASH_SST25TYPE is set and writeBytes is called, it will use opcode 0xAD #SPIFLASH_AAIWORDPROGRAM and care for Byte alignment.
+/// Note: AAI Wordprogramming is independent of Pages, so pagebreaking is not an issue when using AAI Wordprogramming.
+///
+ #ifdef DOXYGEN //needed to tell doxygen not to ignore the define which is actually made somewhere else
+ #define MY_SPIFLASH_SST25TYPE
+ #endif
+
+/** SPIFlash class */
+class SPIFlash {
+public:
+ static uint8_t UNIQUEID[8]; //!< Storage for unique identifier
+ SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); //!< Constructor
+ boolean initialize(); //!< setup SPI, read device ID etc...
+ void command(uint8_t cmd, boolean isWrite=false); //!< Send a command to the flash chip, pass TRUE for isWrite when its a write command
+ uint8_t readStatus(); //!< return the STATUS register
+ uint8_t readByte(uint32_t addr); //!< read 1 byte from flash memory
+ void readBytes(uint32_t addr, void* buf, uint16_t len); //!< read unlimited # of bytes
+ void writeByte(uint32_t addr, uint8_t byt); //!< Write 1 byte to flash memory
+ void writeBytes(uint32_t addr, const void* buf, uint16_t len); //!< write multiple bytes to flash memory (up to 64K), if define SPIFLASH_SST25TYPE is set AAI Word Programming will be used
+ boolean busy(); //!< check if the chip is busy erasing/writing
+ void chipErase(); //!< erase entire flash memory array
+ void blockErase4K(uint32_t address); //!< erase a 4Kbyte block
+ void blockErase32K(uint32_t address); //!< erase a 32Kbyte block
+ uint16_t readDeviceId(); //!< Get the manufacturer and device ID bytes (as a short word)
+ uint8_t* readUniqueId(); //!< Get the 64 bit unique identifier, stores it in @ref UNIQUEID[8]
+
+ void sleep(); //!< Put device to sleep
+ void wakeup(); //!< Wake device
+ void end(); //!< end
+protected:
+ void select(); //!< select
+ void unselect(); //!< unselect
+ uint8_t _slaveSelectPin; //!< Slave select pin
+ uint16_t _jedecID; //!< JEDEC ID
+ uint8_t _SPCR; //!< SPCR
+ uint8_t _SPSR; //!< SPSR
+#ifdef SPI_HAS_TRANSACTION
+ SPISettings _settings;
+#endif
+};
+
+#endif
diff --git a/libraries/MySensors/drivers/pubsubclient/CHANGES.txt b/drivers/pubsubclient/CHANGES.txt
similarity index 92%
rename from libraries/MySensors/drivers/pubsubclient/CHANGES.txt
rename to drivers/pubsubclient/CHANGES.txt
index 5202dda..8c8bef6 100644
--- a/libraries/MySensors/drivers/pubsubclient/CHANGES.txt
+++ b/drivers/pubsubclient/CHANGES.txt
@@ -1,3 +1,8 @@
+2.4
+ * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
+ whilst waiting for inbound data
+ * Fixed return code when publishing >256 bytes
+
2.3
* Add publish(topic,payload,retained) function
diff --git a/libraries/MySensors/drivers/pubsubclient/LICENSE.txt b/drivers/pubsubclient/LICENSE.txt
similarity index 100%
rename from libraries/MySensors/drivers/pubsubclient/LICENSE.txt
rename to drivers/pubsubclient/LICENSE.txt
diff --git a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino
similarity index 88%
rename from libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino
rename to examples/AirQualitySensor/AirQualitySensor.ino
index b26bc62..f2bc01b 100644
--- a/libraries/MySensors/examples/AirQualitySensor/AirQualitySensor.ino
+++ b/examples/AirQualitySensor/AirQualitySensor.ino
@@ -21,30 +21,30 @@
* DESCRIPTION
*
* Connect the MQ2 sensor as follows :
- *
+ *
* A H A >>> 5V
* B >>> A0
* H >>> GND
* B >>> 10K ohm >>> GND
- *
+ *
* Contribution: epierre
* Based on http://sandboxelectronics.com/?p=165
* License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
* Modified by HEK to work in 1.4
- *
+ *
*/
// Enable debug prints to serial monitor
-#define MY_DEBUG
+#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#include
-#include
+#include
-#define CHILD_ID_MQ 0
+#define CHILD_ID_MQ 0
/************************Hardware Related Macros************************************/
#define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use
#define RL_VALUE (5) //define the load resistance on the board, in kilo ohms
@@ -55,7 +55,7 @@
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
-#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
+#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
//normal operation
/**********************Application Related Macros**********************************/
#define GAS_LPG (0)
@@ -68,25 +68,25 @@ float Ro = 10000.0; // this has to be tuned 10K Ohm
int val = 0; // variable to store the value coming from the sensor
float valMQ =0.0;
float lastMQ =0.0;
-float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
+float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
//with these two points, a line is formed which is "approximately equivalent"
- //to the original curve.
- //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
-float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
- //with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
- //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
-float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve.
- //with these two points, a line is formed which is "approximately equivalent"
+ //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
+float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
+ //with these two points, a line is formed which is "approximately equivalent"
//to the original curve.
- //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
+ //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
+float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve.
+ //with these two points, a line is formed which is "approximately equivalent"
+ //to the original curve.
+ //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
MyMessage msg(CHILD_ID_MQ, V_LEVEL);
-void setup()
-{
- Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
+void setup()
+{
+ Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
}
void presentation() {
@@ -94,33 +94,33 @@ void presentation() {
sendSketchInfo("Air Quality Sensor", "1.0");
// Register all sensors to gateway (they will be created as child devices)
- present(CHILD_ID_MQ, S_AIR_QUALITY);
+ present(CHILD_ID_MQ, S_AIR_QUALITY);
}
-void loop()
-{
+void loop()
+{
uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO);
Serial.println(val);
-
- Serial.print("LPG:");
+
+ Serial.print("LPG:");
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) );
Serial.print( "ppm" );
- Serial.print(" ");
- Serial.print("CO:");
+ Serial.print(" ");
+ Serial.print("CO:");
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) );
Serial.print( "ppm" );
- Serial.print(" ");
- Serial.print("SMOKE:");
+ Serial.print(" ");
+ Serial.print("SMOKE:");
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) );
Serial.print( "ppm" );
Serial.print("\n");
-
+
if (valMQ != lastMQ) {
- send(msg.set((int)ceil(valMQ)));
+ send(msg.set((int16_t)ceil(valMQ)));
lastMQ = ceil(valMQ);
}
-
- sleep(SLEEP_TIME); //sleep for: sleepTime
+
+ sleep(SLEEP_TIME); //sleep for: sleepTime
}
/****************** MQResistanceCalculation ****************************************
@@ -129,35 +129,35 @@ Output: the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
across the load resistor and its resistance, the resistance of the sensor
could be derived.
-************************************************************************************/
+************************************************************************************/
float MQResistanceCalculation(int raw_adc)
{
return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}
-
+
/***************************** MQCalibration ****************************************
Input: mq_pin - analog channel
Output: Ro of the sensor
-Remarks: This function assumes that the sensor is in clean air. It use
- MQResistanceCalculation to calculates the sensor resistance in clean air
- and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
+Remarks: This function assumes that the sensor is in clean air. It use
+ MQResistanceCalculation to calculates the sensor resistance in clean air
+ and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
10, which differs slightly between different sensors.
-************************************************************************************/
+************************************************************************************/
float MQCalibration(int mq_pin)
{
int i;
float val=0;
-
+
for (i=0;i
-#include
+#include
int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
diff --git a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
similarity index 91%
rename from libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
rename to examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
index 8a8ce43..3c6c08f 100644
--- a/libraries/MySensors/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
+++ b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino
@@ -22,23 +22,23 @@
*
* Interrupt driven binary switch example with dual interrupts
* Author: Patrick 'Anticimex' Fallberg
- * Connect one button or door/window reed switch between
+ * Connect one button or door/window reed switch between
* digitial I/O pin 3 (BUTTON_PIN below) and GND and the other
* one in similar fashion on digital I/O pin 2.
* This example is designed to fit Arduino Nano/Pro Mini
- *
+ *
*/
// Enable debug prints to serial monitor
-#define MY_DEBUG
+#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define SKETCH_NAME "Binary Sensor"
#define SKETCH_MAJOR_VER "1"
@@ -62,14 +62,14 @@
#if (PRIMARY_CHILD_ID == SECONDARY_CHILD_ID)
#error PRIMARY_CHILD_ID and SECONDARY_CHILD_ID cannot be the same
#endif
-
+
// Change to V_LIGHT if you use S_LIGHT in presentation below
MyMessage msg(PRIMARY_CHILD_ID, V_TRIPPED);
MyMessage msg2(SECONDARY_CHILD_ID, V_TRIPPED);
-void setup()
-{
+void setup()
+{
// Setup the buttons
pinMode(PRIMARY_BUTTON_PIN, INPUT);
pinMode(SECONDARY_BUTTON_PIN, INPUT);
@@ -84,14 +84,14 @@ void presentation() {
sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER);
// Register binary input sensor to sensor_node (they will be created as child devices)
- // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
+ // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
// If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
- present(PRIMARY_CHILD_ID, S_DOOR);
- present(SECONDARY_CHILD_ID, S_DOOR);
+ present(PRIMARY_CHILD_ID, S_DOOR);
+ present(SECONDARY_CHILD_ID, S_DOOR);
}
// Loop will iterate on changes on the BUTTON_PINs
-void loop()
+void loop()
{
uint8_t value;
static uint8_t sentValue=2;
@@ -99,23 +99,23 @@ void loop()
// Short delay to allow buttons to properly settle
sleep(5);
-
+
value = digitalRead(PRIMARY_BUTTON_PIN);
-
+
if (value != sentValue) {
// Value has changed from last transmission, send the updated value
- send(msg.set(value==HIGH ? 1 : 0));
+ send(msg.set(value==HIGH));
sentValue = value;
}
value = digitalRead(SECONDARY_BUTTON_PIN);
-
+
if (value != sentValue2) {
// Value has changed from last transmission, send the updated value
- send(msg2.set(value==HIGH ? 1 : 0));
+ send(msg2.set(value==HIGH));
sentValue2 = value;
}
// Sleep until something happens with the sensor
sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SECONDARY_BUTTON_PIN-2, CHANGE, 0);
-}
+}
diff --git a/libraries/MySensors/examples/CO2Sensor/CO2Sensor.ino b/examples/CO2Sensor/CO2Sensor.ino
similarity index 99%
rename from libraries/MySensors/examples/CO2Sensor/CO2Sensor.ino
rename to examples/CO2Sensor/CO2Sensor.ino
index 1dcb75e..cd6e7fc 100644
--- a/libraries/MySensors/examples/CO2Sensor/CO2Sensor.ino
+++ b/examples/CO2Sensor/CO2Sensor.ino
@@ -46,7 +46,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID_AIQ 0
#define AIQ_SENSOR_ANALOG_PIN 6
diff --git a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino b/examples/ClearEepromConfig/ClearEepromConfig.ino
similarity index 98%
rename from libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino
rename to examples/ClearEepromConfig/ClearEepromConfig.ino
index 272bf43..f2a7e79 100644
--- a/libraries/MySensors/examples/ClearEepromConfig/ClearEepromConfig.ino
+++ b/examples/ClearEepromConfig/ClearEepromConfig.ino
@@ -27,7 +27,7 @@
#define MY_CORE_ONLY
#include
-#include
+#include
void setup()
{
diff --git a/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino b/examples/DimmableLEDActuator/DimmableLEDActuator.ino
similarity index 87%
rename from libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino
rename to examples/DimmableLEDActuator/DimmableLEDActuator.ino
index abc81f7..aa04a93 100644
--- a/libraries/MySensors/examples/DimmableLEDActuator/DimmableLEDActuator.ino
+++ b/examples/DimmableLEDActuator/DimmableLEDActuator.ino
@@ -20,30 +20,30 @@
*
* REVISION HISTORY
* Version 1.0 - February 15, 2014 - Bruce Lacey
- * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek)
+ * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek)
*
* DESCRIPTION
- * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad
- * Vera Arduino Sensor project.
+ * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad
+ * Vera Arduino Sensor project.
* Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches.
- *
- * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.
+ *
+ * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.
* The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected
- * to the LED negative terminal and the MOSFET Source pin is connected to ground.
+ * to the LED negative terminal and the MOSFET Source pin is connected to ground.
*
* This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit.
* http://www.mysensors.org/build/dimmer
*/
// Enable debug prints to serial monitor
-#define MY_DEBUG
+#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define SN "DimmableLED"
#define SV "1.1"
@@ -51,7 +51,7 @@
#define LED_PIN 3 // Arduino pin attached to MOSFET Gate pin
#define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
-static int currentLevel = 0; // Current dim level...
+static int16_t currentLevel = 0; // Current dim level...
MyMessage dimmerMsg(0, V_DIMMER);
MyMessage lightMsg(0, V_LIGHT);
@@ -59,8 +59,8 @@ MyMessage lightMsg(0, V_LIGHT);
/***
* Dimmable LED initialization method
*/
-void setup()
-{
+void setup()
+{
// Pull the gateway's current dim level - restore light level upon sendor node power-up
request( 0, V_DIMMER );
}
@@ -68,14 +68,14 @@ void setup()
void presentation() {
// Register the LED Dimmable Light with the gateway
present( 0, S_DIMMER );
-
+
sendSketchInfo(SN, SV);
}
/***
- * Dimmable LED main processing loop
+ * Dimmable LED main processing loop
*/
-void loop()
+void loop()
{
}
@@ -83,31 +83,31 @@ void loop()
void receive(const MyMessage &message) {
if (message.type == V_LIGHT || message.type == V_DIMMER) {
-
+
// Retrieve the power or dim level from the incoming request message
int requestedLevel = atoi( message.data );
-
+
// Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
-
+
// Clip incoming level to valid range of 0 to 100
requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
requestedLevel = requestedLevel < 0 ? 0 : requestedLevel;
-
+
Serial.print( "Changing level to " );
Serial.print( requestedLevel );
- Serial.print( ", from " );
+ Serial.print( ", from " );
Serial.println( currentLevel );
fadeToLevel( requestedLevel );
-
+
// Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
- send(lightMsg.set(currentLevel > 0 ? 1 : 0));
+ send(lightMsg.set(currentLevel > 0));
// hek comment: Is this really nessesary?
send( dimmerMsg.set(currentLevel) );
-
+
}
}
@@ -117,11 +117,10 @@ void receive(const MyMessage &message) {
void fadeToLevel( int toLevel ) {
int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1;
-
+
while ( currentLevel != toLevel ) {
currentLevel += delta;
analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) );
delay( FADE_DELAY );
}
}
-
diff --git a/libraries/MySensors/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino
similarity index 90%
rename from libraries/MySensors/examples/DimmableLight/DimmableLight.ino
rename to examples/DimmableLight/DimmableLight.ino
index ddbf9d5..e834daf 100644
--- a/libraries/MySensors/examples/DimmableLight/DimmableLight.ino
+++ b/examples/DimmableLight/DimmableLight.ino
@@ -20,13 +20,13 @@
*
* REVISION HISTORY
* Version 1.0 - January 30, 2015 - Developed by GizMoCuz (Domoticz)
- *
+ *
* DESCRIPTION
- * This sketch provides an example how to implement a Dimmable Light
+ * This sketch provides an example how to implement a Dimmable Light
* It is pure virtual and it logs messages to the serial output
* It can be used as a base sketch for actual hardware.
* Stores the last light state and level in eeprom.
- *
+ *
*/
// Enable debug prints
@@ -37,7 +37,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID_LIGHT 1
@@ -50,19 +50,19 @@
#define SN "Dimable Light"
#define SV "1.0"
-int LastLightState=LIGHT_OFF;
-int LastDimValue=100;
+int16_t LastLightState=LIGHT_OFF;
+int16_t LastDimValue=100;
MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
-void setup()
-{
+void setup()
+{
//Retreive our last light state from the eprom
- int LightState=loadState(EPROM_LIGHT_STATE);
+ int LightState=loadState(EPROM_LIGHT_STATE);
if (LightState<=1) {
LastLightState=LightState;
- int DimValue=loadState(EPROM_DIMMER_LEVEL);
+ int DimValue=loadState(EPROM_DIMMER_LEVEL);
if ((DimValue>0)&&(DimValue<=100)) {
//There should be no Dim value of 0, this would mean LIGHT_OFF
LastDimValue=DimValue;
@@ -71,8 +71,8 @@ void setup()
//Here you actualy switch on/off the light with the last known dim level
SetCurrentState2Hardware();
-
- Serial.println( "Node ready to receive messages..." );
+
+ Serial.println( "Node ready to receive messages..." );
}
void presentation() {
@@ -82,7 +82,7 @@ void presentation() {
present(CHILD_ID_LIGHT, S_DIMMER );
}
-void loop()
+void loop()
{
}
@@ -90,7 +90,7 @@ void receive(const MyMessage &message)
{
if (message.type == V_LIGHT) {
Serial.println( "V_LIGHT command received..." );
-
+
int lstate= atoi( message.data );
if ((lstate<0)||(lstate>1)) {
Serial.println( "V_LIGHT data invalid (should be 0/1)" );
@@ -98,7 +98,7 @@ void receive(const MyMessage &message)
}
LastLightState=lstate;
saveState(EPROM_LIGHT_STATE, LastLightState);
-
+
if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) {
//In the case that the Light State = On, but the dimmer value is zero,
//then something (probably the controller) did something wrong,
@@ -106,13 +106,13 @@ void receive(const MyMessage &message)
LastDimValue=100;
saveState(EPROM_DIMMER_LEVEL, LastDimValue);
}
-
+
//When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value
//This means if you previously set the lights dimmer value to 50%, and turn the light ON
//it will do so at 50%
}
else if (message.type == V_DIMMER) {
- Serial.println( "V_DIMMER command received..." );
+ Serial.println( "V_DIMMER command received..." );
int dimvalue= atoi( message.data );
if ((dimvalue<0)||(dimvalue>100)) {
Serial.println( "V_DIMMER data invalid (should be 0..100)" );
@@ -128,7 +128,7 @@ void receive(const MyMessage &message)
}
}
else {
- Serial.println( "Invalid command received..." );
+ Serial.println( "Invalid command received..." );
return;
}
@@ -153,10 +153,9 @@ void SetCurrentState2Hardware()
void SendCurrentState2Controller()
{
if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) {
- send(dimmerMsg.set(0));
+ send(dimmerMsg.set((int16_t)0));
}
else {
send(dimmerMsg.set(LastDimValue));
}
}
-
diff --git a/libraries/MySensors/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino
similarity index 97%
rename from libraries/MySensors/examples/DustSensor/DustSensor.ino
rename to examples/DustSensor/DustSensor.ino
index 9542d17..8b4cedd 100644
--- a/libraries/MySensors/examples/DustSensor/DustSensor.ino
+++ b/examples/DustSensor/DustSensor.ino
@@ -46,7 +46,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID_DUST 0
#define DUST_SENSOR_ANALOG_PIN 1
@@ -94,7 +94,7 @@ void loop() {
Serial.println(dustDensity); // unit: ug/m3
if (ceil(dustDensity) != lastDUST) {
- send(dustMsg.set((int)ceil(dustDensity)));
+ send(dustMsg.set((int16_t)ceil(dustDensity)));
lastDUST = ceil(dustDensity);
}
diff --git a/libraries/MySensors/examples/DustSensorDSM/DustSensorDSM.ino b/examples/DustSensorDSM/DustSensorDSM.ino
similarity index 99%
rename from libraries/MySensors/examples/DustSensorDSM/DustSensorDSM.ino
rename to examples/DustSensorDSM/DustSensorDSM.ino
index b004344..e27a37a 100644
--- a/libraries/MySensors/examples/DustSensorDSM/DustSensorDSM.ino
+++ b/examples/DustSensorDSM/DustSensorDSM.ino
@@ -38,7 +38,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID_DUST_PM10 0
#define CHILD_ID_DUST_PM25 1
diff --git a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
similarity index 96%
rename from libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
rename to examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
index 9b957de..2785679 100644
--- a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
+++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
@@ -42,13 +42,12 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!)
#define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter
#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false.
#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers.
-#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 1 // Id of the sensor child
unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
@@ -74,8 +73,8 @@ void setup()
// Use the internal pullup to be able to hook up this sketch directly to an energy meter with S0 output
// If no pullup is used, the reported usage will be too high because of the floating pin
pinMode(DIGITAL_INPUT_SENSOR,INPUT_PULLUP);
-
- attachInterrupt(INTERRUPT, onPulse, RISING);
+
+ attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, RISING);
lastSend=millis();
}
diff --git a/libraries/MySensors/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino
similarity index 96%
rename from libraries/MySensors/examples/GatewayESP8266/GatewayESP8266.ino
rename to examples/GatewayESP8266/GatewayESP8266.ino
index 803eb7d..2408bea 100644
--- a/libraries/MySensors/examples/GatewayESP8266/GatewayESP8266.ino
+++ b/examples/GatewayESP8266/GatewayESP8266.ino
@@ -86,6 +86,10 @@
// Enable UDP communication
//#define MY_USE_UDP
+// Set the hostname for the WiFi Client. This is the hostname
+// it will pass to the DHCP server if not static.
+// #define MY_ESP8266_HOSTNAME "sensor-gateway"
+
// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
//#define MY_IP_ADDRESS 192,168,178,87
@@ -130,7 +134,7 @@
#include
#endif
-#include
+#include
void setup() {
}
diff --git a/libraries/MySensors/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
similarity index 94%
rename from libraries/MySensors/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
rename to examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
index 60d052e..164aa12 100644
--- a/libraries/MySensors/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
+++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino
@@ -73,7 +73,7 @@
#define MY_GATEWAY_MQTT_CLIENT
#define MY_GATEWAY_ESP8266
-// Set this nodes subscripe and publish topic prefix
+// Set this node's subscribe and publish topic prefix
#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
@@ -88,6 +88,10 @@
#define MY_ESP8266_SSID "MySSID"
#define MY_ESP8266_PASSWORD "MyVerySecretPassword"
+// Set the hostname for the WiFi Client. This is the hostname
+// it will pass to the DHCP server if not static.
+// #define MY_ESP8266_HOSTNAME "mqtt-sensor-gateway"
+
// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
#define MY_IP_ADDRESS 192,168,178,87
@@ -123,7 +127,7 @@
*/
#include
-#include
+#include
void setup() {
}
diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino
new file mode 100644
index 0000000..f89ccf8
--- /dev/null
+++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino
@@ -0,0 +1,179 @@
+/**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ *******************************
+ *
+ * REVISION HISTORY
+ * Version 1.0 - Henrik EKblad
+ * Contribution by tekka,
+ * Contribution by a-lurker and Anticimex,
+ * Contribution by Norbert Truchsess
+ * Contribution by Ivo Pullens (ESP8266 support)
+ *
+ * DESCRIPTION
+ * The EthernetGateway sends data received from sensors to the WiFi link.
+ * The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
+ *
+ * VERA CONFIGURATION:
+ * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
+ * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
+ *
+ * LED purposes:
+ * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
+ * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
+ * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ *
+ * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions.
+ * nRF24L01+ ESP8266
+ * VCC VCC
+ * CE GPIO4
+ * CSN/CS GPIO15
+ * SCK GPIO14
+ * MISO GPIO12
+ * MOSI GPIO13
+ * GND GND
+ *
+ * Not all ESP8266 modules have all pins available on their external interface.
+ * This code has been tested on an ESP-12 module.
+ * The ESP8266 requires a certain pin configuration to download code, and another one to run code:
+ * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
+ * - Connect GPIO15 via 10K pulldown resistor to GND
+ * - Connect CH_PD via 10K resistor to VCC
+ * - Connect GPIO2 via 10K resistor to VCC
+ * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
+ *
+ * Inclusion mode button:
+ * - Connect GPIO5 via switch to GND ('inclusion switch')
+ *
+ * Hardware SHA204 signing is currently not supported!
+ *
+ * Make sure to fill in your ssid and WiFi password below for ssid & pass.
+ */
+
+#include
+#include
+#include
+
+// Enable debug prints to serial monitor
+#define MY_DEBUG
+
+// Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h
+#define MY_BAUD_RATE 9600
+
+// Enables and select radio type (if attached)
+#define MY_RADIO_NRF24
+//#define MY_RADIO_RFM69
+
+#define MY_GATEWAY_ESP8266
+
+#define MY_ESP8266_SSID "MySSID"
+#define MY_ESP8266_PASSWORD "MyVerySecretPassword"
+
+// Set the hostname for the WiFi Client. This is the hostname
+// it will pass to the DHCP server if not static.
+// #define MY_ESP8266_HOSTNAME "sensor-ota-gateway"
+
+// Enable UDP communication
+//#define MY_USE_UDP
+
+// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP)
+//#define MY_IP_ADDRESS 192,168,178,87
+
+// If using static ip you need to define Gateway and Subnet address as well
+#define MY_IP_GATEWAY_ADDRESS 192,168,178,1
+#define MY_IP_SUBNET_ADDRESS 255,255,255,0
+
+// The port to keep open on node server mode
+#define MY_PORT 5003
+
+// How many clients should be able to connect to this gateway (default 1)
+#define MY_GATEWAY_MAX_CLIENTS 2
+
+// Controller ip address. Enables client mode (default is "server" mode).
+// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere.
+//#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68
+
+// Enable inclusion mode
+#define MY_INCLUSION_MODE_FEATURE
+
+// Enable Inclusion mode button on gateway
+// #define MY_INCLUSION_BUTTON_FEATURE
+// Set inclusion mode duration (in seconds)
+#define MY_INCLUSION_MODE_DURATION 60
+// Digital pin used for inclusion mode button
+#define MY_INCLUSION_MODE_BUTTON_PIN 3
+
+
+// Flash leds on rx/tx/err
+// #define MY_LEDS_BLINKING_FEATURE
+// Set blinking period
+// #define MY_DEFAULT_LED_BLINK_PERIOD 300
+
+// Led pins used if blinking feature is enabled above
+#define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin
+#define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin
+#define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED
+
+#if defined(MY_USE_UDP)
+ #include
+#else
+ #include
+#endif
+
+#include
+
+void setup() {
+
+ ArduinoOTA.onStart([]() {
+ Serial.println("ArduinoOTA start");
+ });
+ ArduinoOTA.onEnd([]() {
+ Serial.println("\nArduinoOTA end");
+ });
+ ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+ Serial.printf("OTA Progress: %u%%\r", (progress / (total / 100)));
+ });
+ ArduinoOTA.onError([](ota_error_t error) {
+ Serial.printf("Error[%u]: ", error);
+ if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
+ else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
+ else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
+ else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
+ else if (error == OTA_END_ERROR) Serial.println("End Failed");
+ });
+ ArduinoOTA.begin();
+ Serial.println("Ready");
+ Serial.print("IP address: ");
+ Serial.println(WiFi.localIP());
+
+}
+
+void presentation() {
+ // Present locally attached sensors here
+}
+
+
+void loop() {
+ // Send locally attech sensors data here
+ ArduinoOTA.handle();
+}
+
+
+
+
diff --git a/libraries/MySensors/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino
similarity index 92%
rename from libraries/MySensors/examples/GatewaySerial/GatewaySerial.ino
rename to examples/GatewaySerial/GatewaySerial.ino
index 6430de8..4d72270 100644
--- a/libraries/MySensors/examples/GatewaySerial/GatewaySerial.ino
+++ b/examples/GatewaySerial/GatewaySerial.ino
@@ -51,6 +51,11 @@
// Enable serial gateway
#define MY_GATEWAY_SERIAL
+// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
+#if F_CPU == 8000000L
+#define MY_BAUD_RATE 38400
+#endif
+
// Flash leds on rx/tx/err
#define MY_LEDS_BLINKING_FEATURE
// Set blinking period
@@ -62,7 +67,7 @@
// Enable inclusion mode
#define MY_INCLUSION_MODE_FEATURE
// Enable Inclusion mode button on gateway
-#define MY_INCLUSION_BUTTON_FEATURE
+//#define MY_INCLUSION_BUTTON_FEATURE
// Inverses behavior of inclusion button (if using external pullup)
//#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP
@@ -70,7 +75,7 @@
// Set inclusion mode duration (in seconds)
#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
-#define MY_INCLUSION_MODE_BUTTON_PIN 3
+//#define MY_INCLUSION_MODE_BUTTON_PIN 3
// Uncomment to override default HW configurations
//#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin
@@ -78,7 +83,7 @@
//#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED
#include
-#include
+#include
void setup() {
// Setup locally attached sensors
diff --git a/libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino
similarity index 99%
rename from libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino
rename to examples/GatewaySerialRS485/GatewaySerialRS485.ino
index 3cdf756..3c3ca92 100644
--- a/libraries/MySensors/examples/GatewaySerialRS485/GatewaySerialRS485.ino
+++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino
@@ -83,7 +83,7 @@
#define MY_DEFAULT_TX_LED_PIN 6 // the PCB, on board LED
#include
-#include
+#include
void setup() {
// Setup locally attached sensors
diff --git a/libraries/MySensors/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino
similarity index 95%
rename from libraries/MySensors/examples/GatewayW5100/GatewayW5100.ino
rename to examples/GatewayW5100/GatewayW5100.ino
index d634db9..5e7ca3f 100644
--- a/libraries/MySensors/examples/GatewayW5100/GatewayW5100.ino
+++ b/examples/GatewayW5100/GatewayW5100.ino
@@ -65,8 +65,12 @@
#endif
// When W5100 is connected we have to move CE/CSN pins for NRF radio
-#define MY_RF24_CE_PIN 5
-#define MY_RF24_CS_PIN 6
+#ifndef MY_RF24_CE_PIN
+ #define MY_RF24_CE_PIN 5
+#endif
+#ifndef MY_RF24_CS_PIN
+ #define MY_RF24_CS_PIN 6
+#endif
// Enable to UDP
//#define MY_USE_UDP
@@ -94,11 +98,11 @@
// Enable inclusion mode
#define MY_INCLUSION_MODE_FEATURE
// Enable Inclusion mode button on gateway
-#define MY_INCLUSION_BUTTON_FEATURE
+//#define MY_INCLUSION_BUTTON_FEATURE
// Set inclusion mode duration (in seconds)
#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
-#define MY_INCLUSION_MODE_BUTTON_PIN 3
+//#define MY_INCLUSION_MODE_BUTTON_PIN 3
// Uncomment to override default HW configurations
//#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin
@@ -111,7 +115,7 @@
#include
#endif
#include
-#include
+#include
void setup()
diff --git a/libraries/MySensors/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
similarity index 93%
rename from libraries/MySensors/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
rename to examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
index 37c8f26..8798c3a 100644
--- a/libraries/MySensors/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
+++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino
@@ -68,7 +68,7 @@
#define MY_GATEWAY_MQTT_CLIENT
-// Set this nodes subscripe and publish topic prefix
+// Set this node's subscribe and publish topic prefix
#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out"
#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in"
@@ -89,8 +89,12 @@
#endif
// When W5100 is connected we have to move CE/CSN pins for NRF radio
-#define MY_RF24_CE_PIN 5
-#define MY_RF24_CS_PIN 6
+#ifndef MY_RF24_CE_PIN
+ #define MY_RF24_CE_PIN 5
+#endif
+#ifndef MY_RF24_CS_PIN
+ #define MY_RF24_CS_PIN 6
+#endif
// Enable these if your MQTT broker requires usenrame/password
//#define MY_MQTT_USER "username"
@@ -119,11 +123,11 @@
// Enable inclusion mode
#define MY_INCLUSION_MODE_FEATURE
// Enable Inclusion mode button on gateway
-#define MY_INCLUSION_BUTTON_FEATURE
+//#define MY_INCLUSION_BUTTON_FEATURE
// Set inclusion mode duration (in seconds)
#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
-#define MY_INCLUSION_MODE_BUTTON_PIN 3
+//#define MY_INCLUSION_MODE_BUTTON_PIN 3
// Uncomment to override default HW configurations
//#define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin
@@ -132,7 +136,7 @@
*/
#include
-#include
+#include
void setup() {
}
@@ -143,7 +147,7 @@ void presentation() {
void loop() {
- // Send locally attech sensors data here
+ // Send locally attached sensors data here
}
diff --git a/libraries/MySensors/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino
similarity index 95%
rename from libraries/MySensors/examples/LightSensor/LightSensor.ino
rename to examples/LightSensor/LightSensor.ino
index a59fc51..193130d 100644
--- a/libraries/MySensors/examples/LightSensor/LightSensor.ino
+++ b/examples/LightSensor/LightSensor.ino
@@ -34,7 +34,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID_LIGHT 0
#define LIGHT_SENSOR_ANALOG_PIN 0
@@ -55,7 +55,7 @@ void presentation() {
void loop()
{
- int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
+ int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
Serial.println(lightLevel);
if (lightLevel != lastLightLevel) {
send(msg.set(lightLevel));
diff --git a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino
similarity index 95%
rename from libraries/MySensors/examples/MockMySensors/MockMySensors.ino
rename to examples/MockMySensors/MockMySensors.ino
index e40e301..dfed9be 100644
--- a/libraries/MySensors/examples/MockMySensors/MockMySensors.ino
+++ b/examples/MockMySensors/MockMySensors.ino
@@ -7,7 +7,7 @@
*/
// Enable debug prints to serial monitor
-#define MY_DEBUG
+#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
@@ -16,7 +16,7 @@
#define MY_NODE_ID 254
#include
-#include
+#include
#define RADIO_ERROR_LED_PIN 4 // Error led pin
#define RADIO_RX_LED_PIN 6 // Receive led pin
@@ -37,7 +37,7 @@
*/
////#define ID_S_ARDUINO_NODE //auto defined in initialization
-////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization
+////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization
// Some of these ID's have not been updated for v1.5. Uncommenting too many of them
@@ -57,15 +57,15 @@
//#define ID_S_WIND 10
//#define ID_S_RAIN 11
//#define ID_S_UV 12
-//#define ID_S_WEIGHT 13
+//#define ID_S_WEIGHT 13
//#define ID_S_POWER 14
//#define ID_S_HEATER 15
//#define ID_S_DISTANCE 16
-//#define ID_S_LIGHT_LEVEL 17
+//#define ID_S_LIGHT_LEVEL 17
//#define ID_S_LOCK 18
//#define ID_S_IR 19
-//#define ID_S_WATER 20
-//#define ID_S_AIR_QUALITY 21
+//#define ID_S_WATER 20
+//#define ID_S_AIR_QUALITY 21
//#define ID_S_DUST 22
//#define ID_S_SCENE_CONTROLLER 23
//// Lib 1.5 sensors
@@ -170,20 +170,20 @@ long randNumber;
#ifdef ID_S_HEATER
//////// REVIEW IMPLEMENTATION ////////////
-
+
MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC
MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER
-
+
//MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS);
//MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP);
-
+
float heater_setpoint=21.5;
String heater_flow_state="Off";
-
+
// float heater_temp=23.5;
// bool heater_status=false;
-
-
+
+
// V_TEMP // Temperature
// V_STATUS // Binary status. 0=off 1=on
// V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver"
@@ -229,22 +229,22 @@ long randNumber;
// not sure if scene controller sends int or chars
// betting on ints as Touch Display Scen by Hek // compiler warnings
char *scenes[] = {
- (char *)"Good Morning",
- (char *)"Clean Up!",
- (char *)"All Lights Off",
+ (char *)"Good Morning",
+ (char *)"Clean Up!",
+ (char *)"All Lights Off",
(char *)"Music On/Off"
};
-
+
int sceneVal=0;
int sceneValPrevious=0;
-
+
#endif
-#ifdef ID_S_RGB_LIGHT
+#ifdef ID_S_RGB_LIGHT
MyMessage msg_S_RGB_LIGHT_V_RGB(ID_S_RGB_LIGHT,V_RGB);
MyMessage msg_S_RGB_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT);
String rgbState="000000";
- //RGB light V_RGB, V_WATT
+ //RGB light V_RGB, V_WATT
//RGB value transmitted as ASCII hex string (I.e "ff0000" for red)
#endif
@@ -268,20 +268,20 @@ long randNumber;
MyMessage msg_S_HVAC_V_HVAC_FLOW_STATET(ID_S_HVAC,V_HVAC_FLOW_STATE);
MyMessage msg_S_HVAC_V_HVAC_FLOW_MODE(ID_S_HVAC,V_HVAC_FLOW_MODE);
MyMessage msg_S_HVAC_V_HVAC_SPEED(ID_S_HVAC,V_HVAC_SPEED);
-
+
float hvac_SetPointHeat = 16.5;
float hvac_SetPointCool = 25.5;
String hvac_FlowState = "AutoChangeOver";
String hvac_FlowMode = "Auto";
String hvac_Speed = "Normal";
- //Thermostat/HVAC device
+ //Thermostat/HVAC device
//V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint
//V_HVAC_SETPOINT_COOL, // HVAC cold setpoint
//V_HVAC_FLOW_STATE, // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver"
//V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
//V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
-
+
// NOT IMPLEMENTED YET
//V_TEMP // Temperature
//V_STATUS // Binary status. 0=off 1=on
@@ -300,7 +300,7 @@ long randNumber;
#ifdef ID_S_SPRINKLER
// S_SPRINKLER 31 Sprinkler device V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
- // V_STATUS 2 Binary status. 0=off 1=on
+ // V_STATUS 2 Binary status. 0=off 1=on
// V_ARMED 15 Armed status of a security sensor. 1=Armed, 0=Bypassed
// V_TRIPPED 16 Tripped status of a security sensor. 1=Tripped, 0=Untripped
#endif
@@ -316,7 +316,7 @@ long randNumber;
#ifdef ID_S_MOISTURE
MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL);
-#endif
+#endif
#ifdef ID_S_CUSTOM
MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1);
@@ -329,11 +329,11 @@ long randNumber;
-void setup()
-{
+void setup()
+{
// Random SEED
randomSeed(analogRead(0));
-
+
wait(LONG_WAIT);
Serial.println("GW Started");
}
@@ -345,190 +345,190 @@ void presentation() {
Serial.print(SKETCH_NAME);
Serial.println(SKETCH_VERSION);
wait(LONG_WAIT);
-
+
// Get controller configuration
Serial.print("Get Config: ");
metric = getConfig().isMetric;
Serial.println(metric ? "Metric":"Imperial");
wait(LONG_WAIT);
-
+
// Init Armed
#ifdef ID_S_ARMED
isArmed = true;
#endif
-
+
// Register all sensors to gw (they will be created as child devices)
Serial.println("Presenting Nodes");
Serial.println("________________");
-
+
#ifdef ID_S_DOOR
Serial.println(" S_DOOR");
present(ID_S_DOOR,S_DOOR,"Outside Door");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_MOTION
Serial.println(" S_MOTION");
present(ID_S_MOTION,S_MOTION,"Outside Motion");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_SMOKE
Serial.println(" S_SMOKE");
present(ID_S_SMOKE,S_SMOKE,"Kitchen Smoke");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_LIGHT
Serial.println(" S_LIGHT");
present(ID_S_LIGHT,S_LIGHT,"Hall Light");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_DIMMER
Serial.println(" S_DIMMER");
present(ID_S_DIMMER,S_DIMMER,"Living room dimmer");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_COVER
Serial.println(" S_COVER");
present(ID_S_COVER,S_COVER,"Window cover");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_TEMP
Serial.println(" S_TEMP");
present(ID_S_TEMP,S_TEMP,"House Temperarue");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_HUM
Serial.println(" S_HUM");
present(ID_S_HUM,S_HUM,"Current Humidity");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_BARO
Serial.println(" S_BARO");
present(ID_S_BARO,S_BARO," Air pressure");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_WIND
Serial.println(" S_WIND");
present(ID_S_WIND,S_WIND,"Wind Station");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_RAIN
Serial.println(" S_RAIN");
present(ID_S_RAIN,S_RAIN,"Rain Station");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_UV
Serial.println(" S_UV");
present(ID_S_UV,S_UV,"Ultra Violet");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_WEIGHT
Serial.println(" S_WEIGHT");
present(ID_S_WEIGHT,S_WEIGHT,"Outdoor Scale");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_POWER
Serial.println(" S_POWER");
present(ID_S_POWER,S_POWER,"Power Metric");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_HEATER
Serial.println(" S_HEATER");
present(ID_S_HEATER,S_HEATER,"Garage Heater");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_DISTANCE
Serial.println(" S_DISTANCE");
present(ID_S_DISTANCE,S_DISTANCE,"Distance Measure");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_LIGHT_LEVEL
Serial.println(" S_LIGHT_LEVEL");
present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL,"Outside Light Level");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_LOCK
Serial.println(" S_LOCK");
present(ID_S_LOCK,S_LOCK,"Front Door Lock");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_IR
Serial.println(" S_IR");
present(ID_S_IR,S_IR,"Univeral Command");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_WATER
Serial.println(" S_WATER");
present(ID_S_WATER,S_WATER,"Water Level");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_AIR_QUALITY
Serial.println(" S_AIR_QUALITY");
present(ID_S_AIR_QUALITY,S_AIR_QUALITY,"Air Station");
wait(SHORT_WAIT);
#endif
-
- #ifdef ID_S_DUST
+
+ #ifdef ID_S_DUST
Serial.println(" S_DUST");
present(ID_S_DUST,S_DUST,"Dust Level");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_SCENE_CONTROLLER
Serial.println(" S_SCENE_CONTROLLER");
present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER,"Scene Controller");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_RGB_LIGHT
Serial.println(" RGB_LIGHT");
present(ID_S_RGB_LIGHT,S_RGB_LIGHT,"Mood Light");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_RGBW_LIGHT
Serial.println(" RGBW_LIGHT");
present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT,"Mood Light 2");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_COLOR_SENSOR
Serial.println(" COLOR_SENSOR");
present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR,"Hall Painting");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_HVAC
Serial.println(" HVAC");
present(ID_S_HVAC,S_HVAC,"HVAC");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_MULTIMETER
Serial.println(" MULTIMETER");
present(ID_S_MULTIMETER,S_MULTIMETER,"Electric Staion");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_SPRINKLER
#endif
#ifdef ID_S_WATER_LEAK
@@ -545,7 +545,7 @@ void presentation() {
present(ID_S_MOISTURE,S_MOISTURE,"Basement Sensor");
wait(SHORT_WAIT);
#endif
-
+
#ifdef ID_S_CUSTOM
Serial.println(" S_CUSTOM");
present(ID_S_CUSTOM,S_CUSTOM,"Other Stuff");
@@ -558,139 +558,139 @@ Serial.println("________________");
}
-void loop()
-{
+void loop()
+{
Serial.println("");
Serial.println("");
Serial.println("");
- Serial.println("#########################");
+ Serial.println("#########################");
randNumber=random(0,101);
-
+
Serial.print("RandomNumber:");
Serial.println(randNumber);
// Send fake battery level
Serial.println("Send Battery Level");
sendBatteryLevel(randNumber);
wait(LONG_WAIT);
-
+
// Request time
Serial.println("Request Time");
requestTime();
wait(LONG_WAIT);
-
+
//Read Sensors
- #ifdef ID_S_DOOR
- door();
+ #ifdef ID_S_DOOR
+ door();
#endif
-
+
#ifdef ID_S_MOTION
motion();
#endif
-
+
#ifdef ID_S_SMOKE
smoke();
#endif
-
+
#ifdef ID_S_LIGHT
light();
#endif
-
+
#ifdef ID_S_DIMMER
dimmer();
#endif
-
+
#ifdef ID_S_COVER
cover();
#endif
-
+
#ifdef ID_S_TEMP
temp();
#endif
-
+
#ifdef ID_S_HUM
hum();
#endif
-
+
#ifdef ID_S_BARO
baro();
#endif
-
+
#ifdef ID_S_WIND
wind();
#endif
-
+
#ifdef ID_S_RAIN
rain();
#endif
-
+
#ifdef ID_S_UV
uv();
#endif
-
+
#ifdef ID_S_WEIGHT
weight();
#endif
-
+
#ifdef ID_S_POWER
power();
#endif
-
+
#ifdef ID_S_HEATER
heater();
#endif
-
+
#ifdef ID_S_DISTANCE
distance();
#endif
-
+
#ifdef ID_S_LIGHT_LEVEL
light_level();
#endif
-
+
#ifdef ID_S_LOCK
lock();
#endif
-
+
#ifdef ID_S_IR
ir();
#endif
-
+
#ifdef ID_S_WATER
water();
#endif
-
+
#ifdef ID_S_AIR_QUALITY
air();
#endif
-
+
#ifdef ID_S_DUST
dust();
#endif
-
+
#ifdef ID_S_SCENE_CONTROLLER
scene();
#endif
-
+
#ifdef ID_S_RGB_LIGHT
rgbLight();
#endif
-
+
#ifdef ID_S_RGBW_LIGHT
rgbwLight();
#endif
-
+
#ifdef ID_S_COLOR_SENSOR
color();
#endif
-
+
#ifdef ID_S_HVAC
hvac();
#endif
-
+
#ifdef ID_S_MULTIMETER
multimeter();
#endif
-
+
#ifdef ID_S_SPRINKLER
#endif
#ifdef ID_S_WATER_LEAK
@@ -701,15 +701,15 @@ void loop()
#endif
#ifdef ID_S_MOISTURE
#endif
-
+
#ifdef ID_S_MOISTURE
moisture();
- #endif
-
+ #endif
+
#ifdef ID_S_CUSTOM
custom();
#endif
-
+
sendBatteryLevel(randNumber);
wait(SHORT_WAIT);
Serial.println("#########################");
@@ -728,15 +728,15 @@ void receiveTime(unsigned long controllerTime) {
#ifdef ID_S_DOOR
void door(){
-
+
Serial.print("Door is: " );
-
+
if (randNumber <= 50) {
Serial.println("Open");
- send(msg_S_DOOR_T.set(1));
+ send(msg_S_DOOR_T.set((int16_t)1));
} else {
Serial.println("Closed");
- send(msg_S_DOOR_T.set(0));
+ send(msg_S_DOOR_T.set((int16_t)0));
}
#ifdef ID_S_ARMED
Serial.print("System is: " );
@@ -748,9 +748,9 @@ void door(){
#ifdef ID_S_MOTION
void motion(){
-
+
Serial.print("Motion is: " );
-
+
if (randNumber <= 50) {
Serial.println("Active");
send(msg_S_MOTION_T.set(1));
@@ -758,7 +758,7 @@ void motion(){
Serial.println("Quiet");
send(msg_S_MOTION_T.set(0));
}
-
+
#ifdef ID_S_ARMED
Serial.print("System is: " );
Serial.println((isArmed ? "Armed":"Disarmed"));
@@ -771,7 +771,7 @@ void motion(){
void smoke(){
Serial.print("Smoke is: " );
-
+
if (randNumber <= 50) {
Serial.println("Active");
send(msg_S_SMOKE_T.set(1));
@@ -779,13 +779,13 @@ void smoke(){
Serial.println("Quiet");
send(msg_S_SMOKE_T.set(0));
}
-
+
#ifdef ID_S_ARMED
Serial.print("System is: " );
Serial.println((isArmed ? "Armed":"Disarmed"));
send(msg_S_SMOKE_A.set(isArmed));
#endif
-
+
}
#endif
@@ -794,7 +794,7 @@ void light(){
Serial.print("Light is: " );
Serial.println((isLightOn ? "On":"Off"));
-
+
send(msg_S_LIGHT.set(isLightOn));
}
@@ -805,7 +805,7 @@ void dimmer(){
Serial.print("Dimmer is set to: " );
Serial.println(dimmerVal);
-
+
send(msg_S_DIMMER.set(dimmerVal));
}
@@ -832,73 +832,73 @@ void cover(){
#ifdef ID_S_TEMP
void temp(){
-
+
Serial.print("Temperature is: " );
Serial.println(map(randNumber,1,100,0,45));
-
+
send(msg_S_TEMP.set(map(randNumber,1,100,0,45)));
-
+
}
#endif
#ifdef ID_S_HUM
void hum(){
-
+
Serial.print("Humitidty is: " );
Serial.println(randNumber);
-
+
send(msg_S_HUM.set(randNumber));
-
+
}
#endif
#ifdef ID_S_BARO
void baro(){
-
+
const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"};
long pressure = map(randNumber,1,100,870,1086);// hPa?
int forecast = map(randNumber,1,100,0,5);
-
+
Serial.print("Atmosferic Pressure is: " );
Serial.println(pressure);
send(msg_S_BARO_P.set(pressure));
-
+
Serial.print("Weather forecast: " );
Serial.println(weather[forecast]);
send(msg_S_BARO_F.set(weather[forecast]));
-
+
}
#endif
#ifdef ID_S_WIND
void wind(){
-
+
Serial.print("Wind Speed is: " );
Serial.println(randNumber);
send(msg_S_WIND_S.set(randNumber));
-
+
Serial.print("Wind Gust is: " );
Serial.println(randNumber+10);
send(msg_S_WIND_G.set(randNumber+10));
-
+
Serial.print("Wind Direction is: " );
Serial.println(map(randNumber,1,100,0,360));
send(msg_S_WIND_D.set(map(randNumber,1,100,0,360)));
-
+
}
#endif
#ifdef ID_S_RAIN
void rain(){
-
+
Serial.print("Rain ammount is: " );
Serial.println(randNumber);
-
+
send(msg_S_RAIN_A.set(randNumber));
-
+
Serial.print("Rain rate is: " );
Serial.println(randNumber/60);
-
+
send(msg_S_RAIN_R.set(randNumber/60,1));
}
@@ -906,10 +906,10 @@ void rain(){
#ifdef ID_S_UV
void uv(){
-
+
Serial.print("Ultra Violet level is: " );
Serial.println(map(randNumber,1,100,0,15));
-
+
send(msg_S_UV.set(map(randNumber,1,100,0,15)));
}
@@ -917,10 +917,10 @@ void uv(){
#ifdef ID_S_WEIGHT
void weight(){
-
+
Serial.print("Weight is: " );
Serial.println(map(randNumber,1,100,0,150));
-
+
send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150)));
}
@@ -928,13 +928,13 @@ void weight(){
#ifdef ID_S_POWER
void power(){
-
+
Serial.print("Watt is: " );
- Serial.println(map(randNumber,1,100,0,150));
+ Serial.println(map(randNumber,1,100,0,150));
send(msg_S_POWER_W.set(map(randNumber,1,100,0,150)));
Serial.print("KWH is: " );
- Serial.println(map(randNumber,1,100,0,150));
+ Serial.println(map(randNumber,1,100,0,150));
send(msg_S_POWER_K.set(map(randNumber,1,100,0,150)));
}
@@ -946,7 +946,7 @@ void heater(){
// float heater_temp=23.5;
// bool heater_status=false;
// String heatState="Off";
-
+
Serial.print("Heater flow state is: " );
Serial.println(heater_flow_state);
send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str()));
@@ -954,7 +954,7 @@ void heater(){
// Serial.print("Heater on/off is: " );
// Serial.println((heater_status==true)?"On":"Off");
// send(msg_S_HEATER_STATUS.set(heater_status));
-
+
// Serial.print("Heater Temperature is: " );
// Serial.println(heater_temp,1);
// send(msg_S_HEATER_TEMP.set(heater_temp,1));
@@ -967,10 +967,10 @@ void heater(){
#ifdef ID_S_DISTANCE
void distance(){
-
+
Serial.print("Distance is: " );
Serial.println(map(randNumber,1,100,0,150));
-
+
send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150)));
}
@@ -978,10 +978,10 @@ void distance(){
#ifdef ID_S_LIGHT_LEVEL
void light_level(){
-
+
Serial.print("Light is: " );
Serial.println(map(randNumber,1,100,0,150));
-
+
send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150)));
}
@@ -993,33 +993,33 @@ void lock(){
Serial.print("Lock is: " );
Serial.println((isLocked ? "Locked":"Unlocked"));
send(msg_S_LOCK.set(isLocked));
-
+
}
#endif
#ifdef ID_S_IR
void ir(){
-
+
Serial.print("Infrared is: " );
Serial.println(irVal);
-
+
send(msg_S_IR_S.set(irVal));
send(msg_S_IR_R.set(irVal));
-
+
}
#endif
#ifdef ID_S_WATER
void water(){
-
+
Serial.print("Water flow is: " );
Serial.println(map(randNumber,1,100,0,150));
-
+
send(msg_S_WATER_F.set(map(randNumber,1,100,0,150)));
-
+
Serial.print("Water volume is: " );
Serial.println(map(randNumber,1,100,0,150));
-
+
send(msg_S_WATER_V.set(map(randNumber,1,100,0,150)));
}
@@ -1027,10 +1027,10 @@ void water(){
#ifdef ID_S_AIR_QUALITY
void air(){
-
+
Serial.print("Air Quality is: " );
Serial.println(randNumber);
-
+
send(msg_S_AIR_QUALITY.set(randNumber));
}
@@ -1038,10 +1038,10 @@ void air(){
#ifdef ID_S_DUST
void dust(){
-
+
Serial.print("Dust level is: " );
Serial.println(randNumber);
-
+
send(msg_S_DUST.set(randNumber));
}
@@ -1052,90 +1052,90 @@ void scene(){
Serial.print("Scene is: " );
Serial.println(scenes[sceneVal]);
-
+
if(sceneValPrevious != sceneVal){
send(msg_S_SCENE_CONTROLLER_OF.set(sceneValPrevious));
send(msg_S_SCENE_CONTROLLER_ON.set(sceneVal));
sceneValPrevious=sceneVal;
}
-
+
}
#endif
#ifdef ID_S_RGB_LIGHT
void rgbLight(){
-
+
Serial.print("RGB Light state is: " );
Serial.println(rgbState);
send(msg_S_RGB_LIGHT_V_RGB.set(rgbState.c_str()));
-
+
Serial.print("RGB Light Watt is: " );
- Serial.println(map(randNumber,1,100,0,150));
+ Serial.println(map(randNumber,1,100,0,150));
send(msg_S_RGB_LIGHT_V_WATT.set(map(randNumber,1,100,0,150)));
-
+
}
#endif
#ifdef ID_S_RGBW_LIGHT
void rgbwLight(){
-
+
Serial.print("RGBW Light state is: " );
Serial.println(rgbwState);
send(msg_S_RGBW_LIGHT_V_RGBW.set(rgbwState.c_str()));
-
+
Serial.print("RGBW Light Watt is: " );
- Serial.println(map(randNumber,1,100,0,150));
+ Serial.println(map(randNumber,1,100,0,150));
send(msg_S_RGBW_LIGHT_V_WATT.set(map(randNumber,1,100,0,150)));
-
+
}
#endif
#ifdef ID_S_COLOR_SENSOR
void color(){
String colorState;
-
+
String red = String(random(0,256),HEX);
String green = String(random(0,256),HEX);
String blue = String(random(0,256),HEX);
-
+
colorState=String(red + green + blue);
Serial.print("Color state is: " );
Serial.println(colorState);
send(msg_S_COLOR_SENSOR_V_RGB.set(colorState.c_str()));
-
+
}
#endif
#ifdef ID_S_HVAC
void hvac(){
-
+
// float hvac_SetPointHeat = 16.5;
// float hvac_SetPointCool = 25.5;
// String hvac_FlowState = "AutoChangeOver";
// String hvac_FlowMode = "Auto";
// String hvac_Speed = "Normal";
-
+
Serial.print("HVAC Set Point Heat is: " );
Serial.println(hvac_SetPointHeat);
send(msg_S_HVAC_V_HVAC_SETPOINT_HEAT.set(hvac_SetPointHeat,1));
-
+
Serial.print("HVAC Set Point Cool is: " );
Serial.println(hvac_SetPointCool);
send(msg_S_HVAC_V_HVAC_SETPOINT_COOL.set(hvac_SetPointCool,1));
-
+
Serial.print("HVAC Flow State is: " );
Serial.println(hvac_FlowState);
send(msg_S_HVAC_V_HVAC_FLOW_STATET.set(hvac_FlowState.c_str()));
-
+
Serial.print("HVAC Flow Mode is: " );
Serial.println(hvac_FlowMode);
send(msg_S_HVAC_V_HVAC_FLOW_MODE.set(hvac_FlowMode.c_str()));
-
+
Serial.print("HVAC Speed is: " );
Serial.println(hvac_Speed);
send(msg_S_HVAC_V_HVAC_SPEED.set(hvac_Speed.c_str()));
-
+
}
#endif
@@ -1144,7 +1144,7 @@ void multimeter(){
int impedance=map(randNumber,1,100,0,15000);
int volt=map(randNumber,1,100,0,380);
int amps=map(randNumber,1,100,0,16);
-
+
Serial.print("Impedance is: " );
Serial.println(impedance);
send(msg_S_MULTIMETER_V_IMPEDANCE.set(impedance));
@@ -1155,7 +1155,7 @@ void multimeter(){
Serial.print("Current is: " );
Serial.println(amps);
- send(msg_S_MULTIMETER_V_CURRENT.set(amps));
+ send(msg_S_MULTIMETER_V_CURRENT.set(amps));
}
#endif
@@ -1173,20 +1173,20 @@ void multimeter(){
#ifdef ID_S_MOISTURE
void moisture(){
-
+
Serial.print("Moisture level is: " );
Serial.println(randNumber);
-
+
send(msg_S_MOISTURE.set(randNumber));
}
#endif
#ifdef ID_S_CUSTOM
void custom(){
-
+
Serial.print("Custom value is: " );
Serial.println(randNumber);
-
+
send(msg_S_CUSTOM_1.set(randNumber));
send(msg_S_CUSTOM_2.set(randNumber));
send(msg_S_CUSTOM_3.set(randNumber));
@@ -1217,8 +1217,8 @@ void receive(const MyMessage &message) {
#endif
break;
#endif
-
-
+
+
case V_STATUS: // V_LIGHT:
#ifdef ID_S_LIGHT
if(message.sensor==ID_S_LIGHT){
@@ -1241,8 +1241,8 @@ void receive(const MyMessage &message) {
// }
// #endif
break;
-
-
+
+
#ifdef ID_S_DIMMER
case V_DIMMER:
if ((message.getInt()<0)||(message.getInt()>100)) {
@@ -1257,8 +1257,8 @@ void receive(const MyMessage &message) {
dimmer();// temp ack
break;
#endif
-
- #ifdef ID_S_COVER
+
+ #ifdef ID_S_COVER
case V_UP:
coverState=1;
Serial.print("Incoming change for ID_S_COVER:");
@@ -1267,7 +1267,7 @@ void receive(const MyMessage &message) {
Serial.println("V_UP");
cover(); // temp ack
break;
-
+
case V_DOWN:
coverState=-1;
Serial.print("Incoming change for ID_S_COVER:");
@@ -1276,7 +1276,7 @@ void receive(const MyMessage &message) {
Serial.println("V_DOWN");
cover(); //temp ack
break;
-
+
case V_STOP:
coverState=0;
Serial.print("Incoming change for ID_S_COVER:");
@@ -1286,14 +1286,14 @@ void receive(const MyMessage &message) {
cover(); //temp ack
break;
#endif
-
-
+
+
case V_HVAC_SETPOINT_HEAT:
-
+
#ifdef ID_S_HEATER
if(message.sensor == ID_S_HEATER){
heater_setpoint=message.getFloat();
-
+
Serial.print("Incoming set point for ID_S_HEATER:");
Serial.print(message.sensor);
Serial.print(", New status: ");
@@ -1301,7 +1301,7 @@ void receive(const MyMessage &message) {
heater();//temp ack
}
#endif
-
+
#ifdef ID_S_HVAC
if(message.sensor == ID_S_HVAC){
hvac_SetPointHeat=message.getFloat();
@@ -1325,11 +1325,11 @@ void receive(const MyMessage &message) {
heater();//temp ack
}
#endif
-
+
#ifdef ID_S_HVAC
if(message.sensor == ID_S_HVAC){
hvac_FlowState=message.getString();
-
+
Serial.print("Incoming set point for ID_S_HVAC:");
Serial.print(message.sensor);
Serial.print(", New status: ");
@@ -1338,7 +1338,7 @@ void receive(const MyMessage &message) {
}
#endif
break;
-
+
#ifdef ID_S_LOCK
case V_LOCK_STATUS:
isLocked = message.getBool();
@@ -1349,7 +1349,7 @@ void receive(const MyMessage &message) {
lock(); //temp ack
break;
#endif
-
+
#ifdef ID_S_IR
case V_IR_SEND:
irVal = message.getLong();
@@ -1368,7 +1368,7 @@ void receive(const MyMessage &message) {
ir(); // temp ack
break;
#endif
-
+
#ifdef ID_S_SCENE_CONTROLLER
case V_SCENE_ON:
sceneVal = message.getInt();
@@ -1389,7 +1389,7 @@ void receive(const MyMessage &message) {
scene();// temp ack
break;
#endif
-
+
#ifdef ID_S_RGB_LIGHT
case V_RGB:
rgbState=message.getString();
@@ -1398,10 +1398,10 @@ void receive(const MyMessage &message) {
Serial.print(", New status: ");
Serial.println(rgbState);
rgbLight(); // temp ack
-
+
break;
#endif
-
+
#ifdef ID_S_RGBW_LIGHT
case V_RGBW:
rgbwState=message.getString();
@@ -1412,37 +1412,37 @@ void receive(const MyMessage &message) {
rgbwLight();
break;
#endif
-
+
#ifdef ID_S_HVAC
- // hvac_SetPointHeat
- // hvac_SetPointCool
- // hvac_FlowState
- // hvac_FlowMode
- // hvac_Speed
-
+ // hvac_SetPointHeat
+ // hvac_SetPointCool
+ // hvac_FlowState
+ // hvac_FlowMode
+ // hvac_Speed
+
case V_HVAC_SETPOINT_COOL:
hvac_SetPointCool=message.getFloat();
-
+
Serial.print("Incoming set point for ID_S_HVAC:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(hvac_SetPointCool,1);
hvac();//temp ack
break;
-
+
case V_HVAC_FLOW_MODE:
hvac_Speed=message.getString();
-
+
Serial.print("Incoming set point for ID_S_HVAC:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(hvac_Speed);
hvac();//temp ack
break;
-
+
case V_HVAC_SPEED:
hvac_FlowMode=message.getString();
-
+
Serial.print("Incoming set point for ID_S_HVAC:");
Serial.print(message.sensor);
Serial.print(", New status: ");
@@ -1450,17 +1450,10 @@ void receive(const MyMessage &message) {
hvac();//temp ack
break;
#endif
-
- default:
+
+ default:
Serial.print("Unknown/UnImplemented message type: ");
Serial.println(message.type);
}
}
-
-
-
-
-
-
-
diff --git a/libraries/MySensors/examples/MockMySensors/README.md b/examples/MockMySensors/README.md
similarity index 100%
rename from libraries/MySensors/examples/MockMySensors/README.md
rename to examples/MockMySensors/README.md
diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/examples/MotionSensor/MotionSensor.ino
similarity index 92%
rename from libraries/MySensors/examples/MotionSensor/MotionSensor.ino
rename to examples/MotionSensor/MotionSensor.ino
index dc74ffa..77c01df 100644
--- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino
+++ b/examples/MotionSensor/MotionSensor.ino
@@ -35,11 +35,10 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!)
-#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 1 // Id of the sensor child
// Initialize motion message
@@ -65,9 +64,9 @@ void loop()
Serial.println(tripped);
send(msg.set(tripped?"1":"0")); // Send tripped value to gw
-
- // Sleep until interrupt comes in on motion sensor. Send update every two minute.
- sleep(INTERRUPT,CHANGE, SLEEP_TIME);
+
+ // Sleep until interrupt comes in on motion sensor. Send update every two minute.
+ sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME);
}
diff --git a/libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino b/examples/MotionSensorRS485/MotionSensorRS485.ino
similarity index 94%
rename from libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino
rename to examples/MotionSensorRS485/MotionSensorRS485.ino
index f53ee99..9252243 100644
--- a/libraries/MySensors/examples/MotionSensorRS485/MotionSensorRS485.ino
+++ b/examples/MotionSensorRS485/MotionSensorRS485.ino
@@ -54,11 +54,10 @@
#define MY_RS485_BAUD_RATE 9600
#include
-#include
+#include
unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!)
-#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 1 // Id of the sensor child
// Initialize motion message
@@ -84,9 +83,9 @@ void loop()
Serial.println(tripped);
send(msg.set(tripped?"1":"0")); // Send tripped value to gw
-
- // Sleep until interrupt comes in on motion sensor. Send update every two minute.
- sleep(INTERRUPT,CHANGE, SLEEP_TIME);
+
+ // Sleep until interrupt comes in on motion sensor. Send update every two minute.
+ sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME);
}
diff --git a/libraries/MySensors/examples/PHSensor/PHSensor.ino b/examples/PHSensor/PHSensor.ino
similarity index 98%
rename from libraries/MySensors/examples/PHSensor/PHSensor.ino
rename to examples/PHSensor/PHSensor.ino
index 9e7a6c6..befd8ec 100644
--- a/libraries/MySensors/examples/PHSensor/PHSensor.ino
+++ b/examples/PHSensor/PHSensor.ino
@@ -30,7 +30,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define COMPARE_PH 1 // Send PH only if changed? 1 = Yes 0 = No
diff --git a/libraries/MySensors/examples/PingPongSensor/MYSLog.h b/examples/PingPongSensor/MYSLog.h
similarity index 100%
rename from libraries/MySensors/examples/PingPongSensor/MYSLog.h
rename to examples/PingPongSensor/MYSLog.h
diff --git a/libraries/MySensors/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino
similarity index 99%
rename from libraries/MySensors/examples/PingPongSensor/PingPongSensor.ino
rename to examples/PingPongSensor/PingPongSensor.ino
index 2b0123a..4a98b31 100644
--- a/libraries/MySensors/examples/PingPongSensor/PingPongSensor.ino
+++ b/examples/PingPongSensor/PingPongSensor.ino
@@ -16,7 +16,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#include "MYSLog.h"
#define VSN "v1.0"
diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/examples/RelayActuator/RelayActuator.ino
similarity index 99%
rename from libraries/MySensors/examples/RelayActuator/RelayActuator.ino
rename to examples/RelayActuator/RelayActuator.ino
index fd789a3..dd26414 100644
--- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino
+++ b/examples/RelayActuator/RelayActuator.ino
@@ -38,7 +38,7 @@
#define MY_REPEATER_FEATURE
#include
-#include
+#include
#define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define NUMBER_OF_RELAYS 1 // Total number of attached relays
diff --git a/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino b/examples/RepeaterNode/RepeaterNode.ino
similarity index 98%
rename from libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino
rename to examples/RepeaterNode/RepeaterNode.ino
index 5a8f7b4..fae8609 100644
--- a/libraries/MySensors/examples/RepeaterNode/RepeaterNode.ino
+++ b/examples/RepeaterNode/RepeaterNode.ino
@@ -39,7 +39,7 @@
#define MY_REPEATER_FEATURE
#include
-#include
+#include
void setup() {
diff --git a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino
similarity index 99%
rename from libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino
rename to examples/SecretKnockSensor/SecretKnockSensor.ino
index 5156e29..d032197 100644
--- a/libraries/MySensors/examples/SecretKnockSensor/SecretKnockSensor.ino
+++ b/examples/SecretKnockSensor/SecretKnockSensor.ino
@@ -59,7 +59,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define CHILD_ID 99 // Id of the sensor child
diff --git a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino b/examples/SecureActuator/SecureActuator.ino
similarity index 99%
rename from libraries/MySensors/examples/SecureActuator/SecureActuator.ino
rename to examples/SecureActuator/SecureActuator.ino
index 655055f..80f34ea 100644
--- a/libraries/MySensors/examples/SecureActuator/SecureActuator.ino
+++ b/examples/SecureActuator/SecureActuator.ino
@@ -66,7 +66,7 @@
#define MY_SIGNING_ATSHA204_PIN 17 //!< A3 - pin where ATSHA204 is attached
#include
-#include
+#include
#define LOCK_1 3 //!< Arduino Digital I/O pin number for first lock (second on pin+1 etc)
diff --git a/libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino
similarity index 99%
rename from libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino
rename to examples/SecurityPersonalizer/SecurityPersonalizer.ino
index 43e25be..7c7954b 100644
--- a/libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino
+++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino
@@ -77,13 +77,13 @@
* data for EEPROM and ATSHA204A so it is recommended to use different serial and HMAC
* keys on the same device for ATSHA204A vs soft signing settings.
*
- * Details on personalization procedure is given in @ref perzonalization.
+ * Details on personalization procedure is given in @ref personalization.
*/
-#include
-#include
+#include "sha204_library.h"
+#include "sha204_lib_return_codes.h"
#define MY_CORE_ONLY
-#include
+#include
// Doxygen specific constructs, not included when built normally
// This is used to enable disabled macros/definitions to be included in the documentation as well.
@@ -879,7 +879,7 @@ void setup()
(void)key;
Serial.begin(115200);
-
+ hwInit();
Serial.println(F("Personalization sketch for MySensors usage."));
Serial.println(F("-------------------------------------------"));
diff --git a/libraries/sha204/sha204_lib_return_codes.h b/examples/SecurityPersonalizer/sha204_lib_return_codes.h
similarity index 100%
rename from libraries/sha204/sha204_lib_return_codes.h
rename to examples/SecurityPersonalizer/sha204_lib_return_codes.h
diff --git a/libraries/sha204/sha204_library.cpp b/examples/SecurityPersonalizer/sha204_library.cpp
similarity index 100%
rename from libraries/sha204/sha204_library.cpp
rename to examples/SecurityPersonalizer/sha204_library.cpp
diff --git a/libraries/sha204/sha204_library.h b/examples/SecurityPersonalizer/sha204_library.h
similarity index 100%
rename from libraries/sha204/sha204_library.h
rename to examples/SecurityPersonalizer/sha204_library.h
diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino
new file mode 100644
index 0000000..11fb45c
--- /dev/null
+++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino
@@ -0,0 +1,253 @@
+ /**
+ * The MySensors Arduino library handles the wireless radio link and protocol
+ * between your home built sensors/actuators and HA controller of choice.
+ * The sensors forms a self healing radio network with optional repeaters. Each
+ * repeater and gateway builds a routing tables in EEPROM which keeps track of the
+ * network topology allowing messages to be routed to nodes.
+ *
+ * Created by Henrik Ekblad
+ * Copyright (C) 2013-2015 Sensnology AB
+ * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
+ *
+ * Documentation: http://www.mysensors.org
+ * Support Forum: http://forum.mysensors.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ *******************************
+ *
+ * DESCRIPTION
+ * The ArduinoGateway prints data received from sensors on the serial link.
+ * The gateway accepts input on seral which will be sent out on radio network.
+ *
+ * This GW code is designed for Sensebender GateWay / Arduino Zero
+ *
+ * Wire connections (OPTIONAL):
+ * - Inclusion button should be connected between digital pin 3 and GND
+ * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series
+ *
+ * LEDs (OPTIONAL):
+ * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h
+ * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
+ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
+ * - ERR (red) - fast blink on error during transmission error or recieve crc error
+ *
+ */
+
+#define SKETCH_VERSION "0.1"
+// Enable debug prints to serial monitor
+#define MY_DEBUG
+
+// Enable and select radio type attached
+#define MY_RADIO_NRF24
+//#define MY_RADIO_RFM69
+
+// Set LOW transmit power level as default, if you have an amplified NRF-module and
+// power your radio separately with a good regulator you can turn up PA level.
+#define MY_RF24_PA_LEVEL RF24_PA_HIGH
+
+// Enable serial gateway
+#define MY_GATEWAY_SERIAL
+
+// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
+#if F_CPU == 8000000L
+#define MY_BAUD_RATE 38400
+#endif
+
+// Flash leds on rx/tx/err
+#define MY_LEDS_BLINKING_FEATURE
+// Set blinking period
+#define MY_DEFAULT_LED_BLINK_PERIOD 300
+
+// Inverses the behavior of leds
+//#define MY_WITH_LEDS_BLINKING_INVERSE
+
+// Enable inclusion mode
+#define MY_INCLUSION_MODE_FEATURE
+// Enable Inclusion mode button on gateway
+#define MY_INCLUSION_BUTTON_FEATURE
+
+// Inverses behavior of inclusion button (if using external pullup)
+//#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP
+
+// Set inclusion mode duration (in seconds)
+#define MY_INCLUSION_MODE_DURATION 60
+// Digital pin used for inclusion mode button
+//#define MY_INCLUSION_MODE_BUTTON_PIN 3
+
+// Uncomment to override default HW configurations
+//#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin
+//#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin
+//#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED
+
+#include
+#include
+#include
+#include
+
+Sd2Card card;
+
+#define EEPROM_VERIFICATION_ADDRESS 0x01
+
+static uint8_t num_of_leds = 5;
+static uint8_t leds[] = {LED_BLUE, LED_RED, LED_GREEN, LED_YELLOW, LED_ORANGE};
+
+void setup() {
+ // Setup locally attached sensors
+}
+
+void presentation() {
+ // Present locally attached sensors
+}
+
+void loop() {
+ // Send locally attached sensor data here
+}
+
+
+void preHwInit() {
+
+ pinMode(MY_SWC1, INPUT_PULLUP);
+ pinMode(MY_SWC2, INPUT_PULLUP);
+ if (digitalRead(MY_SWC1) && digitalRead(MY_SWC2)) return;
+
+ uint8_t tests = 0;
+
+ for (int i=0; i< num_of_leds; i++) {
+ pinMode(leds[i], OUTPUT);
+ }
+ uint8_t led_state = 0;
+ if (digitalRead(MY_SWC1)) {
+ while (!Serial) {
+ digitalWrite(LED_BLUE, led_state);
+ led_state ^= 0x01;
+ delay(500);
+ } // Wait for USB to be connected, before spewing out data.
+ }
+ if (Serial) {
+ Serial.println("Sensebender GateWay test routine");
+ Serial.print("Mysensors core version : ");
+ Serial.println(MYSENSORS_LIBRARY_VERSION);
+ Serial.print("GateWay sketch version : ");
+ Serial.println(SKETCH_VERSION);
+ Serial.println("----------------------------------");
+ Serial.println();
+ }
+ if (testSha204()) {
+ digitalWrite(LED_GREEN, HIGH);
+ tests++;
+ }
+ if (testSDCard()) {
+ digitalWrite(LED_YELLOW, HIGH);
+ tests++;
+ }
+
+ if (testEEProm()) {
+ digitalWrite(LED_ORANGE, HIGH);
+ tests++;
+ }
+ if (tests == 3) {
+ while(1) {
+ for (int i=0; i SHA204 ");
+ atsha204_init(MY_SIGNING_ATSHA204_PIN);
+ ret_code = atsha204_wakeup(rx_buffer);
+
+ if (ret_code == SHA204_SUCCESS)
+ {
+ ret_code = atsha204_getSerialNumber(rx_buffer);
+ if (ret_code != SHA204_SUCCESS)
+ {
+ if (Serial) Serial.println(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
+ }
+ else
+ {
+ if (Serial) {
+ Serial.print(F("Ok (serial : "));
+ for (int i=0; i<9; i++)
+ {
+ if (rx_buffer[i] < 0x10)
+ {
+ Serial.print('0'); // Because Serial.print does not 0-pad HEX
+ }
+ Serial.print(rx_buffer[i], HEX);
+ }
+ Serial.println(")");
+ }
+ return true;
+ }
+ }
+ else {
+ if (Serial) Serial.println(F("Failed to wakeup SHA204"));
+ }
+ return false;
+}
+
+bool testSDCard() {
+ if (Serial) Serial.print("- > SD CARD ");
+ if (!card.init(SPI_HALF_SPEED, MY_SDCARD_CS)) {
+ if (Serial) Serial.println("SD CARD did not initialize!");
+ }
+ else {
+ if (Serial) {
+ Serial.print("SD Card initialized correct! - ");
+ Serial.print("type detected : ");
+ switch(card.type()) {
+ case SD_CARD_TYPE_SD1:
+ Serial.println("SD1");
+ break;
+ case SD_CARD_TYPE_SD2:
+ Serial.println("SD2");
+ break;
+ case SD_CARD_TYPE_SDHC:
+ Serial.println("SDHC");
+ break;
+ default:
+ Serial.println("Unknown");
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool testEEProm() {
+ uint8_t eeprom_d1, eeprom_d2;
+ SerialUSB.print(" -> EEPROM ");
+ Wire.begin();
+ eeprom_d1 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS);
+ delay(500);
+ eeprom_d1 = ~eeprom_d1; // invert the bits
+ i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, eeprom_d1);
+ delay(500);
+ eeprom_d2 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS);
+ if (eeprom_d1 == eeprom_d2) {
+ SerialUSB.println("PASSED");
+ i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, ~eeprom_d1);
+ return true;
+ }
+ SerialUSB.println("FAILED!");
+ return false;
+}
diff --git a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino
similarity index 99%
rename from libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino
rename to examples/SoilMoistSensor/SoilMoistSensor.ino
index 7577f27..9d51e0d 100644
--- a/libraries/MySensors/examples/SoilMoistSensor/SoilMoistSensor.ino
+++ b/examples/SoilMoistSensor/SoilMoistSensor.ino
@@ -69,7 +69,7 @@
#include // Conversion equation from resistance to %
#include
-#include
+#include
// Setting up format for reading 3 soil sensors
#define NUM_READS 10 // Number of sensor reads for filtering
diff --git a/libraries/MySensors/examples/UVSensor/UVSensor.ino b/examples/UVSensor/UVSensor.ino
similarity index 99%
rename from libraries/MySensors/examples/UVSensor/UVSensor.ino
rename to examples/UVSensor/UVSensor.ino
index 9a6cdad..2b70dee 100644
--- a/libraries/MySensors/examples/UVSensor/UVSensor.ino
+++ b/examples/UVSensor/UVSensor.ino
@@ -44,7 +44,7 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define UV_SENSOR_ANALOG_PIN 0
diff --git a/libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino b/examples/VibrationSensor/VibrationSensor.ino
similarity index 87%
rename from libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino
rename to examples/VibrationSensor/VibrationSensor.ino
index f3b350d..f060982 100644
--- a/libraries/MySensors/examples/VibrationSensor/VibrationSensor.ino
+++ b/examples/VibrationSensor/VibrationSensor.ino
@@ -33,14 +33,14 @@
**/
// Enable debug prints to serial monitor
-#define MY_DEBUG
+#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#include
-#include
+#include
#include
#define CHILD_ID_VIBRATION 0
@@ -57,11 +57,11 @@ unsigned char state = 0;
MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL);
-void setup()
+void setup()
{
pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT);
- attachInterrupt(1, blink, FALLING);// Trigger the blink function when the falling edge is detected
- pinMode(SensorLED, OUTPUT);
+ attachInterrupt(digitalPinToInterrupt(VIBRATION_SENSOR_DIGITAL_PIN), blink, FALLING); // Trigger the blink function when the falling edge is detected
+ pinMode(SensorLED, OUTPUT);
}
void presentation() {
@@ -72,19 +72,19 @@ void presentation() {
present(CHILD_ID_VIBRATION, S_VIBRATION);
}
-void loop()
-{
-
+void loop()
+{
+
if(state>=40){ // basically below 40 so ignire basic level
- send(vibrationMsg.set(int(state)));
- state = 0;
+ send(vibrationMsg.set(int16_t(state)));
+ state = 0;
digitalWrite(SensorLED,HIGH);
} else {
- state = 0;
+ state = 0;
digitalWrite(SensorLED,LOW);
- }
+ }
+
-
// Power down the radio. Note that the radio will get powered back up
// on the next write() call.
delay(1000); //delay to allow serial to fully print before sleep
diff --git a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
similarity index 96%
rename from libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
rename to examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
index ac15f9f..1c9163a 100644
--- a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
+++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino
@@ -42,10 +42,9 @@
//#define MY_RADIO_RFM69
#include
-#include
+#include
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
-#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter)
@@ -87,7 +86,7 @@ void setup()
lastSend = lastPulse = millis();
- attachInterrupt(SENSOR_INTERRUPT, onPulse, FALLING);
+ attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, FALLING);
}
void presentation() {
diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt
deleted file mode 100644
index c8f138f..0000000
--- a/hardware/MySensors/avr/boards.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-menu.cpu=Processor
-
-######################################
-## Sensebender Micro
-
-MysensorsMicro.name=Sensebender Micro
-
-MysensorsMicro.upload.tool=arduino:avrdude
-MysensorsMicro.upload.protocol=arduino
-MysensorsMicro.upload.maximum_size=30720
-MysensorsMicro.upload.maximum_data_size=2048
-MysensorsMicro.upload.speed=57600
-
-MysensorsMicro.bootloader.tool=arduino:avrdude
-MysensorsMicro.bootloader.unlock_bits=0x3F
-MysensorsMicro.bootloader.lock_bits=0x0F
-MysensorsMicro.bootloader.low_fuses=0xE2
-MysensorsMicro.bootloader.high_fuses=0xD2
-MysensorsMicro.bootloader.extended_fuses=0x06
-MysensorsMicro.bootloader.file=DualOptiboot/optiboot_atmega328_pro_8MHz.hex
-
-MysensorsMicro.build.board=AVR_MICRO8
-MysensorsMicro.build.core=arduino:arduino
-MysensorsMicro.build.variant=micro
-MysensorsMicro.build.mcu=atmega328p
-#MysensorsMicro.build.f_cpu=8000000L
-
-MysensorsMicro.menu.cpu.8Mhz=Atmega328 8Mhz
-MysensorsMicro.menu.cpu.8Mhz.build.f_cpu=8000000L
-
-MysensorsMicro.menu.cpu.1Mhz=Atmega328 1Mhz
-MysensorsMicro.menu.cpu.1Mhz.build.f_cpu=1000000L
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/License.txt b/hardware/MySensors/avr/bootloaders/DualOptiboot/License.txt
deleted file mode 100644
index 94a9ed0..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/License.txt
+++ /dev/null
@@ -1,674 +0,0 @@
- 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/hardware/MySensors/avr/bootloaders/DualOptiboot/Makefile b/hardware/MySensors/avr/bootloaders/DualOptiboot/Makefile
deleted file mode 100644
index 95c806b..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/Makefile
+++ /dev/null
@@ -1,649 +0,0 @@
-# Makefile for ATmegaBOOT
-# E.Lins, 18.7.2005
-# $Id$
-#
-# Instructions
-#
-# To make bootloader .hex file:
-# make diecimila
-# make lilypad
-# make ng
-# etc...
-#
-# To burn bootloader .hex file:
-# make diecimila_isp
-# make lilypad_isp
-# make ng_isp
-# etc...
-#
-# Edit History
-# 201303xx: WestfW: Major Makefile restructuring.
-# Allows options on Make command line "make xx LED=B3"
-# (see also pin_defs.h)
-# Divide into "chip" targets and "board" targets.
-# Most boards are (recursive) board targets with options.
-# Move isp target to separate makefile (fixes m8 EFUSE)
-# Some (many) targets will now be rebuilt when not
-# strictly necessary, so that options will be included.
-# (any "make" with options will always compile.)
-# Set many variables with ?= so they can be overridden
-# Use arduinoISP settings as default for ISP targets
-#
-
-#----------------------------------------------------------------------
-#
-# program name should not be changed...
-PROGRAM = optiboot
-
-# The default behavior is to build using tools that are in the users
-# current path variables, but we can also build using an installed
-# Arduino user IDE setup, or the Arduino source tree.
-# Uncomment this next lines to build within the arduino environment,
-# using the arduino-included avrgcc toolset (mac and pc)
-# ENV ?= arduino
-# ENV ?= arduinodev
-# OS ?= macosx
-# OS ?= windows
-
-# export symbols to recursive makes (for ISP)
-export
-
-# defaults
-MCU_TARGET = atmega168
-LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
-
-# Build environments
-# Start of some ugly makefile-isms to allow optiboot to be built
-# in several different environments. See the README.TXT file for
-# details.
-
-# default
-fixpath = $(1)
-
-ifeq ($(ENV), arduino)
-# For Arduino, we assume that we're connected to the optiboot directory
-# included with the arduino distribution, which means that the full set
-# of avr-tools are "right up there" in standard places.
-TOOLROOT = ../../../tools
-GCCROOT = $(TOOLROOT)/avr/bin/
-
-ifeq ($(OS), windows)
-# On windows, SOME of the tool paths will need to have backslashes instead
-# of forward slashes (because they use windows cmd.exe for execution instead
-# of a unix/mingw shell?) We also have to ensure that a consistent shell
-# is used even if a unix shell is installed (ie as part of WINAVR)
-fixpath = $(subst /,\,$1)
-SHELL = cmd.exe
-endif
-
-else ifeq ($(ENV), arduinodev)
-# Arduino IDE source code environment. Use the unpacked compilers created
-# by the build (you'll need to do "ant build" first.)
-ifeq ($(OS), macosx)
-TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
-endif
-ifeq ($(OS), windows)
-TOOLROOT = ../../../../build/windows/work/hardware/tools
-endif
-
-GCCROOT = $(TOOLROOT)/avr/bin/
-AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
-
-else
-GCCROOT =
-AVRDUDE_CONF =
-endif
-
-STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
-STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
- -lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
-STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt
-#
-# End of build environment code.
-
-
-OBJ = $(PROGRAM).o
-OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types -mrelax
-
-DEFS =
-LIBS =
-
-CC = $(GCCROOT)avr-gcc
-
-# Override is only needed by avr-lib build system.
-
-override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
-override LDFLAGS = $(LDSECTIONS) -Wl,--relax -nostartfiles -nostdlib
-#-Wl,--gc-sections
-
-OBJCOPY = $(GCCROOT)avr-objcopy
-OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
-
-SIZE = $(GCCROOT)avr-size
-
-#
-# Make command-line Options.
-# Permit commands like "make atmega328 LED_START_FLASHES=10" to pass the
-# appropriate parameters ("-DLED_START_FLASHES=10") to gcc
-#
-
-ifdef BAUD_RATE
-BAUD_RATE_CMD = -DBAUD_RATE=$(BAUD_RATE)
-dummy = FORCE
-else
-BAUD_RATE_CMD = -DBAUD_RATE=115200
-endif
-
-ifdef LED_START_FLASHES
-LED_START_FLASHES_CMD = -DLED_START_FLASHES=$(LED_START_FLASHES)
-dummy = FORCE
-else
-LED_START_FLASHES_CMD = -DLED_START_FLASHES=3
-endif
-
-# BIG_BOOT: Include extra features, up to 1K.
-ifdef BIGBOOT
-BIGBOOT_CMD = -DBIGBOOT=1
-dummy = FORCE
-endif
-
-ifdef SOFT_UART
-SOFT_UART_CMD = -DSOFT_UART=1
-dummy = FORCE
-endif
-
-ifdef LED_DATA_FLASH
-LED_DATA_FLASH_CMD = -DLED_DATA_FLASH=1
-dummy = FORCE
-endif
-
-ifdef LED
-LED_CMD = -DLED=$(LED)
-dummy = FORCE
-endif
-
-ifdef SINGLESPEED
-SSCMD = -DSINGLESPEED=1
-endif
-
-COMMON_OPTIONS = $(BAUD_RATE_CMD) $(LED_START_FLASHES_CMD) $(BIGBOOT_CMD)
-COMMON_OPTIONS += $(SOFT_UART_CMD) $(LED_DATA_FLASH_CMD) $(LED_CMD) $(SSCMD)
-
-#UART is handled separately and only passed for devices with more than one.
-ifdef UART
-UARTCMD = -DUART=$(UART)
-endif
-
-# Not supported yet
-# ifdef SUPPORT_EEPROM
-# SUPPORT_EEPROM_CMD = -DSUPPORT_EEPROM
-# dummy = FORCE
-# endif
-
-# Not supported yet
-# ifdef TIMEOUT_MS
-# TIMEOUT_MS_CMD = -DTIMEOUT_MS=$(TIMEOUT_MS)
-# dummy = FORCE
-# endif
-#
-
-#---------------------------------------------------------------------------
-# "Chip-level Platform" targets.
-# A "Chip-level Platform" compiles for a particular chip, but probably does
-# not have "standard" values for things like clock speed, LED pin, etc.
-# Makes for chip-level platforms should usually explicitly define their
-# options like: "make atmega1285 AVR_FREQ=16000000L LED=D0"
-#---------------------------------------------------------------------------
-#
-# Note about fuses:
-# the efuse should really be 0xf8; since, however, only the lower
-# three bits of that byte are used on the atmega168, avrdude gets
-# confused if you specify 1's for the higher bits, see:
-# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
-#
-# similarly, the lock bits should be 0xff instead of 0x3f (to
-# unlock the bootloader section) and 0xcf instead of 0x2f (to
-# lock it), but since the high two bits of the lock byte are
-# unused, avrdude would get confused.
-#---------------------------------------------------------------------------
-#
-
-# Test platforms
-# Virtual boot block test
-virboot328: TARGET = atmega328
-virboot328: MCU_TARGET = atmega328p
-virboot328: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT'
-virboot328: AVR_FREQ ?= 16000000L
-virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
-virboot328: $(PROGRAM)_atmega328.hex
-virboot328: $(PROGRAM)_atmega328.lst
-
-# Diecimila, Duemilanove with m168, and NG use identical bootloaders
-# Call it "atmega168" for generality and clarity, keep "diecimila" for
-# backward compatibility of makefile
-#
-atmega168: TARGET = atmega168
-atmega168: MCU_TARGET = atmega168
-atmega168: CFLAGS += $(COMMON_OPTIONS)
-atmega168: AVR_FREQ ?= 16000000L
-atmega168: $(PROGRAM)_atmega168.hex
-atmega168: $(PROGRAM)_atmega168.lst
-
-atmega168_isp: atmega168
-atmega168_isp: TARGET = atmega168
-# 2.7V brownout
-atmega168_isp: HFUSE ?= DD
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-atmega168_isp: LFUSE ?= FF
-# 512 byte boot
-atmega168_isp: EFUSE ?= 04
-atmega168_isp: isp
-
-atmega328: TARGET = atmega328
-atmega328: MCU_TARGET = atmega328p
-atmega328: CFLAGS += $(COMMON_OPTIONS)
-atmega328: AVR_FREQ ?= 16000000L
-atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffe
-atmega328: $(PROGRAM)_atmega328.hex
-atmega328: $(PROGRAM)_atmega328.lst
-
-atmega328_isp: atmega328
-atmega328_isp: TARGET = atmega328
-atmega328_isp: MCU_TARGET = atmega328p
-# 512 byte boot, SPIEN
-atmega328_isp: HFUSE ?= DE
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-atmega328_isp: LFUSE ?= FF
-# 2.7V brownout
-atmega328_isp: EFUSE ?= FD
-atmega328_isp: isp
-
-atmega644p: TARGET = atmega644p
-atmega644p: MCU_TARGET = atmega644p
-atmega644p: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(LED_CMD)
-atmega644p: AVR_FREQ ?= 16000000L
-atmega644p: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe
-atmega644p: CFLAGS += $(UARTCMD)
-atmega644p: $(PROGRAM)_atmega644p.hex
-atmega644p: $(PROGRAM)_atmega644p.lst
-
-atmega1284: TARGET = atmega1284p
-atmega1284: MCU_TARGET = atmega1284p
-atmega1284: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(LED_CMD)
-atmega1284: AVR_FREQ ?= 16000000L
-atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
-atmega1284: CFLAGS += $(UARTCMD)
-atmega1284: $(PROGRAM)_atmega1284p.hex
-atmega1284: $(PROGRAM)_atmega1284p.lst
-
-atmega1284p: atmega1284
-
-atmega1284_isp: atmega1284
-atmega1284_isp: TARGET = atmega1284p
-atmega1284_isp: MCU_TARGET = atmega1284p
-# 1024 byte boot
-atmega1284_isp: HFUSE ?= DE
-# Full Swing xtal (16MHz) 16KCK/14CK+65ms
-atmega1284_isp: LFUSE ?= F7
-# 2.7V brownout
-atmega1284_isp: EFUSE ?= FD
-atmega1284_isp: isp
-
-#Atmega1280
-atmega1280: MCU_TARGET = atmega1280
-atmega1280: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
-atmega1280: AVR_FREQ ?= 16000000L
-atmega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe
-atmega1280: $(PROGRAM)_atmega1280.hex
-atmega1280: $(PROGRAM)_atmega1280.lst
-
-
-# ATmega8
-#
-atmega8: TARGET = atmega8
-atmega8: MCU_TARGET = atmega8
-atmega8: CFLAGS += $(COMMON_OPTIONS)
-atmega8: AVR_FREQ ?= 16000000L
-atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
-atmega8: $(PROGRAM)_atmega8.hex
-atmega8: $(PROGRAM)_atmega8.lst
-
-atmega8_isp: atmega8
-atmega8_isp: TARGET = atmega8
-atmega8_isp: MCU_TARGET = atmega8
-# SPIEN, CKOPT (for full swing xtal), Bootsize=512B
-atmega8_isp: HFUSE ?= CC
-# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms
-atmega8_isp: LFUSE ?= BF
-atmega8_isp: isp
-
-# ATmega88
-#
-atmega88: TARGET = atmega88
-atmega88: MCU_TARGET = atmega88
-atmega88: CFLAGS += $(COMMON_OPTIONS)
-atmega88: AVR_FREQ ?= 16000000L
-atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
-atmega88: $(PROGRAM)_atmega88.hex
-atmega88: $(PROGRAM)_atmega88.lst
-
-atmega88_isp: atmega88
-atmega88_isp: TARGET = atmega88
-atmega88_isp: MCU_TARGET = atmega88
-# 2.7V brownout
-atmega88_isp: HFUSE ?= DD
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-atemga88_isp: LFUSE ?= FF
-# 512 byte boot
-atmega88_isp: EFUSE ?= 04
-atmega88_isp: isp
-
-atmega32: TARGET = atmega32
-atmega32: MCU_TARGET = atmega32
-atmega32: CFLAGS += $(COMMON_OPTIONS)
-atmega32: AVR_FREQ ?= 11059200L
-atmega32: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
-atmega32: $(PROGRAM)_atmega32.hex
-atmega32: $(PROGRAM)_atmega32.lst
-
-atmega32_isp: atmega32
-atmega32_isp: TARGET = atmega32
-atmega32_isp: MCU_TARGET = atmega32
-# No OCD or JTAG, SPIEN, CKOPT (for full swing xtal), Bootsize=512B
-atmega32_isp: HFUSE ?= CE
-# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms
-atemga32_isp: LFUSE ?= BF
-atmega32_isp: isp
-
-
-
-#---------------------------------------------------------------------------
-# "Board-level Platform" targets.
-# A "Board-level Platform" implies a manufactured platform with a particular
-# AVR_FREQ, LED, and so on. Parameters are not particularly changable from
-# the "make" command line.
-# Most of the board-level platform builds should envoke make recursively
-# appropriate specific options
-#---------------------------------------------------------------------------
-# 20MHz clocked platforms
-#
-# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue)
-#
-
-pro20: TARGET = pro_20mhz
-pro20: CHIP = atmega168
-pro20:
- $(MAKE) atmega168 AVR_FREQ=20000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-pro20_isp: pro20
-pro20_isp: TARGET = pro_20mhz
-# 2.7V brownout
-pro20_isp: HFUSE ?= DD
-# Full swing xtal (20MHz) 258CK/14CK+4.1ms
-pro20_isp: LFUSE ?= C6
-# 512 byte boot
-pro20_isp: EFUSE ?= 04
-pro20_isp: isp
-
-# 16MHz clocked platforms
-#
-# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue)
-#
-
-pro16: TARGET = pro_16MHz
-pro16: CHIP = atmega168
-pro16:
- $(MAKE) $(CHIP) AVR_FREQ=16000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-pro16_isp: pro16
-pro16_isp: TARGET = pro_16MHz
-# 2.7V brownout
-pro16_isp: HFUSE ?= DD
-# Full swing xtal (20MHz) 258CK/14CK+4.1ms
-pro16_isp: LFUSE ?= C6
-# 512 byte boot
-pro16_isp: EFUSE ?= 04
-pro16_isp: isp
-
-diecimila: TARGET = diecimila
-diecimila: CHIP = atmega168
-diecimila:
- $(MAKE) $(CHIP) AVR_FREQ=16000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-diecimila_isp: diecimila
-diecimila_isp: TARGET = diecimila
-# 2.7V brownout
-diecimila_isp: HFUSE ?= DD
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-diecimila_isp: LFUSE ?= FF
-# 512 byte boot
-diecimila_isp: EFUSE ?= 04
-diecimila_isp: isp
-
-# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
-#
-sanguino: TARGET = $@
-sanguino: CHIP = atmega644p
-sanguino:
- $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=B0
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-sanguino_isp: sanguino
-sanguino_isp: TARGET = sanguino
-sanguino_isp: MCU_TARGET = atmega644p
-# 1024 byte boot
-sanguino_isp: HFUSE ?= DE
-# Full swing xtal (16MHz) 16KCK/14CK+65ms
-sanguino_isp: LFUSE ?= F7
-# 2.7V brownout
-sanguino_isp: EFUSE ?= FD
-sanguino_isp: isp
-
-mighty1284: TARGET = $@
-mighty1284: CHIP = atmega1284p
-mighty1284:
- $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=D7
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-mighty1284_isp: mighty1284
-mighty1284_isp: TARGET = mighty1284
-mighty1284_isp: MCU_TARGET = atmega1284p
-# 1024 byte boot
-mighty1284_isp: HFUSE ?= DE
-# Full swing xtal (16MHz) 16KCK/14CK+65ms
-mighty1284_isp: LFUSE ?= F7
-# 2.7V brownout
-mighty1284_isp: EFUSE ?= FD
-mighty1284_isp: isp
-
-bobuino: TARGET = $@
-bobuino: CHIP = atmega1284p
-bobuino:
- $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=B5
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-bobuino_isp: bobuino
-bobuino_isp: TARGET = bobuino
-bobuino_isp: MCU_TARGET = atmega1284p
-# 1024 byte boot
-bobuino_isp: HFUSE ?= DE
-# Full swing xtal (16MHz) 16KCK/14CK+65ms
-bobuino_isp: LFUSE ?= F7
-# 2.7V brownout
-bobuino_isp: EFUSE ?= FD
-bobuino_isp: isp
-
-# MEGA1280 Board (this is different from the atmega1280 chip platform)
-# Mega has a minimum boot size of 1024 bytes, so enable extra functions
-# Note that optiboot does not (can not) work on the MEGA2560
-#mega: TARGET = atmega1280
-mega1280: atmega1280
-
-
-mega1280_isp: mega1280
-mega1280_isp: TARGET = atmega1280
-mega1280_isp: MCU_TARGET = atmega1280
-# 1024 byte boot
-mega1280_isp: HFUSE ?= DE
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-mega1280_isp: LFUSE ?= FF
-# 2.7V brownout; wants F5 for some reason...
-mega1280_isp: EFUSE ?= F5
-mega1280_isp: isp
-
-# 8MHz clocked platforms
-#
-# These are capable of 115200 baud
-# Note that "new" Arduinos with an AVR as USB/Serial converter will NOT work
-# with an 8MHz target Arduino. The bitrate errors are in opposite directions,
-# and total too large a number.
-#
-
-lilypad: TARGET = $@
-lilypad: CHIP = atmega168
-lilypad:
- $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-lilypad_isp: lilypad
-lilypad_isp: TARGET = lilypad
-# 2.7V brownout
-lilypad_isp: HFUSE ?= DD
-# Internal 8MHz osc (8MHz) Slow rising power
-lilypad_isp: LFUSE ?= E2
-# 512 byte boot
-lilypad_isp: EFUSE ?= 04
-lilypad_isp: isp
-
-# lilypad_resonator is the same as a 8MHz lilypad, except for fuses.
-lilypad_resonator: lilypad
-
-lilypad_resonator_isp: lilypad
-lilypad_resonator_isp: TARGET = lilypad
-# 2.7V brownout
-lilypad_resonator_isp: HFUSE ?= DD
-# Full swing xtal (20MHz) 258CK/14CK+4.1ms
-lilypad_resonator_isp: LFUSE ?= C6
-# 512 byte boot
-lilypad_resonator_isp: EFUSE ?= 04
-lilypad_resonator_isp: isp
-
-pro8: TARGET = pro_8MHz
-pro8: CHIP = atmega328
-pro8:
- $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-pro8_isp: pro8
-pro8_isp: TARGET = pro_8MHz
-# 2.7V brownout
-pro8_isp: HFUSE ?= DD
-# Full swing xtal (20MHz) 258CK/14CK+4.1ms
-pro8_isp: LFUSE ?= C6
-# 512 byte boot
-pro8_isp: EFUSE ?= 04
-pro8_isp: isp
-
-atmega328_pro8: TARGET = atmega328_pro_8MHz
-atmega328_pro8: CHIP = atmega328
-atmega328_pro8:
- $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3
- mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
- mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
-
-atmega328_pro8_isp: atmega328_pro8
-atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
-atmega328_pro8_isp: MCU_TARGET = atmega328p
-# 512 byte boot, SPIEN
-atmega328_pro8_isp: HFUSE ?= DE
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-atmega328_pro8_isp: LFUSE ?= FF
-# 2.7V brownout
-atmega328_pro8_isp: EFUSE ?= DE
-atmega328_pro8_isp: isp
-
-mysensor_micro: atmega328_pro8
-mysensor_micro: target = atmega_pro_8MHz
-mysensor_micro: MCU_TARGET = atmega328p
-# 512 byte boot, SPIEN
-mysensor_micro: HFUSE ?= DE
-# Low power xtal (16MHz) 16KCK/14CK+65ms
-mysensor_micro: LFUSE ?= FF
-# 2.7V brownout
-mysensor_micro: EFUSE ?= DE
-mysensor_micro: LED=C3
-mysensor_micro: BAUD_RATE=57600
-
-# 1MHz clocked platforms
-#
-# These are capable of 9600 baud
-#
-
-luminet: TARGET = luminet
-luminet: MCU_TARGET = attiny84
-luminet: CFLAGS += $(COMMON_OPTIONS) '-DSOFT_UART' '-DBAUD_RATE=9600'
-luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
-luminet: AVR_FREQ ?= 1000000L
-luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
-luminet: $(PROGRAM)_luminet.hex
-luminet: $(PROGRAM)_luminet.lst
-
-luminet_isp: luminet
-luminet_isp: TARGET = luminet
-luminet_isp: MCU_TARGET = attiny84
-# Brownout disabled
-luminet_isp: HFUSE ?= DF
-# 1MHz internal oscillator, slowly rising power
-luminet_isp: LFUSE ?= 62
-# Self-programming enable
-luminet_isp: EFUSE ?= FE
-luminet_isp: isp
-
-
-#---------------------------------------------------------------------------
-#
-# Generic build instructions
-#
-
-FORCE:
-
-baudcheck: FORCE
- - @$(CC) $(CFLAGS) -E baudcheck.c -o baudcheck.tmp.sh
- - @sh baudcheck.tmp.sh
-
-isp: $(TARGET)
- $(MAKE) -f Makefile.isp isp TARGET=$(TARGET)
-
-isp-stk500: $(PROGRAM)_$(TARGET).hex
- $(STK500-1)
- $(STK500-2)
-
-%.elf: $(OBJ) $(dummy)
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
- $(SIZE) $@
-
-clean:
- rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.tmp.sh
-
-%.lst: %.elf
- $(OBJDUMP) -h -S $< > $@
-
-%.hex: %.elf
- $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
-
-%.srec: %.elf
- $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
-
-%.bin: %.elf
- $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/README.md b/hardware/MySensors/avr/bootloaders/DualOptiboot/README.md
deleted file mode 100644
index 06bb760..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/README.md
+++ /dev/null
@@ -1,40 +0,0 @@
-DualOptiboot
-============
-
-Custom Optiboot to add wireless programming capability to Moteino
-Copyright Felix Rusu (2013-2014), felix@lowpowerlab.com
-More at: http://lowpowerlab.com/Moteino
-
-This Optiboot version is modified to add the capability of reflashing
-from an external SPI flash memory chip. As configured this will work
-with Moteino (www.lowpowerlab.com/Moteino) provided a SPI flash chip
-is present on the dedicated onboard footprint.
-Summary of how this Optiboot version works:
-- it looks for an external flash chip
-- if one is found (SPI returns valid data) it will further look
- for a new sketch flash image signature and size
- starting at address 0: FLXIMG:9999:XXXXXXXXXXX
- where: - 'FLXIMG' is fixed signature indicating FLASH chip
- contains a valid new flash image to be burned
- - '9999' are 4 size bytes indicating how long the
- new flash image is (how many bytes to read)
- - 'XXXXXX' are the de-hexified bytes of the flash
- pages to be burned
- - ':' colons have fixed positions (delimiters)
-- if no valid signature/size are found, it will skip and
- function as it normally would (listen to STK500 protocol on serial port)
-
-The added code will result in a compiled size of just under 1kb
-(Originally Optiboot takes just under 0.5kb)
-
--------------------------------------------------------------------------------------------------------------
-
-To compile copy the Optiboot.c and Makefile files where Optiboot is originally located, mine is at:
-arduino-install-dir\hardware\arduino\bootloaders\optiboot\
-Backup the original files andbefore overwrite both files.
-Then compile by running:
-make atmega328
-make atmega1284p
-
-##License
-GPL 3.0. See License.txt file.
\ No newline at end of file
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/boot.h b/hardware/MySensors/avr/bootloaders/DualOptiboot/boot.h
deleted file mode 100644
index 2639cd8..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/boot.h
+++ /dev/null
@@ -1,848 +0,0 @@
-/* Modified to use out for SPM access
-** Peter Knight, Optiboot project http://optiboot.googlecode.com
-**
-** Todo: Tidy up
-**
-** "_short" routines execute 1 cycle faster and use 1 less word of flash
-** by using "out" instruction instead of "sts".
-**
-** Additional elpm variants that trust the value of RAMPZ
-*/
-
-/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. */
-
-/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
-
-#ifndef _AVR_BOOT_H_
-#define _AVR_BOOT_H_ 1
-
-/** \file */
-/** \defgroup avr_boot : Bootloader Support Utilities
- \code
- #include
- #include
- \endcode
-
- The macros in this module provide a C language interface to the
- bootloader support functionality of certain AVR processors. These
- macros are designed to work with all sizes of flash memory.
-
- Global interrupts are not automatically disabled for these macros. It
- is left up to the programmer to do this. See the code example below.
- Also see the processor datasheet for caveats on having global interrupts
- enabled during writing of the Flash.
-
- \note Not all AVR processors provide bootloader support. See your
- processor datasheet to see if it provides bootloader support.
-
- \todo From email with Marek: On smaller devices (all except ATmega64/128),
- __SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
- instructions - since the boot loader has a limited size, this could be an
- important optimization.
-
- \par API Usage Example
- The following code shows typical usage of the boot API.
-
- \code
- #include
- #include
- #include
-
- void boot_program_page (uint32_t page, uint8_t *buf)
- {
- uint16_t i;
- uint8_t sreg;
-
- // Disable interrupts.
-
- sreg = SREG;
- cli();
-
- eeprom_busy_wait ();
-
- boot_page_erase (page);
- boot_spm_busy_wait (); // Wait until the memory is erased.
-
- for (i=0; i
-#include
-#include
-#include
-
-/* Check for SPM Control Register in processor. */
-#if defined (SPMCSR)
-# define __SPM_REG SPMCSR
-#elif defined (SPMCR)
-# define __SPM_REG SPMCR
-#else
-# error AVR processor does not provide bootloader support!
-#endif
-
-
-/* Check for SPM Enable bit. */
-#if defined(SPMEN)
-# define __SPM_ENABLE SPMEN
-#elif defined(SELFPRGEN)
-# define __SPM_ENABLE SELFPRGEN
-#else
-# error Cannot find SPM Enable bit definition!
-#endif
-
-/** \ingroup avr_boot
- \def BOOTLOADER_SECTION
-
- Used to declare a function or variable to be placed into a
- new section called .bootloader. This section and its contents
- can then be relocated to any address (such as the bootloader
- NRWW area) at link-time. */
-
-#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
-
-/* Create common bit definitions. */
-#ifdef ASB
-#define __COMMON_ASB ASB
-#else
-#define __COMMON_ASB RWWSB
-#endif
-
-#ifdef ASRE
-#define __COMMON_ASRE ASRE
-#else
-#define __COMMON_ASRE RWWSRE
-#endif
-
-/* Define the bit positions of the Boot Lock Bits. */
-
-#define BLB12 5
-#define BLB11 4
-#define BLB02 3
-#define BLB01 2
-
-/** \ingroup avr_boot
- \def boot_spm_interrupt_enable()
- Enable the SPM interrupt. */
-
-#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
-
-/** \ingroup avr_boot
- \def boot_spm_interrupt_disable()
- Disable the SPM interrupt. */
-
-#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
-
-/** \ingroup avr_boot
- \def boot_is_spm_interrupt()
- Check if the SPM interrupt is enabled. */
-
-#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
-
-/** \ingroup avr_boot
- \def boot_rww_busy()
- Check if the RWW section is busy. */
-
-#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
-
-/** \ingroup avr_boot
- \def boot_spm_busy()
- Check if the SPM instruction is busy. */
-
-#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
-
-/** \ingroup avr_boot
- \def boot_spm_busy_wait()
- Wait while the SPM instruction is busy. */
-
-#define boot_spm_busy_wait() do{}while(boot_spm_busy())
-
-#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
-#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
-#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
-#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
-#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
-
-#define __boot_page_fill_short(address, data) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r0, %3\n\t" \
- "out %0, %1\n\t" \
- "spm\n\t" \
- "clr r1\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_FILL), \
- "z" ((uint16_t)address), \
- "r" ((uint16_t)data) \
- : "r0" \
- ); \
-}))
-
-#define __boot_page_fill_normal(address, data) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r0, %3\n\t" \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- "clr r1\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_FILL), \
- "z" ((uint16_t)address), \
- "r" ((uint16_t)data) \
- : "r0" \
- ); \
-}))
-
-#define __boot_page_fill_alternate(address, data)\
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r0, %3\n\t" \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- ".word 0xffff\n\t" \
- "nop\n\t" \
- "clr r1\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_FILL), \
- "z" ((uint16_t)address), \
- "r" ((uint16_t)data) \
- : "r0" \
- ); \
-}))
-
-#define __boot_page_fill_extended(address, data) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r0, %4\n\t" \
- "movw r30, %A3\n\t" \
- "sts %1, %C3\n\t" \
- "sts %0, %2\n\t" \
- "spm\n\t" \
- "clr r1\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "i" (_SFR_MEM_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_FILL), \
- "r" ((uint32_t)address), \
- "r" ((uint16_t)data) \
- : "r0", "r30", "r31" \
- ); \
-}))
-
-#define __boot_page_fill_extended_short(address, data) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r0, %4\n\t" \
- "movw r30, %A3\n\t" \
- "out %1, %C3\n\t" \
- "out %0, %2\n\t" \
- "spm\n\t" \
- "clr r1\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "i" (_SFR_IO_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_FILL), \
- "r" ((uint32_t)address), \
- "r" ((uint16_t)data) \
- : "r0", "r30", "r31" \
- ); \
-}))
-
-#define __boot_page_erase_short(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "out %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_ERASE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-
-#define __boot_page_erase_normal(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_ERASE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-#define __boot_page_erase_alternate(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- ".word 0xffff\n\t" \
- "nop\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_ERASE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-#define __boot_page_erase_extended(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r30, %A3\n\t" \
- "sts %1, %C3\n\t" \
- "sts %0, %2\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "i" (_SFR_MEM_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_ERASE), \
- "r" ((uint32_t)address) \
- : "r30", "r31" \
- ); \
-}))
-#define __boot_page_erase_extended_short(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r30, %A3\n\t" \
- "out %1, %C3\n\t" \
- "out %0, %2\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "i" (_SFR_IO_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_ERASE), \
- "r" ((uint32_t)address) \
- : "r30", "r31" \
- ); \
-}))
-
-#define __boot_page_write_short(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "out %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_WRITE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-#define __boot_page_write_normal(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_WRITE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-#define __boot_page_write_alternate(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- ".word 0xffff\n\t" \
- "nop\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_PAGE_WRITE), \
- "z" ((uint16_t)address) \
- ); \
-}))
-
-#define __boot_page_write_extended(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r30, %A3\n\t" \
- "sts %1, %C3\n\t" \
- "sts %0, %2\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "i" (_SFR_MEM_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_WRITE), \
- "r" ((uint32_t)address) \
- : "r30", "r31" \
- ); \
-}))
-#define __boot_page_write_extended_short(address) \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "movw r30, %A3\n\t" \
- "out %1, %C3\n\t" \
- "out %0, %2\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "i" (_SFR_IO_ADDR(RAMPZ)), \
- "r" ((uint8_t)__BOOT_PAGE_WRITE), \
- "r" ((uint32_t)address) \
- : "r30", "r31" \
- ); \
-}))
-
-#define __boot_rww_enable_short() \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "out %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_RWW_ENABLE) \
- ); \
-}))
-
-#define __boot_rww_enable() \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_RWW_ENABLE) \
- ); \
-}))
-
-#define __boot_rww_enable_alternate() \
-(__extension__({ \
- __asm__ __volatile__ \
- ( \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- ".word 0xffff\n\t" \
- "nop\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_RWW_ENABLE) \
- ); \
-}))
-
-/* From the mega16/mega128 data sheets (maybe others):
-
- Bits by SPM To set the Boot Loader Lock bits, write the desired data to
- R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
- after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
- that may prevent the Application and Boot Loader section from any
- software update by the MCU.
-
- If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
- will be programmed if an SPM instruction is executed within four cycles
- after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
- don't care during this operation, but for future compatibility it is
- recommended to load the Z-pointer with $0001 (same as used for reading the
- Lock bits). For future compatibility It is also recommended to set bits 7,
- 6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
- Lock bits the entire Flash can be read during the operation. */
-
-#define __boot_lock_bits_set_short(lock_bits) \
-(__extension__({ \
- uint8_t value = (uint8_t)(~(lock_bits)); \
- __asm__ __volatile__ \
- ( \
- "ldi r30, 1\n\t" \
- "ldi r31, 0\n\t" \
- "mov r0, %2\n\t" \
- "out %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
- "r" (value) \
- : "r0", "r30", "r31" \
- ); \
-}))
-
-#define __boot_lock_bits_set(lock_bits) \
-(__extension__({ \
- uint8_t value = (uint8_t)(~(lock_bits)); \
- __asm__ __volatile__ \
- ( \
- "ldi r30, 1\n\t" \
- "ldi r31, 0\n\t" \
- "mov r0, %2\n\t" \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
- "r" (value) \
- : "r0", "r30", "r31" \
- ); \
-}))
-
-#define __boot_lock_bits_set_alternate(lock_bits) \
-(__extension__({ \
- uint8_t value = (uint8_t)(~(lock_bits)); \
- __asm__ __volatile__ \
- ( \
- "ldi r30, 1\n\t" \
- "ldi r31, 0\n\t" \
- "mov r0, %2\n\t" \
- "sts %0, %1\n\t" \
- "spm\n\t" \
- ".word 0xffff\n\t" \
- "nop\n\t" \
- : \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
- "r" (value) \
- : "r0", "r30", "r31" \
- ); \
-}))
-
-/*
- Reading lock and fuse bits:
-
- Similarly to writing the lock bits above, set BLBSET and SPMEN (or
- SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
- LPM instruction.
-
- Z address: contents:
- 0x0000 low fuse bits
- 0x0001 lock bits
- 0x0002 extended fuse bits
- 0x0003 high fuse bits
-
- Sounds confusing, doesn't it?
-
- Unlike the macros in pgmspace.h, no need to care for non-enhanced
- cores here as these old cores do not provide SPM support anyway.
- */
-
-/** \ingroup avr_boot
- \def GET_LOW_FUSE_BITS
- address to read the low fuse bits, using boot_lock_fuse_bits_get
- */
-#define GET_LOW_FUSE_BITS (0x0000)
-/** \ingroup avr_boot
- \def GET_LOCK_BITS
- address to read the lock bits, using boot_lock_fuse_bits_get
- */
-#define GET_LOCK_BITS (0x0001)
-/** \ingroup avr_boot
- \def GET_EXTENDED_FUSE_BITS
- address to read the extended fuse bits, using boot_lock_fuse_bits_get
- */
-#define GET_EXTENDED_FUSE_BITS (0x0002)
-/** \ingroup avr_boot
- \def GET_HIGH_FUSE_BITS
- address to read the high fuse bits, using boot_lock_fuse_bits_get
- */
-#define GET_HIGH_FUSE_BITS (0x0003)
-
-/** \ingroup avr_boot
- \def boot_lock_fuse_bits_get(address)
-
- Read the lock or fuse bits at \c address.
-
- Parameter \c address can be any of GET_LOW_FUSE_BITS,
- GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
-
- \note The lock and fuse bits returned are the physical values,
- i.e. a bit returned as 0 means the corresponding fuse or lock bit
- is programmed.
- */
-#define boot_lock_fuse_bits_get_short(address) \
-(__extension__({ \
- uint8_t __result; \
- __asm__ __volatile__ \
- ( \
- "ldi r30, %3\n\t" \
- "ldi r31, 0\n\t" \
- "out %1, %2\n\t" \
- "lpm %0, Z\n\t" \
- : "=r" (__result) \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
- "M" (address) \
- : "r0", "r30", "r31" \
- ); \
- __result; \
-}))
-
-#define boot_lock_fuse_bits_get(address) \
-(__extension__({ \
- uint8_t __result; \
- __asm__ __volatile__ \
- ( \
- "ldi r30, %3\n\t" \
- "ldi r31, 0\n\t" \
- "sts %1, %2\n\t" \
- "lpm %0, Z\n\t" \
- : "=r" (__result) \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
- "M" (address) \
- : "r0", "r30", "r31" \
- ); \
- __result; \
-}))
-
-/** \ingroup avr_boot
- \def boot_signature_byte_get(address)
-
- Read the Signature Row byte at \c address. For some MCU types,
- this function can also retrieve the factory-stored oscillator
- calibration bytes.
-
- Parameter \c address can be 0-0x1f as documented by the datasheet.
- \note The values are MCU type dependent.
-*/
-
-#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
-
-#define boot_signature_byte_get_short(addr) \
-(__extension__({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint8_t __result; \
- __asm__ __volatile__ \
- ( \
- "out %1, %2\n\t" \
- "lpm %0, Z" "\n\t" \
- : "=r" (__result) \
- : "i" (_SFR_IO_ADDR(__SPM_REG)), \
- "r" ((uint8_t) __BOOT_SIGROW_READ), \
- "z" (__addr16) \
- ); \
- __result; \
-}))
-
-#define boot_signature_byte_get(addr) \
-(__extension__({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint8_t __result; \
- __asm__ __volatile__ \
- ( \
- "sts %1, %2\n\t" \
- "lpm %0, Z" "\n\t" \
- : "=r" (__result) \
- : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
- "r" ((uint8_t) __BOOT_SIGROW_READ), \
- "z" (__addr16) \
- ); \
- __result; \
-}))
-
-/** \ingroup avr_boot
- \def boot_page_fill(address, data)
-
- Fill the bootloader temporary page buffer for flash
- address with data word.
-
- \note The address is a byte address. The data is a word. The AVR
- writes data to the buffer a word at a time, but addresses the buffer
- per byte! So, increment your address by 2 between calls, and send 2
- data bytes in a word format! The LSB of the data is written to the lower
- address; the MSB of the data is written to the higher address.*/
-
-/** \ingroup avr_boot
- \def boot_page_erase(address)
-
- Erase the flash page that contains address.
-
- \note address is a byte address in flash, not a word address. */
-
-/** \ingroup avr_boot
- \def boot_page_write(address)
-
- Write the bootloader temporary page buffer
- to flash page that contains address.
-
- \note address is a byte address in flash, not a word address. */
-
-/** \ingroup avr_boot
- \def boot_rww_enable()
-
- Enable the Read-While-Write memory section. */
-
-/** \ingroup avr_boot
- \def boot_lock_bits_set(lock_bits)
-
- Set the bootloader lock bits.
-
- \param lock_bits A mask of which Boot Loader Lock Bits to set.
-
- \note In this context, a 'set bit' will be written to a zero value.
- Note also that only BLBxx bits can be programmed by this command.
-
- For example, to disallow the SPM instruction from writing to the Boot
- Loader memory section of flash, you would use this macro as such:
-
- \code
- boot_lock_bits_set (_BV (BLB11));
- \endcode
-
- \note Like any lock bits, the Boot Loader Lock Bits, once set,
- cannot be cleared again except by a chip erase which will in turn
- also erase the boot loader itself. */
-
-/* Normal versions of the macros use 16-bit addresses.
- Extended versions of the macros use 32-bit addresses.
- Alternate versions of the macros use 16-bit addresses and require special
- instruction sequences after LPM.
-
- FLASHEND is defined in the ioXXXX.h file.
- USHRT_MAX is defined in . */
-
-#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
- || defined(__AVR_ATmega323__)
-
-/* Alternate: ATmega161/163/323 and 16 bit address */
-#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
-#define boot_page_erase(address) __boot_page_erase_alternate(address)
-#define boot_page_write(address) __boot_page_write_alternate(address)
-#define boot_rww_enable() __boot_rww_enable_alternate()
-#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
-
-#elif (FLASHEND > USHRT_MAX)
-
-/* Extended: >16 bit address */
-#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
-#define boot_page_erase(address) __boot_page_erase_extended_short(address)
-#define boot_page_write(address) __boot_page_write_extended_short(address)
-#define boot_rww_enable() __boot_rww_enable_short()
-#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
-
-#else
-
-/* Normal: 16 bit address */
-#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
-#define boot_page_erase(address) __boot_page_erase_short(address)
-#define boot_page_write(address) __boot_page_write_short(address)
-#define boot_rww_enable() __boot_rww_enable_short()
-#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
-
-#endif
-
-/** \ingroup avr_boot
-
- Same as boot_page_fill() except it waits for eeprom and spm operations to
- complete before filling the page. */
-
-#define boot_page_fill_safe(address, data) \
-do { \
- boot_spm_busy_wait(); \
- eeprom_busy_wait(); \
- boot_page_fill(address, data); \
-} while (0)
-
-/** \ingroup avr_boot
-
- Same as boot_page_erase() except it waits for eeprom and spm operations to
- complete before erasing the page. */
-
-#define boot_page_erase_safe(address) \
-do { \
- boot_spm_busy_wait(); \
- eeprom_busy_wait(); \
- boot_page_erase (address); \
-} while (0)
-
-/** \ingroup avr_boot
-
- Same as boot_page_write() except it waits for eeprom and spm operations to
- complete before writing the page. */
-
-#define boot_page_write_safe(address) \
-do { \
- boot_spm_busy_wait(); \
- eeprom_busy_wait(); \
- boot_page_write (address); \
-} while (0)
-
-/** \ingroup avr_boot
-
- Same as boot_rww_enable() except waits for eeprom and spm operations to
- complete before enabling the RWW mameory. */
-
-#define boot_rww_enable_safe() \
-do { \
- boot_spm_busy_wait(); \
- eeprom_busy_wait(); \
- boot_rww_enable(); \
-} while (0)
-
-/** \ingroup avr_boot
-
- Same as boot_lock_bits_set() except waits for eeprom and spm operations to
- complete before setting the lock bits. */
-
-#define boot_lock_bits_set_safe(lock_bits) \
-do { \
- boot_spm_busy_wait(); \
- eeprom_busy_wait(); \
- boot_lock_bits_set (lock_bits); \
-} while (0)
-
-#endif /* _AVR_BOOT_H_ */
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot.c b/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot.c
deleted file mode 100644
index a527c28..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot.c
+++ /dev/null
@@ -1,1068 +0,0 @@
-//////////////////////////////////////////////////////////////////////////
-//
-// DualOptiboot
-// Optiboot based custom bootloader for Moteino
-// Enables wireless programming of Moteino wireless arduino clone
-// Copyright Felix Rusu (2013), felix@lowpowerlab.com
-// http://lowpowerlab.com/Moteino
-//
-//////////////////////////////////////////////////////////////////////////
-//
-// 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
-//
-//////////////////////////////////////////////////////////////////////////
-//
-// This Optiboot version is modified to add the capability of reflashing
-// from an external SPI flash memory chip. As configured this will work
-// with Moteino (www.lowpowerlab.com/Moteino) provided a SPI flash chip
-// is present on the dedicated onboard footprint.
-// Summary of how this Optiboot version works:
-// - it looks for an external flash chip
-// - if one is found (SPI returns valid data) it will further look
-// for a new sketch flash image signature and size
-// starting at address 0: FLXIMG:NN:XXXXXXXXXXX
-// where: - 'FLXIMG' is fixed signature indicating FLASH chip
-// contains a valid new flash image to be burned
-// - 'NN' are 2 size bytes (uint_16) indicating how long the
-// new flash image is (how many bytes to read), max 65536Bytes
-// - 'XXXXXX' are the de-hexified bytes of the flash
-// pages to be burned
-// - ':' colons have fixed positions (delimiters)
-// - if no valid signature/size are found, it will skip and
-// function as it normally would (listen to STK500 protocol on serial port)
-//
-// The added code will result in a compiled size of just under 1kb
-// (Originally Optiboot takes just under 0.5kb)
-// - Examples at: http://lowpowerlab.com/blog/category/moteino/wireless-programming/
-// - Tested on atmega328P and atmega644/1284P
-// - Limited to 31K sketches for atmega328p and 64K sketches for atmega1284P.
-//////////////////////////////////////////////////////////////////////////
-/**********************************************************/
-/* Optiboot bootloader for Arduino */
-/* */
-/* http://optiboot.googlecode.com */
-/* */
-/* Arduino-maintained version : See README.TXT */
-/* http://code.google.com/p/arduino/ */
-/* It is the intent that changes not relevant to the */
-/* Arduino production envionment get moved from the */
-/* optiboot project to the arduino project in "lumps." */
-/* */
-/* Heavily optimised bootloader that is faster and */
-/* smaller than the Arduino standard bootloader */
-/* */
-/* Enhancements: */
-/* Fits in 512 bytes, saving 1.5K of code space */
-/* Background page erasing speeds up programming */
-/* Higher baud rate speeds up programming */
-/* Written almost entirely in C */
-/* Customisable timeout with accurate timeconstant */
-/* Optional virtual UART. No hardware UART required. */
-/* Optional virtual boot partition for devices without. */
-/* */
-/* What you lose: */
-/* Implements a skeleton STK500 protocol which is */
-/* missing several features including EEPROM */
-/* programming and non-page-aligned writes */
-/* High baud rate breaks compatibility with standard */
-/* Arduino flash settings */
-/* */
-/* Fully supported: */
-/* ATmega168 based devices (Diecimila etc) */
-/* ATmega328P based devices (Duemilanove etc) */
-/* */
-/* Beta test (believed working.) */
-/* ATmega8 based devices (Arduino legacy) */
-/* ATmega328 non-picopower devices */
-/* ATmega644P based devices (Sanguino) */
-/* ATmega1284P based devices */
-/* ATmega1280 based devices (Arduino Mega) */
-/* */
-/* Alpha test */
-/* ATmega32 */
-/* */
-/* Work in progress: */
-/* ATtiny84 based devices (Luminet) */
-/* */
-/* Does not support: */
-/* USB based devices (eg. Teensy, Leonardo) */
-/* */
-/* Assumptions: */
-/* The code makes several assumptions that reduce the */
-/* code size. They are all true after a hardware reset, */
-/* but may not be true if the bootloader is called by */
-/* other means or on other hardware. */
-/* No interrupts can occur */
-/* UART and Timer 1 are set to their reset state */
-/* SP points to RAMEND */
-/* */
-/* Code builds on code, libraries and optimisations from: */
-/* stk500boot.c by Jason P. Kyle */
-/* Arduino bootloader http://arduino.cc */
-/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
-/* avr-libc project http://nongnu.org/avr-libc */
-/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
-/* AVR305 Atmel Application Note */
-/* */
-/* 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 */
-/* */
-/**********************************************************/
-
-
-/**********************************************************/
-/* */
-/* Optional defines: */
-/* */
-/**********************************************************/
-/* */
-/* BIG_BOOT: */
-/* Build a 1k bootloader, not 512 bytes. This turns on */
-/* extra functionality. */
-/* */
-/* BAUD_RATE: */
-/* Set bootloader baud rate. */
-/* */
-/* LUDICROUS_SPEED: */
-/* 230400 baud :-) */
-/* */
-/* SOFT_UART: */
-/* Use AVR305 soft-UART instead of hardware UART. */
-/* */
-/* LED_START_FLASHES: */
-/* Number of LED flashes on bootup. */
-/* */
-/* LED_DATA_FLASH: */
-/* Flash LED when transferring data. For boards without */
-/* TX or RX LEDs, or for people who like blinky lights. */
-/* */
-/* SUPPORT_EEPROM: */
-/* Support reading and writing from EEPROM. This is not */
-/* used by Arduino, so off by default. */
-/* */
-/* TIMEOUT_MS: */
-/* Bootloader timeout period, in milliseconds. */
-/* 500,1000,2000,4000,8000 supported. */
-/* */
-/* UART: */
-/* UART number (0..n) for devices with more than */
-/* one hardware uart (644P, 1284P, etc) */
-/* */
-/**********************************************************/
-
-/**********************************************************/
-/* Version Numbers! */
-/* */
-/* Arduino Optiboot now includes this Version number in */
-/* the source and object code. */
-/* */
-/* Version 3 was released as zip from the optiboot */
-/* repository and was distributed with Arduino 0022. */
-/* Version 4 starts with the arduino repository commit */
-/* that brought the arduino repository up-to-date with */
-/* the optiboot source tree changes since v3. */
-/* Version 5 was created at the time of the new Makefile */
-/* structure (Mar, 2013), even though no binaries changed*/
-/* It would be good if versions implemented outside the */
-/* official repository used an out-of-seqeunce version */
-/* number (like 104.6 if based on based on 4.5) to */
-/* prevent collisions. */
-/* */
-/**********************************************************/
-
-/**********************************************************/
-/* Edit History: */
-/* */
-/* Mar 2013 */
-/* 5.0 WestfW: Major Makefile restructuring. */
-/* See Makefile and pin_defs.h */
-/* (no binary changes) */
-/* */
-/* 4.6 WestfW/Pito: Add ATmega32 support */
-/* 4.6 WestfW/radoni: Don't set LED_PIN as an output if */
-/* not used. (LED_START_FLASHES = 0) */
-/* Jan 2013 */
-/* 4.6 WestfW/dkinzer: use autoincrement lpm for read */
-/* 4.6 WestfW/dkinzer: pass reset cause to app in R2 */
-/* Mar 2012 */
-/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
-/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
-/* Jan 2012: */
-/* 4.5 WestfW: fix NRWW value for m1284. */
-/* 4.4 WestfW: use attribute OS_main instead of naked for */
-/* main(). This allows optimizations that we */
-/* count on, which are prohibited in naked */
-/* functions due to PR42240. (keeps us less */
-/* than 512 bytes when compiler is gcc4.5 */
-/* (code from 4.3.2 remains the same.) */
-/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
-/* does not change the 328 binary, so the */
-/* version number didn't change either. (?) */
-/* June 2011: */
-/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
-/* know what it was doing or why.) Added a */
-/* check of the calculated BRG value instead. */
-/* Version stays 4.4; existing binaries are */
-/* not changed. */
-/* 4.4 WestfW: add initialization of address to keep */
-/* the compiler happy. Change SC'ed targets. */
-/* Return the SW version via READ PARAM */
-/* 4.3 WestfW: catch framing errors in getch(), so that */
-/* AVRISP works without HW kludges. */
-/* http://code.google.com/p/arduino/issues/detail?id=368n*/
-/* 4.2 WestfW: reduce code size, fix timeouts, change */
-/* verifySpace to use WDT instead of appstart */
-/* 4.1 WestfW: put version number in binary. */
-/**********************************************************/
-
-#define LED_DATA_FLASH 1
-#define OPTIBOOT_MAJVER 5
-#define OPTIBOOT_MINVER 0
-
-#define MAKESTR(a) #a
-#define MAKEVER(a, b) MAKESTR(a*256+b)
-
-asm(" .section .version\n"
- "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
- " .section .text\n");
-
-#include
-#include
-#include
-
-// uses sts instructions, but this version uses out instructions
-// This saves cycles and program memory.
-#include "boot.h"
-
-
-// We don't use as those routines have interrupt overhead we don't need.
-
-#include "pin_defs.h"
-#include "stk500.h"
-
-#ifndef LED_START_FLASHES
-#define LED_START_FLASHES 1
-#endif
-
-#ifdef LUDICROUS_SPEED
-#define BAUD_RATE 230400L
-#endif
-
-/* set the UART baud rate defaults */
-#ifndef BAUD_RATE
-#if F_CPU >= 8000000L
-#define BAUD_RATE 115200L // Highest rate Avrdude win32 will support
-#elsif F_CPU >= 1000000L
-#define BAUD_RATE 9600L // 19200 also supported, but with significant error
-#elsif F_CPU >= 128000L
-#define BAUD_RATE 4800L // Good for 128kHz internal RC
-#else
-#define BAUD_RATE 1200L // Good even at 32768Hz
-#endif
-#endif
-
-#ifndef UART
-#define UART 0
-#endif
-
-#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 )
-#define BAUD_ACTUAL (F_CPU/(8 * ((BAUD_SETTING)+1)))
-#define BAUD_ERROR (( 100*(BAUD_RATE - BAUD_ACTUAL) ) / BAUD_RATE)
-
-#if BAUD_ERROR >= 5
-#error BAUD_RATE error greater than 5%
-#elif BAUD_ERROR <= -5
-#error BAUD_RATE error greater than -5%
-#elif BAUD_ERROR >= 2
-#warning BAUD_RATE error greater than 2%
-#elif BAUD_ERROR <= -2
-#warning BAUD_RATE error greater than -2%
-#endif
-
-#if 0
-/* Switch in soft UART for hard baud rates */
-/*
- * I don't understand what this was supposed to accomplish, where the
- * constant "280" came from, or why automatically (and perhaps unexpectedly)
- * switching to a soft uart is a good thing, so I'm undoing this in favor
- * of a range check using the same calc used to config the BRG...
- */
-#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
-#ifndef SOFT_UART
-#define SOFT_UART
-#endif
-#endif
-#else // 0
-#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
-#error Unachievable baud rate (too slow) BAUD_RATE
-#endif // baud rate slow check
-#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
-#error Unachievable baud rate (too fast) BAUD_RATE
-#endif // baud rate fastn check
-#endif
-
-/* Watchdog settings */
-#define WATCHDOG_OFF (0)
-#define WATCHDOG_16MS (_BV(WDE))
-#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
-#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
-#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
-#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
-#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
-#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
-#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
-#ifndef __AVR_ATmega8__
-#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
-#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
-#endif
-
-/* Function Prototypes */
-/* The main function is in init9, which removes the interrupt vector table */
-/* we don't need. It is also 'naked', which means the compiler does not */
-/* generate any entry or exit code itself. */
-int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9")));
-void putch(char);
-uint8_t getch(void);
-static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
-void verifySpace();
-static inline void flash_led(uint8_t);
-uint8_t getLen();
-static inline void watchdogReset();
-void watchdogConfig(uint8_t x);
-#ifdef SOFT_UART
-void uartDelay() __attribute__ ((naked));
-#endif
-void appStart(uint8_t rstFlags) __attribute__ ((naked));
-
-/*
- * NRWW memory
- * Addresses below NRWW (Non-Read-While-Write) can be programmed while
- * continuing to run code from flash, slightly speeding up programming
- * time. Beware that Atmel data sheets specify this as a WORD address,
- * while optiboot will be comparing against a 16-bit byte address. This
- * means that on a part with 128kB of memory, the upper part of the lower
- * 64k will get NRWW processing as well, even though it doesn't need it.
- * That's OK. In fact, you can disable the overlapping processing for
- * a part entirely by setting NRWWSTART to zero. This reduces code
- * space a bit, at the expense of being slightly slower, overall.
- *
- * RAMSTART should be self-explanatory. It's bigger on parts with a
- * lot of peripheral registers.
- */
-#if defined(__AVR_ATmega168__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0x3800)
-#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0x7000)
-#elif defined (__AVR_ATmega644P__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0xE000)
-// correct for a bug in avr-libc
-#undef SIGNATURE_2
-#define SIGNATURE_2 0x0A
-#elif defined (__AVR_ATmega1284P__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0xE000)
-#elif defined(__AVR_ATtiny84__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0x0000)
-#elif defined(__AVR_ATmega1280__)
-#define RAMSTART (0x200)
-#define NRWWSTART (0xE000)
-#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
-#define RAMSTART (0x100)
-#define NRWWSTART (0x1800)
-#endif
-
-/* C zero initialises all global variables. However, that requires */
-/* These definitions are NOT zero initialised, but that doesn't matter */
-/* This allows us to drop the zero init code, saving us memory */
-#define buff ((uint8_t*)(RAMSTART))
-#ifdef VIRTUAL_BOOT_PARTITION
-#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
-#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
-#endif
-
-/*
- * Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly.
- * Note that mega8/m32 still needs special handling, because ubrr is handled
- * differently.
- */
-#if UART == 0
-# define UART_SRA UCSR0A
-# define UART_SRB UCSR0B
-# define UART_SRC UCSR0C
-# define UART_SRL UBRR0L
-# define UART_UDR UDR0
-#elif UART == 1
-#if !defined(UDR1)
-#error UART == 1, but no UART1 on device
-#endif
-# define UART_SRA UCSR1A
-# define UART_SRB UCSR1B
-# define UART_SRC UCSR1C
-# define UART_SRL UBRR1L
-# define UART_UDR UDR1
-#elif UART == 2
-#if !defined(UDR2)
-#error UART == 2, but no UART2 on device
-#endif
-# define UART_SRA UCSR2A
-# define UART_SRB UCSR2B
-# define UART_SRC UCSR2C
-# define UART_SRL UBRR2L
-# define UART_UDR UDR2
-#elif UART == 3
-#if !defined(UDR1)
-#error UART == 3, but no UART3 on device
-#endif
-# define UART_SRA UCSR3A
-# define UART_SRB UCSR3B
-# define UART_SRC UCSR3C
-# define UART_SRL UBRR3L
-# define UART_UDR UDR3
-#endif
-
-/******************* SPI FLASH Code **********************************/
-// This code will handle the reading/erasing the external SPI FLASH memory
-// assumed to have the SPI_CS on D8 on Moteino (Atmega328P)
-#define SPI_MODE0 0x00
-#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
-#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
-#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
-#define SPI_CLOCK_DIV2 0x04
-
-#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
- #define FLASHSS_DDR DDRB
- #define FLASHSS_PORT PORTB
- #define FLASHSS PINB0
- #define SS PINB2
-#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__)
- #define FLASHSS_DDR DDRC
- #define FLASHSS_PORT PORTC
- #define FLASHSS PINC7
- #define SS PINB4
-#endif
-
-#define FLASH_SELECT { FLASHSS_PORT &= ~(_BV(FLASHSS)); }
-#define FLASH_UNSELECT { FLASHSS_PORT |= _BV(FLASHSS); }
-
-#define SPIFLASH_STATUSWRITE 0x01 // write status register
-#define SPIFLASH_STATUSREAD 0x05 // read status register
-#define SPIFLASH_WRITEENABLE 0x06 // write enable
-#define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency)
-#define SPIFLASH_BLOCKERASE_32K 0x52 // erase one 32K block of flash memory
-#define SPIFLASH_BLOCKERASE_64K 0xD8 // erase one 32K block of flash memory
-#define SPIFLASH_JEDECID 0x9F // read JEDEC ID
-//#define DEBUG_ON // uncomment to enable Serial debugging
- // (will output different characters depending on which path the bootloader takes)
-
-uint8_t SPI_transfer(uint8_t _data) {
- SPDR = _data;
- while (!(SPSR & _BV(SPIF)));
- return SPDR;
-}
-
-uint8_t FLASH_busy()
-{
- FLASH_SELECT;
- SPI_transfer(SPIFLASH_STATUSREAD);
- uint8_t status = SPI_transfer(0);
- FLASH_UNSELECT;
- return status & 1;
-}
-
-void FLASH_command(uint8_t cmd, uint8_t isWrite){
- if (isWrite)
- {
- FLASH_command(SPIFLASH_WRITEENABLE, 0); // Write Enable
- FLASH_UNSELECT;
- }
- while(FLASH_busy()); //wait for chip to become available
- FLASH_SELECT;
- SPI_transfer(cmd);
-}
-
-uint8_t FLASH_readByte(uint32_t addr) {
- FLASH_command(SPIFLASH_ARRAYREADLOWFREQ, 0);
- SPI_transfer(addr >> 16);
- SPI_transfer(addr >> 8);
- SPI_transfer(addr);
- //SPI.transfer(0); //"dont care", needed with SPIFLASH_ARRAYREAD command only
- uint8_t result = SPI_transfer(0);
- FLASH_UNSELECT;
- return result;
-}
-
-void CheckFlashImage() {
-#ifdef DEBUG_ON
- putch('F');
-#endif
- watchdogConfig(WATCHDOG_OFF);
-
- //SPI INIT
-#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
- DDRB |= _BV(FLASHSS) | _BV(SS) | _BV(PB3) | _BV(PB5); //OUTPUTS for FLASH_SS and SS, MOSI, SCK
- FLASH_UNSELECT; //unselect FLASH chip
- PORTB |= _BV(SS); //set SS HIGH
-#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__)
- DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS
- DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK
- FLASH_UNSELECT; //unselect FLASH chip
- PORTB |= _BV(SS); //set SS HIGH
-#endif
-
- //SPCR &= ~(_BV(DORD)); //MSB first
- //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0
- //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2
- //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK);
-
- // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT.
- SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode
-
- //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value
- FLASH_SELECT;
- SPI_transfer(SPIFLASH_JEDECID);
- uint8_t deviceId = SPI_transfer(0);
- FLASH_UNSELECT;
- if (deviceId==0 || deviceId==0xFF) return;
-
- //global unprotect
- FLASH_command(SPIFLASH_STATUSWRITE, 1);
- SPI_transfer(0);
- FLASH_UNSELECT;
-
- //check if any flash image exists on external FLASH chip
- if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':')
- {
-#ifdef DEBUG_ON
- putch('L');
-#endif
-
- uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8);
- if (imagesize%2!=0) return; //basic check that we got even # of bytes
-
- uint16_t b, i, nextAddress=0;
-
- LED_PIN |= _BV(LED);
- for (i=0; i 0
- // Set up Timer 1 for timeout counter
- TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
-#endif
-#ifndef SOFT_UART
-#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
- UCSRA = _BV(U2X); //Double speed mode USART
- UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx
- UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1
- UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
-#else
- UART_SRA = _BV(U2X0); //Double speed mode USART0
- UART_SRB = _BV(RXEN0) | _BV(TXEN0);
- UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
- UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
-#endif
-#endif
-
- // Set up watchdog to trigger after 500ms
- watchdogConfig(WATCHDOG_1S);
-
-#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
- /* Set LED pin as output */
- LED_DDR |= _BV(LED);
-#endif
-
-#ifdef SOFT_UART
- /* Set TX pin as output */
- UART_DDR |= _BV(UART_TX_BIT);
-#endif
-
-#if LED_START_FLASHES > 0
- /* Flash onboard LED to signal entering of bootloader */
- flash_led(LED_START_FLASHES * 2);
-#endif
-
- /* Forever loop */
- for (;;) {
- /* get character from UART */
- ch = getch();
-
- if(ch == STK_GET_PARAMETER) {
- unsigned char which = getch();
- verifySpace();
- if (which == 0x82) {
- /*
- * Send optiboot version as "minor SW version"
- */
- putch(OPTIBOOT_MINVER);
- } else if (which == 0x81) {
- putch(OPTIBOOT_MAJVER);
- } else {
- /*
- * GET PARAMETER returns a generic 0x03 reply for
- * other parameters - enough to keep Avrdude happy
- */
- putch(0x03);
- }
- }
- else if(ch == STK_SET_DEVICE) {
- // SET DEVICE is ignored
- getNch(20);
- }
- else if(ch == STK_SET_DEVICE_EXT) {
- // SET DEVICE EXT is ignored
- getNch(5);
- }
- else if(ch == STK_LOAD_ADDRESS) {
- // LOAD ADDRESS
- uint16_t newAddress;
- newAddress = getch();
- newAddress = (newAddress & 0xff) | (getch() << 8);
-#ifdef RAMPZ
- // Transfer top bit to RAMPZ
- RAMPZ = (newAddress & 0x8000) ? 1 : 0;
-#endif
- newAddress += newAddress; // Convert from word address to byte address
- address = newAddress;
- verifySpace();
- }
- else if(ch == STK_UNIVERSAL) {
- // UNIVERSAL command is ignored
- getNch(4);
- putch(0x00);
- }
- /* Write memory, length is big endian and is in bytes */
- else if(ch == STK_PROG_PAGE) {
- // PROGRAM PAGE - we support flash programming only, not EEPROM
- uint8_t *bufPtr;
- uint16_t addrPtr;
-
- getch(); /* getlen() */
- length = getch();
- getch();
-
- // If we are in RWW section, immediately start page erase
- if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
-
- // While that is going on, read in page contents
- bufPtr = buff;
- do *bufPtr++ = getch();
- while (--length);
-
- // If we are in NRWW section, page erase has to be delayed until now.
- // Todo: Take RAMPZ into account (not doing so just means that we will
- // treat the top of both "pages" of flash as NRWW, for a slight speed
- // decrease, so fixing this is not urgent.)
- if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
-
- // Read command terminator, start reply
- verifySpace();
-
- // If only a partial page is to be programmed, the erase might not be complete.
- // So check that here
- boot_spm_busy_wait();
-
-#ifdef VIRTUAL_BOOT_PARTITION
- if ((uint16_t)(void*)address == 0) {
- // This is the reset vector page. We need to live-patch the code so the
- // bootloader runs.
- //
- // Move RESET vector to WDT vector
- uint16_t vect = buff[0] | (buff[1]<<8);
- rstVect = vect;
- wdtVect = buff[8] | (buff[9]<<8);
- vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
- buff[8] = vect & 0xff;
- buff[9] = vect >> 8;
-
- // Add jump to bootloader at RESET vector
- buff[0] = 0x7f;
- buff[1] = 0xce; // rjmp 0x1d00 instruction
- }
-#endif
-
- // Copy buffer into programming buffer
- bufPtr = buff;
- addrPtr = (uint16_t)(void*)address;
- ch = SPM_PAGESIZE / 2;
- do {
- uint16_t a;
- a = *bufPtr++;
- a |= (*bufPtr++) << 8;
- __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
- addrPtr += 2;
- } while (--ch);
-
- // Write from programming buffer
- __boot_page_write_short((uint16_t)(void*)address);
- boot_spm_busy_wait();
-
-#if defined(RWWSRE)
- // Reenable read access to flash
- boot_rww_enable();
-#endif
-
- }
- /* Read memory block mode, length is big endian. */
- else if(ch == STK_READ_PAGE) {
- // READ PAGE - we only read flash
- getch(); /* getlen() */
- length = getch();
- getch();
-
- verifySpace();
- do {
-#ifdef VIRTUAL_BOOT_PARTITION
- // Undo vector patch in bottom page so verify passes
- if (address == 0) ch=rstVect & 0xff;
- else if (address == 1) ch=rstVect >> 8;
- else if (address == 8) ch=wdtVect & 0xff;
- else if (address == 9) ch=wdtVect >> 8;
- else ch = pgm_read_byte_near(address);
- address++;
-#elif defined(RAMPZ)
- // Since RAMPZ should already be set, we need to use EPLM directly.
- // Also, we can use the autoincrement version of lpm to update "address"
- // do putch(pgm_read_byte_near(address++));
- // while (--length);
- // read a Flash and increment the address (may increment RAMPZ)
- __asm__ ("elpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
-#else
- // read a Flash byte and increment the address
- __asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
-#endif
- putch(ch);
- } while (--length);
- }
-
- /* Get device signature bytes */
- else if(ch == STK_READ_SIGN) {
- // READ SIGN - return what Avrdude wants to hear
- verifySpace();
- putch(SIGNATURE_0);
- putch(SIGNATURE_1);
- putch(SIGNATURE_2);
- }
- else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
- // Adaboot no-wait mod
- watchdogConfig(WATCHDOG_16MS);
- verifySpace();
- }
- else {
- // This covers the response to commands like STK_ENTER_PROGMODE
- verifySpace();
- }
- putch(STK_OK);
- }
-}
-
-void putch(char ch) {
-#ifndef SOFT_UART
- while (!(UART_SRA & _BV(UDRE0)));
- UART_UDR = ch;
-#else
- __asm__ __volatile__ (
- " com %[ch]\n" // ones complement, carry set
- " sec\n"
- "1: brcc 2f\n"
- " cbi %[uartPort],%[uartBit]\n"
- " rjmp 3f\n"
- "2: sbi %[uartPort],%[uartBit]\n"
- " nop\n"
- "3: rcall uartDelay\n"
- " rcall uartDelay\n"
- " lsr %[ch]\n"
- " dec %[bitcnt]\n"
- " brne 1b\n"
- :
- :
- [bitcnt] "d" (10),
- [ch] "r" (ch),
- [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
- [uartBit] "I" (UART_TX_BIT)
- :
- "r25"
- );
-#endif
-}
-
-uint8_t getch(void) {
- uint8_t ch;
-
-#ifdef LED_DATA_FLASH
-#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
- LED_PORT ^= _BV(LED);
-#else
- LED_PIN |= _BV(LED);
-#endif
-#endif
-
-#ifdef SOFT_UART
- __asm__ __volatile__ (
- "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
- " rjmp 1b\n"
- " rcall uartDelay\n" // Get to middle of start bit
- "2: rcall uartDelay\n" // Wait 1 bit period
- " rcall uartDelay\n" // Wait 1 bit period
- " clc\n"
- " sbic %[uartPin],%[uartBit]\n"
- " sec\n"
- " dec %[bitCnt]\n"
- " breq 3f\n"
- " ror %[ch]\n"
- " rjmp 2b\n"
- "3:\n"
- :
- [ch] "=r" (ch)
- :
- [bitCnt] "d" (9),
- [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
- [uartBit] "I" (UART_RX_BIT)
- :
- "r25"
-);
-#else
- while(!(UART_SRA & _BV(RXC0)))
- ;
- if (!(UART_SRA & _BV(FE0))) {
- /*
- * A Framing Error indicates (probably) that something is talking
- * to us at the wrong bit rate. Assume that this is because it
- * expects to be talking to the application, and DON'T reset the
- * watchdog. This should cause the bootloader to abort and run
- * the application "soon", if it keeps happening. (Note that we
- * don't care that an invalid char is returned...)
- */
- watchdogReset();
- }
-
- ch = UART_UDR;
-#endif
-
-#ifdef LED_DATA_FLASH
-#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
- LED_PORT ^= _BV(LED);
-#else
- LED_PIN |= _BV(LED);
-#endif
-#endif
-
- return ch;
-}
-
-#ifdef SOFT_UART
-// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
-// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
-#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
-#if UART_B_VALUE > 255
-#error Baud rate too slow for soft UART
-#endif
-
-void uartDelay() {
- __asm__ __volatile__ (
- "ldi r25,%[count]\n"
- "1:dec r25\n"
- "brne 1b\n"
- "ret\n"
- ::[count] "M" (UART_B_VALUE)
- );
-}
-#endif
-
-void getNch(uint8_t count) {
- do getch(); while (--count);
- verifySpace();
-}
-
-void verifySpace() {
- if (getch() != CRC_EOP) {
- watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
- while (1) // and busy-loop so that WD causes
- ; // a reset and app start.
- }
- putch(STK_INSYNC);
-}
-
-#if LED_START_FLASHES > 0
-void flash_led(uint8_t count) {
- do {
- TCNT1 = -(F_CPU/(1024*16));
- TIFR1 = _BV(TOV1);
- while(!(TIFR1 & _BV(TOV1)));
-#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
- LED_PORT ^= _BV(LED);
-#else
- LED_PIN |= _BV(LED);
-#endif
- watchdogReset();
- } while (--count);
-}
-#endif
-
-// Watchdog functions. These are only safe with interrupts turned off.
-void watchdogReset() {
- __asm__ __volatile__ (
- "wdr\n"
- );
-}
-
-void watchdogConfig(uint8_t x) {
- WDTCSR = _BV(WDCE) | _BV(WDE);
- WDTCSR = x;
-}
-
-void appStart(uint8_t rstFlags) {
- // save the reset flags in the designated register
- // This can be saved in a main program by putting code in .init0 (which
- // executes before normal c init code) to save R2 to a global variable.
- __asm__ __volatile__ ("mov r2, %0\n" :: "r" (rstFlags));
-
- watchdogConfig(WATCHDOG_OFF);
- __asm__ __volatile__ (
-#ifdef VIRTUAL_BOOT_PARTITION
- // Jump to WDT vector
- "ldi r30,4\n"
- "clr r31\n"
-#else
- // Jump to RST vector
- "clr r30\n"
- "clr r31\n"
-#endif
- "ijmp\n"
- );
-}
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.hex b/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.hex
deleted file mode 100644
index 58f396e..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.hex
+++ /dev/null
@@ -1,67 +0,0 @@
-:107C00001F92CDB7DEB7112484B714BE81FD06C024
-:107C100083FF03C08983F4D08981E3D185E0809319
-:107C2000810082E08093C00088E18093C10096E0EB
-:107C30009093C20090E19093C400809360008EE026
-:107C4000809360003B9A86E028E13EEF91E030931C
-:107C500085002093840096BBB09BFECF339AA895F5
-:107C60008150A9F7612C712C08E128E0F22EEE2456
-:107C7000E39435E0D32E41E1C42E13E08BD181345F
-:107C800069F488D1898394D189818238F9F0813867
-:107C900011F485E001C083E076D17BC0823411F419
-:107CA00084E103C0853419F485E08ED172C0853536
-:107CB00049F470D1B82E6ED16B2C712C782A660CD9
-:107CC000771C66C0863521F484E07ED180E0E4CF65
-:107CD000843609F03FC05ED15DD1982E5BD161142E
-:107CE00080E7780618F4F30117BFE895A12CBB24B0
-:107CF000B39450D1F50181935F019E12FACF6114C4
-:107D0000F0E77F0618F0F30117BFE89551D107B6E9
-:107D100000FCFDCFA301A0E0B1E08C9112969D0183
-:107D200021503109F901208190E0922BFA010C01D8
-:107D3000E7BEE89511244E5F5F4FA038F1E0BF0722
-:107D400061F7F301D7BEE89507B600FCFDCFC7BECB
-:107D5000E8951FC0843769F41DD11CD1B82E1AD103
-:107D600027D1F30185913F010ED1BA94B110F9CF1B
-:107D700010C0853739F41CD18EE105D185E903D1D6
-:107D80008FE08ACF813521F400936000F09260008B
-:107D90000FD180E1F8D072CF8EBD0DB407FEFDCFBC
-:107DA0008EB50895289885E0F7DF80E0F5DF289A02
-:107DB00081700895CF93C82F662321F060E086E09C
-:107DC000F9DF289AEFDF8111FDCF28988C2FCF9112
-:107DD000E3CFCF92DF92EF92FF926B017C0160E0E4
-:107DE00083E0E8DF8E2DD8DF8D2DD6DF8C2DD4DF1C
-:107DF00080E0D2DF289AFF90EF90DF90CF90089537
-:107E00009F92AF92BF92CF92DF92EF92FF920F9329
-:107E10001F93CF93DF9388E18093600010926000FE
-:107E200084B18D6284B9289A2A9A8CB580658CBDFC
-:107E300028988FE9B1DF80E0AFDF289A81508E3F2C
-:107E400008F095C061E081E0B5DF80E0A5DF289A09
-:107E500060E070E0CB01BDDF863409F088C061E0EE
-:107E600070E080E090E0B5DF8C3409F080C062E023
-:107E700070E080E090E0ADDF883509F078C066E022
-:107E800070E080E090E0A5DF8A3309F070C069E01F
-:107E900070E080E090E09DDF8A3309F068C067E021
-:107EA00070E080E090E095DFC82F68E070E080E04F
-:107EB00090E08FDFD0E0DC2FCC27C82BC0FD57C06F
-:107EC000339AC12CD12C00E010E0BB24B39483E0A2
-:107ED000A82E95E0992E0C171D0770F5B801665F66
-:107EE0007F4F80E090E075DFE82EF12CB801655FF0
-:107EF0007F4F80E090E06DDFF82AF8010701B7BE00
-:107F0000E89511240E5F1F4FC8018F779927892BA1
-:107F100019F00C171D07F9F6F601A7BEE89507B68C
-:107F200000FCFDCFF60197BEE89507B600FCFDCF3B
-:107F3000F0E8CF0ED11CCFCF339881E187BFE89511
-:107F40002A9661E0C130D04810F482E501C088ED86
-:107F500031DF80E021DF80E01FDF80E01DDF289A35
-:107F600088E18093600088E080936000FFCFDF911C
-:107F7000CF911F910F91FF90EF90DF90CF90BF9026
-:107F8000AF909F9008959091C00095FFFCCF809393
-:107F9000C6000895339A8091C00087FFFCCF80917E
-:107FA000C00084FD01C0A8958091C600339A089551
-:107FB000F1DF803239F088E18093600088E08093BF
-:107FC0006000FFCF84E1DFCFCF93C82FE3DFC15044
-:107FD000E9F7CF91EDCFE0E6F0E098E19083808380
-:107FE0000895282EE0E6F0E088E180831082EE27F5
-:047FF000FF270994CA
-:027FFE0000057C
-:0400000300007C007D
-:00000001FF
diff --git a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.lst b/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.lst
deleted file mode 100644
index 75a47a7..0000000
--- a/hardware/MySensors/avr/bootloaders/DualOptiboot/optiboot_atmega328_pro_8MHz.lst
+++ /dev/null
@@ -1,787 +0,0 @@
-
-optiboot_atmega328.elf: filformat elf32-avr
-
-Sektioner:
-Idx Navn Størrelse VMA LMA Filoffs Just
- 0 .data 00000000 00800100 00007ff4 00000468 2**0
- CONTENTS, ALLOC, LOAD, DATA
- 1 .text 000003f4 00007c00 00007c00 00000074 2**1
- CONTENTS, ALLOC, LOAD, READONLY, CODE
- 2 .version 00000002 00007ffe 00007ffe 00000468 2**0
- CONTENTS, READONLY
- 3 .stab 000011c4 00000000 00000000 0000046c 2**2
- CONTENTS, READONLY, DEBUGGING
- 4 .stabstr 00000ddc 00000000 00000000 00001630 2**0
- CONTENTS, READONLY, DEBUGGING
- 5 .comment 00000027 00000000 00000000 0000240c 2**0
- CONTENTS, READONLY
-
-Disassemblering af sektion .text:
-
-00007c00 :
- 7c00: 1f 92 push r1
- 7c02: cd b7 in r28, 0x3d ; 61
- 7c04: de b7 in r29, 0x3e ; 62
- 7c06: 11 24 eor r1, r1
- 7c08: 84 b7 in r24, 0x34 ; 52
- 7c0a: 14 be out 0x34, r1 ; 52
- 7c0c: 81 fd sbrc r24, 1
- 7c0e: 06 c0 rjmp .+12 ; 0x7c1c
- 7c10: 83 ff sbrs r24, 3
- 7c12: 03 c0 rjmp .+6 ; 0x7c1a
- 7c14: 89 83 std Y+1, r24 ; 0x01
- 7c16: f4 d0 rcall .+488 ; 0x7e00
- 7c18: 89 81 ldd r24, Y+1 ; 0x01
- 7c1a: e3 d1 rcall .+966 ; 0x7fe2
- 7c1c: 85 e0 ldi r24, 0x05 ; 5
- 7c1e: 80 93 81 00 sts 0x0081, r24
- 7c22: 82 e0 ldi r24, 0x02 ; 2
- 7c24: 80 93 c0 00 sts 0x00C0, r24
- 7c28: 88 e1 ldi r24, 0x18 ; 24
- 7c2a: 80 93 c1 00 sts 0x00C1, r24
- 7c2e: 96 e0 ldi r25, 0x06 ; 6
- 7c30: 90 93 c2 00 sts 0x00C2, r25
- 7c34: 90 e1 ldi r25, 0x10 ; 16
- 7c36: 90 93 c4 00 sts 0x00C4, r25
- 7c3a: 80 93 60 00 sts 0x0060, r24
- 7c3e: 8e e0 ldi r24, 0x0E ; 14
- 7c40: 80 93 60 00 sts 0x0060, r24
- 7c44: 3b 9a sbi 0x07, 3 ; 7
- 7c46: 86 e0 ldi r24, 0x06 ; 6
- 7c48: 28 e1 ldi r18, 0x18 ; 24
- 7c4a: 3e ef ldi r19, 0xFE ; 254
- 7c4c: 91 e0 ldi r25, 0x01 ; 1
- 7c4e: 30 93 85 00 sts 0x0085, r19
- 7c52: 20 93 84 00 sts 0x0084, r18
- 7c56: 96 bb out 0x16, r25 ; 22
- 7c58: b0 9b sbis 0x16, 0 ; 22
- 7c5a: fe cf rjmp .-4 ; 0x7c58
- 7c5c: 33 9a sbi 0x06, 3 ; 6
- 7c5e: a8 95 wdr
- 7c60: 81 50 subi r24, 0x01 ; 1
- 7c62: a9 f7 brne .-22 ; 0x7c4e
- 7c64: 61 2c mov r6, r1
- 7c66: 71 2c mov r7, r1
- 7c68: 08 e1 ldi r16, 0x18 ; 24
- 7c6a: 28 e0 ldi r18, 0x08 ; 8
- 7c6c: f2 2e mov r15, r18
- 7c6e: ee 24 eor r14, r14
- 7c70: e3 94 inc r14
- 7c72: 35 e0 ldi r19, 0x05 ; 5
- 7c74: d3 2e mov r13, r19
- 7c76: 41 e1 ldi r20, 0x11 ; 17
- 7c78: c4 2e mov r12, r20
- 7c7a: 13 e0 ldi r17, 0x03 ; 3
- 7c7c: 8b d1 rcall .+790 ; 0x7f94
- 7c7e: 81 34 cpi r24, 0x41 ; 65
- 7c80: 69 f4 brne .+26 ; 0x7c9c
- 7c82: 88 d1 rcall .+784 ; 0x7f94
- 7c84: 89 83 std Y+1, r24 ; 0x01
- 7c86: 94 d1 rcall .+808 ; 0x7fb0
- 7c88: 89 81 ldd r24, Y+1 ; 0x01
- 7c8a: 82 38 cpi r24, 0x82 ; 130
- 7c8c: f9 f0 breq .+62 ; 0x7ccc
- 7c8e: 81 38 cpi r24, 0x81 ; 129
- 7c90: 11 f4 brne .+4 ; 0x7c96
- 7c92: 85 e0 ldi r24, 0x05 ; 5
- 7c94: 01 c0 rjmp .+2 ; 0x7c98
- 7c96: 83 e0 ldi r24, 0x03 ; 3
- 7c98: 76 d1 rcall .+748 ; 0x7f86
- 7c9a: 7b c0 rjmp .+246 ; 0x7d92
- 7c9c: 82 34 cpi r24, 0x42 ; 66
- 7c9e: 11 f4 brne .+4 ; 0x7ca4
- 7ca0: 84 e1 ldi r24, 0x14 ; 20
- 7ca2: 03 c0 rjmp .+6 ; 0x7caa
- 7ca4: 85 34 cpi r24, 0x45 ; 69
- 7ca6: 19 f4 brne .+6 ; 0x7cae
- 7ca8: 85 e0 ldi r24, 0x05 ; 5
- 7caa: 8e d1 rcall .+796 ; 0x7fc8
- 7cac: 72 c0 rjmp .+228 ; 0x7d92
- 7cae: 85 35 cpi r24, 0x55 ; 85
- 7cb0: 49 f4 brne .+18 ; 0x7cc4
- 7cb2: 70 d1 rcall .+736 ; 0x7f94
- 7cb4: b8 2e mov r11, r24
- 7cb6: 6e d1 rcall .+732 ; 0x7f94
- 7cb8: 6b 2c mov r6, r11
- 7cba: 71 2c mov r7, r1
- 7cbc: 78 2a or r7, r24
- 7cbe: 66 0c add r6, r6
- 7cc0: 77 1c adc r7, r7
- 7cc2: 66 c0 rjmp .+204 ; 0x7d90
- 7cc4: 86 35 cpi r24, 0x56 ; 86
- 7cc6: 21 f4 brne .+8 ; 0x7cd0
- 7cc8: 84 e0 ldi r24, 0x04 ; 4
- 7cca: 7e d1 rcall .+764 ; 0x7fc8
- 7ccc: 80 e0 ldi r24, 0x00 ; 0
- 7cce: e4 cf rjmp .-56 ; 0x7c98
- 7cd0: 84 36 cpi r24, 0x64 ; 100
- 7cd2: 09 f0 breq .+2 ; 0x7cd6
- 7cd4: 3f c0 rjmp .+126 ; 0x7d54
- 7cd6: 5e d1 rcall .+700 ; 0x7f94
- 7cd8: 5d d1 rcall .+698 ; 0x7f94
- 7cda: 98 2e mov r9, r24
- 7cdc: 5b d1 rcall .+694 ; 0x7f94
- 7cde: 61 14 cp r6, r1
- 7ce0: 80 e7 ldi r24, 0x70 ; 112
- 7ce2: 78 06 cpc r7, r24
- 7ce4: 18 f4 brcc .+6 ; 0x7cec
- 7ce6: f3 01 movw r30, r6
- 7ce8: 17 bf out 0x37, r17 ; 55
- 7cea: e8 95 spm
- 7cec: a1 2c mov r10, r1
- 7cee: bb 24 eor r11, r11
- 7cf0: b3 94 inc r11
- 7cf2: 50 d1 rcall .+672 ; 0x7f94
- 7cf4: f5 01 movw r30, r10
- 7cf6: 81 93 st Z+, r24
- 7cf8: 5f 01 movw r10, r30
- 7cfa: 9e 12 cpse r9, r30
- 7cfc: fa cf rjmp .-12 ; 0x7cf2
- 7cfe: 61 14 cp r6, r1
- 7d00: f0 e7 ldi r31, 0x70 ; 112
- 7d02: 7f 06 cpc r7, r31
- 7d04: 18 f0 brcs .+6 ; 0x7d0c