#include "storage.h" #include "hardware/flash.h" #include "pico/flash.h" #include #include #define MAGIC 0x53425831u /* "SBX1" */ #define VERSION 3 /* 3: KEYS GEN. Older records are ignored. */ #define OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE) #define BUFSZ 512 typedef struct { uint32_t magic, version; uint32_t seed, salts[2]; int32_t gen, keys, bpm, scale, root, mono_ch, mono_oct; uint8_t on[SB_NT]; pad_t learn[NKIT]; slot_t slots[NSLOTS]; uint32_t crc; } record_t; _Static_assert(sizeof(record_t) <= BUFSZ, "record too big"); static uint32_t crc(const record_t *r){ const uint8_t *p = (const uint8_t *)r; uint32_t h = 0x811C9DC5u; size_t i; for(i = 0; i < offsetof(record_t, crc); i++) h = (h ^ p[i]) * 0x01000193u; return h; } /* defaults from app.js DEF and app */ void storage_defaults(live_t *L, slot_t *slots){ int t; memset(L, 0, sizeof *L); L->state.seed = 0x5EEDB0C5u; L->gen = 0; L->keys = 0; L->scale = -1; L->root = -1; L->energy = 64; L->drift = 32; L->bpm = 165; for(t = 0; t < SB_NT; t++) L->on[t] = 1; L->mono_ch = 1; L->mono_oct = 0; L->clock = 1; memset(slots, 0, sizeof(slot_t) * NSLOTS); } int storage_load(live_t *L, slot_t *slots){ const record_t *r = (const record_t *)(XIP_BASE + OFFSET); int t; storage_defaults(L, slots); if(r->magic != MAGIC || r->version != VERSION || r->crc != crc(r)) return 0; L->state.seed = r->seed; L->state.salts[0] = r->salts[0]; L->state.salts[1] = r->salts[1]; L->gen = r->gen; L->keys = r->keys; L->bpm = r->bpm; L->scale = r->scale; L->root = r->root; L->mono_ch = r->mono_ch; L->mono_oct = r->mono_oct; for(t = 0; t < SB_NT; t++) L->on[t] = r->on[t] ? 1 : 0; memcpy(L->learn, r->learn, sizeof L->learn); memcpy(slots, r->slots, sizeof r->slots); return 1; } static void do_write(void *buf){ flash_range_erase(OFFSET, FLASH_SECTOR_SIZE); flash_range_program(OFFSET, (const uint8_t *)buf, BUFSZ); } int storage_save(const live_t *L, const slot_t *slots){ static uint8_t buf[BUFSZ] __attribute__((aligned(4))); record_t *r = (record_t *)buf; memset(buf, 0xFF, sizeof buf); memset(r, 0, sizeof *r); r->magic = MAGIC; r->version = VERSION; r->seed = L->state.seed; r->salts[0] = L->state.salts[0]; r->salts[1] = L->state.salts[1]; r->gen = L->gen; r->keys = L->keys; r->bpm = L->bpm; r->scale = L->scale; r->root = L->root; r->mono_ch = L->mono_ch; r->mono_oct = L->mono_oct; memcpy(r->on, L->on, sizeof r->on); memcpy(r->learn, L->learn, sizeof r->learn); memcpy(r->slots, slots, sizeof r->slots); r->crc = crc(r); return flash_safe_execute(do_write, buf, 500) == PICO_OK; }