Skip to content

Commit

Permalink
Initial untested OTA feature
Browse files Browse the repository at this point in the history
  • Loading branch information
henrikekblad committed Mar 30, 2015
1 parent c1a9a53 commit 3a59929
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 33 deletions.
10 changes: 2 additions & 8 deletions libraries/MySensors/MyConfig.h
Expand Up @@ -21,14 +21,8 @@
#define MY_OTA_FIRMWARE_FEATURE
// Slave select pin for external flash
#define MY_OTA_FLASH_SS 8
// Number of times to request a fw block before giving up
#define MY_OTA_RETRY 5
// Number of millisecons before re-request a fw block
#define MY_OTA_RETRY_DELAY 500
// Bootloader version
#define MY_OTA_BOOTLOADER_MAJOR_VERSION 2
#define MY_OTA_BOOTLOADER_MINOR_VERSION 0
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION)
// Flash jdecid
#define MY_OTA_FLASH_JDECID 0x1F65


/**********************************
Expand Down
1 change: 0 additions & 1 deletion libraries/MySensors/MyHwATMega328.h
Expand Up @@ -10,7 +10,6 @@
#include <avr/power.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/crc16.h>



Expand Down
137 changes: 114 additions & 23 deletions libraries/MySensors/MySensor.cpp
Expand Up @@ -49,21 +49,24 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw
radio(_radio),
#ifdef MY_SIGNING_FEATURE
signer(_signer),
#endif
#ifdef MY_OTA_FIRMWARE_FEATURE
flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID),
#endif
hw(_hw)
{
}


#ifdef MY_OTA_FRIMWARE_FEATURE
#ifdef MY_OTA_FIRMWARE_FEATURE
// do a crc16 on the whole received firmware
bool MySensor::isValidFirmware() {
void* ptr = 0;
uint16_t crc = ~0;
int j;

for (uint16_t i = 0; i < fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
uint8_t a = pgm_read_byte((uint16_t) ptr + i);
uint8_t a = flash.readByte((uint16_t) ptr + i + FIRMWARE_START_OFFSET);
crc ^= a;
for (j = 0; j < 8; ++j)
{
Expand Down Expand Up @@ -95,7 +98,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
hw_readConfigBlock((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig));
// Read latest received controller configuration from EEPROM
hw_readConfigBlock((void*)&cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig));
#ifdef MY_OTA_FRIMWARE_FEATURE
#ifdef MY_OTA_FIRMWARE_FEATURE
// Read firmware config from EEPROM, i.e. type, version, CRC, blocks
hw_readConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
#endif
Expand Down Expand Up @@ -189,29 +192,17 @@ void MySensor::setupNode() {
// Wait configuration reply.
wait(2000);

#ifdef MY_OTA_FRIMWARE_FEATURE
#ifdef MY_OTA_FIRMWARE_FEATURE
RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)msg.data;
mSetLength(msg, sizeof(RequestFirmwareConfig));
mSetCommand(msg, C_STREAM);
mSetPayloadType(msg,P_CUSTOM);
// copy node settings to reqFWConfig
memcpy(reqFWConfig,&fc,sizeof(NodeFirmwareConfig));
// add bootloader information
reqFWConfig->BLVersion = MYSBOOTLOADER_VERSION;

// send node config and request FW config from controller
if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE)) {
startup();
}

NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data;

// compare with current node configuration, if equal startup
if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
startup();
}


reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
fwUpdateOngoing = false;
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false));
#endif


Expand Down Expand Up @@ -408,7 +399,29 @@ boolean MySensor::process() {
hw_watchdogReset();
uint8_t to = 0;
if (!radio.available(&to))
{
#ifdef MY_OTA_FIRMWARE_FEATURE
unsigned long enter = hw_millis();
if (fwUpdateOngoing && (enter - fwLastRequestTime > MY_OTA_RETRY_DELAY)) {
if (fwRetry == 0) {
debug(PSTR("fw upd fail\n"));
// Give up. We have requested MY_OTA_RETRY times without any packet in return.
fwUpdateOngoing = false;
return false;
}
fwRetry--;
fwLastRequestTime = enter;
// Time to (re-)request firmware block from controller
RequestFWBlock *firmwareRequest = (RequestFWBlock *)msg.data;
mSetLength(msg, sizeof(RequestFWBlock));
firmwareRequest->type = fc.type;
firmwareRequest->version = fc.version;
firmwareRequest->block = (fwBlock - 1);
sendRoute(build(msg, nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false));
}
#endif
return false;
}

#ifdef MY_SIGNING_FEATURE
(void)signer.checkTimer(); // Manage signing timeout
Expand Down Expand Up @@ -567,6 +580,55 @@ boolean MySensor::process() {
return false;
}
}
#ifdef MY_OTA_FIRMWARE_FEATURE
else if (command == C_STREAM) {
if (type == ST_FIRMWARE_CONFIG_RESPONSE) {
NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)msg.data;
// compare with current node configuration, if they differ, start fw fetch process
if (memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
debug(PSTR("fw update\n"));
fwUpdateOngoing = true;
fwBlock = fc.blocks;
// copy new FW config
memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
// Init flash
if (!flash.initialize()) {
debug(PSTR("flash init fail\n"));
}

}
} else if (type == ST_FIRMWARE_RESPONSE) {
// Save block to eeprom
debug(PSTR("fw block %d\n"), fwBlock);

ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)msg.data;
// write to flash
flash.writeBytes(((fwBlock-1)*FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
fwBlock--;
if (fwBlock == 0) {
// We're finished! Do a checksum and reboot.
if (isValidFirmware()) {
debug(PSTR("fw checksum ok\n"));
// All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
uint16_t fwsize = FIRMWARE_BLOCK_SIZE*fc.blocks;
flash.writeBytes(0, "FLXIMG:", 7);
flash.writeByte(7, fwsize >> 8);
flash.writeByte(8, fwsize);
flash.writeByte(9, ':');
// Write the new firmware config to eeprom
hw_writeConfigBlock((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
hw_reboot();
} else {
debug(PSTR("fw checksum fail\n"));
}
}
}
// Make sure packet request occurs next time process() is called by timing out requestTime.
fwRetry = MY_OTA_RETRY+1;
fwLastRequestTime = 0;
return false;
}
#endif
// Call incoming message callback if available
if (msgCallback != NULL) {
msgCallback(msg);
Expand Down Expand Up @@ -613,17 +675,46 @@ void MySensor::wait(unsigned long ms) {
}

void MySensor::sleep(unsigned long ms) {
radio.powerDown();
hw.sleep(ms);
#ifdef MY_OTA_FIRMWARE_FEATURE
if (fwUpdateOngoing) {
// Do not sleep node while fw update is ongoing
process();
} else {
#endif
radio.powerDown();
hw.sleep(ms);
#ifdef MY_OTA_FIRMWARE_FEATURE
}
#endif
}

bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
#ifdef MY_OTA_FIRMWARE_FEATURE
if (fwUpdateOngoing) {
// Do not sleep node while fw update is ongoing
process();
return false;
} else {
#endif
radio.powerDown();
return hw.sleep(interrupt, mode, ms) ;
#ifdef MY_OTA_FIRMWARE_FEATURE
}
#endif
}

int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
radio.powerDown();
return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ;
#ifdef MY_OTA_FIRMWARE_FEATURE
if (fwUpdateOngoing) {
// Do not sleep node while fw update is ongoing
process();
return -1;
} else {
#endif
radio.powerDown();
return hw.sleep(interrupt1, mode1, interrupt2, mode2, ms) ;
#ifdef MY_OTA_FIRMWARE_FEATURE
}
#endif
}

21 changes: 20 additions & 1 deletion libraries/MySensors/MySensor.h
Expand Up @@ -23,6 +23,9 @@
#include "MySigningNone.h"
#endif
#include "MyMessage.h"
#ifdef MY_OTA_FIRMWARE_FEATURE
#include "utility/SPIFlash.h"
#endif
#include <stddef.h>
#include <stdarg.h>

Expand Down Expand Up @@ -78,6 +81,17 @@ struct ControllerConfig {
#define FIRMWARE_BLOCK_SIZE 16
// Number of times a firmware block should be requested before giving up
#define FIRMWARE_MAX_REQUESTS 5
// Number of times to request a fw block before giving up
#define MY_OTA_RETRY 5
// Number of millisecons before re-request a fw block
#define MY_OTA_RETRY_DELAY 500
// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first)
#define FIRMWARE_START_OFFSET 10
// Bootloader version
#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3
#define MY_OTA_BOOTLOADER_MINOR_VERSION 0
#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION)


// FW config structure, stored in eeprom
typedef struct {
Expand Down Expand Up @@ -282,6 +296,11 @@ class MySensor
ControllerConfig cc; // Configuration coming from controller
#ifdef MY_OTA_FIRMWARE_FEATURE
NodeFirmwareConfig fc;
bool fwUpdateOngoing;
unsigned long fwLastRequestTime;
uint16_t fwBlock;
uint8_t fwRetry;
SPIFlash flash;
#endif

bool repeaterMode;
Expand Down Expand Up @@ -309,7 +328,7 @@ class MySensor
void (*timeCallback)(unsigned long); // Callback for requested time messages
void (*msgCallback)(const MyMessage &); // Callback for incoming messages from other nodes and gateway.

#ifdef MY_OTA_FRIMWARE_FEATURE
#ifdef MY_OTA_FIRMWARE_FEATURE
// do a crc16 on the whole received firmware
bool isValidFirmware();
#endif
Expand Down

0 comments on commit 3a59929

Please sign in to comment.