feat: Ring-Log für den Lichtzustand
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
#include "config/nl_state_log.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "light/nl_boot_state.h"
|
||||
#include "util/nl_crc.h"
|
||||
|
||||
#define ENTRY_MAGIC 0xA5u
|
||||
|
||||
static uint32_t s_sector[2];
|
||||
static bool s_have;
|
||||
static nl_light_state_t s_latest;
|
||||
static uint32_t s_seq;
|
||||
static uint32_t s_active;
|
||||
static uint32_t s_next; /* next free slot in the active sector */
|
||||
|
||||
static uint32_t slot_addr(uint32_t sec, uint32_t slot)
|
||||
{
|
||||
return s_sector[sec] + slot * NL_STATE_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
static void encode(const nl_light_state_t *s, uint32_t seq, uint8_t e[NL_STATE_ENTRY_SIZE])
|
||||
{
|
||||
memset(e, 0, NL_STATE_ENTRY_SIZE);
|
||||
e[0] = ENTRY_MAGIC;
|
||||
e[1] = (uint8_t)((s->on ? 1u : 0u) | (s->mode == NL_MODE_WHITE ? 2u : 0u));
|
||||
e[2] = s->brightness;
|
||||
e[3] = s->r;
|
||||
e[4] = s->g;
|
||||
e[5] = s->b;
|
||||
e[6] = (uint8_t)(s->ct & 0xFFu);
|
||||
e[7] = (uint8_t)(s->ct >> 8);
|
||||
e[8] = (uint8_t)seq;
|
||||
e[9] = (uint8_t)(seq >> 8);
|
||||
e[10] = (uint8_t)(seq >> 16);
|
||||
e[11] = (uint8_t)(seq >> 24);
|
||||
e[15] = nl_crc8(e, NL_STATE_ENTRY_SIZE - 1);
|
||||
}
|
||||
|
||||
static bool decode(const uint8_t e[NL_STATE_ENTRY_SIZE], nl_light_state_t *s, uint32_t *seq)
|
||||
{
|
||||
if (e[0] != ENTRY_MAGIC || nl_crc8(e, NL_STATE_ENTRY_SIZE - 1) != e[15])
|
||||
return false;
|
||||
s->on = (e[1] & 1u) != 0;
|
||||
s->mode = (e[1] & 2u) ? NL_MODE_WHITE : NL_MODE_COLOR;
|
||||
s->brightness = e[2];
|
||||
s->r = e[3];
|
||||
s->g = e[4];
|
||||
s->b = e[5];
|
||||
s->ct = (uint16_t)(e[6] | (e[7] << 8));
|
||||
*seq = (uint32_t)e[8] | ((uint32_t)e[9] << 8) | ((uint32_t)e[10] << 16) | ((uint32_t)e[11] << 24);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_free(const uint8_t e[NL_STATE_ENTRY_SIZE])
|
||||
{
|
||||
for (uint32_t i = 0; i < NL_STATE_ENTRY_SIZE; i++)
|
||||
if (e[i] != 0xFF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t next_free_slot(uint32_t sec)
|
||||
{
|
||||
uint8_t e[NL_STATE_ENTRY_SIZE];
|
||||
uint32_t next = 0;
|
||||
for (uint32_t slot = 0; slot < NL_STATE_LOG_SLOTS; slot++) {
|
||||
if (nl_flash_read(slot_addr(sec, slot), e, sizeof e) != 0 || !is_free(e))
|
||||
next = slot + 1;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
void nl_state_log_init(uint32_t sector0, uint32_t sector1)
|
||||
{
|
||||
uint8_t e[NL_STATE_ENTRY_SIZE];
|
||||
nl_light_state_t st;
|
||||
uint32_t seq;
|
||||
|
||||
s_sector[0] = sector0;
|
||||
s_sector[1] = sector1;
|
||||
s_have = false;
|
||||
s_seq = 0;
|
||||
s_active = 0;
|
||||
for (uint32_t sec = 0; sec < 2; sec++) {
|
||||
for (uint32_t slot = 0; slot < NL_STATE_LOG_SLOTS; slot++) {
|
||||
if (nl_flash_read(slot_addr(sec, slot), e, sizeof e) != 0)
|
||||
continue;
|
||||
if (decode(e, &st, &seq) && (!s_have || seq > s_seq)) {
|
||||
s_have = true;
|
||||
s_seq = seq;
|
||||
s_latest = st;
|
||||
s_active = sec;
|
||||
}
|
||||
}
|
||||
}
|
||||
s_next = next_free_slot(s_active);
|
||||
}
|
||||
|
||||
bool nl_state_log_load(nl_light_state_t *out)
|
||||
{
|
||||
if (!s_have)
|
||||
return false;
|
||||
*out = s_latest;
|
||||
return true;
|
||||
}
|
||||
|
||||
int nl_state_log_append(const nl_light_state_t *s)
|
||||
{
|
||||
uint8_t e[NL_STATE_ENTRY_SIZE];
|
||||
uint32_t sec = s_active;
|
||||
int r;
|
||||
|
||||
if (s_have && nl_light_state_equal(&s_latest, s))
|
||||
return 0;
|
||||
|
||||
if (!s_have) {
|
||||
sec = 0;
|
||||
if (s_active != 0 || s_next != 0) {
|
||||
if (nl_flash_erase_sector(s_sector[0]) != 0)
|
||||
return -1;
|
||||
}
|
||||
s_next = 0;
|
||||
} else if (s_next >= NL_STATE_LOG_SLOTS) {
|
||||
sec = 1u - s_active;
|
||||
if (nl_flash_erase_sector(s_sector[sec]) != 0)
|
||||
return -1;
|
||||
s_next = 0;
|
||||
}
|
||||
|
||||
encode(s, s_seq + 1, e);
|
||||
r = nl_flash_write(slot_addr(sec, s_next), e, sizeof e);
|
||||
s_active = sec;
|
||||
s_next++; /* also skip a half written slot */
|
||||
if (r != 0)
|
||||
return -1;
|
||||
s_seq++;
|
||||
s_latest = *s;
|
||||
s_have = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nl_state_log_erase(void)
|
||||
{
|
||||
int r0 = nl_flash_erase_sector(s_sector[0]);
|
||||
int r1 = nl_flash_erase_sector(s_sector[1]);
|
||||
s_have = false;
|
||||
s_seq = 0;
|
||||
s_active = 0;
|
||||
s_next = 0;
|
||||
return (r0 == 0 && r1 == 0) ? 0 : -1;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef NL_STATE_LOG_H
|
||||
#define NL_STATE_LOG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config/nl_flash.h"
|
||||
#include "light/nl_light_types.h"
|
||||
|
||||
#define NL_STATE_ENTRY_SIZE 16u
|
||||
#define NL_STATE_LOG_SLOTS (NL_FLASH_SECTOR_SIZE / NL_STATE_ENTRY_SIZE)
|
||||
|
||||
void nl_state_log_init(uint32_t sector0, uint32_t sector1);
|
||||
bool nl_state_log_load(nl_light_state_t *out);
|
||||
int nl_state_log_append(const nl_light_state_t *s);
|
||||
int nl_state_log_erase(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user