Repo restyled using astyle (#683)

The rules are in .tools/astyle/config/style.cfg
and can also be reviewed at
https://www.mysensors.org/view/260#coding-guidelines-core-library
This commit is contained in:
Patrick Fallberg
2016-12-07 23:44:29 +01:00
committed by GitHub
parent d4c4ab82ea
commit 8e1ef13804
167 changed files with 16103 additions and 15168 deletions
+21 -21
View File
@@ -22,60 +22,60 @@
#define MyCapabilities_h
#if defined(MY_DISABLE_REMOTE_RESET)
#define MY_CAP_RESET "N"
#define MY_CAP_RESET "N"
#else
#define MY_CAP_RESET "R"
#define MY_CAP_RESET "R"
#endif
#if defined(MY_OTA_FIRMWARE_FEATURE)
#define MY_CAP_OTA_FW "O"
#define MY_CAP_OTA_FW "O"
#else
#define MY_CAP_OTA_FW "N"
#define MY_CAP_OTA_FW "N"
#endif
#if defined(MY_RADIO_NRF24)
#define MY_CAP_RADIO "N"
#define MY_CAP_RADIO "N"
#elif defined(MY_RADIO_RFM69)
#define MY_CAP_RADIO "R"
#define MY_CAP_RADIO "R"
#elif defined(MY_RADIO_RFM95)
#define MY_CAP_RADIO "L"
#define MY_CAP_RADIO "L"
#elif defined(MY_RS485)
#define MY_CAP_RADIO "S"
#define MY_CAP_RADIO "S"
#else
#define MY_CAP_RADIO "-"
#define MY_CAP_RADIO "-"
#endif
#if defined(MY_GATEWAY_FEATURE)
#define MY_CAP_TYPE "G"
#define MY_CAP_TYPE "G"
#elif defined(MY_REPEATER_FEATURE)
#define MY_CAP_TYPE "R"
#define MY_CAP_TYPE "R"
#else
#define MY_CAP_TYPE "N"
#define MY_CAP_TYPE "N"
#endif
#if defined(ARDUINO_ARCH_SAMD)
#define MY_CAP_ARCH "S"
#define MY_CAP_ARCH "S"
#elif defined(ARDUINO_ARCH_ESP8266)
#define MY_CAP_ARCH "E"
#define MY_CAP_ARCH "E"
#elif defined(ARDUINO_ARCH_AVR)
#define MY_CAP_ARCH "A"
#define MY_CAP_ARCH "A"
#else
#define MY_CAP_ARCH "-"
#define MY_CAP_ARCH "-"
#endif
#if defined(MY_SIGNING_ATSHA204)
#define MY_CAP_SIGN "A"
#define MY_CAP_SIGN "A"
#elif defined(MY_SIGNING_SOFT)
#define MY_CAP_SIGN "S"
#define MY_CAP_SIGN "S"
#else
#define MY_CAP_SIGN "-"
#define MY_CAP_SIGN "-"
#endif
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
#define MY_CAP_RXBUF "Q"
#define MY_CAP_RXBUF "Q"
#else
#define MY_CAP_RXBUF "-"
#define MY_CAP_RXBUF "-"
#endif
+13 -13
View File
@@ -17,17 +17,17 @@
* version 2 as published by the Free Software Foundation.
*/
/**
* @file MyEepromAddresses.h
* @brief Eeprom addresses for MySensors library data
*
* @defgroup MyEepromAddressesgrp MyEepromAddresses
* @ingroup internals
* @{
*
*/
/**
* @file MyEepromAddresses.h
* @brief Eeprom addresses for MySensors library data
*
* @defgroup MyEepromAddressesgrp MyEepromAddresses
* @ingroup internals
* @{
*
*/
#ifndef MyEepromAddresses_h
#define MyEepromAddresses_h
@@ -60,7 +60,7 @@
/** @brief Address routing table */
#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS + SIZE_DISTANCE)
/** @brief Address configuration bytes sent by controller */
#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES)
#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES)
/** @brief Address firmware type */
#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS + SIZE_CONTROLLER_CONFIG)
/** @brief Address firmware version */
@@ -76,13 +76,13 @@
/** @brief Address soft signing HMAC key. This is set with @ref SecurityPersonalizer.ino */
#define EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS + SIZE_WHITELIST_REQUIREMENT_TABLE)
/** @brief Address soft signing serial key. This is set with @ref SecurityPersonalizer.ino */
#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS + SIZE_SIGNING_SOFT_HMAC_KEY)
#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS + SIZE_SIGNING_SOFT_HMAC_KEY)
/** @brief Address RF AES encryption key. This is set with @ref SecurityPersonalizer.ino */
#define EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS (EEPROM_SIGNING_SOFT_SERIAL_ADDRESS + SIZE_SIGNING_SOFT_SERIAL)
/** @brief Address node lock couner. This is set with @ref SecurityPersonalizer.ino */
#define EEPROM_NODE_LOCK_COUNTER (EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS + SIZE_RF_ENCRYPTION_AES_KEY)
/** @brief First free address for sketch static configuration */
#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER + SIZE_NODE_LOCK_COUNTER)
#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER + SIZE_NODE_LOCK_COUNTER)
#endif // MyEepromAddresses_h
+9 -7
View File
@@ -25,7 +25,8 @@ extern bool transportSendRoute(MyMessage &message);
extern MyMessage _msg;
extern MyMessage _msgTmp;
inline void gatewayTransportProcess() {
inline void gatewayTransportProcess()
{
if (gatewayTransportAvailable()) {
_msg = gatewayTransportReceive();
if (_msg.destination == GATEWAY_ADDRESS) {
@@ -34,7 +35,8 @@ inline void gatewayTransportProcess() {
if (mGetRequestAck(_msg)) {
// Copy message
_msgTmp = _msg;
mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop)
mSetRequestAck(_msgTmp,
false); // Reply without ack flag (otherwise we would end up in an eternal loop)
mSetAck(_msgTmp, true);
_msgTmp.sender = getNodeId();
_msgTmp.destination = _msg.sender;
@@ -44,11 +46,11 @@ inline void gatewayTransportProcess() {
if (_msg.type == I_VERSION) {
// Request for version. Create the response
gatewayTransportSend(buildGw(_msgTmp, I_VERSION).set(MYSENSORS_LIBRARY_VERSION));
#ifdef MY_INCLUSION_MODE_FEATURE
#ifdef MY_INCLUSION_MODE_FEATURE
} else if (_msg.type == I_INCLUSION_MODE) {
// Request to change inclusion mode
inclusionModeSet(atoi(_msg.data) == 1);
#endif
#endif
} else {
_processInternalMessages();
}
@@ -59,9 +61,9 @@ inline void gatewayTransportProcess() {
}
}
} else {
#if defined(MY_SENSOR_NETWORK)
transportSendRoute(_msg);
#endif
#if defined(MY_SENSOR_NETWORK)
transportSendRoute(_msg);
#endif
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
* network topology allowing messages to be routed to nodes.
*
* Created by Tomas Hozza <thozza@gmail.com>
* Copyright (C) 2015 Tomas Hozza
* Copyright (C) 2015 Tomas Hozza
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
+303 -308
View File
@@ -19,15 +19,15 @@
#include "MyGatewayTransport.h"
// global variables
// global variables
extern MyMessage _msgTmp;
#if defined(MY_CONTROLLER_IP_ADDRESS)
IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
#endif
#if defined(MY_IP_ADDRESS)
IPAddress _ethernetGatewayIP(MY_IP_ADDRESS);
IPAddress _ethernetGatewayIP(MY_IP_ADDRESS);
#endif
uint8_t _ethernetGatewayMAC[] = { MY_MAC_ADDRESS };
uint16_t _ethernetGatewayPort = MY_PORT;
@@ -35,137 +35,133 @@ MyMessage _ethernetMsg;
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
typedef struct
{
typedef struct {
char string[MY_GATEWAY_MAX_RECEIVE_LENGTH];
uint8_t idx;
} inputBuffer;
#if defined(MY_GATEWAY_ESP8266)
// Some re-defines to make code more readable below
#define EthernetServer WiFiServer
#define EthernetClient WiFiClient
#define EthernetUDP WiFiUDP
// Some re-defines to make code more readable below
#define EthernetServer WiFiServer
#define EthernetClient WiFiClient
#define EthernetUDP WiFiUDP
#if defined(MY_IP_ADDRESS)
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
#endif
#if defined(MY_IP_ADDRESS)
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
#endif
#endif
#if defined(MY_USE_UDP)
EthernetUDP _ethernetServer;
EthernetUDP _ethernetServer;
#elif defined(MY_GATEWAY_LINUX)
EthernetServer _ethernetServer(_ethernetGatewayPort, MY_GATEWAY_MAX_CLIENTS);
EthernetServer _ethernetServer(_ethernetGatewayPort, MY_GATEWAY_MAX_CLIENTS);
#elif defined(MY_GATEWAY_CLIENT_MODE)
// Nothing to do here
// Nothing to do here
#else
EthernetServer _ethernetServer(_ethernetGatewayPort);
EthernetServer _ethernetServer(_ethernetGatewayPort);
#endif
#if defined(MY_GATEWAY_CLIENT_MODE)
static EthernetClient client = EthernetClient();
static inputBuffer inputString;
static EthernetClient client = EthernetClient();
static inputBuffer inputString;
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS];
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS];
static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS];
static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS];
static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS];
#else
static EthernetClient client = EthernetClient();
static inputBuffer inputString;
static EthernetClient client = EthernetClient();
static inputBuffer inputString;
#endif
#ifndef MY_IP_ADDRESS
void gatewayTransportRenewIP();
void gatewayTransportRenewIP();
#endif
// 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(bool enable)
{
if (enable)
{
// Pull up pin
hwPinMode(MY_W5100_SPI_EN, INPUT);
hwDigitalWrite(MY_W5100_SPI_EN, HIGH);
}
else
{
// Ground pin
hwPinMode(MY_W5100_SPI_EN, OUTPUT);
hwDigitalWrite(MY_W5100_SPI_EN, LOW);
}
void _w5100_spi_en(bool enable)
{
if (enable) {
// Pull up pin
hwPinMode(MY_W5100_SPI_EN, INPUT);
hwDigitalWrite(MY_W5100_SPI_EN, HIGH);
} else {
// Ground pin
hwPinMode(MY_W5100_SPI_EN, OUTPUT);
hwDigitalWrite(MY_W5100_SPI_EN, LOW);
}
}
#else
#define _w5100_spi_en(x)
#define _w5100_spi_en(x)
#endif
bool gatewayTransportInit() {
bool gatewayTransportInit()
{
_w5100_spi_en(true);
#if defined(MY_GATEWAY_ESP8266)
#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)
{
wait(500);
MY_SERIALDEVICE.print(F("."));
}
MY_SERIALDEVICE.print(F("IP: "));
MY_SERIALDEVICE.println(WiFi.localIP());
#endif
#elif defined(MY_GATEWAY_LINUX)
// Nothing to do here
#else
#ifdef MY_IP_ADDRESS
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP);
#else
// Get IP address from DHCP
if (!Ethernet.begin(_ethernetGatewayMAC)) {
MY_SERIALDEVICE.print(F("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
delay(1000);
#endif /* MY_GATEWAY_ESP8266 */
#if defined(MY_GATEWAY_ESP8266)
#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) {
wait(500);
MY_SERIALDEVICE.print(F("."));
}
MY_SERIALDEVICE.print(F("IP: "));
MY_SERIALDEVICE.println(WiFi.localIP());
#endif
#elif defined(MY_GATEWAY_LINUX)
// Nothing to do here
#else
#ifdef MY_IP_ADDRESS
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP);
#else
// Get IP address from DHCP
if (!Ethernet.begin(_ethernetGatewayMAC)) {
MY_SERIALDEVICE.print(F("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
delay(1000);
#endif /* MY_GATEWAY_ESP8266 */
#ifdef MY_USE_UDP
_ethernetServer.begin(_ethernetGatewayPort);
#elif defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
} else {
client.stop();
debug(PSTR("Eth: Failed to connect\n"));
}
#else
#if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS)
_ethernetServer.begin(_ethernetGatewayIP);
#else
// we have to use pointers due to the constructor of EthernetServer
_ethernetServer.begin();
#endif
#endif /* USE_UDP */
#ifdef MY_USE_UDP
_ethernetServer.begin(_ethernetGatewayPort);
#elif defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
} else {
client.stop();
debug(PSTR("Eth: Failed to connect\n"));
}
#else
#if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS)
_ethernetServer.begin(_ethernetGatewayIP);
#else
// we have to use pointers due to the constructor of EthernetServer
_ethernetServer.begin();
#endif
#endif /* USE_UDP */
_w5100_spi_en(false);
return true;
}
@@ -178,240 +174,239 @@ bool gatewayTransportSend(MyMessage &message)
setIndication(INDICATION_GW_TX);
_w5100_spi_en(true);
#if defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_USE_UDP)
#if defined(MY_CONTROLLER_URL_ADDRESS)
_ethernetServer.beginPacket(MY_CONTROLLER_URL_ADDRESS, MY_PORT);
#else
_ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT);
#endif
_ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg));
// returns 1 if the packet was sent successfully
nbytes = _ethernetServer.endPacket();
#else
if (!client.connected()) {
client.stop();
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
} else {
// connecting to the server failed!
debug(PSTR("Eth: Failed to connect\n"));
_w5100_spi_en(false);
return false;
}
}
nbytes = client.write(_ethernetMsg, strlen(_ethernetMsg));
#endif
#else
// Send message to connected clients
#if defined(MY_GATEWAY_ESP8266)
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
if (clients[i] && clients[i].connected())
{
nbytes += clients[i].write((uint8_t*)_ethernetMsg, strlen(_ethernetMsg));
}
}
#else
nbytes = _ethernetServer.write(_ethernetMsg);
#endif
#endif /* MY_GATEWAY_CLIENT_MODE */
#if defined(MY_GATEWAY_CLIENT_MODE)
#if defined(MY_USE_UDP)
#if defined(MY_CONTROLLER_URL_ADDRESS)
_ethernetServer.beginPacket(MY_CONTROLLER_URL_ADDRESS, MY_PORT);
#else
_ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT);
#endif
_ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg));
// returns 1 if the packet was sent successfully
nbytes = _ethernetServer.endPacket();
#else
if (!client.connected()) {
client.stop();
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
} else {
// connecting to the server failed!
debug(PSTR("Eth: Failed to connect\n"));
_w5100_spi_en(false);
return false;
}
}
nbytes = client.write(_ethernetMsg, strlen(_ethernetMsg));
#endif
#else
// Send message to connected clients
#if defined(MY_GATEWAY_ESP8266)
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
if (clients[i] && clients[i].connected()) {
nbytes += clients[i].write((uint8_t*)_ethernetMsg, strlen(_ethernetMsg));
}
}
#else
nbytes = _ethernetServer.write(_ethernetMsg);
#endif
#endif /* MY_GATEWAY_CLIENT_MODE */
_w5100_spi_en(false);
return (nbytes > 0);
}
#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE)
bool _readFromClient(uint8_t i) {
while (clients[i].connected() && clients[i].available()) {
char inChar = clients[i].read();
if (inputString[i].idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) {
// if newline then command is complete
if (inChar == '\n' || inChar == '\r') {
// Add string terminator and prepare for the next message
inputString[i].string[inputString[i].idx] = 0;
debug(PSTR("Client %d: %s\n"), i, inputString[i].string);
inputString[i].idx = 0;
if (protocolParse(_ethernetMsg, inputString[i].string)) {
return true;
}
} else {
// add it to the inputString:
inputString[i].string[inputString[i].idx++] = inChar;
}
} else {
// Incoming message too long. Throw away
debug(PSTR("Client %d: Message too long\n"), i);
bool _readFromClient(uint8_t i)
{
while (clients[i].connected() && clients[i].available()) {
char inChar = clients[i].read();
if (inputString[i].idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) {
// if newline then command is complete
if (inChar == '\n' || inChar == '\r') {
// Add string terminator and prepare for the next message
inputString[i].string[inputString[i].idx] = 0;
debug(PSTR("Client %d: %s\n"), i, inputString[i].string);
inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
}
}
return false;
}
#else
bool _readFromClient() {
while (client.connected() && client.available()) {
char inChar = client.read();
if (inputString.idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) {
// if newline then command is complete
if (inChar == '\n' || inChar == '\r') {
// Add string terminator and prepare for the next message
inputString.string[inputString.idx] = 0;
debug(PSTR("Eth: %s\n"), inputString.string);
inputString.idx = 0;
if (protocolParse(_ethernetMsg, inputString.string)) {
return true;
}
} else {
// add it to the inputString:
inputString.string[inputString.idx++] = inChar;
if (protocolParse(_ethernetMsg, inputString[i].string)) {
return true;
}
} else {
// Incoming message too long. Throw away
debug(PSTR("Eth: Message too long\n"));
inputString.idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
// add it to the inputString:
inputString[i].string[inputString[i].idx++] = inChar;
}
} else {
// Incoming message too long. Throw away
debug(PSTR("Client %d: Message too long\n"), i);
inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
}
return false;
}
return false;
}
#else
bool _readFromClient()
{
while (client.connected() && client.available()) {
char inChar = client.read();
if (inputString.idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) {
// if newline then command is complete
if (inChar == '\n' || inChar == '\r') {
// Add string terminator and prepare for the next message
inputString.string[inputString.idx] = 0;
debug(PSTR("Eth: %s\n"), inputString.string);
inputString.idx = 0;
if (protocolParse(_ethernetMsg, inputString.string)) {
return true;
}
} else {
// add it to the inputString:
inputString.string[inputString.idx++] = inChar;
}
} else {
// Incoming message too long. Throw away
debug(PSTR("Eth: Message too long\n"));
inputString.idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
}
}
return false;
}
#endif
bool gatewayTransportAvailable()
{
_w5100_spi_en(true);
#if !defined(MY_IP_ADDRESS) && defined(MY_GATEWAY_W5100)
// renew IP address using DHCP
gatewayTransportRenewIP();
#endif
#if !defined(MY_IP_ADDRESS) && defined(MY_GATEWAY_W5100)
// renew IP address using DHCP
gatewayTransportRenewIP();
#endif
#ifdef MY_USE_UDP
int packet_size = _ethernetServer.parsePacket();
#ifdef MY_USE_UDP
int packet_size = _ethernetServer.parsePacket();
if (packet_size) {
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
#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);
const bool ok = protocolParse(_ethernetMsg, inputString[0].string);
#else
_ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
inputString.string[packet_size] = 0;
debug(PSTR("UDP packet received: %s\n"), inputString.string);
_w5100_spi_en(false);
const bool ok = protocolParse(_ethernetMsg, inputString.string);
#endif
if (ok)
{
setIndication(INDICATION_GW_RX);
}
return ok;
if (packet_size) {
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
#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);
const bool ok = protocolParse(_ethernetMsg, inputString[0].string);
#else
_ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
inputString.string[packet_size] = 0;
debug(PSTR("UDP packet received: %s\n"), inputString.string);
_w5100_spi_en(false);
const bool ok = protocolParse(_ethernetMsg, inputString.string);
#endif
if (ok) {
setIndication(INDICATION_GW_RX);
}
#elif defined(MY_GATEWAY_CLIENT_MODE)
if (!client.connected()) {
client.stop();
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
return ok;
}
#elif defined(MY_GATEWAY_CLIENT_MODE)
if (!client.connected()) {
client.stop();
#if defined(MY_CONTROLLER_URL_ADDRESS)
if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) {
#else
if (client.connect(_ethernetControllerIP, MY_PORT)) {
#endif
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
} else {
debug(PSTR("Eth: Failed to connect\n"));
_w5100_spi_en(false);
return false;
}
}
if (_readFromClient()) {
setIndication(INDICATION_GW_RX);
_w5100_spi_en(false);
return true;
}
#else
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
// ESP8266: Go over list of clients and stop any that are no longer connected.
// If the server has a new client connection it will be assigned to a free slot.
bool allSlotsOccupied = true;
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
if (!clients[i].connected()) {
if (clientsConnected[i]) {
debug(PSTR("Client %d disconnected\n"), i);
clients[i].stop();
}
//check if there are any new clients
if (_ethernetServer.hasClient()) {
clients[i] = _ethernetServer.available();
inputString[i].idx = 0;
debug(PSTR("Client %d connected\n"), i);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
// Send presentation of locally attached sensors (and node if applicable)
presentNode();
} else {
debug(PSTR("Eth: Failed to connect\n"));
_w5100_spi_en(false);
return false;
}
}
if (_readFromClient()) {
bool connected = clients[i].connected();
clientsConnected[i] = connected;
allSlotsOccupied &= connected;
}
if (allSlotsOccupied && _ethernetServer.hasClient()) {
//no free/disconnected spot so reject
debug(PSTR("No free slot available\n"));
EthernetClient c = _ethernetServer.available();
c.stop();
}
// 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;
}
#else
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
// ESP8266: Go over list of clients and stop any that are no longer connected.
// If the server has a new client connection it will be assigned to a free slot.
bool allSlotsOccupied = true;
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
if (!clients[i].connected()) {
if (clientsConnected[i]) {
debug(PSTR("Client %d disconnected\n"), i);
clients[i].stop();
}
//check if there are any new clients
if (_ethernetServer.hasClient()) {
clients[i] = _ethernetServer.available();
inputString[i].idx = 0;
debug(PSTR("Client %d connected\n"), i);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
// Send presentation of locally attached sensors (and node if applicable)
presentNode();
}
}
bool connected = clients[i].connected();
clientsConnected[i] = connected;
allSlotsOccupied &= connected;
}
#else
// W5100/ENC module does not have hasClient-method. We can only serve one client at the time.
EthernetClient newclient = _ethernetServer.available();
// if a new client connects make sure to dispose any previous existing sockets
if (newclient) {
if (client != newclient) {
client.stop();
client = newclient;
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
}
}
if (client) {
if (!client.connected()) {
debug(PSTR("Eth: disconnect\n"));
client.stop();
} else {
if (_readFromClient()) {
setIndication(INDICATION_GW_RX);
_w5100_spi_en(false);
return true;
}
if (allSlotsOccupied && _ethernetServer.hasClient()) {
//no free/disconnected spot so reject
debug(PSTR("No free slot available\n"));
EthernetClient c = _ethernetServer.available();
c.stop();
}
// 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;
}
}
#else
// W5100/ENC module does not have hasClient-method. We can only serve one client at the time.
EthernetClient newclient = _ethernetServer.available();
// if a new client connects make sure to dispose any previous existing sockets
if (newclient) {
if (client != newclient) {
client.stop();
client = newclient;
debug(PSTR("Eth: connect\n"));
_w5100_spi_en(false);
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
_w5100_spi_en(true);
presentNode();
}
}
if (client) {
if (!client.connected()) {
debug(PSTR("Eth: disconnect\n"));
client.stop();
} else {
if (_readFromClient()) {
setIndication(INDICATION_GW_RX);
_w5100_spi_en(false);
return true;
}
}
}
#endif /* MY_GATEWAY_ESP8266 */
#endif
}
}
#endif /* MY_GATEWAY_ESP8266 */
#endif
_w5100_spi_en(false);
return false;
}
+70 -63
View File
@@ -23,23 +23,23 @@
#include "MyGatewayTransport.h"
#if defined MY_CONTROLLER_IP_ADDRESS
IPAddress _brokerIp(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
#define EthernetClient WiFiClient
#if defined(MY_IP_ADDRESS)
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
#endif
#elif defined(MY_GATEWAY_LINUX)
// Nothing to do here
// Nothing to do here
#else
uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
#endif
#if defined(MY_IP_ADDRESS)
IPAddress _MQTT_clientIp(MY_IP_ADDRESS);
IPAddress _MQTT_clientIp(MY_IP_ADDRESS);
#endif
static EthernetClient _MQTT_ethClient;
@@ -48,7 +48,8 @@ static bool _MQTT_connecting = true;
static bool _MQTT_available = false;
static MyMessage _MQTT_msg;
bool gatewayTransportSend(MyMessage &message) {
bool gatewayTransportSend(MyMessage &message)
{
if (!_MQTT_client.connected()) {
return false;
}
@@ -58,19 +59,21 @@ bool gatewayTransportSend(MyMessage &message) {
return _MQTT_client.publish(topic, message.getString(_convBuffer));
}
void incomingMQTT(char* topic, uint8_t* payload, unsigned int length) {
void incomingMQTT(char* topic, uint8_t* payload, unsigned int length)
{
debug(PSTR("Message arrived on topic: %s\n"), topic);
_MQTT_available = protocolMQTTParse(_MQTT_msg, topic, payload, length);
}
bool reconnectMQTT() {
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
, MY_MQTT_USER, MY_MQTT_PASSWORD
#endif
)) {
)) {
debug(PSTR("MQTT connected\n"));
// Send presentation of locally attached sensors (and node if applicable)
@@ -85,58 +88,60 @@ bool reconnectMQTT() {
return false;
}
bool gatewayTransportConnect() {
#if defined(MY_GATEWAY_ESP8266)
while (WiFi.status() != WL_CONNECTED) {
wait(500);
MY_SERIALDEVICE.print(".");
}
MY_SERIALDEVICE.print("IP: ");
MY_SERIALDEVICE.println(WiFi.localIP());
#elif defined(MY_GATEWAY_LINUX)
#if defined(MY_IP_ADDRESS)
//TODO
#endif
#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
bool gatewayTransportConnect()
{
#if defined(MY_GATEWAY_ESP8266)
while (WiFi.status() != WL_CONNECTED) {
wait(500);
MY_SERIALDEVICE.print(".");
}
MY_SERIALDEVICE.print("IP: ");
MY_SERIALDEVICE.println(WiFi.localIP());
#elif defined(MY_GATEWAY_LINUX)
#if defined(MY_IP_ADDRESS)
//TODO
#endif
#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() {
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
#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);
_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
#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();
@@ -144,10 +149,11 @@ bool gatewayTransportInit() {
return true;
}
bool gatewayTransportAvailable() {
bool gatewayTransportAvailable()
{
if (_MQTT_connecting) {
return false;
}
}
//keep lease on dhcp address
//Ethernet.maintain();
if (!_MQTT_client.connected()) {
@@ -161,7 +167,8 @@ bool gatewayTransportAvailable() {
return _MQTT_available;
}
MyMessage & gatewayTransportReceive() {
MyMessage & gatewayTransportReceive()
{
// Return the last parsed message
_MQTT_available = false;
return _MQTT_msg;
+14 -11
View File
@@ -23,21 +23,23 @@
#include "MyMessage.h"
#include "MyProtocol.h"
// global variables
// global variables
extern MyMessage _msgTmp;
char _serialInputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface
uint8_t _serialInputPos;
MyMessage _serialMsg;
bool gatewayTransportSend(MyMessage &message) {
setIndication(INDICATION_GW_TX);
bool gatewayTransportSend(MyMessage &message)
{
setIndication(INDICATION_GW_TX);
MY_SERIALDEVICE.print(protocolFormat(message));
// Serial print is always successful
return true;
}
bool gatewayTransportInit() {
bool gatewayTransportInit()
{
gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete."));
// Send presentation of locally attached sensors (and node if applicable)
presentNode();
@@ -45,7 +47,8 @@ bool gatewayTransportInit() {
return true;
}
bool gatewayTransportAvailable() {
bool gatewayTransportAvailable()
{
while (MY_SERIALDEVICE.available()) {
// get the new byte:
char inChar = (char) MY_SERIALDEVICE.read();
@@ -55,11 +58,10 @@ bool gatewayTransportAvailable() {
if (inChar == '\n') {
_serialInputString[_serialInputPos] = 0;
bool ok = protocolParse(_serialMsg, _serialInputString);
if (ok)
{
setIndication(INDICATION_GW_RX);
}
_serialInputPos = 0;
if (ok) {
setIndication(INDICATION_GW_RX);
}
_serialInputPos = 0;
return ok;
} else {
// add it to the inputString:
@@ -74,7 +76,8 @@ bool gatewayTransportAvailable() {
return false;
}
MyMessage & gatewayTransportReceive() {
MyMessage & gatewayTransportReceive()
{
// Return the last parsed message
return _serialMsg;
}
+12 -11
View File
@@ -17,12 +17,12 @@
* version 2 as published by the Free Software Foundation.
*/
/**
* @file MyHw.h
*
* MySensors hardware abstraction layer
*/
/**
* @file MyHw.h
*
* MySensors hardware abstraction layer
*/
#ifndef MyHw_h
#define MyHw_h
@@ -76,7 +76,8 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms);
* @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);
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms);
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
/**
@@ -102,7 +103,7 @@ uint16_t hwFreeMem();
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
@@ -112,12 +113,12 @@ void hwDebugPrint(const char *fmt, ... );
* platform (e.g AVR):
* @code
* volatile uint16_t val = 0;
*
*
* void interrupHandler()
* {
* val = ~val;
* }
*
*
* void loop()
* {
* uint16_t copy_val;
@@ -131,7 +132,7 @@ void hwDebugPrint(const char *fmt, ... );
* interrupted during execution.
*/
#ifdef DOXYGEN
#define MY_CRITICAL_SECTION
#define MY_CRITICAL_SECTION
#endif /* DOXYGEN */
#endif // #ifdef MyHw_h
+126 -86
View File
@@ -23,32 +23,33 @@
#define INVALID_INTERRUPT_NUM (0xFFu)
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.
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
{
detachInterrupt(_wakeUp1Interrupt);
if (_wakeUp2Interrupt != INVALID_INTERRUPT_NUM)
{
detachInterrupt(_wakeUp2Interrupt);
}
if (_wakeUp2Interrupt != INVALID_INTERRUPT_NUM) {
detachInterrupt(_wakeUp2Interrupt);
}
_wokeUpByInterrupt = _wakeUp1Interrupt;
}
void wakeUp2() //place to send the second interrupts
{
detachInterrupt(_wakeUp2Interrupt);
if (_wakeUp1Interrupt != INVALID_INTERRUPT_NUM)
{
detachInterrupt(_wakeUp1Interrupt);
}
if (_wakeUp1Interrupt != INVALID_INTERRUPT_NUM) {
detachInterrupt(_wakeUp1Interrupt);
}
_wokeUpByInterrupt = _wakeUp2Interrupt;
}
bool interruptWakeUp()
{
return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
}
// Watchdog Timer interrupt service routine. This routine is required
@@ -57,13 +58,13 @@ ISR (WDT_vect)
{
}
void hwPowerDown(period_t period) {
void hwPowerDown(period_t period)
{
// disable ADC for power saving
ADCSRA &= ~(1 << ADEN);
// save WDT settings
uint8_t WDTsave = WDTCSR;
if (period != SLEEP_FOREVER)
{
if (period != SLEEP_FOREVER) {
wdt_enable(period);
// enable WDT interrupt before system reset
WDTCSR |= (1 << WDCE) | (1 << WDIE);
@@ -74,14 +75,14 @@ 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();
// Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet)
// Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet)
sleep_cpu();
sleep_disable();
sleep_disable();
// restore previous WDT settings
cli();
wdt_reset();
@@ -94,42 +95,77 @@ void hwPowerDown(period_t period) {
ADCSRA |= (1 << ADEN);
}
void hwInternalSleep(unsigned long ms) {
void hwInternalSleep(unsigned long ms)
{
// Let serial prints finish (debug, log etc)
#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; }
#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) {
int8_t hwSleep(unsigned long ms)
{
hwInternalSleep(ms);
return MY_WAKE_UP_BY_TIMER;
}
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long 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) {
// 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!
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms)
{
// 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
_wakeUp1Interrupt = interrupt1;
_wakeUp2Interrupt = interrupt2;
if (interrupt1 != INVALID_INTERRUPT_NUM) {
attachInterrupt(interrupt1, wakeUp1, mode1);
}
_wakeUp1Interrupt = interrupt1;
_wakeUp2Interrupt = interrupt2;
if (interrupt1 != INVALID_INTERRUPT_NUM) {
attachInterrupt(interrupt1, wakeUp1, mode1);
}
if (interrupt2 != INVALID_INTERRUPT_NUM) {
attachInterrupt(interrupt2, wakeUp2, mode2);
}
@@ -139,40 +175,41 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo
hwInternalSleep(ms);
} else {
// sleep until ext interrupt triggered
hwPowerDown(SLEEP_FOREVER);
hwPowerDown(SLEEP_FOREVER);
}
// Assure any interrupts attached, will get detached when they did not occur.
if (interrupt1 != INVALID_INTERRUPT_NUM) {
detachInterrupt(interrupt1);
}
// Assure any interrupts attached, will get detached when they did not occur.
if (interrupt1 != INVALID_INTERRUPT_NUM) {
detachInterrupt(interrupt1);
}
if (interrupt2 != INVALID_INTERRUPT_NUM) {
detachInterrupt(interrupt2);
}
// Return what woke the mcu.
int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up
if (interruptWakeUp()) {
ret = static_cast<int8_t>(_wokeUpByInterrupt);
}
// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
// Return what woke the mcu.
int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up
if (interruptWakeUp()) {
ret = static_cast<int8_t>(_wokeUpByInterrupt);
}
// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
return ret;
}
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
uint16_t hwCPUVoltage() {
uint16_t hwCPUVoltage()
{
// Measure Vcc against 1.1V Vref
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = (_BV(MUX5) | _BV(MUX0));
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = (_BV(MUX3) | _BV(MUX2));
#else
ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
#endif
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = (_BV(MUX5) | _BV(MUX0));
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = (_BV(MUX3) | _BV(MUX2));
#else
ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
#endif
// Vref settle
delay(70);
// Do conversion
@@ -182,7 +219,8 @@ uint16_t hwCPUVoltage() {
return (1125300UL) / ADC;
}
uint16_t hwCPUFrequency() {
uint16_t hwCPUFrequency()
{
cli();
// setup timer1
TIFR1 = 0xFF;
@@ -210,7 +248,8 @@ uint16_t hwCPUFrequency() {
return TCNT1 * 2048UL / 100000UL;
}
uint16_t hwFreeMem() {
uint16_t hwFreeMem()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
@@ -218,27 +257,28 @@ uint16_t hwFreeMem() {
#endif
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) {
void hwDebugPrint(const char *fmt, ... )
{
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(fmtBuffer);
#else
// prepend timestamp (AVR nodes)
MY_SERIALDEVICE.print(hwMillis());
MY_SERIALDEVICE.print(" ");
#endif
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(fmtBuffer);
#else
// prepend timestamp (AVR nodes)
MY_SERIALDEVICE.print(hwMillis());
MY_SERIALDEVICE.print(" ");
#endif
va_list args;
va_start (args, fmt );
#ifdef MY_GATEWAY_FEATURE
// Truncate message if this is gateway node
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
#else
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
#endif
#ifdef MY_GATEWAY_FEATURE
// Truncate message if this is gateway node
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
#else
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
#endif
va_end (args);
MY_SERIALDEVICE.print(fmtBuffer);
MY_SERIALDEVICE.flush();
+15 -15
View File
@@ -39,18 +39,18 @@
#if defined __AVR_ATmega328P__
#ifndef sleep_bod_disable
#define sleep_bod_disable() \
do { \
unsigned char tempreg; \
__asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
"ori %[tempreg], %[bods_bodse]" "\n\t" \
"out %[mcucr], %[tempreg]" "\n\t" \
"andi %[tempreg], %[not_bodse]" "\n\t" \
"out %[mcucr], %[tempreg]" \
: [tempreg] "=&d" (tempreg) \
: [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
[bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
[not_bodse] "i" (~_BV(BODSE))); \
} while (0)
do { \
unsigned char tempreg; \
__asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
"ori %[tempreg], %[bods_bodse]" "\n\t" \
"out %[mcucr], %[tempreg]" "\n\t" \
"andi %[tempreg], %[not_bodse]" "\n\t" \
"out %[mcucr], %[tempreg]" \
: [tempreg] "=&d" (tempreg) \
: [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
[bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
[not_bodse] "i" (~_BV(BODSE))); \
} while (0)
#endif
#endif
@@ -63,9 +63,9 @@ do { \
#if defined(MY_DISABLED_SERIAL)
#define hwInit()
#define hwInit()
#else
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE)
#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE)
#endif
#define hwWatchdogReset() wdt_reset()
@@ -96,7 +96,7 @@ enum period_t {
void hwInternalSleep(unsigned long ms);
#ifndef DOXYGEN
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif /* DOXYGEN */
#endif
+37 -30
View File
@@ -23,7 +23,7 @@
void hwInit(void)
{
#if !defined(MY_DISABLED_SERIAL)
MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1);
MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1);
MY_SERIALDEVICE.setDebugOutput(true);
#endif
EEPROM.begin(EEPROM_size);
@@ -31,12 +31,11 @@ void hwInit(void)
void hwReadConfigBlock(void* buf, void* addr, size_t length)
{
uint8_t* dst = static_cast<uint8_t*>(buf);
int pos = reinterpret_cast<int>(addr);
while (length-- > 0)
{
*dst++ = EEPROM.read(pos++);
}
uint8_t* dst = static_cast<uint8_t*>(buf);
int pos = reinterpret_cast<int>(addr);
while (length-- > 0) {
*dst++ = EEPROM.read(pos++);
}
}
void hwWriteConfigBlock(void* buf, void* addr, size_t length)
@@ -52,9 +51,9 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length)
uint8_t hwReadConfig(const int addr)
{
uint8_t value;
hwReadConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
return value;
uint8_t value;
hwReadConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
return value;
}
void hwWriteConfig(const int addr, uint8_t value)
@@ -63,13 +62,15 @@ void hwWriteConfig(const int addr, uint8_t value)
}
int8_t hwSleep(unsigned long ms) {
int8_t hwSleep(unsigned long ms)
{
// TODO: Not supported!
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
{
// TODO: Not supported!
(void)interrupt;
(void)mode;
@@ -77,7 +78,9 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
return MY_SLEEP_NOT_POSSIBLE;
}
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms)
{
// TODO: Not supported!
(void)interrupt1;
(void)mode1;
@@ -90,39 +93,43 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
ADC_MODE(ADC_VCC);
uint16_t hwCPUVoltage() {
uint16_t hwCPUVoltage()
{
// in mV
return ESP.getVcc();
}
uint16_t hwCPUFrequency() {
uint16_t hwCPUFrequency()
{
// in 1/10Mhz
return ESP.getCpuFreqMHz()*10;
}
uint16_t hwFreeMem() {
uint16_t hwFreeMem()
{
return ESP.getFreeHeap();
}
#endif
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) {
void hwDebugPrint(const char *fmt, ... )
{
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(fmtBuffer);
#endif
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(fmtBuffer);
#endif
va_list args;
va_start (args, fmt );
#ifdef MY_GATEWAY_FEATURE
// Truncate message if this is gateway node
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
#else
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
#endif
#ifdef MY_GATEWAY_FEATURE
// Truncate message if this is gateway node
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
#else
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
#endif
va_end (args);
MY_SERIALDEVICE.print(fmtBuffer);
MY_SERIALDEVICE.flush();
+3 -3
View File
@@ -54,11 +54,11 @@ uint8_t hwReadConfig(const int addr);
*/
static __inline__ void __psRestore(const uint32_t *__s)
{
xt_wsr_ps( *__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 )
#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
+11 -10
View File
@@ -30,12 +30,12 @@ void hwInit()
{
#ifdef MY_GATEWAY_SERIAL
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
#ifdef MY_LINUX_SERIAL_GROUPNAME
if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) {
logError("Unable to change permission for serial port device.\n");
exit(1);
}
#endif
#ifdef MY_LINUX_SERIAL_GROUPNAME
if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) {
logError("Unable to change permission for serial port device.\n");
exit(1);
}
#endif
#endif
}
@@ -88,14 +88,15 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
}
// Not supported!
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms)
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms)
{
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
@@ -105,13 +106,13 @@ uint16_t hwCPUVoltage()
// TODO: Not supported!
return 0;
}
uint16_t hwCPUFrequency()
{
// TODO: Not supported!
return 0;
}
uint16_t hwFreeMem()
{
// TODO: Not supported!
+22 -20
View File
@@ -16,7 +16,7 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef MyHwLinuxGeneric_h
#define MyHwLinuxGeneric_h
@@ -26,9 +26,9 @@
#include "SerialPort.h"
#ifdef MY_IS_SERIAL_PTY
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true);
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true);
#else
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT);
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT);
#endif
#define MY_SERIALDEVICE Serial
@@ -50,38 +50,40 @@ inline void hwRandomNumberInit();
inline unsigned long hwMillis();
#ifdef MY_RF24_IRQ_PIN
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
static __inline__ void __hwUnlock(const uint8_t *__s) {
pthread_mutex_unlock(&hw_mutex);
(void)__s;
}
static __inline__ void __hwUnlock(const uint8_t *__s)
{
pthread_mutex_unlock(&hw_mutex);
(void)__s;
}
static __inline__ void __hwLock() {
pthread_mutex_lock(&hw_mutex);
}
static __inline__ void __hwLock()
{
pthread_mutex_lock(&hw_mutex);
}
#endif
#if defined(DOXYGEN)
#define ATOMIC_BLOCK_CLEANUP
#define ATOMIC_BLOCK_CLEANUP
#elif defined(MY_RF24_IRQ_PIN)
#define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \
__attribute__((__cleanup__( __hwUnlock ))) = 1
#define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \
__attribute__((__cleanup__( __hwUnlock ))) = 1
#else
#define ATOMIC_BLOCK_CLEANUP
#define ATOMIC_BLOCK_CLEANUP
#endif /* DOXYGEN */
#if defined(DOXYGEN)
#define ATOMIC_BLOCK
#define ATOMIC_BLOCK
#elif defined(MY_RF24_IRQ_PIN)
#define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \
__atomic_loop ; __atomic_loop = 0 )
#define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \
__atomic_loop ; __atomic_loop = 0 )
#else
#define ATOMIC_BLOCK
#define ATOMIC_BLOCK
#endif /* DOXYGEN */
#ifndef DOXYGEN
#define MY_CRITICAL_SECTION ATOMIC_BLOCK
#define MY_CRITICAL_SECTION ATOMIC_BLOCK
#endif /* DOXYGEN */
#endif
+33 -32
View File
@@ -29,12 +29,12 @@ void hwInit()
{
#ifdef MY_GATEWAY_SERIAL
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
#ifdef MY_LINUX_SERIAL_GROUPNAME
if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) {
logError("Unable to change permission for serial port device.\n");
exit(1);
}
#endif
#ifdef MY_LINUX_SERIAL_GROUPNAME
if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) {
logError("Unable to change permission for serial port device.\n");
exit(1);
}
#endif
#endif
}
@@ -87,46 +87,47 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
}
// Not supported!
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms)
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms)
{
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
uint16_t hwCPUVoltage()
{
// TODO: Not supported!
return 0;
}
uint16_t hwCPUFrequency()
{
// TODO: Not supported!
return 0;
}
uint16_t hwFreeMem()
{
// TODO: Not supported!
return 0;
}
uint16_t hwCPUVoltage()
{
// TODO: Not supported!
return 0;
}
uint16_t hwCPUFrequency()
{
// TODO: Not supported!
return 0;
}
uint16_t hwFreeMem()
{
// TODO: Not supported!
return 0;
}
#endif
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ...)
{
va_list args;
void hwDebugPrint(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogDebug(fmt, args);
va_end(args);
}
va_start(args, fmt);
vlogDebug(fmt, args);
va_end(args);
}
#endif
void hwDigitalWrite(uint8_t pin, uint8_t value)
+7 -4
View File
@@ -16,7 +16,7 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef MyHwRPi_h
#define MyHwRPi_h
@@ -26,15 +26,18 @@
#include "log.h"
#include "bcm2835.h"
class Bcm2835Init {
class Bcm2835Init
{
public:
Bcm2835Init() {
Bcm2835Init()
{
if (!bcm2835_init()) {
logError("Failed to initialized bcm2835.\n");
exit(1);
}
}
~Bcm2835Init() {
~Bcm2835Init()
{
bcm2835_close();
}
};
+95 -85
View File
@@ -42,118 +42,125 @@ ISR (WDT_vect)
void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) {
int rdata = data;
Wire.beginTransmission(I2C_EEP_ADDRESS);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(rdata);
Wire.endTransmission();
void i2c_eeprom_write_byte(unsigned int eeaddress, byte data )
{
int rdata = data;
Wire.beginTransmission(I2C_EEP_ADDRESS);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(rdata);
Wire.endTransmission();
}
byte i2c_eeprom_read_byte(unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(I2C_EEP_ADDRESS);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(I2C_EEP_ADDRESS,1);
if (Wire.available()) {
rdata = Wire.read();
}
return rdata;
byte i2c_eeprom_read_byte(unsigned int eeaddress )
{
byte rdata = 0xFF;
Wire.beginTransmission(I2C_EEP_ADDRESS);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(I2C_EEP_ADDRESS,1);
if (Wire.available()) {
rdata = Wire.read();
}
return rdata;
}
void hwReadConfigBlock(void* buf, void* adr, size_t length)
{
uint8_t* dst = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0)
{
*dst++ = i2c_eeprom_read_byte(offs++);
}
uint8_t* dst = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0) {
*dst++ = i2c_eeprom_read_byte(offs++);
}
}
void hwWriteConfigBlock(void* buf, void* adr, size_t length)
{
uint8_t* src = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0)
{
i2c_eeprom_write_byte(offs++, *src++);
}
uint8_t* src = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0) {
i2c_eeprom_write_byte(offs++, *src++);
}
}
uint8_t hwReadConfig(int adr)
{
uint8_t value;
hwReadConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
return value;
uint8_t value;
hwReadConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
return value;
}
void hwWriteConfig(int adr, uint8_t value)
{
uint8_t curr = hwReadConfig(adr);
if (curr != value)
{
hwWriteConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
}
uint8_t curr = hwReadConfig(adr);
if (curr != value) {
hwWriteConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
}
}
void hwInit() {
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
#if defined(MY_GATEWAY_SERIAL)
while (!MY_SERIALDEVICE) {}
#endif
Wire.begin();
void hwInit()
{
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
#if defined(MY_GATEWAY_SERIAL)
while (!MY_SERIALDEVICE) {}
#endif
Wire.begin();
}
void hwWatchdogReset() {
// TODO: Not supported!
void hwWatchdogReset()
{
// TODO: Not supported!
}
void hwReboot() {
void hwReboot()
{
NVIC_SystemReset();
while (true);
}
int8_t hwSleep(unsigned long ms) {
// TODO: Not supported!
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
int8_t hwSleep(unsigned long ms)
{
// TODO: Not supported!
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
// TODO: Not supported!
(void)interrupt;
(void)mode;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
{
// TODO: Not supported!
(void)interrupt;
(void)mode;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
// TODO: Not supported!
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
unsigned long ms)
{
// TODO: Not supported!
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
(void)ms;
return MY_SLEEP_NOT_POSSIBLE;
}
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
uint16_t hwCPUVoltage() {
uint16_t hwCPUVoltage()
{
// disable ADC
while (ADC->STATUS.bit.SYNCBUSY);
ADC->CTRLA.bit.ENABLE = 0x00;
// internal 1V reference (default)
analogReference(AR_INTERNAL1V0);
// 12 bit resolution (default)
analogWriteResolution(12);
// MUXp 0x1B = SCALEDIOVCC/4 => connected to Vcc
ADC->INPUTCTRL.bit.MUXPOS = 0x1B ;
ADC->INPUTCTRL.bit.MUXPOS = 0x1B ;
// enable ADC
while (ADC->STATUS.bit.SYNCBUSY);
@@ -178,41 +185,44 @@ uint16_t hwCPUVoltage() {
return valueRead * 4;
}
uint16_t hwCPUFrequency() {
uint16_t hwCPUFrequency()
{
// TODO: currently reporting compile time frequency (in 1/10MHz)
return F_CPU / 100000UL;
}
uint16_t hwFreeMem() {
uint16_t hwFreeMem()
{
// TODO: Not supported!
return 0;
}
#endif
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) {
if (MY_SERIALDEVICE) {
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
#ifdef MY_GATEWAY_FEATURE
void hwDebugPrint(const char *fmt, ... )
{
if (MY_SERIALDEVICE) {
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(fmtBuffer);
#endif
va_list args;
va_start (args, fmt );
#ifdef MY_GATEWAY_FEATURE
#endif
va_list args;
va_start (args, fmt );
#ifdef MY_GATEWAY_FEATURE
// Truncate message if this is gateway node
vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
#else
#else
vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
#endif
va_end (args);
MY_SERIALDEVICE.print(fmtBuffer);
// MY_SERIALDEVICE.flush();
#endif
va_end (args);
MY_SERIALDEVICE.print(fmtBuffer);
// MY_SERIALDEVICE.flush();
//MY_SERIALDEVICE.write(freeRam());
}
//MY_SERIALDEVICE.write(freeRam());
}
}
#endif
+6 -6
View File
@@ -59,21 +59,21 @@ uint8_t hwReadConfig(int adr);
*/
static __inline__ uint8_t __disableIntsRetVal(void)
{
__disable_irq();
return 1;
__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);
__set_PRIMASK(*priMask);
}
#ifndef DOXYGEN
#define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 )
#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
+22 -19
View File
@@ -19,41 +19,44 @@
#include "MyInclusionMode.h"
// global variables
// global variables
extern MyMessage _msgTmp;
unsigned long _inclusionStartTime;
bool _inclusionMode;
inline void inclusionInit() {
inline void inclusionInit()
{
_inclusionMode = false;
#if defined(MY_INCLUSION_BUTTON_FEATURE)
// Setup digital in that triggers inclusion mode
hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT);
hwDigitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH);
#endif
#if defined(MY_INCLUSION_BUTTON_FEATURE)
// Setup digital in that triggers inclusion mode
hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT);
hwDigitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH);
#endif
}
void inclusionModeSet(bool newMode) {
if (newMode != _inclusionMode) {
_inclusionMode = newMode;
// Send back mode change to controller
gatewayTransportSend(buildGw(_msgTmp, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0)));
if (_inclusionMode) {
_inclusionStartTime = hwMillis();
}
}
void inclusionModeSet(bool newMode)
{
if (newMode != _inclusionMode) {
_inclusionMode = newMode;
// Send back mode change to controller
gatewayTransportSend(buildGw(_msgTmp, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0)));
if (_inclusionMode) {
_inclusionStartTime = hwMillis();
}
}
}
inline void inclusionProcess() {
#ifdef MY_INCLUSION_BUTTON_FEATURE
inline void inclusionProcess()
{
#ifdef MY_INCLUSION_BUTTON_FEATURE
if (!_inclusionMode && hwDigitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED) {
// Start inclusion mode
inclusionModeSet(true);
}
#endif
#endif
if (_inclusionMode && hwMillis()-_inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
+13 -16
View File
@@ -25,25 +25,22 @@
void setIndication( const indication_t ind )
{
#if defined(MY_DEFAULT_TX_LED_PIN)
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind))
{
ledsBlinkTx(1);
} else
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) {
ledsBlinkTx(1);
} else
#endif
#if defined(MY_DEFAULT_RX_LED_PIN)
if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind))
{
ledsBlinkRx(1);
} else
if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) {
ledsBlinkRx(1);
} else
#endif
#if defined(MY_DEFAULT_ERR_LED_PIN)
if (ind > INDICATION_ERR_START)
{
// Number of blinks indicates which error occurred.
ledsBlinkErr(ind-INDICATION_ERR_START);
}
if (ind > INDICATION_ERR_START) {
// Number of blinks indicates which error occurred.
ledsBlinkErr(ind-INDICATION_ERR_START);
}
#endif
if (indication) {
indication(ind);
}
if (indication) {
indication(ind);
}
}
+34 -34
View File
@@ -24,44 +24,44 @@
* 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_CHECK_UPLINK, //!< Check uplink
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 routing 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_TX = 0, //!< Sent a message.
INDICATION_RX, //!< Received a message.
INDICATION_ERR_START = 100,
INDICATION_ERR_TX, //!< Failed to transmit 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_CHECK_UPLINK, //!< Check uplink
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 routing 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_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_CHECK_UPLINK, //!< Failed to check uplink
INDICATION_ERR_SIGN, //!< Error signing.
INDICATION_ERR_SIGN, //!< Error signing.
INDICATION_ERR_LENGTH, //!< Invalid message length.
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_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;
/**
+43 -37
View File
@@ -34,22 +34,24 @@ inline void ledsInit()
countRx = 0;
countTx = 0;
countErr = 0;
// Setup led pins
#if defined(MY_DEFAULT_RX_LED_PIN)
hwPinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
#endif
#if defined(MY_DEFAULT_TX_LED_PIN)
hwPinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
#endif
#if defined(MY_DEFAULT_ERR_LED_PIN)
hwPinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT);
#endif
prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run.
#if defined(MY_DEFAULT_RX_LED_PIN)
hwPinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
#endif
#if defined(MY_DEFAULT_TX_LED_PIN)
hwPinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
#endif
#if defined(MY_DEFAULT_ERR_LED_PIN)
hwPinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT);
#endif
prevTime = hwMillis() -
LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run.
ledsProcess();
}
void ledsProcess() {
void ledsProcess()
{
// Just return if it is not the time...
if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) {
return;
@@ -60,52 +62,56 @@ void ledsProcess() {
// For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off]
// until the counter becomes 0.
#if defined(MY_DEFAULT_RX_LED_PIN)
if (countRx) {
--countRx;
}
state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state);
#endif
#if defined(MY_DEFAULT_RX_LED_PIN)
if (countRx) {
--countRx;
}
state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state);
#endif
#if defined(MY_DEFAULT_TX_LED_PIN)
if (countTx) {
--countTx;
}
state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state);
#endif
#if defined(MY_DEFAULT_TX_LED_PIN)
if (countTx) {
--countTx;
}
state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state);
#endif
#if defined(MY_DEFAULT_ERR_LED_PIN)
if (countErr) {
--countErr;
}
state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state);
#endif
#if defined(MY_DEFAULT_ERR_LED_PIN)
if (countErr) {
--countErr;
}
state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state);
#endif
}
void ledsBlinkRx(uint8_t cnt) {
void ledsBlinkRx(uint8_t cnt)
{
if (!countRx) {
countRx = cnt*LED_ON_OFF_RATIO;
}
ledsProcess();
}
void ledsBlinkTx(uint8_t cnt) {
void ledsBlinkTx(uint8_t cnt)
{
if(!countTx) {
countTx = cnt*LED_ON_OFF_RATIO;
}
ledsProcess();
}
void ledsBlinkErr(uint8_t cnt) {
void ledsBlinkErr(uint8_t cnt)
{
if(!countErr) {
countErr = cnt*LED_ON_OFF_RATIO;
}
ledsProcess();
}
bool ledsBlinking() {
bool ledsBlinking()
{
return countRx || countTx || countErr;
}
+21 -21
View File
@@ -30,30 +30,30 @@
#endif
#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
#define ledBlinkTx(x,...) ledsBlinkTx(x)
#define ledBlinkRx(x,...) ledsBlinkRx(x)
#define ledBlinkErr(x,...) ledsBlinkErr(x)
#define ledBlinkTx(x,...) ledsBlinkTx(x)
#define ledBlinkRx(x,...) ledsBlinkRx(x)
#define ledBlinkErr(x,...) ledsBlinkErr(x)
/**
* Blink with LEDs
* @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms
*/
void ledsInit();
void ledsBlinkRx(uint8_t cnt);
void ledsBlinkTx(uint8_t cnt);
void ledsBlinkErr(uint8_t cnt);
void ledsProcess(); // do the actual blinking
/**
* Test if any LED is currently blinking.
* @return true when one or more LEDs are blinking, false otherwise.
*/
bool ledsBlinking();
/**
* Blink with LEDs
* @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms
*/
void ledsInit();
void ledsBlinkRx(uint8_t cnt);
void ledsBlinkTx(uint8_t cnt);
void ledsBlinkErr(uint8_t cnt);
void ledsProcess(); // do the actual blinking
/**
* Test if any LED is currently blinking.
* @return true when one or more LEDs are blinking, false otherwise.
*/
bool ledsBlinking();
#else
// Remove led functions if feature is disabled
#define ledBlinkTx(x,...)
#define ledBlinkRx(x,...)
#define ledBlinkErr(x,...)
// Remove led functions if feature is disabled
#define ledBlinkTx(x,...)
#define ledBlinkRx(x,...)
#define ledBlinkErr(x,...)
#endif
#endif
+10 -9
View File
@@ -16,20 +16,21 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
// Initialize library and handle sketch functions like we want to
extern "C" void __libc_init_array(void);
int main(void) {
int main(void)
{
init();
#if defined(USBCON)
#if defined(ARDUINO_ARCH_SAMD)
__libc_init_array();
USBDevice.init();
#endif
USBDevice.attach();
#endif
#if defined(USBCON)
#if defined(ARDUINO_ARCH_SAMD)
__libc_init_array();
USBDevice.init();
#endif
USBDevice.attach();
#endif
_begin(); // Startup MySensors library
for(;;) {
+33 -22
View File
@@ -16,7 +16,7 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
//This may be used to change user task stack size:
//#define CONT_STACKSIZE 4096
#include "Schedule.h"
@@ -38,27 +38,31 @@ extern "C" {
struct rst_info resetInfo;
extern "C" {
extern const uint32_t __attribute__((section(".ver_number"))) core_version = ARDUINO_ESP8266_GIT_VER;
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;
ARDUINO_ESP8266_RELEASE;
#else
NULL;
NULL;
#endif
} // extern "C"
int atexit(void(*func)()) {
int atexit(void(*func)())
{
(void)func;
return 0;
}
extern "C" void ets_update_cpu_frequency(int freqmhz);
void initVariant() __attribute__((weak));
void initVariant() {
void initVariant()
{
}
void preloop_update_frequency() __attribute__((weak));
void preloop_update_frequency() {
void preloop_update_frequency()
{
#if defined(F_CPU) && (F_CPU == 160000000L)
REG_SET_BIT(0x3ff00014, BIT(0));
ets_update_cpu_frequency(160);
@@ -73,37 +77,40 @@ static os_event_t g_loop_queue[LOOP_QUEUE_SIZE];
static uint32_t g_micros_at_task_start;
extern "C" void esp_yield() {
extern "C" void esp_yield()
{
if (cont_can_yield(&g_cont)) {
cont_yield(&g_cont);
}
}
extern "C" void esp_schedule() {
extern "C" void esp_schedule()
{
ets_post(LOOP_TASK_PRIORITY, 0, 0);
}
extern "C" void __yield() {
extern "C" void __yield()
{
if (cont_can_yield(&g_cont)) {
esp_schedule();
esp_yield();
}
else {
} else {
panic();
}
}
extern "C" void yield(void) __attribute__((weak, alias("__yield")));
extern "C" void optimistic_yield(uint32_t interval_us) {
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)
{
(system_get_time() - g_micros_at_task_start) > interval_us) {
yield();
}
}
static void loop_wrapper() {
static void loop_wrapper()
{
static bool setup_done = false;
preloop_update_frequency();
if (!setup_done) {
@@ -116,7 +123,8 @@ static void loop_wrapper() {
esp_schedule();
}
static void loop_task(os_event_t *events) {
static void loop_task(os_event_t *events)
{
(void)events;
g_micros_at_task_start = system_get_time();
cont_run(&g_cont, &loop_wrapper);
@@ -125,7 +133,8 @@ static void loop_task(os_event_t *events) {
}
}
static void do_global_ctors(void) {
static void do_global_ctors(void)
{
void(**p)(void) = &__init_array_end;
while (p != &__init_array_start) {
(*--p)();
@@ -138,7 +147,8 @@ 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() {
void init_done()
{
system_set_os_print(1);
gdb_init();
do_global_ctors();
@@ -146,7 +156,8 @@ void init_done() {
}
extern "C" void user_init(void) {
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));
@@ -159,8 +170,8 @@ extern "C" void user_init(void) {
cont_init(&g_cont);
ets_task(loop_task,
LOOP_TASK_PRIORITY, g_loop_queue,
LOOP_QUEUE_SIZE);
LOOP_TASK_PRIORITY, g_loop_queue,
LOOP_QUEUE_SIZE);
system_init_done_cb(&init_done);
}
+86 -77
View File
@@ -16,7 +16,7 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
// Initialize library and handle sketch functions like we want to
// Initialize library and handle sketch functions like we want to
#include <stdio.h>
#include <csignal>
@@ -40,13 +40,13 @@ void handle_sigint(int sig)
return;
}
#ifdef MY_RF24_IRQ_PIN
detachInterrupt(MY_RF24_IRQ_PIN);
#endif
#ifdef MY_RF24_IRQ_PIN
detachInterrupt(MY_RF24_IRQ_PIN);
#endif
#if defined(MY_GATEWAY_SERIAL)
MY_SERIALDEVICE.end();
#endif
#if defined(MY_GATEWAY_SERIAL)
MY_SERIALDEVICE.end();
#endif
closelog();
@@ -103,19 +103,19 @@ static int daemonize(void)
void print_usage()
{
printf("Usage: mysgw [options]\n\n" \
"Options:\n" \
" -h, --help Display a short summary of all program options.\n" \
" -d, --debug Enable debug.\n" \
" -b, --background Run as a background process.\n"
" --gen-soft-hmac-key Generate and print a soft hmac key.\n"
" --gen-soft-serial-key Generate and print a soft serial key.\n"
" --gen-aes-key Generate and print an aes encryption key.\n"
" --print-soft-hmac-key Print the soft hmac key from the config file.\n"
" --print-soft-serial-key Print the soft serial key from the config file.\n"
" --print-aes-key Print the aes encryption key from the config file.\n"
" --set-soft-hmac-key Write a soft hmac key to the config file.\n"
" --set-soft-serial-key Write a soft serial key to the config file.\n"
" --set-aes-key Write an aes encryption key to the config file.\n");
"Options:\n" \
" -h, --help Display a short summary of all program options.\n" \
" -d, --debug Enable debug.\n" \
" -b, --background Run as a background process.\n"
" --gen-soft-hmac-key Generate and print a soft hmac key.\n"
" --gen-soft-serial-key Generate and print a soft serial key.\n"
" --gen-aes-key Generate and print an aes encryption key.\n"
" --print-soft-hmac-key Print the soft hmac key from the config file.\n"
" --print-soft-serial-key Print the soft serial key from the config file.\n"
" --print-aes-key Print the aes encryption key from the config file.\n"
" --set-soft-hmac-key Write a soft hmac key to the config file.\n"
" --set-soft-serial-key Write a soft serial key to the config file.\n"
" --set-aes-key Write an aes encryption key to the config file.\n");
}
void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
@@ -137,7 +137,9 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
printf("#define MY_SOFT_HMAC_KEY ");
for (int i=0; i<32; i++) {
printf("%#02X", key_ptr[i]);
if (i < 31) printf(",");
if (i < 31) {
printf(",");
}
}
printf("\n\n");
}
@@ -155,7 +157,7 @@ void generate_soft_sign_hmac_key()
print_soft_sign_hmac_key(key);
printf("To use this key, run mysgw with:\n"
" --set-soft-hmac-key=");
" --set-soft-hmac-key=");
for (int i = 0; i < 32; i++) {
printf("%02X", key[i]);
}
@@ -172,12 +174,13 @@ void set_soft_sign_hmac_key(char *key_str)
} else {
for (int i = 0; i < 64; ++i) {
char c = key_str[i];
if (c <= '9')
if (c <= '9') {
n = c - '0';
else if (c >= 'a')
} else if (c >= 'a') {
n = c - 'a' + 10;
else
} else {
n = c - 'A' + 10;
}
if ((i & 0x1) == 0) {
key[i/2] = n * 16;
@@ -209,7 +212,9 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL)
printf("#define MY_SOFT_SERIAL ");
for (int i=0; i<9; i++) {
printf("%#02X", key_ptr[i]);
if (i < 8) printf(",");
if (i < 8) {
printf(",");
}
}
printf("\n\n");
}
@@ -227,7 +232,7 @@ void generate_soft_sign_serial_key()
print_soft_sign_serial_key(key);
printf("To use this key, run mysgw with:\n"
" --set-soft-serial-key=");
" --set-soft-serial-key=");
for (int i = 0; i < 9; i++) {
printf("%02X", key[i]);
}
@@ -244,12 +249,13 @@ void set_soft_sign_serial_key(char *key_str)
} else {
for (int i = 0; i < 18; ++i) {
char c = key_str[i];
if (c <= '9')
if (c <= '9') {
n = c - '0';
else if (c >= 'a')
} else if (c >= 'a') {
n = c - 'a' + 10;
else
} else {
n = c - 'A' + 10;
}
if ((i & 0x1) == 0) {
key[i/2] = n * 16;
@@ -281,7 +287,9 @@ void print_aes_key(uint8_t *key_ptr = NULL)
printf("#define MY_AES_KEY ");
for (int i=0; i<16; i++) {
printf("%#02X", key_ptr[i]);
if (i < 15) printf(",");
if (i < 15) {
printf(",");
}
}
printf("\n\n");
}
@@ -299,7 +307,7 @@ void generate_aes_key()
print_aes_key(key);
printf("To use this key, run mysgw with:\n"
" --set-aes-key=");
" --set-aes-key=");
for (int i = 0; i < 16; i++) {
printf("%02X", key[i]);
}
@@ -316,12 +324,13 @@ void set_aes_key(char *key_str)
} else {
for (int i = 0; i < 32; ++i) {
char c = key_str[i];
if (c <= '9')
if (c <= '9') {
n = c - '0';
else if (c >= 'a')
} else if (c >= 'a') {
n = c - 'a' + 10;
else
} else {
n = c - 'A' + 10;
}
if ((i & 0x1) == 0) {
key[i/2] = n * 16;
@@ -364,48 +373,48 @@ int main(int argc, char *argv[])
int long_index = 0;
while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) {
switch (opt) {
case 'h':
print_usage();
exit(0);
case 'd':
debug = 1;
break;
case 'b':
foreground = 0;
break;
case 'A':
generate_soft_sign_hmac_key();
exit(0);
case 'B':
generate_soft_sign_serial_key();
exit(0);
case 'C':
generate_aes_key();
exit(0);
case 'D':
print_soft_sign_hmac_key();
exit(0);
case 'E':
print_soft_sign_serial_key();
exit(0);
case 'F':
print_aes_key();
exit(0);
case 'G':
key = strdup(optarg);
set_soft_sign_hmac_key(key);
exit(0);
case 'H':
key = strdup(optarg);
set_soft_sign_serial_key(key);
exit(0);
case 'I':
key = strdup(optarg);
set_aes_key(key);
exit(0);
default:
print_usage();
exit(0);
case 'h':
print_usage();
exit(0);
case 'd':
debug = 1;
break;
case 'b':
foreground = 0;
break;
case 'A':
generate_soft_sign_hmac_key();
exit(0);
case 'B':
generate_soft_sign_serial_key();
exit(0);
case 'C':
generate_aes_key();
exit(0);
case 'D':
print_soft_sign_hmac_key();
exit(0);
case 'E':
print_soft_sign_serial_key();
exit(0);
case 'F':
print_aes_key();
exit(0);
case 'G':
key = strdup(optarg);
set_soft_sign_hmac_key(key);
exit(0);
case 'H':
key = strdup(optarg);
set_soft_sign_serial_key(key);
exit(0);
case 'I':
key = strdup(optarg);
set_aes_key(key);
exit(0);
default:
print_usage();
exit(0);
}
}
+66 -41
View File
@@ -25,45 +25,49 @@
MyMessage::MyMessage()
{
clear();
clear();
}
MyMessage::MyMessage(uint8_t _sensor, uint8_t _type)
{
clear();
clear();
sensor = _sensor;
type = _type;
}
void MyMessage::clear()
{
last = 0u;
sender = 0u;
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));
version_length = 0u;
command_ack_payload = 0u;
type = 0u;
sensor = 0u;
(void)memset(data, 0u, sizeof(data));
// set message protocol version
miSetVersion(PROTOCOL_VERSION);
}
bool MyMessage::isAck() const {
bool MyMessage::isAck() const
{
return miGetAck();
}
uint8_t MyMessage::getCommand() const {
uint8_t MyMessage::getCommand() const
{
return miGetCommand();
}
/* Getters for payload converted to desired form */
void* MyMessage::getCustom() const {
void* MyMessage::getCustom() const
{
return (void *)data;
}
const char* MyMessage::getString() const {
const char* MyMessage::getString() const
{
uint8_t payloadType = miGetPayloadType();
if (payloadType == P_STRING) {
return data;
@@ -73,19 +77,19 @@ const char* MyMessage::getString() const {
}
// handles single character hex (0 - 15)
char MyMessage::i2h(uint8_t i) const {
char MyMessage::i2h(uint8_t i) const
{
uint8_t k = i & 0x0F;
if (k <= 9) {
return '0' + k;
}
else {
} else {
return 'A' + k - 10;
}
}
}
char* MyMessage::getCustomString(char *buffer) const {
for (uint8_t i = 0; i < miGetLength(); i++)
{
char* MyMessage::getCustomString(char *buffer) const
{
for (uint8_t i = 0; i < miGetLength(); i++) {
buffer[i * 2] = i2h(data[i] >> 4);
buffer[(i * 2) + 1] = i2h(data[i]);
}
@@ -93,7 +97,8 @@ char* MyMessage::getCustomString(char *buffer) const {
return buffer;
}
char* MyMessage::getStream(char *buffer) const {
char* MyMessage::getStream(char *buffer) const
{
uint8_t cmd = miGetCommand();
if ((cmd == C_STREAM) && (buffer != NULL)) {
return getCustomString(buffer);
@@ -102,7 +107,8 @@ char* MyMessage::getStream(char *buffer) const {
}
}
char* MyMessage::getString(char *buffer) const {
char* MyMessage::getString(char *buffer) const
{
uint8_t payloadType = miGetPayloadType();
if (buffer != NULL) {
if (payloadType == P_STRING) {
@@ -129,11 +135,13 @@ char* MyMessage::getString(char *buffer) const {
}
}
bool MyMessage::getBool() const {
bool MyMessage::getBool() const
{
return getByte();
}
uint8_t MyMessage::getByte() const {
uint8_t MyMessage::getByte() const
{
if (miGetPayloadType() == P_BYTE) {
return data[0];
} else if (miGetPayloadType() == P_STRING) {
@@ -144,7 +152,8 @@ uint8_t MyMessage::getByte() const {
}
float MyMessage::getFloat() const {
float MyMessage::getFloat() const
{
if (miGetPayloadType() == P_FLOAT32) {
return fValue;
} else if (miGetPayloadType() == P_STRING) {
@@ -154,7 +163,8 @@ float MyMessage::getFloat() const {
}
}
int32_t MyMessage::getLong() const {
int32_t MyMessage::getLong() const
{
if (miGetPayloadType() == P_LONG32) {
return lValue;
} else if (miGetPayloadType() == P_STRING) {
@@ -164,7 +174,8 @@ int32_t MyMessage::getLong() const {
}
}
uint32_t MyMessage::getULong() const {
uint32_t MyMessage::getULong() const
{
if (miGetPayloadType() == P_ULONG32) {
return ulValue;
} else if (miGetPayloadType() == P_STRING) {
@@ -174,7 +185,8 @@ uint32_t MyMessage::getULong() const {
}
}
int16_t MyMessage::getInt() const {
int16_t MyMessage::getInt() const
{
if (miGetPayloadType() == P_INT16) {
return iValue;
} else if (miGetPayloadType() == P_STRING) {
@@ -184,7 +196,8 @@ int16_t MyMessage::getInt() const {
}
}
uint16_t MyMessage::getUInt() const {
uint16_t MyMessage::getUInt() const
{
if (miGetPayloadType() == P_UINT16) {
return uiValue;
} else if (miGetPayloadType() == P_STRING) {
@@ -195,23 +208,27 @@ uint16_t MyMessage::getUInt() const {
}
MyMessage& MyMessage::setType(uint8_t _type) {
MyMessage& MyMessage::setType(uint8_t _type)
{
type = _type;
return *this;
}
MyMessage& MyMessage::setSensor(uint8_t _sensor) {
MyMessage& MyMessage::setSensor(uint8_t _sensor)
{
sensor = _sensor;
return *this;
}
MyMessage& MyMessage::setDestination(uint8_t _destination) {
MyMessage& MyMessage::setDestination(uint8_t _destination)
{
destination = _destination;
return *this;
}
// Set payload
MyMessage& MyMessage::set(void* value, uint8_t length) {
MyMessage& MyMessage::set(void* value, uint8_t length)
{
uint8_t payloadLength = value == NULL ? 0 : min(length, (uint8_t)MAX_PAYLOAD);
miSetLength(payloadLength);
miSetPayloadType(P_CUSTOM);
@@ -219,7 +236,8 @@ MyMessage& MyMessage::set(void* value, uint8_t length) {
return *this;
}
MyMessage& MyMessage::set(const char* value) {
MyMessage& MyMessage::set(const char* value)
{
uint8_t length = value == NULL ? 0 : min(strlen(value), (size_t)MAX_PAYLOAD);
miSetLength(length);
miSetPayloadType(P_STRING);
@@ -231,21 +249,24 @@ MyMessage& MyMessage::set(const char* value) {
return *this;
}
MyMessage& MyMessage::set(bool value) {
MyMessage& MyMessage::set(bool value)
{
miSetLength(1);
miSetPayloadType(P_BYTE);
data[0] = value;
return *this;
}
MyMessage& MyMessage::set(uint8_t value) {
MyMessage& MyMessage::set(uint8_t value)
{
miSetLength(1);
miSetPayloadType(P_BYTE);
data[0] = value;
return *this;
}
MyMessage& MyMessage::set(float value, uint8_t decimals) {
MyMessage& MyMessage::set(float value, uint8_t decimals)
{
miSetLength(5); // 32 bit float + persi
miSetPayloadType(P_FLOAT32);
fValue=value;
@@ -253,28 +274,32 @@ MyMessage& MyMessage::set(float value, uint8_t decimals) {
return *this;
}
MyMessage& MyMessage::set(uint32_t value) {
MyMessage& MyMessage::set(uint32_t value)
{
miSetPayloadType(P_ULONG32);
miSetLength(4);
ulValue = value;
return *this;
}
MyMessage& MyMessage::set(int32_t value) {
MyMessage& MyMessage::set(int32_t value)
{
miSetPayloadType(P_LONG32);
miSetLength(4);
lValue = value;
return *this;
}
MyMessage& MyMessage::set(uint16_t value) {
MyMessage& MyMessage::set(uint16_t value)
{
miSetPayloadType(P_UINT16);
miSetLength(2);
uiValue = value;
return *this;
}
MyMessage& MyMessage::set(int16_t value) {
MyMessage& MyMessage::set(int16_t value)
{
miSetPayloadType(P_INT16);
miSetLength(2);
iValue = value;
+35 -36
View File
@@ -52,11 +52,11 @@ typedef enum {
/// @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_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_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
@@ -70,38 +70,38 @@ typedef enum {
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_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_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_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_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_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
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_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_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
@@ -119,12 +119,12 @@ typedef enum {
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_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_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_VAR1 = 24, //!< VAR1
V_VAR2 = 25, //!< VAR2
V_VAR3 = 26, //!< VAR3
V_VAR4 = 27, //!< VAR4
V_VAR5 = 28, //!< VAR5
@@ -137,11 +137,11 @@ typedef enum {
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_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_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)
@@ -151,11 +151,11 @@ typedef enum {
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]
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;
@@ -284,10 +284,10 @@ public:
char i2h(uint8_t i) const;
/**
* Clear message contents.
*/
void clear();
/**
* Clear message contents.
*/
void clear();
/**
* If payload is something else than P_STRING you can have the payload value converted
@@ -331,8 +331,7 @@ public:
#else
typedef union {
struct
{
struct {
#endif
uint8_t last; // 8 bit - Id of last node this message passed
@@ -340,12 +339,12 @@ struct
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
// 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
// 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.
@@ -364,7 +363,7 @@ struct
};
struct { // Presentation messages
uint8_t version; // Library version
uint8_t sensorType; // Sensor type hint for controller, see table above
uint8_t sensorType; // Sensor type hint for controller, see table above
};
char data[MAX_PAYLOAD + 1];
} __attribute__((packed));
@@ -372,7 +371,7 @@ struct
} __attribute__((packed));
#else
};
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
} __attribute__((packed)) MyMessage;
#endif
#endif
+18 -13
View File
@@ -33,7 +33,8 @@ uint8_t _firmwareRetry;
void readFirmwareSettings(void)
{
hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t));
hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
sizeof(nodeFirmwareConfig_t));
}
void firmwareOTAUpdateRequest(void)
@@ -41,7 +42,7 @@ void firmwareOTAUpdateRequest(void)
const uint32_t enterMS = hwMillis();
if (_firmwareUpdateOngoing && (enterMS - _firmwareLastRequest > MY_OTA_RETRY_DELAY)) {
if (!_firmwareRetry) {
setIndication(INDICATION_ERR_FW_TIMEOUT);
setIndication(INDICATION_ERR_FW_TIMEOUT);
OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed
// Give up. We have requested MY_OTA_RETRY times without any packet in return.
_firmwareUpdateOngoing = false;
@@ -54,8 +55,10 @@ void firmwareOTAUpdateRequest(void)
firmwareRequest.type = _nodeFirmwareConfig.type;
firmwareRequest.version = _nodeFirmwareConfig.version;
firmwareRequest.block = (_firmwareBlock - 1);
OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type, _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t)));
OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type,
_nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST,
false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t)));
}
}
@@ -65,13 +68,13 @@ bool firmwareOTAUpdateProcess(void)
nodeFirmwareConfig_t *firmwareConfigResponse = (nodeFirmwareConfig_t *)_msg.data;
// compare with current node configuration, if they differ, start FW fetch process
if (memcmp(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t))) {
setIndication(INDICATION_FW_UPDATE_START);
setIndication(INDICATION_FW_UPDATE_START);
OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated
// copy new FW config
(void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
// Init flash
if (!_flash.initialize()) {
setIndication(INDICATION_ERR_FW_FLASH_INIT);
setIndication(INDICATION_ERR_FW_FLASH_INIT);
OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
_firmwareUpdateOngoing = false;
} else {
@@ -91,12 +94,13 @@ bool firmwareOTAUpdateProcess(void)
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
if (_firmwareUpdateOngoing) {
// Save block to flash
setIndication(INDICATION_FW_UPDATE_RX);
setIndication(INDICATION_FW_UPDATE_RX);
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _firmwareBlock); // received FW block
// extract FW block
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
// write to flash
_flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
_flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
// wait until flash written
while (_flash.busy()) {}
_firmwareBlock--;
@@ -107,7 +111,8 @@ bool firmwareOTAUpdateProcess(void)
if (transportIsValidFirmware()) {
OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
// Write the new firmware config to eeprom
hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t));
hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
sizeof(nodeFirmwareConfig_t));
// All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks;
const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'};
@@ -116,7 +121,7 @@ bool firmwareOTAUpdateProcess(void)
while (_flash.busy()) {}
hwReboot();
} else {
setIndication(INDICATION_ERR_FW_CHECKSUM);
setIndication(INDICATION_ERR_FW_CHECKSUM);
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
}
}
@@ -142,7 +147,8 @@ void presentBootloaderInformation(void)
// add bootloader information
requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
_firmwareUpdateOngoing = false;
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false));
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
ST_FIRMWARE_CONFIG_REQUEST, false));
}
bool isFirmwareUpdateOngoing(void)
{
@@ -158,8 +164,7 @@ bool transportIsValidFirmware(void)
for (int8_t j = 0; j < 8; ++j) {
if (crc & 1) {
crc = (crc >> 1) ^ 0xA001;
}
else {
} else {
crc = (crc >> 1);
}
}
+34 -34
View File
@@ -17,38 +17,38 @@
* version 2 as published by the Free Software Foundation.
*/
/**
* @file MyOTAFirmwareUpdate.h
*
* @defgroup MyOTAFirmwaregrp MyOTAFirmwareUpdate
* @ingroup internals
* @{
*
* MyOTAFirmwareUpdate-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
* - [!] Exclamation mark is prepended in case of error or warning
* - SYSTEM:
* - <b>OTA</b> messages emitted by MyOTAFirmwareUpdate
* - SUB SYSTEMS:
* - OTA:<b>FRQ</b> from @ref firmwareOTAUpdateRequest()
* - OTA:<b>FWP</b> from @ref firmwareOTAUpdateProcess()
*
* MyOTAFirmwareUpdate debug log messages:
*
* |E| SYS | SUB | Message | Comment
* |-|------|-------|-------------------------------------------|----------------------------------------------------------------------------
* | | OTA | FWP | UPDATE | FW update initiated
* |!| OTA | FWP | FLASH INIT FAIL | Failed to initialise flash
* | | OTA | FWP | UPDATE SKIPPED | FW update skipped, no newer version available
* | | OTA | FWP | RECV B=%04X | Received FW block (B)
* | | OTA | FWP | FW END | FW received, proceed to CRC verification
* | | OTA | FWP | CRC OK | FW CRC verification OK
* |!| OTA | FWP | CRC FAIL | FW CRC verification failed
* | | OTA | FRQ | FW REQ,T=%04X,V=%04X,B=%04X | Request FW update, FW type (T), version (V), block (B)
* |!| OTA | FRQ | FW UPD FAIL | FW update failed
*
*
* @brief API declaration for MyOTAFirmwareUpdate
*/
/**
* @file MyOTAFirmwareUpdate.h
*
* @defgroup MyOTAFirmwaregrp MyOTAFirmwareUpdate
* @ingroup internals
* @{
*
* MyOTAFirmwareUpdate-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
* - [!] Exclamation mark is prepended in case of error or warning
* - SYSTEM:
* - <b>OTA</b> messages emitted by MyOTAFirmwareUpdate
* - SUB SYSTEMS:
* - OTA:<b>FRQ</b> from @ref firmwareOTAUpdateRequest()
* - OTA:<b>FWP</b> from @ref firmwareOTAUpdateProcess()
*
* MyOTAFirmwareUpdate debug log messages:
*
* |E| SYS | SUB | Message | Comment
* |-|------|-------|-------------------------------------------|----------------------------------------------------------------------------
* | | OTA | FWP | UPDATE | FW update initiated
* |!| OTA | FWP | FLASH INIT FAIL | Failed to initialise flash
* | | OTA | FWP | UPDATE SKIPPED | FW update skipped, no newer version available
* | | OTA | FWP | RECV B=%04X | Received FW block (B)
* | | OTA | FWP | FW END | FW received, proceed to CRC verification
* | | OTA | FWP | CRC OK | FW CRC verification OK
* |!| OTA | FWP | CRC FAIL | FW CRC verification failed
* | | OTA | FRQ | FW REQ,T=%04X,V=%04X,B=%04X | Request FW update, FW type (T), version (V), block (B)
* |!| OTA | FRQ | FW UPD FAIL | FW update failed
*
*
* @brief API declaration for MyOTAFirmwareUpdate
*/
#ifndef MyOTAFirmwareUpdate_h
@@ -67,9 +67,9 @@
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version
#if defined(MY_DEBUG)
#define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
#define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
#else
#define OTA_DEBUG(x,...) //!< debug NULL
#define OTA_DEBUG(x,...) //!< debug NULL
#endif
/**
* @brief FW config structure, stored in eeprom
+88 -82
View File
@@ -27,7 +27,8 @@ uint8_t protocolH2i(char c);
char _fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH];
char _convBuffer[MAX_PAYLOAD*2+1];
bool protocolParse(MyMessage &message, char *inputString) {
bool protocolParse(MyMessage &message, char *inputString)
{
char *str, *p, *value=NULL;
uint8_t bvalue[MAX_PAYLOAD];
uint8_t blen = 0;
@@ -36,48 +37,48 @@ bool protocolParse(MyMessage &message, char *inputString) {
// Extract command data coming on serial line
for (str = strtok_r(inputString, ";", &p); // split using semicolon
str && i < 6; // loop while str is not null an max 5 times
str = strtok_r(NULL, ";", &p) // get subsequent tokens
) {
str && i < 6; // loop while str is not null an max 5 times
str = strtok_r(NULL, ";", &p) // get subsequent tokens
) {
switch (i) {
case 0: // Radioid (destination)
message.destination = atoi(str);
break;
case 1: // Childid
message.sensor = atoi(str);
break;
case 2: // Message type
command = atoi(str);
mSetCommand(message, command);
break;
case 3: // Should we request ack from destination?
mSetRequestAck(message, atoi(str)?1:0);
break;
case 4: // Data type
message.type = atoi(str);
break;
case 5: // Variable value
if (command == C_STREAM) {
blen = 0;
uint8_t val;
while (*str) {
val = protocolH2i(*str++) << 4;
val += protocolH2i(*str++);
bvalue[blen] = val;
blen++;
}
} else {
value = str;
// Remove trailing carriage return and newline character (if it exists)
uint8_t lastCharacter = strlen(value)-1;
if (value[lastCharacter] == '\r') {
value[lastCharacter] = 0;
}
if (value[lastCharacter] == '\n') {
value[lastCharacter] = 0;
}
case 0: // Radioid (destination)
message.destination = atoi(str);
break;
case 1: // Childid
message.sensor = atoi(str);
break;
case 2: // Message type
command = atoi(str);
mSetCommand(message, command);
break;
case 3: // Should we request ack from destination?
mSetRequestAck(message, atoi(str)?1:0);
break;
case 4: // Data type
message.type = atoi(str);
break;
case 5: // Variable value
if (command == C_STREAM) {
blen = 0;
uint8_t val;
while (*str) {
val = protocolH2i(*str++) << 4;
val += protocolH2i(*str++);
bvalue[blen] = val;
blen++;
}
break;
} else {
value = str;
// Remove trailing carriage return and newline character (if it exists)
uint8_t lastCharacter = strlen(value)-1;
if (value[lastCharacter] == '\r') {
value[lastCharacter] = 0;
}
if (value[lastCharacter] == '\n') {
value[lastCharacter] = 0;
}
}
break;
}
i++;
}
@@ -91,68 +92,74 @@ bool protocolParse(MyMessage &message, char *inputString) {
mSetAck(message, false);
if (command == C_STREAM) {
message.set(bvalue, blen);
}
else {
} else {
message.set(value);
}
return true;
}
char * protocolFormat(MyMessage &message) {
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));
char * protocolFormat(MyMessage &message)
{
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;
}
char * protocolFormatMQTTTopic(const char* prefix, MyMessage &message) {
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
char * protocolFormatMQTTTopic(const char* prefix, MyMessage &message)
{
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix,
message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
return _fmtBuffer;
}
char * protocolFormatMQTTSubscribe(const char* prefix) {
char * protocolFormatMQTTSubscribe(const char* prefix)
{
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/+/+/+/+/+"), prefix);
return _fmtBuffer;
}
#ifdef MY_GATEWAY_MQTT_CLIENT
bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) {
bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length)
{
char *str, *p;
uint8_t i = 0;
uint8_t bvalue[MAX_PAYLOAD];
uint8_t blen = 0;
uint8_t command = 0;
if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) {
if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) {
// Prefix doesn't match incoming topic
return false;
}
for (str = strtok_r(topic + strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + 1, "/", &p); str && i <= 5;
str = strtok_r(NULL, "/", &p)) {
str = strtok_r(NULL, "/", &p)) {
switch (i) {
case 0: {
// Node id
message.destination = atoi(str);
break;
}
case 1: {
// Sensor id
message.sensor = atoi(str);
break;
}
case 2: {
// Command type
command = atoi(str);
mSetCommand(message, command);
break;
}
case 3: {
// Ack flag
mSetRequestAck(message, atoi(str)?1:0);
break;
}
case 4: {
// Sub type
message.type = atoi(str);
break;
}
case 0: {
// Node id
message.destination = atoi(str);
break;
}
case 1: {
// Sensor id
message.sensor = atoi(str);
break;
}
case 2: {
// Command type
command = atoi(str);
mSetCommand(message, command);
break;
}
case 3: {
// Ack flag
mSetRequestAck(message, atoi(str)?1:0);
break;
}
case 4: {
// Sub type
message.type = atoi(str);
break;
}
}
i++;
}
@@ -188,15 +195,14 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign
}
#endif
uint8_t protocolH2i(char c) {
uint8_t protocolH2i(char c)
{
uint8_t i = 0;
if (c <= '9') {
i += c - '0';
}
else if (c >= 'a') {
} else if (c >= 'a') {
i += c - 'a' + 10;
}
else {
} else {
i += c - 'A' + 10;
}
return i;
+349 -316
View File
@@ -20,8 +20,8 @@
#include "MySensorsCore.h"
#if defined(__linux__)
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#endif
// message buffers
@@ -32,7 +32,7 @@ MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among othe
static coreConfig_t _coreConfig;
#if defined(MY_DEBUG)
char _convBuf[MAX_PAYLOAD*2+1];
char _convBuf[MAX_PAYLOAD*2+1];
#endif
// Callback for transport=ok transition
@@ -47,37 +47,40 @@ void _callbackTransportReady(void)
}
}
void _process(void) {
void _process(void)
{
doYield();
#if defined(MY_INCLUSION_MODE_FEATURE)
inclusionProcess();
#endif
#if defined(MY_INCLUSION_MODE_FEATURE)
inclusionProcess();
#endif
#if defined(MY_GATEWAY_FEATURE)
gatewayTransportProcess();
#endif
#if defined(MY_GATEWAY_FEATURE)
gatewayTransportProcess();
#endif
#if defined(MY_SENSOR_NETWORK)
transportProcess();
#endif
#if defined(MY_SENSOR_NETWORK)
transportProcess();
#endif
#if defined(__linux__)
// To avoid high cpu usage
usleep(10000); // 10ms
#endif
#if defined(__linux__)
// To avoid high cpu usage
usleep(10000); // 10ms
#endif
}
void _infiniteLoop(void) {
void _infiniteLoop(void)
{
while(1) {
doYield();
#if defined(__linux__)
exit(1);
#endif
#if defined(__linux__)
exit(1);
#endif
}
}
void _begin(void) {
void _begin(void)
{
// reset wdt
hwWatchdogReset();
@@ -87,58 +90,60 @@ void _begin(void) {
hwInit();
CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n"));
CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER="
MYSENSORS_LIBRARY_VERSION "\n"));
// set defaults
_coreConfig.presentationSent = false;
// Call before() in sketch (if it exists)
if (before) {
CORE_DEBUG(PSTR("MCO:BGN:BFR\n")); // before callback
before();
}
#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
ledsInit();
#endif
#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
ledsInit();
#endif
signerInit();
// Read latest received controller configuration from EEPROM
// Note: _coreConfig.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default)
hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t));
hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
sizeof(controllerConfig_t));
#if defined(MY_OTA_FIRMWARE_FEATURE)
// Read firmware config from EEPROM, i.e. type, version, CRC, blocks
readFirmwareSettings();
#endif
#if defined(MY_OTA_FIRMWARE_FEATURE)
// Read firmware config from EEPROM, i.e. type, version, CRC, blocks
readFirmwareSettings();
#endif
#if defined(MY_SENSOR_NETWORK)
// Save static parent ID in eeprom (used by bootloader)
hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
// Initialise transport layer
transportInitialise();
// Register transport=ready callback
transportRegisterReadyCallback(_callbackTransportReady);
// wait until transport is ready
(void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS);
#endif
#if defined(MY_SENSOR_NETWORK)
// Save static parent ID in eeprom (used by bootloader)
hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
// Initialise transport layer
transportInitialise();
// Register transport=ready callback
transportRegisterReadyCallback(_callbackTransportReady);
// wait until transport is ready
(void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS);
#endif
_checkNodeLock();
#if defined(MY_GATEWAY_FEATURE)
#if defined(MY_INCLUSION_BUTTON_FEATURE)
inclusionInit();
#endif
// initialise the transport driver
if (!gatewayTransportInit()) {
setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n"));
// Nothing more we can do
_infiniteLoop();
}
#endif
#if defined(MY_GATEWAY_FEATURE)
#if defined(MY_INCLUSION_BUTTON_FEATURE)
inclusionInit();
#endif
// initialise the transport driver
if (!gatewayTransportInit()) {
setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n"));
// Nothing more we can do
_infiniteLoop();
}
#endif
// Call sketch setup
if (setup) {
@@ -164,7 +169,8 @@ void _registerNode(void)
uint8_t counter = MY_REGISTRATION_RETRIES;
// only proceed if register response received or retries exceeded
do {
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION));
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
I_REGISTRATION_REQUEST).set(MY_CORE_VERSION));
} while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--);
#else
_coreConfig.nodeRegistered = true;
@@ -172,40 +178,42 @@ void _registerNode(void)
#endif
}
void presentNode(void) {
void presentNode(void)
{
setIndication(INDICATION_PRESENT);
// Present node and request config
#if defined(MY_GATEWAY_FEATURE)
// Send presentation for this gateway device
#if defined(MY_REPEATER_FEATURE)
(void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
#else
(void)present(NODE_SENSOR_ID, S_ARDUINO_NODE);
#endif
#else
#if defined(MY_GATEWAY_FEATURE)
// Send presentation for this gateway device
#if defined(MY_REPEATER_FEATURE)
(void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
#else
(void)present(NODE_SENSOR_ID, S_ARDUINO_NODE);
#endif
#else
#if defined(MY_OTA_FIRMWARE_FEATURE)
presentBootloaderInformation();
#endif
#if defined(MY_OTA_FIRMWARE_FEATURE)
presentBootloaderInformation();
#endif
// Send signing preferences for this node to the GW
signerPresentation(_msgTmp, GATEWAY_ADDRESS);
// Send signing preferences for this node to the GW
signerPresentation(_msgTmp, GATEWAY_ADDRESS);
// Send presentation for this radio node
#if defined(MY_REPEATER_FEATURE)
(void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
#else
(void)present(NODE_SENSOR_ID, S_ARDUINO_NODE);
#endif
// Send presentation for this radio node
#if defined(MY_REPEATER_FEATURE)
(void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
#else
(void)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
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG).set(getParentNodeId()));
// Send a configuration exchange request to controller
// Node sends parent node. Controller answers with latest node configuration
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
I_CONFIG).set(getParentNodeId()));
// Wait configuration reply.
(void)wait(2000, C_INTERNAL, I_CONFIG);
// Wait configuration reply.
(void)wait(2000, C_INTERNAL, I_CONFIG);
#endif
#endif
if (presentation) {
presentation();
@@ -240,213 +248,229 @@ uint8_t getDistanceGW(void)
#endif
}
controllerConfig_t getConfig(void) {
controllerConfig_t getConfig(void)
{
return _coreConfig.controllerConfig;
}
bool _sendRoute(MyMessage &message) {
#if defined(MY_CORE_ONLY)
(void)message;
#endif
#if defined(MY_GATEWAY_FEATURE)
if (message.destination == getNodeId()) {
// 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_SENSOR_NETWORK)
return transportSendRoute(message);
#else
return false;
#endif
bool _sendRoute(MyMessage &message)
{
#if defined(MY_CORE_ONLY)
(void)message;
#endif
#if defined(MY_GATEWAY_FEATURE)
if (message.destination == getNodeId()) {
// 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_SENSOR_NETWORK)
return transportSendRoute(message);
#else
return false;
#endif
}
bool send(MyMessage &message, const bool enableAck) {
bool send(MyMessage &message, const bool enableAck)
{
message.sender = getNodeId();
mSetCommand(message, C_SET);
mSetRequestAck(message, enableAck);
#if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
if (_coreConfig.nodeRegistered) {
return _sendRoute(message);
}
else {
CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered
return false;
}
#else
#if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
if (_coreConfig.nodeRegistered) {
return _sendRoute(message);
#endif
}
bool sendBatteryLevel(const uint8_t value, const bool ack) {
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, ack).set(value));
}
bool sendHeartbeat(const bool ack) {
#if defined(MY_SENSOR_NETWORK)
const uint32_t heartbeat = transportGetHeartbeat();
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, ack).set(heartbeat));
#else
(void)ack;
} else {
CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered
return false;
#endif
}
#else
return _sendRoute(message);
#endif
}
bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description, const bool ack) {
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, ack).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description));
bool sendBatteryLevel(const uint8_t value, const bool ack)
{
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL,
ack).set(value));
}
bool sendSketchInfo(const char *name, const char *version, const bool ack) {
bool sendHeartbeat(const bool ack)
{
#if defined(MY_SENSOR_NETWORK)
const uint32_t heartbeat = transportGetHeartbeat();
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE,
ack).set(heartbeat));
#else
(void)ack;
return false;
#endif
}
bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description,
const bool ack)
{
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType,
ack).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description));
}
bool sendSketchInfo(const char *name, const char *version, const bool ack)
{
bool result = true;
if (name) {
result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name));
result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME,
ack).set(name));
}
if (version) {
result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version));
result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION,
ack).set(version));
}
return result;
}
bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination) {
bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination)
{
return _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType).set(""));
}
bool requestTime(const bool ack) {
bool requestTime(const bool ack)
{
return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, ack).set(""));
}
// Message delivered through _msg
bool _processInternalMessages(void) {
bool _processInternalMessages(void)
{
const 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)
_coreConfig.nodeRegistered = _msg.getBool();
setIndication(INDICATION_GOT_REGISTRATION);
CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), _coreConfig.nodeRegistered); // node registration
#endif
}
else if (type == I_CONFIG) {
#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)
_coreConfig.nodeRegistered = _msg.getBool();
setIndication(INDICATION_GOT_REGISTRATION);
CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), _coreConfig.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
_coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M
hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t));
}
else if (type == I_PRESENTATION) {
_coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 ||
_msg.data[0] == 'M'; // metric if null terminated or M
hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
sizeof(controllerConfig_t));
} else if (type == I_PRESENTATION) {
// Re-send node presentation to controller
presentNode();
}
else if (type == I_HEARTBEAT_REQUEST) {
} else if (type == I_HEARTBEAT_REQUEST) {
(void)sendHeartbeat();
}
else if (type == I_TIME) {
} 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();
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK"));
}
#endif
}
else if (type == I_DEBUG) {
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
const char debug_msg = _msg.data[0];
if (debug_msg == 'R') { // routing table
#if defined(MY_REPEATER_FEATURE)
for (uint16_t cnt = 0; cnt < SIZE_ROUTES; cnt++) {
const uint8_t route = transportGetRoute(cnt);
if (route != BROADCAST_ADDRESS) {
CORE_DEBUG(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route);
uint8_t outBuf[2] = { (uint8_t)cnt,route };
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf, 2));
wait(200);
}
} 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();
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK"));
}
#endif
} else if (type == I_DEBUG) {
#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG)
const char debug_msg = _msg.data[0];
if (debug_msg == 'R') { // routing table
#if defined(MY_REPEATER_FEATURE)
for (uint16_t cnt = 0; cnt < SIZE_ROUTES; cnt++) {
const uint8_t route = transportGetRoute(cnt);
if (route != BROADCAST_ADDRESS) {
CORE_DEBUG(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route);
uint8_t outBuf[2] = { (uint8_t)cnt,route };
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf,
2));
wait(200);
}
#endif
}
else if (debug_msg == 'V') { // CPU voltage
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUVoltage()));
#endif
} else if (debug_msg == 'V') { // CPU voltage
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
I_DEBUG).set(hwCPUVoltage()));
} else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
I_DEBUG).set(hwCPUFrequency()));
} else if (debug_msg == 'M') { // free memory
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
I_DEBUG).set(hwFreeMem()));
} else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK"));
for (int i = EEPROM_START; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
hwWriteConfig(i, 0xFF);
}
else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUFrequency()));
}
else if (debug_msg == 'M') { // free memory
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwFreeMem()));
}
else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK"));
for (int i = EEPROM_START; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
hwWriteConfig(i, 0xFF);
}
setIndication(INDICATION_REBOOT);
hwReboot();
}
#endif
setIndication(INDICATION_REBOOT);
hwReboot();
}
#endif
} else {
return false;
}
else return false;
}
else {
} else {
// sender is a node
if (type == I_REGISTRATION_REQUEST) {
#if defined(MY_GATEWAY_FEATURE)
// registeration requests are exclusively handled by GW/Controller
#if !defined(MY_REGISTRATION_CONTROLLER)
// auto registration if version compatible
bool approveRegistration = true;
#if defined(MY_GATEWAY_FEATURE)
// registeration requests are exclusively handled by GW/Controller
#if !defined(MY_REGISTRATION_CONTROLLER)
// auto registration if version compatible
bool approveRegistration = true;
#if defined(MY_CORE_COMPATIBILITY_CHECK)
approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION);
#endif
#if defined(MY_CORE_COMPATIBILITY_CHECK)
approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION);
#endif
#if (F_CPU>16000000)
// delay for fast GW and slow nodes
delay(5);
#endif
(void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_RESPONSE).set(approveRegistration));
#else
return false; // processing of this request via controller
#endif
#endif
#if (F_CPU>16000000)
// delay for fast GW and slow nodes
delay(5);
#endif
(void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL,
I_REGISTRATION_RESPONSE).set(approveRegistration));
#else
return false; // processing of this request via controller
#endif
#endif
} else {
return false;
}
else return false;
}
return true;
}
void saveState(const uint8_t pos, const uint8_t value) {
void saveState(const uint8_t pos, const uint8_t value)
{
hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value);
}
uint8_t loadState(const uint8_t pos) {
uint8_t loadState(const uint8_t pos)
{
return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos);
}
void wait(const uint32_t waitingMS) {
void wait(const uint32_t waitingMS)
{
const uint32_t enteringMS = hwMillis();
while (hwMillis() - enteringMS < waitingMS) {
_process();
}
}
bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) {
bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType)
{
const uint32_t enteringMS = hwMillis();
// invalidate msg type
_msg.type = !msgType;
@@ -458,127 +482,138 @@ bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) {
return expectedResponse;
}
void doYield(void) {
void doYield(void)
{
hwWatchdogReset();
yield();
#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
ledsProcess();
#endif
#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
ledsProcess();
#endif
}
int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) {
CORE_DEBUG(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2);
int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1,
const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2)
{
CORE_DEBUG(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep,
interrupt1, mode1, interrupt2, mode2);
// OTA FW feature: do not sleep if FW update ongoing
#if defined(MY_OTA_FIRMWARE_FEATURE)
if (isFirmwareUpdateOngoing()) {
debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
wait(sleepingMS);
return MY_SLEEP_NOT_POSSIBLE;
}
#endif
// repeater feature: sleeping not possible
#if defined(MY_REPEATER_FEATURE)
(void)smartSleep;
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled
#if defined(MY_OTA_FIRMWARE_FEATURE)
if (isFirmwareUpdateOngoing()) {
debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
wait(sleepingMS);
return MY_SLEEP_NOT_POSSIBLE;
#else
uint32_t sleepingTimeMS = sleepingMS;
#if defined(MY_SENSOR_NETWORK)
// Do not sleep if transport not ready
if (!isTransportReady()) {
CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready
const uint32_t sleepEnterMS = hwMillis();
uint32_t sleepDeltaMS = 0;
while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) && (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) {
_process();
sleepDeltaMS = hwMillis() - sleepEnterMS;
}
// sleep remainder
if (sleepDeltaMS < sleepingTimeMS) {
sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time
CORE_DEBUG(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS);
}
else {
// no sleeping time left
return MY_SLEEP_NOT_POSSIBLE;
}
}
#endif
}
#endif
// repeater feature: sleeping not possible
#if defined(MY_REPEATER_FEATURE)
(void)smartSleep;
(void)interrupt1;
(void)mode1;
(void)interrupt2;
(void)mode2;
if (smartSleep) {
// notify controller about going to sleep
(void)sendHeartbeat();
wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages
CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled
wait(sleepingMS);
return MY_SLEEP_NOT_POSSIBLE;
#else
uint32_t sleepingTimeMS = sleepingMS;
#if defined(MY_SENSOR_NETWORK)
// Do not sleep if transport not ready
if (!isTransportReady()) {
CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready
const uint32_t sleepEnterMS = hwMillis();
uint32_t sleepDeltaMS = 0;
while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) &&
(sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) {
_process();
sleepDeltaMS = hwMillis() - sleepEnterMS;
}
#if defined(MY_SENSOR_NETWORK)
CORE_DEBUG(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport
transportPowerDown();
#endif
#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
// Wait until leds finish their blinking pattern
while (ledsBlinking()) {
doYield();
}
#endif
setIndication(INDICATION_SLEEP);
int8_t result = MY_SLEEP_NOT_POSSIBLE; // default
if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
// both IRQs
result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
}
else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
// one IRQ
result = hwSleep(interrupt1, mode1, sleepingTimeMS);
}
else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
// no IRQ
result = hwSleep(sleepingTimeMS);
// sleep remainder
if (sleepDeltaMS < sleepingTimeMS) {
sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time
CORE_DEBUG(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS);
} else {
// no sleeping time left
return MY_SLEEP_NOT_POSSIBLE;
}
}
#endif
setIndication(INDICATION_WAKEUP);
CORE_DEBUG(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up
return result;
#endif
if (smartSleep) {
// notify controller about going to sleep
(void)sendHeartbeat();
wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages
}
#if defined(MY_SENSOR_NETWORK)
CORE_DEBUG(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport
transportPowerDown();
#endif
#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
// Wait until leds finish their blinking pattern
while (ledsBlinking()) {
doYield();
}
#endif
setIndication(INDICATION_SLEEP);
int8_t result = MY_SLEEP_NOT_POSSIBLE; // default
if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
// both IRQs
result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
} else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
// one IRQ
result = hwSleep(interrupt1, mode1, sleepingTimeMS);
} else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
// no IRQ
result = hwSleep(sleepingTimeMS);
}
setIndication(INDICATION_WAKEUP);
CORE_DEBUG(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up
return result;
#endif
}
// sleep functions
int8_t sleep(const uint32_t sleepingMS, const bool smartSleep) {
int8_t sleep(const uint32_t sleepingMS, const bool smartSleep)
{
return _sleep(sleepingMS, smartSleep);
}
int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS, const bool smartSleep) {
int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS,
const bool smartSleep)
{
return _sleep(sleepingMS, smartSleep, interrupt, mode);
}
int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep) {
int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep)
{
return _sleep(sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2);
}
// deprecated smartSleep() functions
int8_t smartSleep(const uint32_t sleepingMS) {
int8_t smartSleep(const uint32_t sleepingMS)
{
// compatibility
return _sleep(sleepingMS, true);
}
int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS) {
int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS)
{
// compatibility
return _sleep(sleepingMS, true, interrupt, mode);
}
int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS) {
int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
const uint8_t mode2, const uint32_t sleepingMS)
{
// compatibility
return _sleep(sleepingMS, true, interrupt1, mode1, interrupt2, mode2);
}
@@ -595,10 +630,10 @@ void _nodeLock(const char* str)
CORE_DEBUG(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN);
doYield();
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str));
#if defined(MY_SENSOR_NETWORK)
transportPowerDown();
CORE_DEBUG(PSTR("MCO:NLK:TPD\n")); // power down transport
#endif
#if defined(MY_SENSOR_NETWORK)
transportPowerDown();
CORE_DEBUG(PSTR("MCO:NLK:TPD\n")); // power down transport
#endif
setIndication(INDICATION_SLEEP);
(void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message
setIndication(INDICATION_WAKEUP);
@@ -625,14 +660,12 @@ void _checkNodeLock(void)
hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
setIndication(INDICATION_ERR_LOCKED);
CORE_DEBUG(PSTR("MCO:BGN:NODE UNLOCKED\n"));
}
else {
} else {
// Disable pullup
hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
_nodeLock("LDB"); //Locked during boot
}
}
else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) {
} else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) {
// Reset walue
hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX);
}
+67 -57
View File
@@ -17,51 +17,51 @@
* 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 or warning
* - SYSTEM:
* - <b>MCO</b> messages emitted by MySensorsCore
* - SUB SYSTEMS:
* - MCO:<b>BGN</b> from @ref _begin()
* - MCO:<b>REG</b> from @ref _registerNode()
* - MCO:<b>SND</b> from @ref send()
* - MCO:<b>PIM</b> from @ref _processInternalMessages()
* - MCO:<b>NLK</b> from 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 | BFR | Callback before()
* | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled
* | | MCO | BGN | STP | Callback setup()
* | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised, NA=not available
* | | 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 | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2
* | | MCO | SLP | TPD | Sleep node, powerdown transport
* | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP)
* |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing
* |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled
* | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information
* | | MCO | NLK | TPD | Powerdown transport
*
*
* @brief API declaration for MySensorsCore
*/
/**
* @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 or warning
* - SYSTEM:
* - <b>MCO</b> messages emitted by MySensorsCore
* - SUB SYSTEMS:
* - MCO:<b>BGN</b> from @ref _begin()
* - MCO:<b>REG</b> from @ref _registerNode()
* - MCO:<b>SND</b> from @ref send()
* - MCO:<b>PIM</b> from @ref _processInternalMessages()
* - MCO:<b>NLK</b> from 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 | BFR | Callback before()
* | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled
* | | MCO | BGN | STP | Callback setup()
* | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised, NA=not available
* | | 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 | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2
* | | MCO | SLP | TPD | Sleep node, powerdown transport
* | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP)
* |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing
* |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled
* | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information
* | | MCO | NLK | TPD | Powerdown transport
*
*
* @brief API declaration for MySensorsCore
*/
#ifndef MySensorsCore_h
@@ -86,11 +86,11 @@
#ifdef MY_DEBUG
#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug, to be removed (follow-up PR)
#define CORE_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug, to be removed (follow-up PR)
#define CORE_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
#else
#define debug(x,...) //!< debug NULL, to be removed (follow-up PR)
#define CORE_DEBUG(x,...) //!< debug NULL
#define debug(x,...) //!< debug NULL, to be removed (follow-up PR)
#define CORE_DEBUG(x,...) //!< debug NULL
#endif
@@ -143,7 +143,8 @@ void presentNode(void);
* @param description A textual description of the sensor.
* @return true Returns true if message reached the first stop on its way to destination.
*/
bool present(const uint8_t sensorId, const uint8_t sensorType, const char *description="", const bool ack = false);
bool present(const uint8_t sensorId, const uint8_t sensorType, const char *description="",
const bool ack = false);
/**
* Sends sketch meta information to the gateway. Not mandatory but a nice thing to do.
@@ -189,7 +190,8 @@ bool sendHeartbeat(const bool ack = false);
* @param destination The nodeId of other node in radio network. Default is gateway
* @return true Returns true if message reached the first stop on its way to destination.
*/
bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination = GATEWAY_ADDRESS);
bool request(const uint8_t childSensorId, const uint8_t variableType,
const uint8_t destination = GATEWAY_ADDRESS);
/**
* Requests time from controller. Answer will be delivered to receiveTime function in sketch.
@@ -269,7 +271,8 @@ int8_t sleep(const uint32_t sleepingMS, const bool smartSleep = false);
* @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep
* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
*/
int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0, const bool smartSleep = false);
int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0,
const bool smartSleep = false);
/**
* Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts.
@@ -283,7 +286,8 @@ int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepin
* @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep.
* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
*/
int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS = 0, const bool smartSleep = false);
int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
const uint8_t mode2, const uint32_t sleepingMS = 0, const bool smartSleep = false);
/**
* \deprecated Use sleep(ms, true) instead
@@ -316,7 +320,8 @@ int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sl
* @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
*/
int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS = 0);
int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
const uint8_t mode2, const uint32_t sleepingMS = 0);
/**
* Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts.
@@ -330,7 +335,9 @@ int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t i
* @param smartSleep (optional) Set True if sending heartbeat and process incoming messages before going to sleep.
* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
*/
int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false, const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED, const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED);
int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false,
const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED,
const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED);
/**
@@ -412,7 +419,9 @@ void loop(void) __attribute__((weak));
// Inline function and macros
static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor, const uint8_t command, const uint8_t type, const bool ack = false) {
static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor,
const uint8_t command, const uint8_t type, const bool ack = false)
{
msg.sender = getNodeId();
msg.destination = destination;
msg.sensor = sensor;
@@ -423,7 +432,8 @@ static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const
return msg;
}
static inline MyMessage& buildGw(MyMessage &msg, const uint8_t type) {
static inline MyMessage& buildGw(MyMessage &msg, const uint8_t type)
{
msg.sender = GATEWAY_ADDRESS;
msg.destination = GATEWAY_ADDRESS;
msg.sensor = NODE_SENSOR_ID;
+115 -105
View File
@@ -82,22 +82,24 @@ extern bool signerAtsha204SignMsg(MyMessage &msg);
#endif
// Helper function to centralize signing/verification exceptions
static bool skipSign(MyMessage &msg) {
static bool skipSign(MyMessage &msg)
{
if mGetAck(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_REQUEST || msg.type == I_FIND_PARENT_RESPONSE ||
msg.type == I_HEARTBEAT_REQUEST || msg.type == I_HEARTBEAT_RESPONSE ||
msg.type == I_PING || msg.type == I_PONG ||
msg.type == I_REGISTRATION_REQUEST )) {
(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_REQUEST || msg.type == I_FIND_PARENT_RESPONSE ||
msg.type == I_HEARTBEAT_REQUEST || 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 &&
(msg.type == ST_FIRMWARE_REQUEST || msg.type == ST_FIRMWARE_RESPONSE ||
msg.type == ST_SOUND || msg.type == ST_IMAGE)) {
(msg.type == ST_FIRMWARE_REQUEST || msg.type == ST_FIRMWARE_RESPONSE ||
msg.type == ST_SOUND || msg.type == ST_IMAGE)) {
SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type);
return true;
} else {
@@ -107,7 +109,8 @@ static bool skipSign(MyMessage &msg) {
#endif // MY_SIGNING_FEATURE
// Helper to prepare a signing presentation message
static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) {
static void prepareSigningPresentation(MyMessage &msg, uint8_t destination)
{
// Only supports version 1 for now
(void)build(msg, destination, NODE_SENSOR_ID, C_INTERNAL, I_SIGNING_PRESENTATION).set("");
mSetLength(msg, 2);
@@ -116,15 +119,16 @@ static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) {
msg.data[1] = 0;
}
void signerInit(void) {
void signerInit(void)
{
#if defined(MY_SIGNING_FEATURE)
// Read out the signing requirements from EEPROM
hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doSign));
sizeof(_doSign));
// Read out the whitelist requirements from EEPROM
hwReadConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doWhitelist));
sizeof(_doWhitelist));
#if defined(MY_SIGNING_SOFT)
signerAtsha204SoftInit();
@@ -135,7 +139,8 @@ void signerInit(void) {
#endif
}
void signerPresentation(MyMessage &msg, uint8_t destination) {
void signerPresentation(MyMessage &msg, uint8_t destination)
{
prepareSigningPresentation(msg, destination);
#if defined(MY_SIGNING_REQUEST_SIGNATURES)
@@ -157,7 +162,8 @@ void signerPresentation(MyMessage &msg, uint8_t destination) {
}
}
bool signerProcessInternal(MyMessage &msg) {
bool signerProcessInternal(MyMessage &msg)
{
uint8_t sender = msg.sender;
(void)sender;
#if !defined(MY_SIGNING_FEATURE)
@@ -166,8 +172,9 @@ bool signerProcessInternal(MyMessage &msg) {
// If we act as gateway and do not have the signing feature and receive a signing request we still
// need to do make sure the requester does not believe the gateway still require signatures
prepareSigningPresentation(msg, sender);
SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"),
sender);
SIGN_DEBUG(
PSTR("Informing node %d that we do not require signatures because we do not support it\n"),
sender);
if (!_sendRoute(msg)) {
SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n"));
}
@@ -183,7 +190,8 @@ bool signerProcessInternal(MyMessage &msg) {
if (msg.type == I_NONCE_REQUEST) {
#if defined(MY_NODE_LOCK_FEATURE)
nof_nonce_requests++;
SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests);
SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"),
MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests);
if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) {
_nodeLock("TMNR"); //Too many nonces requested
}
@@ -192,113 +200,113 @@ bool signerProcessInternal(MyMessage &msg) {
if (signerAtsha204SoftGetNonce(msg)) {
#endif
#if defined(MY_SIGNING_ATSHA204)
if (signerAtsha204GetNonce(msg)) {
if (signerAtsha204GetNonce(msg)) {
#endif
if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) {
SIGN_DEBUG(PSTR("Failed to transmit nonce!\n"));
if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) {
SIGN_DEBUG(PSTR("Failed to transmit nonce!\n"));
} else {
SIGN_DEBUG(PSTR("Transmitted nonce\n"));
}
} else {
SIGN_DEBUG(PSTR("Transmitted nonce\n"));
SIGN_DEBUG(PSTR("Failed to generate nonce!\n"));
}
return true; // No need to further process I_NONCE_REQUEST
} else if (msg.type == I_SIGNING_PRESENTATION) {
if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) {
SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]);
return true; // Just drop this presentation message
}
} else {
SIGN_DEBUG(PSTR("Failed to generate nonce!\n"));
}
return true; // No need to further process I_NONCE_REQUEST
} else if (msg.type == I_SIGNING_PRESENTATION) {
if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) {
SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]);
return true; // Just drop this presentation message
}
// We only handle version 1 here...
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) {
// We received an indicator that the sender require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), msg.sender);
SET_SIGN(msg.sender);
} else {
// We received an indicator that the sender does not require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), msg.sender);
CLEAR_SIGN(msg.sender);
}
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) {
// We received an indicator that the sender require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), msg.sender);
SET_SIGN(msg.sender);
} else {
// We received an indicator that the sender does not require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), msg.sender);
CLEAR_SIGN(msg.sender);
}
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) {
// We received an indicator that the sender require us to salt signatures with serial
SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), msg.sender);
SET_WHITELIST(msg.sender);
} else {
// We received an indicator that the sender does not require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), msg.sender);
CLEAR_WHITELIST(msg.sender);
}
// We received an indicator that the sender require us to salt signatures with serial
SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), msg.sender);
SET_WHITELIST(msg.sender);
} else {
// We received an indicator that the sender does not require us to sign all messages we send to it
SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), msg.sender);
CLEAR_WHITELIST(msg.sender);
}
// Save updated tables
hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doSign));
hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doWhitelist));
// Save updated tables
hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doSign));
hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS,
sizeof(_doWhitelist));
// Inform sender about our preference if we are a gateway, but only require signing if the sender
// required signing unless we explicitly configure it to
// We do not want a gateway to require signing from all nodes in a network just because it wants one node
// to sign it's messages unless we explicitly configure it to
// Inform sender about our preference if we are a gateway, but only require signing if the sender
// required signing unless we explicitly configure it to
// We do not want a gateway to require signing from all nodes in a network just because it wants one node
// to sign it's messages unless we explicitly configure it to
#if defined(MY_GATEWAY_FEATURE)
prepareSigningPresentation(msg, sender);
prepareSigningPresentation(msg, sender);
#if defined(MY_SIGNING_REQUEST_SIGNATURES)
if (DO_SIGN(sender)) {
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES;
}
if (DO_SIGN(sender)) {
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES;
}
#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL)
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES;
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES;
#endif
#endif
#if defined(MY_SIGNING_NODE_WHITELISTING)
if (DO_WHITELIST(sender)) {
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING;
}
if (DO_WHITELIST(sender)) {
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING;
}
#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL)
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING;
msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING;
#endif
#endif
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) {
SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), sender);
} else {
SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), sender);
}
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) {
SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), sender);
} else {
SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), sender);
}
if (!_sendRoute(msg)) {
SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n"));
}
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) {
SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), sender);
} else {
SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), sender);
}
if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) {
SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), sender);
} else {
SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), sender);
}
if (!_sendRoute(msg)) {
SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n"));
}
#endif // MY_GATEWAY_FEATURE
return true; // No need to further process I_SIGNING_PRESENTATION
} else if (msg.type == I_NONCE_RESPONSE) {
// Proceed with signing if nonce has been received
SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender);
if (sender != _msgSign.destination) {
SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! "
"It came from %d.\n"), _msgSign.destination, sender);
SIGN_DEBUG(PSTR("Silently discarding this nonce\n"));
return true; // No need to further process I_NONCE_RESPONSE
}
return true; // No need to further process I_SIGNING_PRESENTATION
} else if (msg.type == I_NONCE_RESPONSE) {
// Proceed with signing if nonce has been received
SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender);
if (sender != _msgSign.destination) {
SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! "
"It came from %d.\n"), _msgSign.destination, sender);
SIGN_DEBUG(PSTR("Silently discarding this nonce\n"));
return true; // No need to further process I_NONCE_RESPONSE
}
#if defined(MY_SIGNING_SOFT)
signerAtsha204SoftPutNonce(msg);
signerAtsha204SoftPutNonce(msg);
#endif
#if defined(MY_SIGNING_ATSHA204)
signerAtsha204PutNonce(msg);
signerAtsha204PutNonce(msg);
#endif
#if defined(MY_SIGNING_SOFT)
if (!signerAtsha204SoftSignMsg(_msgSign)) {
if (!signerAtsha204SoftSignMsg(_msgSign)) {
#endif
#if defined(MY_SIGNING_ATSHA204)
if (!signerAtsha204SignMsg(_msgSign)) {
if (!signerAtsha204SignMsg(_msgSign)) {
#endif
SIGN_DEBUG(PSTR("Failed to sign message!\n"));
} else {
SIGN_DEBUG(PSTR("Message signed\n"));
_signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission
}
return true; // No need to further process I_NONCE_RESPONSE
}
SIGN_DEBUG(PSTR("Failed to sign message!\n"));
} else {
SIGN_DEBUG(PSTR("Message signed\n"));
_signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission
}
return true; // No need to further process I_NONCE_RESPONSE
}
#endif // MY_SIGNING_FEATURE
return false;
}
@@ -323,7 +331,8 @@ bool signerSignMsg(MyMessage &msg) {
} else {
// Send nonce-request
_signingNonceStatus=SIGN_WAITING_FOR_NONCE;
if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL, I_NONCE_REQUEST).set(""))) {
if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL,
I_NONCE_REQUEST).set(""))) {
SIGN_DEBUG(PSTR("Failed to transmit nonce request!\n"));
return false;
}
@@ -332,7 +341,8 @@ bool signerSignMsg(MyMessage &msg) {
// Other messages could come in-between. We trust _process() takes care of them
unsigned long enter = hwMillis();
_msgSign = msg; // Copy the message to sign since message buffer might be touched in _process()
while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && _signingNonceStatus==SIGN_WAITING_FOR_NONCE) {
while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS &&
_signingNonceStatus==SIGN_WAITING_FOR_NONCE) {
_process();
}
if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) {
@@ -375,8 +385,7 @@ bool signerVerifyMsg(MyMessage &msg) {
// Internal messages of certain types are not verified
if (skipSign(msg)) {
verificationResult = true;
}
else if (!mGetSigned(msg)) {
} else if (!mGetSigned(msg)) {
// Got unsigned message that should have been signed
SIGN_DEBUG(PSTR("Message is not signed, but it should have been!\n"));
verificationResult = false;
@@ -397,7 +406,8 @@ bool signerVerifyMsg(MyMessage &msg) {
nof_failed_verifications = 0;
} else {
nof_failed_verifications++;
SIGN_DEBUG(PSTR("Failed verification attempts left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_failed_verifications);
SIGN_DEBUG(PSTR("Failed verification attempts left until lockdown: %d\n"),
MY_NODE_LOCK_COUNTER_MAX-nof_failed_verifications);
if (nof_failed_verifications >= MY_NODE_LOCK_COUNTER_MAX) {
_nodeLock("TMFV"); //Too many failed verifications
}
+4 -4
View File
@@ -99,7 +99,7 @@
* scramble into “garbage” when transmitted over the air and then reassembled by a receiving node before being fed in “the clear” up the stack
* at the receiving end.
*
* There are methods and possibilities to provide encryption also in software, but if this is done, it is my recommendation that this is done
* There are methods and possibilities to provide encryption also in software, but if this is done, it is my recommendation that this is done
* after integrity- and authentication information has been provided to the message (if this is desired). Integrity and authentication is of
* course not mandatory and some might be happy with only having encryption to cover their need for security. I, however, have only focused on
* <i>integrity</i> and <i>authenticity</i> while at the same time keeping the current message routing mechanisms intact and therefore leave
@@ -313,7 +313,7 @@
* The whitelist is stored on the node that require signatures. When a received message is verified, the serial of the sender is looked up in a
* list stored on the receiving node, and the corresponding serial stored in the list for that sender is then included in the signature verification
* process. The list is stored as the value of the flag that enables whitelisting, @ref MY_SIGNING_NODE_WHITELISTING.<br>
*
*
* Whitelisting is achieved by 'salting' the signature with some node-unique information known to the receiver. In the case of ATSHA204A this is the
* unique serial number programmed into the circuit. This unique number is never transmitted over the air in clear text, so Eve will not be able to
* figure out a "trusted" serial by snooping on the traffic.<br>
@@ -523,7 +523,7 @@ void signerInit(void);
* @param destination Node ID of the destination.
*/
void signerPresentation(MyMessage &msg, uint8_t destination);
/**
* @brief Manages internal signing message handshaking.
*
@@ -574,7 +574,7 @@ bool signerPutNonce(MyMessage &msg);
* deinitializations and enter a power saving state within this call.
* \n@b Usage: This function is typically called as action when receiving a @ref I_NONCE_RESPONSE
* message and after @ref signerPutNonce() has successfully been executed.
*
*
* @param msg The message to sign.
* @returns @c true if successful, else @c false.
*/
+60 -39
View File
@@ -41,7 +41,7 @@ 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;
const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING;
#endif
static void signerCalculateSignature(MyMessage &msg, bool signing);
@@ -54,21 +54,20 @@ static char i2h(uint8_t i)
uint8_t k = i & 0x0F;
if (k <= 9) {
return '0' + k;
}
else {
} else {
return 'A' + k - 10;
}
}
static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) {
static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz)
{
static char printBuffer[300];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(printBuffer);
#endif
for (int i=0; i<sz; i++)
{
for (int i=0; i<sz; i++) {
printBuffer[i * 2] = i2h(buf[i] >> 4);
printBuffer[(i * 2) + 1] = i2h(buf[i]);
}
@@ -78,8 +77,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf,
printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0';
#endif
MY_SERIALDEVICE.print(str);
if (sz > 0)
{
if (sz > 0) {
MY_SERIALDEVICE.print(printBuffer);
}
MY_SERIALDEVICE.println("");
@@ -88,13 +86,16 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf,
#define DEBUG_SIGNING_PRINTBUF(str, buf, sz)
#endif
void signerAtsha204Init(void) {
void signerAtsha204Init(void)
{
atsha204_init(MY_SIGNING_ATSHA204_PIN);
}
bool signerAtsha204CheckTimer(void) {
bool signerAtsha204CheckTimer(void)
{
if (_signing_verification_ongoing) {
if (hwMillis() < _signing_timestamp || hwMillis() > _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_signing_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH);
@@ -106,14 +107,15 @@ bool signerAtsha204CheckTimer(void) {
return true;
}
bool signerAtsha204GetNonce(MyMessage &msg) {
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 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
(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) {
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;
}
@@ -140,7 +142,8 @@ bool signerAtsha204GetNonce(MyMessage &msg) {
return true;
}
void signerAtsha204PutNonce(MyMessage &msg) {
void signerAtsha204PutNonce(MyMessage &msg)
{
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0);
memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
@@ -148,7 +151,8 @@ void signerAtsha204PutNonce(MyMessage &msg) {
memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD);
}
bool signerAtsha204SignMsg(MyMessage &msg) {
bool signerAtsha204SignMsg(MyMessage &msg)
{
// If we cannot fit any signature in the message, refuse to sign it
if (mGetLength(msg) > MAX_PAYLOAD-2) {
DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0);
@@ -161,10 +165,12 @@ bool signerAtsha204SignMsg(MyMessage &msg) {
if (DO_WHITELIST(msg.destination)) {
// Salt the signature with the senders nodeId and the unique serial of the ATSHA device
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
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
(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);
}
@@ -175,13 +181,16 @@ bool signerAtsha204SignMsg(MyMessage &msg) {
_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)], &_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));
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;
}
bool signerAtsha204VerifyMsg(MyMessage &msg) {
bool signerAtsha204VerifyMsg(MyMessage &msg)
{
if (!_signing_verification_ongoing) {
DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0);
return false;
@@ -198,7 +207,8 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
return false;
}
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg));
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)],
MAX_PAYLOAD-mGetLength(msg));
signerCalculateSignature(msg, false); // Get signature of message
#ifdef MY_SIGNING_NODE_WHITELISTING
@@ -207,10 +217,12 @@ 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_verifying_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed
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
(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;
}
}
@@ -229,8 +241,10 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
_signing_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER;
// Compare the caluclated signature with the provided signature
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));
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
@@ -243,42 +257,49 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) {
}
// Helper to calculate signature of msg (returned in _signing_rx_buffer[SHA204_BUFFER_POS_DATA])
static void signerCalculateSignature(MyMessage &msg, bool signing) {
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)));
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 ? _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);
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 ? _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_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);
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 ? _signing_signing_nonce : _signing_verifying_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_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL,
GENDIG_COUNT_DATA, _signing_tx_buffer, GENDIG_RSP_SIZE, _signing_rx_buffer);
GENDIG_COUNT_DATA, _signing_tx_buffer, GENDIG_RSP_SIZE, _signing_rx_buffer);
// Calculate HMAC of message+nonce digest and secret key
(void)atsha204_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL,
HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer);
HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer);
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 _signing_rx_buffer[SHA204_BUFFER_POS_DATA])
static uint8_t* signerSha256(const uint8_t* data, size_t sz) {
static uint8_t* signerSha256(const uint8_t* data, size_t sz)
{
// Initiate SHA256 calculator
(void)atsha204_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL,
SHA_COUNT_SHORT, _signing_tx_buffer, SHA_RSP_SIZE_SHORT, _signing_rx_buffer);
SHA_COUNT_SHORT, _signing_tx_buffer, SHA_RSP_SIZE_SHORT, _signing_rx_buffer);
// Calculate a hash
memset(_signing_temp_message, 0x00, SHA_MSG_SIZE);
@@ -288,7 +309,7 @@ static uint8_t* signerSha256(const uint8_t* data, size_t sz) {
_signing_temp_message[SHA_MSG_SIZE-2] = (sz >> 5);
_signing_temp_message[SHA_MSG_SIZE-1] = (sz << 3);
(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);
SHA_COUNT_LONG, _signing_tx_buffer, SHA_RSP_SIZE_LONG, _signing_rx_buffer);
DEBUG_SIGNING_PRINTBUF(F("SHA256: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32);
return &_signing_rx_buffer[SHA204_BUFFER_POS_DATA];
+37 -27
View File
@@ -47,49 +47,47 @@ extern uint8_t _doWhitelist[32];
static uint8_t _signing_node_serial_info[9];
#ifdef MY_SIGNING_NODE_WHITELISTING
const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING;
const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING;
#endif
static void signerCalculateSignature(MyMessage &msg, bool signing);
#ifdef MY_DEBUG_VERBOSE_SIGNING
static char i2h(uint8_t i)
{
{
uint8_t k = i & 0x0F;
if (k <= 9) {
return '0' + k;
}
else {
} else {
return 'A' + k - 10;
}
}
#ifdef __linux__
static void DEBUG_SIGNING_PRINTBUF(const char *str, uint8_t* buf, uint8_t sz) {
static void DEBUG_SIGNING_PRINTBUF(const char *str, uint8_t* buf, uint8_t sz)
{
static char printBuffer[300];
for (int i=0; i<sz; i++)
{
for (int i=0; i<sz; i++) {
printBuffer[i * 2] = i2h(buf[i] >> 4);
printBuffer[(i * 2) + 1] = i2h(buf[i]);
}
printBuffer[sz * 2] = '\0';
debug(str);
if (sz > 0)
{
if (sz > 0) {
debug(printBuffer);
}
}
#else
static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) {
static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz)
{
static char printBuffer[300];
#ifdef MY_GATEWAY_FEATURE
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
MY_SERIALDEVICE.print(printBuffer);
#endif
for (int i=0; i<sz; i++)
{
for (int i=0; i<sz; i++) {
printBuffer[i * 2] = i2h(buf[i] >> 4);
printBuffer[(i * 2) + 1] = i2h(buf[i]);
}
@@ -99,8 +97,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf,
printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0';
#endif
MY_SERIALDEVICE.print(str);
if (sz > 0)
{
if (sz > 0) {
MY_SERIALDEVICE.print(printBuffer);
}
MY_SERIALDEVICE.println("");
@@ -110,7 +107,8 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf,
#define DEBUG_SIGNING_PRINTBUF(str, buf, sz)
#endif
void signerAtsha204SoftInit(void) {
void signerAtsha204SoftInit(void)
{
// initialize pseudo-RNG
hwRandomNumberInit();
// Set secrets
@@ -118,9 +116,11 @@ void signerAtsha204SoftInit(void) {
hwReadConfigBlock((void*)_signing_node_serial_info, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
}
bool signerAtsha204SoftCheckTimer(void) {
bool signerAtsha204SoftCheckTimer(void)
{
if (_signing_verification_ongoing) {
if (hwMillis() < _signing_timestamp || hwMillis() > _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_signing_nonce, 0xAA, 32);
@@ -132,7 +132,8 @@ bool signerAtsha204SoftCheckTimer(void) {
return true;
}
bool signerAtsha204SoftGetNonce(MyMessage &msg) {
bool signerAtsha204SoftGetNonce(MyMessage &msg)
{
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0);
// We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is
@@ -160,7 +161,8 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) {
return true;
}
void signerAtsha204SoftPutNonce(MyMessage &msg) {
void signerAtsha204SoftPutNonce(MyMessage &msg)
{
DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0);
memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD);
@@ -168,7 +170,8 @@ void signerAtsha204SoftPutNonce(MyMessage &msg) {
memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD);
}
bool signerAtsha204SoftSignMsg(MyMessage &msg) {
bool signerAtsha204SoftSignMsg(MyMessage &msg)
{
// If we cannot fit any signature in the message, refuse to sign it
if (mGetLength(msg) > MAX_PAYLOAD-2) {
DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0);
@@ -199,12 +202,14 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) {
// Transfer as much signature data as the remaining space in the message permits
memcpy(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg));
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg));
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)],
MAX_PAYLOAD-mGetLength(msg));
return true;
}
bool signerAtsha204SoftVerifyMsg(MyMessage &msg) {
bool signerAtsha204SoftVerifyMsg(MyMessage &msg)
{
if (!_signing_verification_ongoing) {
DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0);
return false;
@@ -222,7 +227,8 @@ 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));
DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)],
MAX_PAYLOAD-mGetLength(msg));
signerCalculateSignature(msg, false);
#ifdef MY_SIGNING_NODE_WHITELISTING
@@ -268,11 +274,15 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) {
}
// Helper to calculate signature of msg (returned in hmac)
static void signerCalculateSignature(MyMessage &msg, bool signing) {
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 ? _signing_signing_nonce : _signing_verifying_nonce, 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 ? _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
+431 -391
View File
File diff suppressed because it is too large Load Diff
+148 -148
View File
@@ -17,166 +17,166 @@
* 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:
* - <b>TSM</b>: messages emitted by the transport state machine
* - <b>TSF</b>: messages emitted by transport support functions
* - SUB SYSTEMS:
* - Transport state machine (<b>TSM</b>)
* - TSM:INIT from <b>stInit</b> Initialize transport and radio
* - TSM:FPAR from <b>stParent</b> Find parent
* - TSM:ID from <b>stID</b> Check/request node ID, if dynamic node ID set
* - TSM:UPL from <b>stUplink</b> Verify uplink connection by pinging GW
* - TSM:READY from <b>stReady</b> Transport is ready and fully operational
* - TSM:FAIL from <b>stFailure</b> Failure in transport link or transport HW
* - Transport support function (<b>TSF</b>)
* - 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:WUR from @ref transportWaitUntilReady(), waits until transport is ready
* - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM
* - TSF:LRT from @ref transportLoadRoutingTable(), loads RAM routing table from EEPROM (only GW/repeaters)
* - TSF:SRT from @ref transportSaveRoutingTable(), saves RAM routing table to EEPROM (only GW/repeaters)
* - 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)
/**
* @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:
* - <b>TSM</b>: messages emitted by the transport state machine
* - <b>TSF</b>: messages emitted by transport support functions
* - SUB SYSTEMS:
* - Transport state machine (<b>TSM</b>)
* - TSM:INIT from <b>stInit</b> Initialize transport and radio
* - TSM:FPAR from <b>stParent</b> Find parent
* - TSM:ID from <b>stID</b> Check/request node ID, if dynamic node ID set
* - TSM:UPL from <b>stUplink</b> Verify uplink connection by pinging GW
* - TSM:READY from <b>stReady</b> Transport is ready and fully operational
* - TSM:FAIL from <b>stFailure</b> Failure in transport link or transport HW
* - Transport support function (<b>TSF</b>)
* - 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:WUR from @ref transportWaitUntilReady(), waits until transport is ready
* - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM
* - TSF:LRT from @ref transportLoadRoutingTable(), loads RAM routing table from EEPROM (only GW/repeaters)
* - TSF:SRT from @ref transportSaveRoutingTable(), saves RAM routing table to EEPROM (only GW/repeaters)
* - 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 | | <b>Transition to stInit state</b>
* | | TSM | INIT | STATID=%%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 | | <b>Transition to stParent state</b>
* | | 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 | | <b>Transition to stID state</b>
* | | 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 | | <b>Transition to stUplink state</b>
* | | TSM | UPL | OK | Uplink OK, GW returned ping
* | | TSF | UPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N)
* |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged
* | | TSM | READY | SRT | Save routing table
* | | TSM | READY | ID=%%d,PAR=%%d,DIS=%%d| <b>Transition to stReady</b> Transport ready, node ID (ID), parent node ID (PAR), distance to GW (DIS)
* |!| 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 | FAIL | CNT=%%d | <b>Transition to stFailure state</b>, consecutive failure counter (CNT)
* | | TSM | FAIL | PDT | Power-down transport
* | | TSM | FAIL | 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 | WUR | MS=%%lu | Wait until transport ready, timeout (MS)
* | | 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 | LEN,%%d!=%%d | Invalid message length, (actual!=expected)
* |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch (actual!=expected)
* |!| 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 | LRT | OK | Loading routing table successful
* | | TSF | SRT | OK | Saving 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 <a href="https://www.mysensors.org/download/serial_api_20">here</a> 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:
* - <b>s</b>=sensor ID
* - <b>c</b>=command
* - <b>t</b>=msg type
* - <b>pt</b>=payload type
* - <b>l</b>=length
* - <b>sg</b>=signing flag
* - <b>ft</b>=failed uplink transmission counter
* - <b>st</b>=send status, OK=success, NACK=no radio ACK received
*
* @brief API declaration for MyTransport
*
*/
*
* Transport debug log messages:
*
* |E| SYS | SUB | Message | Comment
* |-|------|-----------|-----------------------|---------------------------------------------------------------------
* | | TSM | INIT | | <b>Transition to stInit state</b>
* | | TSM | INIT | STATID=%%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 | | <b>Transition to stParent state</b>
* | | 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 | | <b>Transition to stID state</b>
* | | 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 | | <b>Transition to stUplink state</b>
* | | TSM | UPL | OK | Uplink OK, GW returned ping
* | | TSF | UPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N)
* |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged
* | | TSM | READY | SRT | Save routing table
* | | TSM | READY | ID=%%d,PAR=%%d,DIS=%%d| <b>Transition to stReady</b> Transport ready, node ID (ID), parent node ID (PAR), distance to GW (DIS)
* |!| 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 | FAIL | CNT=%%d | <b>Transition to stFailure state</b>, consecutive failure counter (CNT)
* | | TSM | FAIL | PDT | Power-down transport
* | | TSM | FAIL | 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 | WUR | MS=%%lu | Wait until transport ready, timeout (MS)
* | | 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 | LEN,%%d!=%%d | Invalid message length, (actual!=expected)
* |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch (actual!=expected)
* |!| 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 | LRT | OK | Loading routing table successful
* | | TSF | SRT | OK | Saving 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 <a href="https://www.mysensors.org/download/serial_api_20">here</a> 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:
* - <b>s</b>=sensor ID
* - <b>c</b>=command
* - <b>t</b>=msg type
* - <b>pt</b>=payload type
* - <b>l</b>=length
* - <b>sg</b>=signing flag
* - <b>ft</b>=failed uplink transmission counter
* - <b>st</b>=send status, OK=success, NACK=no radio ACK received
*
* @brief API declaration for MyTransport
*
*/
#ifndef MyTransport_h
#define MyTransport_h
#include "MySensorsCore.h"
// debug
// debug
#if defined(MY_DEBUG)
#define TRANSPORT_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
extern char _convBuf[MAX_PAYLOAD * 2 + 1];
#define TRANSPORT_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug
extern char _convBuf[MAX_PAYLOAD * 2 + 1];
#else
#define TRANSPORT_DEBUG(x,...) //!< debug NULL
#define TRANSPORT_DEBUG(x,...) //!< debug NULL
#endif
#if defined(MY_REPEATER_FEATURE)
#define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes
#define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes
#else
#define MY_TRANSPORT_MAX_TX_FAILURES (5u) //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes
#define MY_TRANSPORT_MAX_TX_FAILURES (5u) //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes
#endif
#define MY_TRANSPORT_MAX_TSM_FAILURES (7u) //!< Max. number of consecutive TSM failure state entries (3bits)
#ifndef MY_TRANSPORT_TIMEOUT_FAILURE_STATE
#define MY_TRANSPORT_TIMEOUT_FAILURE_STATE (10*1000ul) //!< Duration failure state (in ms)
#define MY_TRANSPORT_TIMEOUT_FAILURE_STATE (10*1000ul) //!< Duration failure state (in ms)
#endif
#ifndef MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE
#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (60*1000ul) //!< Duration extended failure state (in ms)
#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (60*1000ul) //!< Duration extended failure state (in ms)
#endif
#ifndef MY_TRANSPORT_STATE_TIMEOUT_MS
#define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms)
#define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms)
#endif
#ifndef MY_TRANSPORT_CHKUPL_INTERVAL_MS
#define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms)
#define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms)
#endif
#ifndef MY_TRANSPORT_STATE_RETRIES
#define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE
#define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE
#endif
#define AUTO (255u) //!< ID 255 is reserved
@@ -188,7 +188,7 @@
// parent node check
#if defined(MY_PARENT_NODE_IS_STATIC) && !defined(MY_PARENT_NODE_ID)
#error MY_PARENT_NODE_IS_STATIC but no MY_PARENT_NODE_ID defined!
#error MY_PARENT_NODE_IS_STATIC but no MY_PARENT_NODE_ID defined!
#endif
#define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined
@@ -197,14 +197,14 @@
// RX queue
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
#if defined(MY_RADIO_RFM69)
#error Receive message buffering not supported for RFM69!
#endif
#if defined(MY_RS485)
#error Receive message buffering not supported for RS485!
#endif
#if defined(MY_RADIO_RFM69)
#error Receive message buffering not supported for RFM69!
#endif
#if defined(MY_RS485)
#error Receive message buffering not supported for RS485!
#endif
#elif !defined(MY_RX_MESSAGE_BUFFER_FEATURE) && defined(MY_RX_MESSAGE_BUFFER_SIZE)
#error Receive message buffering requires message buffering feature enabled!
#error Receive message buffering requires message buffering feature enabled!
#endif
/**
@@ -237,7 +237,7 @@ typedef struct {
* @brief Status variables and SM state
*
* This structure stores transport status and SM variables
*/
*/
typedef struct {
// SM variables
transportState_t* currentState; //!< pointer to current fsm state
@@ -252,7 +252,7 @@ typedef struct {
bool transportActive : 1; //!< flag transport active
uint8_t stateRetries : 3; //!< retries / state re-enter (max 7)
// 8 bits
uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15)
uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15)
uint8_t failureCounter : 3; //!< counter for TSM failures (max 7)
bool msgReceived : 1; //!< flag message received
// 8 bits
@@ -309,7 +309,7 @@ void stReadyTransition(void);
*/
void stReadyUpdate(void);
/**
* @brief Transport failure and power down radio
* @brief Transport failure and power down radio
*/
void stFailureTransition(void);
/**
@@ -352,7 +352,7 @@ bool transportAssignNodeID(const uint8_t newNodeId);
* @brief Wait and process messages for a defined amount of time until specified message received
* @param waitingMS Time to wait and process incoming messages in ms
* @param cmd Specific command
* @param msgType Specific message type
* @param msgType Specific message type
* @return true if specified command received within waiting time
*/
bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType);
@@ -364,7 +364,7 @@ bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t ms
uint8_t transportPingNode(const 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
@@ -381,7 +381,7 @@ bool transportSendRoute(MyMessage &message);
* @brief Send message to recipient
* @param to Recipient of message
* @param message
* @return true if message sent successfully
* @return true if message sent successfully
*/
bool transportSendWrite(const uint8_t to, MyMessage &message);
/**
@@ -501,7 +501,7 @@ bool transportSanityCheck();
* @brief Receive message from FIFO
* @return length of recevied message (header + payload)
*/
uint8_t transportReceive(void* data);
uint8_t transportReceive(void* data);
/**
* @brief Power down transport HW
*/
+54 -53
View File
@@ -30,33 +30,34 @@
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
typedef struct _transportQueuedMessage {
uint8_t m_len; // Length of the data
uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data
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<transportQueuedMessage> transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE);
static CircularBuffer<transportQueuedMessage> 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;
}
}
// 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
@@ -69,86 +70,86 @@ uint8_t _psk[16];
bool transportInit(void)
{
#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);
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
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
RF24_registerReceiveCallback( transportRxCallback );
RF24_registerReceiveCallback( transportRxCallback );
#endif
return RF24_initialize();
return RF24_initialize();
}
void transportSetAddress(const uint8_t address)
{
RF24_setNodeAddress(address);
RF24_startListening();
RF24_setNodeAddress(address);
RF24_startListening();
}
uint8_t transportGetAddress(void)
{
return RF24_getNodeID();
return RF24_getNodeID();
}
bool transportSend(const uint8_t recipient, const void* data, uint8_t len)
{
#if defined(MY_RF24_ENABLE_ENCRYPTION)
// copy input data because it is read-only
(void)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);
return RF24_sendMessage(recipient, _dataenc, len);
// copy input data because it is read-only
(void)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);
return RF24_sendMessage(recipient, _dataenc, len);
#else
return RF24_sendMessage(recipient, data, len);
return RF24_sendMessage(recipient, data, len);
#endif
}
bool transportAvailable(void)
{
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
(void)RF24_isDataAvailable; // Prevent 'defined but not used' warning
return !transportRxQueue.empty();
(void)RF24_isDataAvailable; // Prevent 'defined but not used' warning
return !transportRxQueue.empty();
#else
return RF24_isDataAvailable();
return RF24_isDataAvailable();
#endif
}
bool transportSanityCheck(void)
{
return RF24_sanityCheck();
return RF24_sanityCheck();
}
uint8_t transportReceive(void* data)
{
uint8_t len = 0;
uint8_t len = 0;
#if defined(MY_RX_MESSAGE_BUFFER_FEATURE)
transportQueuedMessage* msg = transportRxQueue.getBack();
if (msg) {
len = msg->m_len;
(void)memcpy(data, msg->m_data, len);
(void)transportRxQueue.popBack();
}
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);
len = RF24_readMessage(data);
#endif
#if defined(MY_RF24_ENABLE_ENCRYPTION)
// has to be adjusted, WIP!
_aes.set_IV(0);
// decrypt data
// has to be adjusted, WIP!
_aes.set_IV(0);
// decrypt data
if (_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) {
len = 0;
}
#endif
return len;
return len;
}
void transportPowerDown(void)
{
RF24_powerDown();
RF24_powerDown();
}
+23 -15
View File
@@ -26,43 +26,50 @@ RFM69 _radio(MY_RF69_SPI_CS, MY_RF69_IRQ_PIN, MY_RFM69HW, MY_RF69_IRQ_NUM);
uint8_t _address;
bool transportInit() {
bool transportInit()
{
// Start up the radio library (_address will be set later by the MySensors library)
if (_radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID)) {
#ifdef MY_RFM69_ENABLE_ENCRYPTION
uint8_t _psk[16];
hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
_radio.encrypt((const char*)_psk);
memset(_psk, 0, 16); // Make sure it is purged from memory when set
#endif
#ifdef MY_RFM69_ENABLE_ENCRYPTION
uint8_t _psk[16];
hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
_radio.encrypt((const char*)_psk);
memset(_psk, 0, 16); // Make sure it is purged from memory when set
#endif
return true;
}
return false;
}
void transportSetAddress(uint8_t address) {
void transportSetAddress(uint8_t address)
{
_address = address;
_radio.setAddress(address);
}
uint8_t transportGetAddress() {
uint8_t transportGetAddress()
{
return _address;
}
bool transportSend(uint8_t to, const void* data, uint8_t len) {
bool transportSend(uint8_t to, const void* data, uint8_t len)
{
return _radio.sendWithRetry(to,data,len);
}
bool transportAvailable() {
bool transportAvailable()
{
return _radio.receiveDone();
}
bool transportSanityCheck() {
bool transportSanityCheck()
{
// not implemented yet
return true;
}
uint8_t transportReceive(void* data) {
uint8_t transportReceive(void* data)
{
memcpy(data,(const void *)_radio.DATA, _radio.DATALEN);
// save payload length
const uint8_t dataLen = _radio.DATALEN;
@@ -71,8 +78,9 @@ uint8_t transportReceive(void* data) {
_radio.sendACK();
}
return dataLen;
}
}
void transportPowerDown() {
void transportPowerDown()
{
_radio.sleep();
}
+23 -14
View File
@@ -22,43 +22,52 @@
#include "MyTransport.h"
#include "drivers/RFM95/RFM95.h"
bool transportInit(void) {
bool transportInit(void)
{
const bool result = RFM95_initialise(MY_RFM95_FREQUENCY);
#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM95_ATC_MODE_DISABLED)
// only enable ATC mode nodes
RFM95_ATCmode(true, MY_RFM95_ATC_TARGET_RSSI);
#endif
#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM95_ATC_MODE_DISABLED)
// only enable ATC mode nodes
RFM95_ATCmode(true, MY_RFM95_ATC_TARGET_RSSI);
#endif
return result;
}
void transportSetAddress(uint8_t address) {
void transportSetAddress(uint8_t address)
{
RFM95_setAddress(address);
}
uint8_t transportGetAddress(void) {
uint8_t transportGetAddress(void)
{
return RFM95_getAddress();
}
bool transportSend(uint8_t to, const void* data, uint8_t len) {
bool transportSend(uint8_t to, const void* data, uint8_t len)
{
return RFM95_sendWithRetry(to, data, len);
}
bool transportAvailable(void) {
bool transportAvailable(void)
{
return RFM95_available();
}
bool transportSanityCheck(void) {
bool transportSanityCheck(void)
{
return RFM95_sanityCheck();
}
uint8_t transportReceive(void* data) {
uint8_t transportReceive(void* data)
{
return RFM95_recv((uint8_t*)data);
}
}
void transportPowerDown(void) {
void transportPowerDown(void)
{
(void)RFM95_sleep();
}
int16_t transportGetSignalStrength(void) {
int16_t transportGetSignalStrength(void)
{
return RFM95_getRSSI();
}
+189 -182
View File
@@ -62,16 +62,16 @@
#include "MyTransport.h"
#ifdef __linux__
#include "SerialPort.h"
#include "SerialPort.h"
#endif
#if defined(MY_RS485_DE_PIN)
#define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5)
#define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW)
#define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5)
#define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW)
#else
#define assertDE()
#define deassertDE()
#define assertDE()
#define deassertDE()
#endif
// We only use SYS_PACK in this application
@@ -114,13 +114,14 @@ bool _packet_received;
//Reset the state machine and release the data pointer
void _serialReset(){
_recPhase = 0;
_recPos = 0;
_recLen = 0;
_recCommand = 0;
_recCS = 0;
_recCalcCS = 0;
void _serialReset()
{
_recPhase = 0;
_recPos = 0;
_recLen = 0;
_recCommand = 0;
_recCS = 0;
_recCalcCS = 0;
}
// This is the main reception state machine. Progress through the states
@@ -132,118 +133,118 @@ void _serialReset(){
// function.
bool _serialProcess()
{
char inch;
unsigned char i;
if (!_dev.available()) {
return false;
char inch;
unsigned char i;
if (!_dev.available()) {
return false;
}
while(_dev.available()) {
inch = _dev.read();
switch(_recPhase) {
// Case 0 looks for the header. Bytes arrive in the serial interface and get
// shifted through a header buffer. When the start and end characters in
// the buffer match the SOH/STX pair, and the destination station ID matches
// our ID, save the header information and progress to the next state.
case 0:
memcpy(&_header[0],&_header[1],5);
_header[5] = inch;
if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) {
_recCalcCS = 0;
_recStation = _header[1];
_recSender = _header[2];
_recCommand = _header[3];
_recLen = _header[4];
for (i=1; i<=4; i++) {
_recCalcCS += _header[i];
}
_recPhase = 1;
_recPos = 0;
//Check if we should process this message
//We reject the message if we are the sender
//We reject if we are not the receiver and message is not a broadcast
if ((_recSender == _nodeId) ||
(_recStation != _nodeId &&
_recStation != BROADCAST_ADDRESS)) {
_serialReset();
break;
}
if (_recLen == 0) {
_recPhase = 2;
}
}
break;
// Case 1 receives the data portion of the packet. Read in "_recLen" number
// of bytes and store them in the _data array.
case 1:
_data[_recPos++] = inch;
_recCalcCS += inch;
if (_recPos == _recLen) {
_recPhase = 2;
}
break;
// After the data comes a single ETX character. Do we have it? If not,
// reset the state machine to default and start looking for a new header.
case 2:
// Packet properly terminated?
if (inch == ETX) {
_recPhase = 3;
} else {
_serialReset();
}
break;
// Next comes the checksum. We have already calculated it from the incoming
// data, so just store the incoming checksum byte for later.
case 3:
_recCS = inch;
_recPhase = 4;
break;
// The final state - check the last character is EOT and that the checksum matches.
// If that test passes, then look for a valid command callback to execute.
// Execute it if found.
case 4:
if (inch == EOT) {
if (_recCS == _recCalcCS) {
// First, check for system level commands. It is possible
// to register your own callback as well for system level
// commands which will be called after the system default
// hook.
switch (_recCommand) {
case ICSC_SYS_PACK:
_packet_from = _recSender;
_packet_len = _recLen;
_packet_received = true;
break;
}
}
}
//Clear the data
_serialReset();
//Return true, we have processed one command
return true;
break;
}
while(_dev.available()) {
inch = _dev.read();
switch(_recPhase) {
// Case 0 looks for the header. Bytes arrive in the serial interface and get
// shifted through a header buffer. When the start and end characters in
// the buffer match the SOH/STX pair, and the destination station ID matches
// our ID, save the header information and progress to the next state.
case 0:
memcpy(&_header[0],&_header[1],5);
_header[5] = inch;
if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) {
_recCalcCS = 0;
_recStation = _header[1];
_recSender = _header[2];
_recCommand = _header[3];
_recLen = _header[4];
for (i=1; i<=4; i++) {
_recCalcCS += _header[i];
}
_recPhase = 1;
_recPos = 0;
//Check if we should process this message
//We reject the message if we are the sender
//We reject if we are not the receiver and message is not a broadcast
if ((_recSender == _nodeId) ||
(_recStation != _nodeId &&
_recStation != BROADCAST_ADDRESS)) {
_serialReset();
break;
}
if (_recLen == 0) {
_recPhase = 2;
}
}
break;
// Case 1 receives the data portion of the packet. Read in "_recLen" number
// of bytes and store them in the _data array.
case 1:
_data[_recPos++] = inch;
_recCalcCS += inch;
if (_recPos == _recLen) {
_recPhase = 2;
}
break;
// After the data comes a single ETX character. Do we have it? If not,
// reset the state machine to default and start looking for a new header.
case 2:
// Packet properly terminated?
if (inch == ETX) {
_recPhase = 3;
} else {
_serialReset();
}
break;
// Next comes the checksum. We have already calculated it from the incoming
// data, so just store the incoming checksum byte for later.
case 3:
_recCS = inch;
_recPhase = 4;
break;
// The final state - check the last character is EOT and that the checksum matches.
// If that test passes, then look for a valid command callback to execute.
// Execute it if found.
case 4:
if (inch == EOT) {
if (_recCS == _recCalcCS) {
// First, check for system level commands. It is possible
// to register your own callback as well for system level
// commands which will be called after the system default
// hook.
switch (_recCommand) {
case ICSC_SYS_PACK:
_packet_from = _recSender;
_packet_len = _recLen;
_packet_received = true;
break;
}
}
}
//Clear the data
_serialReset();
//Return true, we have processed one command
return true;
break;
}
}
return true;
}
return true;
}
bool transportSend(uint8_t to, const void* data, uint8_t len)
{
const char *datap = static_cast<char const *>(data);
unsigned char i;
unsigned char cs = 0;
unsigned char del;
unsigned char i;
unsigned char cs = 0;
unsigned char del;
// This is how many times to try and transmit before failing.
unsigned char timeout = 10;
@@ -264,101 +265,107 @@ bool transportSend(uint8_t to, const void* data, uint8_t len)
}
}
#if defined(MY_RS485_DE_PIN)
hwDigitalWrite(MY_RS485_DE_PIN, HIGH);
delayMicroseconds(5);
#endif
#if defined(MY_RS485_DE_PIN)
hwDigitalWrite(MY_RS485_DE_PIN, HIGH);
delayMicroseconds(5);
#endif
// Start of header by writing multiple SOH
for(byte w=0;w<1;w++) {
_dev.write(SOH);
}
_dev.write(to); // Destination address
cs += to;
_dev.write(_nodeId); // Source address
cs += _nodeId;
_dev.write(ICSC_SYS_PACK); // Command code
cs += ICSC_SYS_PACK;
_dev.write(len); // Length of text
cs += len;
_dev.write(STX); // Start of text
for(i=0; i<len; i++) {
_dev.write(datap[i]); // Text bytes
cs += datap[i];
}
_dev.write(ETX); // End of text
_dev.write(cs);
_dev.write(EOT);
// Start of header by writing multiple SOH
for(byte w=0; w<1; w++) {
_dev.write(SOH);
}
_dev.write(to); // Destination address
cs += to;
_dev.write(_nodeId); // Source address
cs += _nodeId;
_dev.write(ICSC_SYS_PACK); // Command code
cs += ICSC_SYS_PACK;
_dev.write(len); // Length of text
cs += len;
_dev.write(STX); // Start of text
for(i=0; i<len; i++) {
_dev.write(datap[i]); // Text bytes
cs += datap[i];
}
_dev.write(ETX); // End of text
_dev.write(cs);
_dev.write(EOT);
#if defined(MY_RS485_DE_PIN)
#ifdef __PIC32MX__
// MPIDE has nothing yet for this. It uses the hardware buffer, which
// could be up to 8 levels deep. For now, let's just delay for 8
// characters worth.
delayMicroseconds((F_CPU/9600)+1);
#else
#if defined(ARDUINO) && ARDUINO >= 100
#if ARDUINO >= 104
// Arduino 1.0.4 and upwards does it right
_dev.flush();
#else
// Between 1.0.0 and 1.0.3 it almost does it - need to compensate
// for the hardware buffer. Delay for 2 bytes worth of transmission.
_dev.flush();
delayMicroseconds((20000000UL/9600)+1);
#endif
#elif defined(__linux__)
_dev.flush();
#endif
#endif
hwDigitalWrite(MY_RS485_DE_PIN, LOW);
#endif
return true;
#if defined(MY_RS485_DE_PIN)
#ifdef __PIC32MX__
// MPIDE has nothing yet for this. It uses the hardware buffer, which
// could be up to 8 levels deep. For now, let's just delay for 8
// characters worth.
delayMicroseconds((F_CPU/9600)+1);
#else
#if defined(ARDUINO) && ARDUINO >= 100
#if ARDUINO >= 104
// Arduino 1.0.4 and upwards does it right
_dev.flush();
#else
// Between 1.0.0 and 1.0.3 it almost does it - need to compensate
// for the hardware buffer. Delay for 2 bytes worth of transmission.
_dev.flush();
delayMicroseconds((20000000UL/9600)+1);
#endif
#elif defined(__linux__)
_dev.flush();
#endif
#endif
hwDigitalWrite(MY_RS485_DE_PIN, LOW);
#endif
return true;
}
bool transportInit() {
// Reset the state machine
bool transportInit()
{
// Reset the state machine
_dev.begin(MY_RS485_BAUD_RATE);
_serialReset();
#if defined(MY_RS485_DE_PIN)
hwPinMode(MY_RS485_DE_PIN, OUTPUT);
hwDigitalWrite(MY_RS485_DE_PIN, LOW);
#endif
return true;
_serialReset();
#if defined(MY_RS485_DE_PIN)
hwPinMode(MY_RS485_DE_PIN, OUTPUT);
hwDigitalWrite(MY_RS485_DE_PIN, LOW);
#endif
return true;
}
void transportSetAddress(uint8_t address) {
void transportSetAddress(uint8_t address)
{
_nodeId = address;
}
uint8_t transportGetAddress() {
uint8_t transportGetAddress()
{
return _nodeId;
}
bool transportAvailable() {
bool transportAvailable()
{
_serialProcess();
return _packet_received;
}
bool transportSanityCheck() {
bool transportSanityCheck()
{
// not implemented yet
return true;
}
uint8_t transportReceive(void* data) {
uint8_t transportReceive(void* data)
{
if (_packet_received) {
memcpy(data,_data,_packet_len);
_packet_received = false;
return _packet_len;
}
else {
} else {
return (0);
}
}
void transportPowerDown() {
void transportPowerDown()
{
// Nothing to shut down here
}