File syn_fwboot.c¶
File List > src > syntropic > system > syn_fwboot.c
Go to the documentation of this file
#if __has_include("syn_config.h")
#include "syn_config.h"
#endif
#if !defined(SYN_USE_BOOT) || SYN_USE_BOOT
#include "../port/syn_port_flash.h"
#include "../util/syn_assert.h"
#include "syn_fwboot.h"
#include "syn_fwimage.h"
#include <string.h>
/* ── Helpers ────────────────────────────────────────────────────────────── */
static SYN_Status read_header(uint32_t addr, SYN_FwImageHeader *hdr)
{
return syn_port_flash_read(addr, hdr, sizeof(*hdr));
}
static SYN_Status write_state(uint32_t addr, const SYN_FwImageHeader *hdr, uint8_t new_state)
{
SYN_FwImageHeader updated = *hdr;
updated.state = new_state;
syn_fwimage_seal_header(&updated);
/* Erase sector containing the header and rewrite */
SYN_Status st = syn_port_flash_erase(addr);
if (st != SYN_OK)
return st;
return syn_port_flash_write(addr, &updated, sizeof(updated));
}
/* ── API ────────────────────────────────────────────────────────────────── */
SYN_Status syn_fwboot_init(SYN_FwBootManager *mgr, uint32_t slot_a, uint32_t slot_b)
{
SYN_ASSERT(mgr != NULL);
memset(mgr, 0, sizeof(*mgr));
mgr->slot_addr[0] = slot_a;
mgr->slot_addr[1] = slot_b;
mgr->active_slot = SYN_FW_SLOT_NONE;
/* Read headers from flash */
read_header(slot_a, &mgr->slot_hdr[0]);
read_header(slot_b, &mgr->slot_hdr[1]);
mgr->initialized = true;
return SYN_OK;
}
uint8_t syn_fwboot_select(SYN_FwBootManager *mgr, bool rollback)
{
SYN_ASSERT(mgr != NULL && mgr->initialized);
bool valid[2];
valid[0] = syn_fwimage_header_valid(&mgr->slot_hdr[0]);
valid[1] = syn_fwimage_header_valid(&mgr->slot_hdr[1]);
/* Handle rollback: if a slot is TESTING, mark it INVALID */
if (rollback) {
for (int i = 0; i < 2; i++) {
if (valid[i] && mgr->slot_hdr[i].state == SYN_FW_STATE_TESTING) {
write_state(mgr->slot_addr[i], &mgr->slot_hdr[i], SYN_FW_STATE_INVALID);
mgr->slot_hdr[i].state = SYN_FW_STATE_INVALID;
syn_fwimage_seal_header(&mgr->slot_hdr[i]);
valid[i] = false; /* No longer bootable */
}
}
}
/* Priority 1: TESTING slot (resume testing) */
for (int i = 0; i < 2; i++) {
if (valid[i] && mgr->slot_hdr[i].state == SYN_FW_STATE_TESTING) {
mgr->active_slot = (uint8_t)i;
return (uint8_t)i;
}
}
/* Priority 2: NEW slot (first boot of update — promote to TESTING) */
for (int i = 0; i < 2; i++) {
if (valid[i] && mgr->slot_hdr[i].state == SYN_FW_STATE_NEW) {
write_state(mgr->slot_addr[i], &mgr->slot_hdr[i], SYN_FW_STATE_TESTING);
mgr->slot_hdr[i].state = SYN_FW_STATE_TESTING;
syn_fwimage_seal_header(&mgr->slot_hdr[i]);
mgr->active_slot = (uint8_t)i;
return (uint8_t)i;
}
}
/* Priority 3: CONFIRMED slot with highest version */
uint8_t best = SYN_FW_SLOT_NONE;
uint32_t best_ver = 0;
for (int i = 0; i < 2; i++) {
if (valid[i] && mgr->slot_hdr[i].state == SYN_FW_STATE_CONFIRMED) {
if (best == SYN_FW_SLOT_NONE || mgr->slot_hdr[i].version_code > best_ver) {
best = (uint8_t)i;
best_ver = mgr->slot_hdr[i].version_code;
}
}
}
mgr->active_slot = best;
return best;
}
SYN_Status syn_fwboot_confirm(SYN_FwBootManager *mgr)
{
SYN_ASSERT(mgr != NULL && mgr->initialized);
if (mgr->active_slot >= 2)
return SYN_ERROR;
SYN_FwImageHeader *hdr = &mgr->slot_hdr[mgr->active_slot];
if (hdr->state != SYN_FW_STATE_TESTING)
return SYN_ERROR;
SYN_Status st = write_state(mgr->slot_addr[mgr->active_slot], hdr, SYN_FW_STATE_CONFIRMED);
if (st == SYN_OK) {
hdr->state = SYN_FW_STATE_CONFIRMED;
syn_fwimage_seal_header(hdr);
}
return st;
}
SYN_Status syn_fwboot_refresh(SYN_FwBootManager *mgr)
{
SYN_ASSERT(mgr != NULL && mgr->initialized);
read_header(mgr->slot_addr[0], &mgr->slot_hdr[0]);
read_header(mgr->slot_addr[1], &mgr->slot_hdr[1]);
return SYN_OK;
}
#endif /* SYN_USE_BOOT */