fiatlux/firmware/system.c
2021-11-21 00:37:10 +01:00

128 lines
No EOL
4 KiB
C

//
// Created by jedi on 25.06.21.
//
#include "system.h"
#include "crc32.h"
#include "log.h"
#include <FreeRTOS.h>
#include <sysparam.h>
#include <spiflash.h>
#include <espressif/user_interface.h>
#include <espressif/esp_system.h>
#include <rboot/rboot.h>
#include <rboot-ota/rboot-api.h>
#include <string.h>
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
void system_clear_config() {
vPortEnterCritical();
uint32_t num_sectors = 0x2000 / sdk_flashchip.sector_size;
//uint32_t start = sdk_flashchip.chip_size - num_sectors * sdk_flashchip.sector_size;
uint32_t start = 0x00100000;
for (uint32_t i = 0; i < num_sectors; i++) {
spiflash_erase_sector(start + i * sdk_flashchip.sector_size);
}
if(sysparam_create_area(start, num_sectors, true) == SYSPARAM_OK) {
sysparam_init(start, start + 0x2000);
}
sysparam_init(start, start + 0x2000);
sdk_system_restart();
}
void system_init_config() {
uint32_t base_addr = 0x00100000;
uint32_t num_sectors;
sysparam_init(base_addr, base_addr + 0x2000);
if(sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) {
syslog("Warning: WiFi config, sysparam not initialized\n");
num_sectors = 0x2000 / sdk_flashchip.sector_size;
//base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size;
if(sysparam_create_area(base_addr, num_sectors, true) == SYSPARAM_OK) {
sysparam_init(base_addr, base_addr + 0x2000);
}
sdk_system_restart();
}
}
#define MAX_IMAGE_SIZE 0x100000 /*1MB images max at the moment */
struct {
rboot_write_status status;
uint32_t head;
uint32_t base;
uint16_t seq;
uint8_t slot;
} otaflash_context;
void system_otaflash_init() {
rboot_config conf;
conf = rboot_get_config();
otaflash_context.slot = (conf.current_rom + 1) % conf.count;
otaflash_context.base = rboot_get_slot_offset(otaflash_context.slot);
otaflash_context.status = rboot_write_init(otaflash_context.base);
otaflash_context.head = otaflash_context.base;
otaflash_context.seq = 0;
//printf("slot: %u, base: %x, sector: %u\n", otaflash_context.slot, otaflash_context.base,
// otaflash_context.status.start_sector);
}
enum return_code system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash, uint16_t *ack) {
uint32_t local_hash = crc32(data, len);
//printf("@%x seq: %u, len: %u, hash: %x =? %x\n", otaflash_context.head, seq, len, hash, local_hash);
if(hash == local_hash && otaflash_context.seq == seq) {
if(otaflash_context.head % SECTOR_SIZE == 0) {
sdk_spi_flash_erase_sector(otaflash_context.head / SECTOR_SIZE);
}
if(((uint32_t) data) % 4) {
uint32 buf[len / 4];
memcpy(buf, data, len);
sdk_spi_flash_write(otaflash_context.head, buf, len);
} else {
sdk_spi_flash_write(otaflash_context.head, (uint32_t *) data, len);
}
otaflash_context.head += len;
otaflash_context.seq++;
return OK;
} else if(hash != local_hash) {
return CHECKSUM_MISMATCH;
} else {
if(ack)
*ack = otaflash_context.seq;
return SEQUENCE_OUT_OF_ORDER;
}
}
void system_otaflash_verify_chunk(void *ctx, void *data, size_t len) {
uint32_t digest = *(uint32_t *) ctx;
digest = crc32_partial(digest, data, len);
*(uint32_t *) ctx = digest;
}
enum return_code system_otaflash_verify_and_switch(uint32_t len, uint32_t hash) {
uint32_t digest = 0;
rboot_digest_image(otaflash_context.base, min(len, MAX_IMAGE_SIZE), system_otaflash_verify_chunk, &digest);
if(hash != digest) {
syslog("OTA failed to verify firmware\r\n");
return CHECKSUM_MISMATCH;
}
vPortEnterCritical();
if(!rboot_set_current_rom(otaflash_context.slot)) {
syslog("OTA Update failed to set new rboot slot\r\n");
vPortExitCritical();
return RBOOT_SWITCH_FAILED;
}
vPortExitCritical();
return OK;
}