MySensors 2.3.0 release
This commit is contained in:
@@ -160,6 +160,8 @@
|
||||
#define MY_CAP_ARCH "N"
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
#define MY_CAP_ARCH "E"
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define MY_CAP_ARCH "F"
|
||||
#elif defined(ARDUINO_ARCH_AVR)
|
||||
#define MY_CAP_ARCH "A"
|
||||
#elif defined(ARDUINO_ARCH_STM32F1)
|
||||
@@ -216,14 +218,14 @@
|
||||
* @def MY_CAP_ENCR
|
||||
* @brief Indicate the encryption setting.
|
||||
*
|
||||
* @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION
|
||||
* @see MY_ENCRYPTION_FEATURE
|
||||
*
|
||||
* | Setting | Indicator
|
||||
* |------------|----------
|
||||
* | Enabled | X
|
||||
* | Disabled | -
|
||||
*/
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined (MY_NRF5_ESB_ENABLE_ENCRYPTION)
|
||||
#if defined(MY_ENCRYPTION_FEATURE)
|
||||
#define MY_CAP_ENCR "X"
|
||||
#else
|
||||
#define MY_CAP_ENCR "-"
|
||||
|
||||
@@ -22,6 +22,35 @@
|
||||
// global variables
|
||||
extern MyMessage _msgTmp;
|
||||
|
||||
// housekeeping, remove for 3.0.0
|
||||
#ifdef MY_ESP8266_SSID
|
||||
#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead!
|
||||
#define MY_WIFI_SSID MY_ESP8266_SSID
|
||||
#undef MY_ESP8266_SSID // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_PASSWORD
|
||||
#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead!
|
||||
#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD
|
||||
#undef MY_ESP8266_PASSWORD // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_BSSID
|
||||
#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead!
|
||||
#define MY_WIFI_BSSID MY_ESP8266_BSSID
|
||||
#undef MY_ESP8266_BSSID // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_HOSTNAME
|
||||
#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead!
|
||||
#define MY_HOSTNAME MY_ESP8266_HOSTNAME
|
||||
#undef MY_ESP8266_HOSTNAME // cleanup
|
||||
#endif
|
||||
|
||||
#ifndef MY_WIFI_BSSID
|
||||
#define MY_WIFI_BSSID NULL
|
||||
#endif
|
||||
|
||||
#if defined(MY_CONTROLLER_IP_ADDRESS)
|
||||
IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
|
||||
#endif
|
||||
@@ -30,14 +59,14 @@ IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS);
|
||||
IPAddress _ethernetGatewayIP(MY_IP_ADDRESS);
|
||||
#if defined(MY_IP_GATEWAY_ADDRESS)
|
||||
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
|
||||
#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
// Assume the gateway will be the machine on the same network as the local IP
|
||||
// but with last octet being '1'
|
||||
IPAddress _gatewayIp(_ethernetGatewayIP[0], _ethernetGatewayIP[1], _ethernetGatewayIP[2], 1);
|
||||
#endif /* End of MY_IP_GATEWAY_ADDRESS */
|
||||
#if defined(MY_IP_SUBNET_ADDRESS)
|
||||
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
|
||||
#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
IPAddress _subnetIp(255, 255, 255, 0);
|
||||
#endif /* End of MY_IP_SUBNET_ADDRESS */
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
@@ -57,12 +86,12 @@ typedef struct {
|
||||
uint8_t idx;
|
||||
} inputBuffer;
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
// Some re-defines to make code more readable below
|
||||
#define EthernetServer WiFiServer
|
||||
#define EthernetClient WiFiClient
|
||||
#define EthernetUDP WiFiUDP
|
||||
#endif /* End of MY_GATEWAY_ESP8266 */
|
||||
#endif
|
||||
|
||||
#if defined(MY_GATEWAY_CLIENT_MODE)
|
||||
#if defined(MY_USE_UDP)
|
||||
@@ -81,7 +110,7 @@ static inputBuffer inputString;
|
||||
#else
|
||||
static EthernetClient client = EthernetClient();
|
||||
#endif /* End of MY_USE_UDP */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_CLIENT_MODE */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || 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];
|
||||
@@ -116,29 +145,31 @@ void _w5100_spi_en(bool enable)
|
||||
bool gatewayTransportInit(void)
|
||||
{
|
||||
_w5100_spi_en(true);
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_ESP8266_SSID)
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
#if defined(MY_WIFI_SSID)
|
||||
// Turn off access point
|
||||
WiFi.mode(WIFI_STA);
|
||||
#if defined(MY_ESP8266_HOSTNAME)
|
||||
WiFi.hostname(MY_ESP8266_HOSTNAME);
|
||||
#endif /* End of MY_ESP8266_HOSTNAME */
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp);
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
#ifndef MY_ESP8266_BSSID
|
||||
#define MY_ESP8266_BSSID NULL
|
||||
#if defined(MY_HOSTNAME)
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
WiFi.hostname(MY_HOSTNAME);
|
||||
#elif defined(MY_GATEWAY_ESP32)
|
||||
WiFi.setHostname(MY_HOSTNAME);
|
||||
#endif
|
||||
(void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID);
|
||||
#endif
|
||||
#ifdef MY_IP_ADDRESS
|
||||
WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp);
|
||||
#endif
|
||||
(void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
wait(500);
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:CONNECTING...\n"));
|
||||
}
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:IP=%s\n"), WiFi.localIP().toString().c_str());
|
||||
#endif /* End of MY_ESP8266_SSID */
|
||||
#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:IP: %s\n"), WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
// Nothing to do here
|
||||
#else /* Else part of MY_GATEWAY_ESP8266 */
|
||||
#else
|
||||
#if defined(MY_IP_GATEWAY_ADDRESS) && defined(MY_IP_SUBNET_ADDRESS)
|
||||
// DNS server set to gateway ip
|
||||
Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP, _gatewayIp, _gatewayIp, _subnetIp);
|
||||
@@ -157,7 +188,7 @@ bool gatewayTransportInit(void)
|
||||
Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]);
|
||||
// give the Ethernet interface a second to initialize
|
||||
delay(1000);
|
||||
#endif /* End of MY_GATEWAY_ESP8266 */
|
||||
#endif /* MY_GATEWAY_ESP8266 / MY_GATEWAY_ESP32 */
|
||||
|
||||
#if defined(MY_GATEWAY_CLIENT_MODE)
|
||||
#if defined(MY_USE_UDP)
|
||||
@@ -236,7 +267,7 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
#endif /* End of MY_USE_UDP */
|
||||
#else /* Else part of MY_GATEWAY_CLIENT_MODE */
|
||||
// Send message to connected clients
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
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));
|
||||
@@ -253,7 +284,7 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
#if defined(MY_USE_UDP)
|
||||
// Nothing to do here
|
||||
#else
|
||||
#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE)
|
||||
#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE)
|
||||
bool _readFromClient(uint8_t i)
|
||||
{
|
||||
while (clients[i].connected() && clients[i].available()) {
|
||||
@@ -366,7 +397,7 @@ bool gatewayTransportAvailable(void)
|
||||
}
|
||||
#endif /* End of MY_USE_UDP */
|
||||
#else /* Else part of MY_GATEWAY_CLIENT_MODE */
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || 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;
|
||||
@@ -443,7 +474,7 @@ MyMessage& gatewayTransportReceive(void)
|
||||
return _ethernetMsg;
|
||||
}
|
||||
|
||||
#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_LINUX)
|
||||
#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_ESP32) && !defined(MY_GATEWAY_LINUX)
|
||||
void gatewayTransportRenewIP(void)
|
||||
{
|
||||
/* renew/rebind IP address
|
||||
|
||||
@@ -22,6 +22,35 @@
|
||||
|
||||
#include "MyGatewayTransport.h"
|
||||
|
||||
// housekeeping, remove for 3.0.0
|
||||
#ifdef MY_ESP8266_SSID
|
||||
#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead!
|
||||
#define MY_WIFI_SSID MY_ESP8266_SSID
|
||||
#undef MY_ESP8266_SSID // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_PASSWORD
|
||||
#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead!
|
||||
#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD
|
||||
#undef MY_ESP8266_PASSWORD // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_BSSID
|
||||
#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead!
|
||||
#define MY_WIFI_BSSID MY_ESP8266_BSSID
|
||||
#undef MY_ESP8266_BSSID // cleanup
|
||||
#endif
|
||||
|
||||
#ifdef MY_ESP8266_HOSTNAME
|
||||
#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead!
|
||||
#define MY_HOSTNAME MY_ESP8266_HOSTNAME
|
||||
#undef MY_ESP8266_HOSTNAME // cleanup
|
||||
#endif
|
||||
|
||||
#ifndef MY_WIFI_BSSID
|
||||
#define MY_WIFI_BSSID NULL
|
||||
#endif
|
||||
|
||||
#if defined MY_CONTROLLER_IP_ADDRESS
|
||||
IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS);
|
||||
#endif
|
||||
@@ -30,19 +59,20 @@ IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS);
|
||||
IPAddress _MQTT_clientIp(MY_IP_ADDRESS);
|
||||
#if defined(MY_IP_GATEWAY_ADDRESS)
|
||||
IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS);
|
||||
#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
// Assume the gateway will be the machine on the same network as the local IP
|
||||
// but with last octet being '1'
|
||||
IPAddress _gatewayIp(_MQTT_clientIp[0], _MQTT_clientIp[1], _MQTT_clientIp[2], 1);
|
||||
#endif /* End of MY_IP_GATEWAY_ADDRESS */
|
||||
|
||||
#if defined(MY_IP_SUBNET_ADDRESS)
|
||||
IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS);
|
||||
#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */
|
||||
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
IPAddress _subnetIp(255, 255, 255, 0);
|
||||
#endif /* End of MY_IP_SUBNET_ADDRESS */
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
#define EthernetClient WiFiClient
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
// Nothing to do here
|
||||
@@ -50,8 +80,24 @@ IPAddress _subnetIp(255, 255, 255, 0);
|
||||
uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS };
|
||||
#endif /* End of MY_GATEWAY_ESP8266 */
|
||||
|
||||
#if defined(MY_GATEWAY_TINYGSM)
|
||||
#if defined(MY_GSM_RX) && defined(MY_GSM_TX)
|
||||
SoftwareSerial SerialAT(MY_GSM_RX, MY_GSM_TX);
|
||||
#endif
|
||||
static TinyGsm modem(SerialAT);
|
||||
static TinyGsmClient _MQTT_gsmClient(modem);
|
||||
static PubSubClient _MQTT_client(_MQTT_gsmClient);
|
||||
#if defined(MY_GSM_BAUDRATE)
|
||||
uint32_t rate = MY_GSM_BAUDRATE;
|
||||
#else /* Else part of MY_GSM_BAUDRATE */
|
||||
uint32_t rate = 0;
|
||||
#endif /* End of MY_GSM_BAUDRATE */
|
||||
#else /* Else part of MY_GATEWAY_TINYGSM */
|
||||
static EthernetClient _MQTT_ethClient;
|
||||
static PubSubClient _MQTT_client(_MQTT_ethClient);
|
||||
#endif /* End of MY_GATEWAY_TINYGSM */
|
||||
|
||||
|
||||
static bool _MQTT_connecting = true;
|
||||
static bool _MQTT_available = false;
|
||||
static MyMessage _MQTT_msg;
|
||||
@@ -104,17 +150,19 @@ bool reconnectMQTT(void)
|
||||
|
||||
bool gatewayTransportConnect(void)
|
||||
{
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
wait(500);
|
||||
GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING...\n"));
|
||||
}
|
||||
GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"),WiFi.localIP().toString().c_str());
|
||||
#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */
|
||||
#elif defined(MY_GATEWAY_LINUX)
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
_MQTT_ethClient.bind(_MQTT_clientIp);
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
#else /* Else part of MY_GATEWAY_ESP8266 */
|
||||
#elif defined(MY_GATEWAY_TINYGSM)
|
||||
GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"), modem.getLocalIP().c_str());
|
||||
#else
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp);
|
||||
#else /* Else part of MY_IP_ADDRESS */
|
||||
@@ -130,13 +178,53 @@ bool gatewayTransportConnect(void)
|
||||
Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]);
|
||||
// give the Ethernet interface a second to initialize
|
||||
delay(1000);
|
||||
#endif /* End of MY_GATEWAY_ESP8266 */
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gatewayTransportInit(void)
|
||||
{
|
||||
_MQTT_connecting = true;
|
||||
|
||||
#if defined(MY_GATEWAY_TINYGSM)
|
||||
|
||||
#if !defined(MY_GSM_BAUDRATE)
|
||||
rate = TinyGsmAutoBaud(SerialAT);
|
||||
#endif /* End of MY_GSM_BAUDRATE */
|
||||
|
||||
SerialAT.begin(rate);
|
||||
delay(3000);
|
||||
|
||||
modem.restart();
|
||||
|
||||
#if defined(MY_GSM_PIN) && !defined(TINY_GSM_MODEM_ESP8266)
|
||||
modem.simUnlock(MY_GSM_PIN);
|
||||
#endif /* End of MY_GSM_PIN */
|
||||
|
||||
#ifndef TINY_GSM_MODEM_ESP8266
|
||||
if (!modem.waitForNetwork()) {
|
||||
GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
|
||||
while (true);
|
||||
}
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
|
||||
|
||||
if (!modem.gprsConnect(MY_GSM_APN, MY_GSM_USR, MY_GSM_PSW)) {
|
||||
GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
|
||||
while (true);
|
||||
}
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
|
||||
delay(1000);
|
||||
#else /* Else part of TINY_GSM_MODEM_ESP8266 */
|
||||
if (!modem.networkConnect(MY_GSM_SSID, MY_GSM_PSW)) {
|
||||
GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n"));
|
||||
while (true);
|
||||
}
|
||||
GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n"));
|
||||
delay(1000);
|
||||
#endif /* End of TINY_GSM_MODEM_ESP8266 */
|
||||
|
||||
#endif /* End of MY_GATEWAY_TINYGSM */
|
||||
|
||||
#if defined(MY_CONTROLLER_IP_ADDRESS)
|
||||
_MQTT_client.setServer(_brokerIp, MY_PORT);
|
||||
#else
|
||||
@@ -148,17 +236,30 @@ bool gatewayTransportInit(void)
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
// Turn off access point
|
||||
WiFi.mode(WIFI_STA);
|
||||
#if defined(MY_ESP8266_HOSTNAME)
|
||||
WiFi.hostname(MY_ESP8266_HOSTNAME);
|
||||
#if defined(MY_HOSTNAME)
|
||||
WiFi.hostname(MY_HOSTNAME);
|
||||
#endif /* End of MY_ESP8266_HOSTNAME */
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp);
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
#ifndef MY_ESP8266_BSSID
|
||||
#define MY_ESP8266_BSSID NULL
|
||||
#ifndef MY_WIFI_BSSID
|
||||
#define MY_WIFI_BSSID NULL
|
||||
#endif
|
||||
(void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
|
||||
#elif defined(MY_GATEWAY_ESP32)
|
||||
// Turn off access point
|
||||
WiFi.mode(WIFI_STA);
|
||||
#if defined(MY_HOSTNAME)
|
||||
WiFi.setHostname(MY_HOSTNAME);
|
||||
#endif /* End of MY_HOSTNAME */
|
||||
#if defined(MY_IP_ADDRESS)
|
||||
WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp);
|
||||
#endif /* End of MY_IP_ADDRESS */
|
||||
#ifndef MY_WIFI_BSSID
|
||||
#define MY_WIFI_BSSID NULL
|
||||
#endif
|
||||
(void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
|
||||
#endif
|
||||
(void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID);
|
||||
#endif /* End of MY_GATEWAY_ESP8266 */
|
||||
|
||||
gatewayTransportConnect();
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ const char* MyMessage::getString() const
|
||||
}
|
||||
}
|
||||
|
||||
// handles single character hex (0 - 15)
|
||||
char MyMessage::i2h(uint8_t i) const
|
||||
{
|
||||
uint8_t k = i & 0x0F;
|
||||
|
||||
+182
-39
@@ -50,6 +50,7 @@ typedef enum {
|
||||
C_STREAM = 4 //!< For firmware and other larger chunks of data that need to be divided into pieces.
|
||||
} mysensor_command;
|
||||
|
||||
#if !DOXYGEN // Hide until we migrate
|
||||
/// @brief Type of sensor (used when presenting sensors)
|
||||
typedef enum {
|
||||
S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED
|
||||
@@ -158,6 +159,7 @@ typedef enum {
|
||||
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;
|
||||
#endif
|
||||
|
||||
|
||||
/// @brief Type of internal messages (for internal messages)
|
||||
@@ -206,7 +208,9 @@ typedef enum {
|
||||
ST_FIRMWARE_REQUEST = 2, //!< Request FW block
|
||||
ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
|
||||
ST_SOUND = 4, //!< Sound
|
||||
ST_IMAGE = 5 //!< Image
|
||||
ST_IMAGE = 5, //!< Image
|
||||
ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
|
||||
ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data
|
||||
} mysensor_stream;
|
||||
|
||||
/// @brief Type of payload
|
||||
@@ -275,23 +279,37 @@ typedef enum {
|
||||
#define miGetPayloadType() (uint8_t)BF_GET(command_ack_payload, 5, 3) //!< Internal getter for payload type field
|
||||
|
||||
|
||||
#if !DOXYGEN
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief MyMessage is used to create, manipulate, send and read MySensors messages
|
||||
*/
|
||||
class MyMessage
|
||||
{
|
||||
private:
|
||||
char* getCustomString(char *buffer) const;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
MyMessage();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param sensor id of the child sensor for this message
|
||||
* @param type see http://korturl.nu/stupidurl
|
||||
*/
|
||||
MyMessage(uint8_t sensor, uint8_t type);
|
||||
|
||||
/**
|
||||
* Single character hex (0 - 15) conversion
|
||||
* @param i byte (only lower 4 bits will be considered)
|
||||
* @return single char with the hex representation (0 to F) of the parameter
|
||||
*/
|
||||
char i2h(uint8_t i) const;
|
||||
|
||||
/**
|
||||
* Clear message contents.
|
||||
* @brief Clear message contents.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
@@ -299,42 +317,158 @@ public:
|
||||
* If payload is something else than P_STRING you can have the payload value converted
|
||||
* into string representation by supplying a buffer with the minimum size of
|
||||
* 2*MAX_PAYLOAD+1. This is to be able to fit hex-conversion of a full binary payload.
|
||||
* @param buffer pointer to a buffer that's at least 2*MAX_PAYLOAD+1 bytes large
|
||||
*/
|
||||
char* getStream(char *buffer) const;
|
||||
|
||||
/**
|
||||
* @brief Copy the payload into the supplied buffer
|
||||
*/
|
||||
char* getString(char *buffer) const;
|
||||
|
||||
/**
|
||||
* @brief Get payload as string
|
||||
* @return pointer to a char array storing the string
|
||||
*/
|
||||
const char* getString() const;
|
||||
|
||||
/**
|
||||
* @brief Get custom payload
|
||||
* @return pointer to the raw payload
|
||||
*/
|
||||
void* getCustom() const;
|
||||
|
||||
/**
|
||||
* @brief Get bool payload
|
||||
* @return a bool with the value of the payload (true/false)
|
||||
*/
|
||||
bool getBool() const;
|
||||
|
||||
/**
|
||||
* @brief Get unsigned 8-bit integer payload
|
||||
* @return the value of the payload, 0 to 255
|
||||
*/
|
||||
uint8_t getByte() const;
|
||||
|
||||
/**
|
||||
* @brief Get float payload
|
||||
* @return the floating-point value of the payload
|
||||
*/
|
||||
float getFloat() const;
|
||||
|
||||
/**
|
||||
* @brief Get signed 16-bit integer payload
|
||||
* @return the value of the payload, –32768 to 32767
|
||||
*/
|
||||
int16_t getInt() const;
|
||||
|
||||
/**
|
||||
* @brief Get unsigned 16-bit integer payload
|
||||
* @return the value of the payload, 0 to 65535
|
||||
*/
|
||||
uint16_t getUInt() const;
|
||||
|
||||
/**
|
||||
* @brief Get signed 32-bit integer payload
|
||||
* @return the value of the payload, –2147483648 to 2147483647
|
||||
*/
|
||||
int32_t getLong() const;
|
||||
|
||||
/**
|
||||
* @brief Get unsigned 32-bit integer payload
|
||||
* @return the value of the payload, 0 to 4294967295
|
||||
*/
|
||||
uint32_t getULong() const;
|
||||
|
||||
// Getter for command type
|
||||
/**
|
||||
* @brief Getter for command type
|
||||
* @return #mysensor_command
|
||||
*/
|
||||
uint8_t getCommand() const;
|
||||
|
||||
// Getter for ack-flag. True if this is an ack message.
|
||||
/**
|
||||
* @brief Getter for ack-flag.
|
||||
* @return true if this is an ack message
|
||||
*/
|
||||
bool isAck() const;
|
||||
|
||||
// Setters for building message "on the fly"
|
||||
/**
|
||||
* @brief Set message type
|
||||
* @param type see http://korturl.nu/stupidurl
|
||||
*/
|
||||
MyMessage& setType(uint8_t type);
|
||||
|
||||
/**
|
||||
* @brief Set which child sensor this message belongs to
|
||||
*/
|
||||
MyMessage& setSensor(uint8_t sensor);
|
||||
|
||||
/**
|
||||
* @brief Set final destination node id for this message
|
||||
*/
|
||||
MyMessage& setDestination(uint8_t destination);
|
||||
|
||||
// Setters for payload
|
||||
/**
|
||||
* @brief Set entire payload
|
||||
* @param payload pointer to the buffer where the payload is stored
|
||||
* @param length of the payload
|
||||
*/
|
||||
MyMessage& set(void* payload, uint8_t length);
|
||||
|
||||
/**
|
||||
* @brief Set payload to character array
|
||||
* @param value pointer to the character array. The array must be null-terminated.
|
||||
*/
|
||||
MyMessage& set(const char* value);
|
||||
#if !defined(__linux__)
|
||||
/**
|
||||
* @brief Set payload to character array from flash
|
||||
* @param value pointer to the character array. The array must be null-terminated.
|
||||
*/
|
||||
MyMessage& set(const __FlashStringHelper* value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set payload to decimal number
|
||||
* @param value float
|
||||
* @param decimals number of decimals to include
|
||||
*/
|
||||
MyMessage& set(float value, uint8_t decimals);
|
||||
|
||||
/**
|
||||
* @brief Set payload to bool value
|
||||
* @param value true or false
|
||||
*/
|
||||
MyMessage& set(bool value);
|
||||
|
||||
/**
|
||||
* @brief Set payload to unsigned 8-bit integer value
|
||||
* @param value (0 to 255)
|
||||
*/
|
||||
MyMessage& set(uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Set payload to unsigned 32-bit integer value
|
||||
* @param value (0 to 4294967295)
|
||||
*/
|
||||
MyMessage& set(uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Set payload to signed 32-bit integer value
|
||||
* @param value (–2147483648 to 2147483647)
|
||||
*/
|
||||
MyMessage& set(int32_t value);
|
||||
|
||||
/**
|
||||
* @brief Set payload to unsigned 16-bit integer value
|
||||
* @param value (0 to 65535)
|
||||
*/
|
||||
MyMessage& set(uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Set payload to signed 16-bit integer value
|
||||
* @param value (–32768 to 32767)
|
||||
*/
|
||||
MyMessage& set(int16_t value);
|
||||
|
||||
#else
|
||||
@@ -343,47 +477,56 @@ typedef union {
|
||||
struct {
|
||||
|
||||
#endif
|
||||
uint8_t last; // 8 bit - Id of last node this message passed
|
||||
uint8_t sender; // 8 bit - Id of sender node (origin)
|
||||
uint8_t destination; // 8 bit - Id of destination node
|
||||
uint8_t last; ///< 8 bit - Id of last node this message passed
|
||||
uint8_t sender; ///< 8 bit - Id of sender node (origin)
|
||||
uint8_t destination; ///< 8 bit - Id of destination node
|
||||
|
||||
uint8_t version_length; // 2 bit - Protocol version
|
||||
// 1 bit - Signed flag
|
||||
// 5 bit - Length of payload
|
||||
uint8_t command_ack_payload; // 3 bit - Command type
|
||||
// 1 bit - Request an ack - Indicator that receiver should send an ack back.
|
||||
// 1 bit - Is ack message - 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.
|
||||
/**
|
||||
* 2 bit - Protocol version<br>
|
||||
* 1 bit - Signed flag<br>
|
||||
* 5 bit - Length of payload
|
||||
*/
|
||||
uint8_t version_length;
|
||||
|
||||
// Each message can transfer a payload. We add one extra byte for string
|
||||
// terminator \0 to be "printable" this is not transferred OTA
|
||||
// This union is used to simplify the construction of the binary data types transferred.
|
||||
/**
|
||||
* 3 bit - Command type<br>
|
||||
* 1 bit - Request an ack - Indicator that receiver should send an ack back<br>
|
||||
* 1 bit - Is ack message - Indicator that this is the actual ack message<br>
|
||||
* 3 bit - Payload data type
|
||||
*/
|
||||
uint8_t command_ack_payload;
|
||||
|
||||
uint8_t type; ///< 8 bit - Type varies depending on command
|
||||
uint8_t sensor; ///< 8 bit - Id of sensor that this message concerns.
|
||||
|
||||
/*
|
||||
* Each message can transfer a payload. We add one extra byte for string
|
||||
* terminator \0 to be "printable" this is not transferred OTA
|
||||
* This union is used to simplify the construction of the binary data types transferred.
|
||||
*/
|
||||
union {
|
||||
uint8_t bValue;
|
||||
uint16_t uiValue;
|
||||
int16_t iValue;
|
||||
uint32_t ulValue;
|
||||
int32_t lValue;
|
||||
struct { // Float messages
|
||||
uint8_t bValue; ///< unsigned byte value (8-bit)
|
||||
uint16_t uiValue; ///< unsigned integer value (16-bit)
|
||||
int16_t iValue; ///< signed integer value (16-bit)
|
||||
uint32_t ulValue; ///< unsigned long value (32-bit)
|
||||
int32_t lValue; ///< signed long value (32-bit)
|
||||
struct { //< Float messages
|
||||
float fValue;
|
||||
uint8_t fPrecision; // Number of decimals when serializing
|
||||
uint8_t fPrecision; ///< Number of decimals when serializing
|
||||
};
|
||||
struct { // Presentation messages
|
||||
uint8_t version; // Library version
|
||||
uint8_t sensorType; // Sensor type hint for controller, see table above
|
||||
struct { //< Presentation messages
|
||||
uint8_t version; ///< Library version
|
||||
uint8_t sensorType; ///< Sensor type hint for controller, see table above
|
||||
};
|
||||
char data[MAX_PAYLOAD + 1];
|
||||
} __attribute__((packed));
|
||||
#ifdef __cplusplus
|
||||
char data[MAX_PAYLOAD + 1]; ///< Buffer for raw payload data
|
||||
} __attribute__((packed)); ///< Doxygen will complain without this comment
|
||||
#if defined(__cplusplus) || defined(DOXYGEN)
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
};
|
||||
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1];
|
||||
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; ///< buffer for entire message
|
||||
} __attribute__((packed)) MyMessage;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/** @}*/
|
||||
|
||||
+144
-66
@@ -26,15 +26,30 @@ extern MyMessage _msgTmp;
|
||||
// local variables
|
||||
#ifdef MY_OTA_USE_I2C_EEPROM
|
||||
I2CEeprom _flash(MY_OTA_I2C_ADDR);
|
||||
#else
|
||||
#elif !defined(MCUBOOT_PRESENT)
|
||||
SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
|
||||
#endif
|
||||
|
||||
// Map flash functions
|
||||
#ifndef MCUBOOT_PRESENT
|
||||
#define _flash_initialize() _flash.initialize()
|
||||
#define _flash_readByte(addr) _flash.readByte(addr)
|
||||
#define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size)
|
||||
#define _flash_blockErase32K(num) _flash.blockErase32K(num)
|
||||
#define _flash_busy() _flash.busy()
|
||||
#else
|
||||
#define _flash_initialize() true
|
||||
#define _flash_readByte(addr) (*((uint8_t *)(addr)))
|
||||
#define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0)
|
||||
#define _flash_busy() false
|
||||
#endif
|
||||
|
||||
LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig;
|
||||
LOCAL bool _firmwareUpdateOngoing = false;
|
||||
LOCAL uint32_t _firmwareLastRequest;
|
||||
LOCAL uint16_t _firmwareBlock;
|
||||
LOCAL uint8_t _firmwareRetry;
|
||||
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data);
|
||||
|
||||
LOCAL void readFirmwareSettings(void)
|
||||
{
|
||||
@@ -83,15 +98,15 @@ LOCAL bool firmwareOTAUpdateProcess(void)
|
||||
// copy new FW config
|
||||
(void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
|
||||
// Init flash
|
||||
if (!_flash.initialize()) {
|
||||
if (!_flash_initialize()) {
|
||||
setIndication(INDICATION_ERR_FW_FLASH_INIT);
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
|
||||
_firmwareUpdateOngoing = false;
|
||||
} else {
|
||||
// erase lower 32K -> max flash size for ATMEGA328
|
||||
_flash.blockErase32K(0);
|
||||
_flash_blockErase32K(0);
|
||||
// wait until flash erased
|
||||
while ( _flash.busy() ) {}
|
||||
while ( _flash_busy() ) {}
|
||||
_firmwareBlock = _nodeFirmwareConfig.blocks;
|
||||
_firmwareUpdateOngoing = true;
|
||||
// reset flags
|
||||
@@ -102,68 +117,46 @@ LOCAL bool firmwareOTAUpdateProcess(void)
|
||||
}
|
||||
OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available
|
||||
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
|
||||
if (_firmwareUpdateOngoing) {
|
||||
// extract FW block
|
||||
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
|
||||
|
||||
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), firmwareResponse->block); // received FW block
|
||||
if (firmwareResponse->block != _firmwareBlock - 1) {
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
|
||||
// wrong firmware block received
|
||||
setIndication(INDICATION_FW_UPDATE_RX_ERR);
|
||||
// no further processing required
|
||||
return true;
|
||||
}
|
||||
setIndication(INDICATION_FW_UPDATE_RX);
|
||||
// Save block to flash
|
||||
_flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
|
||||
firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
|
||||
// wait until flash written
|
||||
while (_flash.busy()) {}
|
||||
#ifdef OTA_EXTRA_FLASH_DEBUG
|
||||
{
|
||||
char prbuf[8];
|
||||
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
|
||||
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
|
||||
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
|
||||
MY_SERIALDEVICE.print(prbuf);
|
||||
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
|
||||
uint8_t data = _flash.readByte(addr + i);
|
||||
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
|
||||
MY_SERIALDEVICE.print(prbuf);
|
||||
}
|
||||
OTA_DEBUG(PSTR("\n"));
|
||||
}
|
||||
#endif
|
||||
_firmwareBlock--;
|
||||
if (!_firmwareBlock) {
|
||||
// We're done! Do a checksum and reboot.
|
||||
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
|
||||
_firmwareUpdateOngoing = false;
|
||||
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));
|
||||
// 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),':'};
|
||||
_flash.writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
|
||||
// wait until flash ready
|
||||
while (_flash.busy()) {}
|
||||
hwReboot();
|
||||
} else {
|
||||
setIndication(INDICATION_ERR_FW_CHECKSUM);
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
|
||||
}
|
||||
}
|
||||
// reset flags
|
||||
_firmwareRetry = MY_OTA_RETRY + 1;
|
||||
_firmwareLastRequest = 0;
|
||||
} else {
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
|
||||
// extract FW block
|
||||
replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
|
||||
// Proceed firmware data
|
||||
return _firmwareResponse(firmwareResponse->block, firmwareResponse->data);
|
||||
#ifdef FIRMWARE_PROTOCOL_31
|
||||
} else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) {
|
||||
// RLE encoded block
|
||||
// extract FW block
|
||||
replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data;
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE];
|
||||
for (uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
|
||||
data[i]=firmwareResponse->data;
|
||||
}
|
||||
while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) {
|
||||
_firmwareResponse(firmwareResponse->block, data);
|
||||
firmwareResponse->number_of_blocks--;
|
||||
firmwareResponse->block--;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef MCUBOOT_PRESENT
|
||||
if (_msg.type == ST_FIRMWARE_CONFIRM) {
|
||||
if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) {
|
||||
if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) {
|
||||
// Calculate data word to write
|
||||
uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise
|
||||
uint32_t img_ok_data = *img_ok_base_addr;
|
||||
// Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01)
|
||||
uint8_t * img_ok_array = (uint8_t*)(&img_ok_data);
|
||||
img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE;
|
||||
// Write word back
|
||||
Flash.write(img_ok_base_addr, img_ok_data);
|
||||
}
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n"));
|
||||
} else {
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -178,6 +171,18 @@ LOCAL void presentBootloaderInformation(void)
|
||||
(void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t));
|
||||
// add bootloader information
|
||||
requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
|
||||
#ifdef FIRMWARE_PROTOCOL_31
|
||||
requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE;
|
||||
#ifndef MCUBOOT_PRESENT
|
||||
requestFirmwareConfig->img_commited = 0x2;
|
||||
requestFirmwareConfig->img_revision = 0x00;
|
||||
requestFirmwareConfig->img_build_num = 0x00;
|
||||
#else
|
||||
requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR));
|
||||
requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR));
|
||||
requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR));
|
||||
#endif
|
||||
#endif
|
||||
_firmwareUpdateOngoing = false;
|
||||
(void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
|
||||
ST_FIRMWARE_CONFIG_REQUEST, false));
|
||||
@@ -192,8 +197,8 @@ LOCAL bool transportIsValidFirmware(void)
|
||||
{
|
||||
// init crc
|
||||
uint16_t crc = ~0;
|
||||
for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
|
||||
crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET);
|
||||
for (uint32_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
|
||||
crc ^= _flash_readByte(i + FIRMWARE_START_OFFSET);
|
||||
for (int8_t j = 0; j < 8; ++j) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
@@ -207,3 +212,76 @@ LOCAL bool transportIsValidFirmware(void)
|
||||
_nodeFirmwareConfig.crc);
|
||||
return crc == _nodeFirmwareConfig.crc;
|
||||
}
|
||||
|
||||
LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data)
|
||||
{
|
||||
if (_firmwareUpdateOngoing) {
|
||||
OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block
|
||||
if (block != _firmwareBlock - 1) {
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
|
||||
// wrong firmware block received
|
||||
setIndication(INDICATION_FW_UPDATE_RX_ERR);
|
||||
// no further processing required
|
||||
return true;
|
||||
}
|
||||
setIndication(INDICATION_FW_UPDATE_RX);
|
||||
// Save block to flash
|
||||
#ifdef MCUBOOT_PRESENT
|
||||
uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)(
|
||||
FIRMWARE_START_OFFSET));
|
||||
if (addr<FLASH_AREA_IMAGE_SCRATCH_OFFSET_0) {
|
||||
Flash.write_block( (uint32_t *)addr, (uint32_t *)data, FIRMWARE_BLOCK_SIZE>>2);
|
||||
}
|
||||
#else
|
||||
_flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
|
||||
data, FIRMWARE_BLOCK_SIZE);
|
||||
#endif
|
||||
// wait until flash written
|
||||
while (_flash_busy()) {}
|
||||
#ifdef OTA_EXTRA_FLASH_DEBUG
|
||||
{
|
||||
char prbuf[8];
|
||||
uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
|
||||
OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
|
||||
sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
|
||||
MY_SERIALDEVICE.print(prbuf);
|
||||
for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
|
||||
uint8_t data = _flash_readByte(addr + i);
|
||||
sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
|
||||
MY_SERIALDEVICE.print(prbuf);
|
||||
}
|
||||
OTA_DEBUG(PSTR("\n"));
|
||||
}
|
||||
#endif
|
||||
_firmwareBlock--;
|
||||
if (!_firmwareBlock) {
|
||||
// We're done! Do a checksum and reboot.
|
||||
OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
|
||||
_firmwareUpdateOngoing = false;
|
||||
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));
|
||||
#ifndef MCUBOOT_PRESENT
|
||||
// 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),':'};
|
||||
_flash_writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
|
||||
// wait until flash ready
|
||||
while (_flash_busy()) {}
|
||||
#endif
|
||||
hwReboot();
|
||||
} else {
|
||||
setIndication(INDICATION_ERR_FW_CHECKSUM);
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
|
||||
}
|
||||
}
|
||||
// reset flags
|
||||
_firmwareRetry = MY_OTA_RETRY + 1;
|
||||
_firmwareLastRequest = 0;
|
||||
} else {
|
||||
OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -58,17 +58,36 @@
|
||||
#define MyOTAFirmwareUpdate_h
|
||||
|
||||
#include "MySensorsCore.h"
|
||||
#ifdef MCUBOOT_PRESENT
|
||||
#include "generated_dts_board.h"
|
||||
#define FIRMWARE_PROTOCOL_31
|
||||
#endif
|
||||
|
||||
#define LOCAL static //!< static
|
||||
|
||||
#if MAX_PAYLOAD >= 22
|
||||
#define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block
|
||||
#else
|
||||
#define FIRMWARE_BLOCK_SIZE (8u) //!< Size of each firmware block
|
||||
#ifndef FIRMWARE_PROTOCOL_31
|
||||
#define FIRMWARE_PROTOCOL_31
|
||||
#endif
|
||||
#endif
|
||||
#define FIRMWARE_MAX_REQUESTS (5u) //!< Number of times a firmware block should be requested before giving up
|
||||
#define MY_OTA_RETRY (5u) //!< Number of times to request a fw block before giving up
|
||||
#define MY_OTA_RETRY_DELAY (500u) //!< Number of milliseconds before re-requesting a FW block
|
||||
#ifndef MCUBOOT_PRESENT
|
||||
#define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first)
|
||||
#else
|
||||
#define FIRMWARE_START_OFFSET (FLASH_AREA_IMAGE_1_OFFSET_0) //!< Use offset from generated_dts_board.h (mcuboot)
|
||||
#endif
|
||||
|
||||
#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major
|
||||
#ifdef FIRMWARE_PROTOCOL_31
|
||||
#define MY_OTA_BOOTLOADER_MINOR_VERSION (1u) //!< Bootloader version minor
|
||||
#else
|
||||
#define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor
|
||||
#endif
|
||||
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version
|
||||
|
||||
#if defined(MY_DEBUG_VERBOSE_OTA_UPDATE)
|
||||
@@ -77,6 +96,18 @@
|
||||
#else
|
||||
#define OTA_DEBUG(x,...) //!< debug NULL
|
||||
#endif
|
||||
|
||||
#if defined(DOXYGEN) && !defined(FIRMWARE_PROTOCOL_31)
|
||||
/**
|
||||
* @brief Enabled FOTA 3.1 protocol extensions
|
||||
*
|
||||
* Supports smaller FIRMWARE_BLOCK_SIZE, RLE and NVM for nRF5 with mcuboot. The
|
||||
* extension is enabled per default when mcuboot is present or full FIRMWARE_BLOCK_SIZE
|
||||
* exeeds MAX_PAYLOAD.
|
||||
*/
|
||||
#define FIRMWARE_PROTOCOL_31
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FW config structure, stored in eeprom
|
||||
*/
|
||||
@@ -96,6 +127,12 @@ typedef struct {
|
||||
uint16_t blocks; //!< Number of blocks
|
||||
uint16_t crc; //!< CRC of block data
|
||||
uint16_t BLVersion; //!< Bootloader version
|
||||
#ifdef FIRMWARE_PROTOCOL_31
|
||||
uint8_t blockSize; //!< Blocksize, when protocol version >= 3.1 is reported. Otherwhise the blocksize is 16
|
||||
uint8_t img_commited; //!< mcuboot image_ok attribute commited firmware=0x01(mcuboot)|0x02(DualOptiboot), when protocol version >= 3.1 is reported
|
||||
uint16_t img_revision; //!< mcuboot revision attribute, when protocol version >= 3.1 is reported
|
||||
uint32_t img_build_num; //!< mcuboot build_num attribute, when protocol version >= 3.1 is reported
|
||||
#endif
|
||||
} __attribute__((packed)) requestFirmwareConfig_t;
|
||||
|
||||
/**
|
||||
@@ -117,6 +154,16 @@ typedef struct {
|
||||
uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data
|
||||
} __attribute__((packed)) replyFirmwareBlock_t;
|
||||
|
||||
/**
|
||||
* @brief FW block reply structure (RLE)
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t type; //!< Type of config
|
||||
uint16_t version; //!< Version of config
|
||||
uint16_t block; //!< Block index
|
||||
uint16_t number_of_blocks; //!< Number of blocks to fill with data
|
||||
uint8_t data; //!< Block data
|
||||
} __attribute__((packed)) replyFirmwareBlockRLE_t;
|
||||
|
||||
/**
|
||||
* @brief Read firmware settings from EEPROM
|
||||
|
||||
@@ -36,11 +36,7 @@ void OTALog(uint8_t logNode, bool enableAck, const char *fmt, ... )
|
||||
|
||||
// create message
|
||||
va_start (args, fmt );
|
||||
#ifdef vsnprintf_P
|
||||
int n = vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#else
|
||||
int n = vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#endif
|
||||
va_end (args);
|
||||
|
||||
// Check number of chars
|
||||
@@ -92,14 +88,9 @@ void OTALogPrintPrefix()
|
||||
{
|
||||
char prefix[37];
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
#ifdef snprintf_P
|
||||
snprintf_P(prefix, sizeof(prefix),
|
||||
PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "),
|
||||
OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis());
|
||||
#else
|
||||
snprintf(prefix, sizeof(prefix), PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "),
|
||||
OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis());
|
||||
#endif
|
||||
MY_SERIALDEVICE.print(prefix);
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -32,6 +32,7 @@
|
||||
#endif
|
||||
|
||||
// message buffers
|
||||
|
||||
MyMessage _msg; // Buffer for incoming messages
|
||||
MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others)
|
||||
|
||||
@@ -88,6 +89,14 @@ void _infiniteLoop(void)
|
||||
|
||||
void _begin(void)
|
||||
{
|
||||
#if defined(MY_CORE_ONLY)
|
||||
// initialize HW and run setup if present
|
||||
(void)hwInit();
|
||||
if (setup) {
|
||||
setup();
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
// reset wdt
|
||||
hwWatchdogReset();
|
||||
|
||||
@@ -168,7 +177,7 @@ void _begin(void)
|
||||
setup();
|
||||
}
|
||||
#if defined(MY_SENSOR_NETWORK)
|
||||
CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady());
|
||||
CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady() && transportSanityCheck());
|
||||
#else
|
||||
// no sensor network defined, call presentation & registration
|
||||
_callbackTransportReady();
|
||||
@@ -585,7 +594,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in
|
||||
#endif // MY_OTA_FIRMWARE_FEATURE
|
||||
if (smartSleep) {
|
||||
// sleeping time left?
|
||||
if (sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
|
||||
if (sleepingTimeMS > 0 && sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
|
||||
wait(sleepingMS);
|
||||
CORE_DEBUG(PSTR("!MCO:SLP:NTL\n")); // sleeping not possible, no time left
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
|
||||
+11
-2
@@ -177,6 +177,16 @@
|
||||
* personalization has finished, you just program the sketch you plan to use (with the appropriate
|
||||
* signing flags set).
|
||||
*
|
||||
* If you are using a Raspberry PI-based gateway, personalizaion is done slightly differently:
|
||||
* 1. Generate keys, execute @c mysgw with arguments
|
||||
* * To generate HMAC key @verbatim --gen-soft-hmac-key @endverbatim
|
||||
* * To generate %AES key @verbatim --gen-aes-key @endverbatim
|
||||
* * To generate a soft serial number @verbatim --gen-soft-serial @endverbatim
|
||||
* 2. Update the gateway config file with the generated keys/valeus
|
||||
* * For HMAC key @verbatim soft_hmac_key=<DATA> @endverbatim
|
||||
* * For %AES key @verbatim aes_key=<DATA> @endverbatim
|
||||
* * For soft serial number @verbatim soft_serial_key=<DATA> @endverbatim
|
||||
*
|
||||
* You are now set and ready to use message signing in your network.
|
||||
* As of now, the following restrictions will be applied to your nodes:
|
||||
* * If a node does require signing, any unsigned message sent to the node will be rejected.
|
||||
@@ -393,8 +403,7 @@
|
||||
* is to set your preferences in your sketch and personalize accordingly.
|
||||
* That is enough to enable protection from both Eve and Mallory in your network
|
||||
* although if you do not also enable encryption, Eve can eavesdrop, but not do anything about,
|
||||
* your messages (except possibly preventing them from arriving). @ref MY_SIGNING_SIMPLE_PASSWD also
|
||||
* enable encryption automatically.
|
||||
* your messages (except possibly preventing them from arriving).
|
||||
*
|
||||
* How are the messages actually affected by the signing?<br>
|
||||
* The following illustration shows what part of the message is signed, and where the signature is
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
|
||||
+2
-2
@@ -47,9 +47,9 @@
|
||||
#define STR(x) STR_HELPER(x) //!< Helper macro, STR()
|
||||
|
||||
#define MYSENSORS_LIBRARY_VERSION_MAJOR 2 //!< Major release version
|
||||
#define MYSENSORS_LIBRARY_VERSION_MINOR 2 //!< Minor release version
|
||||
#define MYSENSORS_LIBRARY_VERSION_MINOR 3 //!< Minor release version
|
||||
#define MYSENSORS_LIBRARY_VERSION_PATCH 0 //!< Patch version
|
||||
#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc
|
||||
#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "alpha" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc
|
||||
#define MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER 0xFF //!< incremental counter, starting at 0x00. 0xFF for final release
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user