Files
MySensors/Bootloader/MyOtaBootloader.c
T
ToSa27 a3a401c1c7 OTA Bootloader FIND_PARENT and include binary
- move from PING to FIND_PARENT
- include compiled hex of bootloader
2014-08-20 09:44:18 +02:00

208 lines
5.7 KiB
C

#include "MyOtaBootloader.h"
int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
volatile char dummy;
EMPTY_INTERRUPT(WDT_vect);
static uint16_t calcCRCrom (const void* ptr, uint16_t len) {
uint16_t crc = ~0;
for (uint16_t i = 0; i < len; ++i)
crc = _crc16_update(crc, pgm_read_byte((uint16_t) ptr + i));
return crc;
}
static uint8_t validFirmware () {
return calcCRCrom(0, fc.blocks * FIRMWARE_BLOCK_SIZE) == fc.crc;
}
static void reboot() {
wdt_enable(WDTO_15MS);
for (;;);
}
static void startup() {
if (validFirmware()) {
wdt_disable();
clock_prescale_set(orgClockDiv);
((void(*)()) 0)();
} else
reboot();
}
static void boot_program_page(uint32_t page, uint8_t *buf) {
uint8_t sreg = SREG;
cli();
eeprom_busy_wait();
boot_page_erase(page);
boot_spm_busy_wait();
for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) {
uint16_t w = *buf++;
w += (*buf++) << 8;
boot_page_fill(page + i, w);
}
boot_page_write(page);
boot_spm_busy_wait();
boot_rww_enable();
SREG = sreg;
}
static boolean sendWrite(MyMessage message) {
return write(nc.parentNodeId, message.array, HEADER_SIZE + mGetLength(message), (message.destination == BROADCAST_ADDRESS));
}
static uint8_t sendAndWait(uint8_t reqType, uint8_t resType) {
msg.type = reqType;
for (uint8_t i = 0; i < 10; i++) {
sendWrite(msg);
for (uint16_t j = 0; j < 20; j++) {
wdt_reset();
for (uint16_t j = 0; j < 100; j++) {
wdt_reset();
uint8_t pipe;
boolean avail = available(&pipe);
if (avail && pipe<=6) {
read(rmsg.array,pipe);
if(!(mGetVersion(rmsg) == PROTOCOL_VERSION))
continue;
if (rmsg.destination == nc.nodeId) {
if (mGetCommand(rmsg) == C_INTERNAL) {
if (rmsg.type == I_FIND_PARENT_RESPONSE) {
if (rmsg.data[0] < nc.distance - 1) {
nc.distance = rmsg.data[0] + 1;
nc.parentNodeId = rmsg.sender;
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId);
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance);
}
}
}
if ((mGetCommand(rmsg) == mGetCommand(msg)) && (rmsg.type == resType))
return 1;
}
}
delaym(1);
}
}
}
return 0;
}
int main () {
asm volatile ("clr __zero_reg__");
// switch to 4 MHz
orgClockDiv = clock_prescale_get();
clock_prescale_set(F_CPU_DIV);
MCUSR = 0;
// enable watchdog to avoid deadlock
wdt_enable(WDTO_8S);
#ifdef LED_DEBUG
// enable LEDs for debugging and blink once as visual "bootloader started" sign
led_init();
blink(LED_MBOTH, 250);
#endif
#ifdef UART_DEBUG
// enable UART for debugging and send start message
uart_init();
uart_puts("Go\n");
#endif
wdt_reset();
// initialize RF module
begin();
wdt_reset();
// Read settings from EEPROM
eeprom_read_block((void*)&nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(struct NodeConfig));
wdt_reset();
msg.sender = nc.nodeId;
msg.last = nc.nodeId;
address(nc.nodeId);
msg.sensor = NODE_SENSOR_ID;
mSetLength(msg, 0);
mSetPayloadType(msg, P_STRING);
mSetAck(msg,false);
mSetVersion(msg, PROTOCOL_VERSION);
nc.distance = 255;
mSetCommand(msg, C_INTERNAL);
msg.destination = BROADCAST_ADDRESS;
if (!sendAndWait(I_FIND_PARENT, I_FIND_PARENT_RESPONSE))
// starting existing firmware if no parent responds (if firmware is valid)
// reboot();
startup();
msg.destination = GATEWAY_ADDRESS;
if (nc.nodeId == AUTO) {
openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(nc.nodeId));
if (!sendAndWait(I_ID_REQUEST, I_ID_RESPONSE))
reboot();
if (mGetPayloadType(rmsg) == P_BYTE)
nc.nodeId = rmsg.data[0];
else if (mGetPayloadType(rmsg) == P_STRING)
nc.nodeId = atoi(rmsg.data);
if (nc.nodeId == AUTO)
reboot();
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, nc.nodeId);
msg.sender = nc.nodeId;
msg.last = nc.nodeId;
address(nc.nodeId);
}
// Read settings from EEPROM
eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
mSetPayloadType(msg,P_CUSTOM);
FirmwareConfigRequest *firmwareConfigRequest = (FirmwareConfigRequest *)msg.data;
mSetLength(msg, sizeof(FirmwareConfigRequest));
mSetCommand(msg, C_STREAM);
firmwareConfigRequest->type = fc.type;
firmwareConfigRequest->version = fc.version;
if (!sendAndWait(ST_FIRMWARE_CONFIG_REQUEST, ST_FIRMWARE_CONFIG_RESPONSE))
// starting existing firmware if no firmware config response (if firmware is valid)
// reboot();
startup();
FirmwareConfigResponse *firmwareConfigResponse = (FirmwareConfigResponse *)rmsg.data;
if (firmwareConfigResponse->version == fc.version)
if (firmwareConfigResponse->blocks == fc.blocks)
if (firmwareConfigResponse->crc == fc.crc)
if (validFirmware())
startup();
fc.type = firmwareConfigResponse->type;
fc.version = firmwareConfigResponse->version;
fc.blocks = firmwareConfigResponse->blocks;
fc.crc = firmwareConfigResponse->crc;
FirmwareRequest *firmwareRequest = (FirmwareRequest *)msg.data;
mSetLength(msg, sizeof(FirmwareRequest));
firmwareRequest->type = fc.type;
firmwareRequest->version = fc.version;
for (uint16_t block = 0; block < fc.blocks; block++) {
firmwareRequest->block = block;
if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE))
reboot();
FirmwareResponse *firmwareResponse = (FirmwareResponse *)rmsg.data;
uint8_t offset = (block * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE;
memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE);
if (offset == SPM_PAGESIZE - FIRMWARE_BLOCK_SIZE)
boot_program_page((block * FIRMWARE_BLOCK_SIZE) - offset, progBuf);
}
wdt_reset();
if (validFirmware()) {
eeprom_write_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(struct FirmwareConfig));
#ifdef UART_DEBUG
uart_puts("fw ok\n");
} else {
uart_puts("fw nok\n");
#endif
}
reboot();
}