Some checks failed
check / check (push) Has been cancelled
First commit of the repo. Contents beyond the v0.1 simulator and layout: - Full Pico 2 W firmware (firmware/app, drivers, engine port, host test). - BANK page and 404 mode A/B removed; learned pads play exactly what was learned. - 404/MiniFreak renamed to KIT/SYNTH throughout (jacks, code, sim, docs, layout labels; wiring rebuilt). - ROLL returns to page select after a re-roll; a freshly learned track turns on. - LCD contrast 66. - ROOT and SCALE pages: 21 scales, AUTO = the seed picks; global and sticky. Intended music change: the scale table grew from 8 to 21 and AUTO picks from all of them, so every seed's scale changed. Vectors regenerated with npm run vectors, plus new key-override cases. Flash record is now version 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
2.6 KiB
C
74 lines
2.6 KiB
C
#include "storage.h"
|
|
#include "hardware/flash.h"
|
|
#include "pico/flash.h"
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#define MAGIC 0x53425831u /* "SBX1" */
|
|
#define VERSION 2 /* 2: ROOT / SCALE added, BANK gone. 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, 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->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->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->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;
|
|
}
|