feat: Power-Cycle-Zähler für den Werksreset

This commit is contained in:
Michael Sauer
2026-09-11 13:39:01 +02:00
parent 35b59a64ed
commit 663825c165
4 changed files with 147 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
#include "config/nl_reset_counter.h"
#include "config/nl_flash.h"
#define REC_TAG 0x5A000000u
#define REC_MASK 0xFF000000u
#define REC_FREE 0xFFFFFFFFu
#define REC_SLOTS (NL_FLASH_SECTOR_SIZE / 4u)
static uint32_t s_sector;
static uint32_t s_next;
static uint8_t s_count;
void nl_resetcnt_init(uint32_t sector)
{
uint32_t w;
s_sector = sector;
s_next = 0;
s_count = 0;
for (uint32_t i = 0; i < REC_SLOTS; i++) {
if (nl_flash_read(sector + i * 4u, &w, 4) != 0 || w == REC_FREE)
continue;
s_next = i + 1;
s_count = ((w & REC_MASK) == REC_TAG) ? (uint8_t)(w & 0xFFu) : 0;
}
}
static int put(uint8_t count)
{
uint32_t w = REC_TAG | count;
int r;
if (s_next >= REC_SLOTS) {
if (nl_flash_erase_sector(s_sector) != 0)
return -1;
s_next = 0;
}
r = nl_flash_write(s_sector + s_next * 4u, &w, 4);
s_next++;
if (r == 0)
s_count = count;
return r;
}
uint8_t nl_resetcnt_boot(void)
{
uint8_t c = s_count < 255 ? (uint8_t)(s_count + 1) : 255;
put(c);
return c;
}
int nl_resetcnt_clear(void)
{
if (s_count == 0)
return 0;
return put(0);
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef NL_RESET_COUNTER_H
#define NL_RESET_COUNTER_H
#include <stdint.h>
#define NL_FACTORY_RESET_BOOTS 5u
#define NL_RESETCNT_CLEAR_MS 5000u
void nl_resetcnt_init(uint32_t sector);
uint8_t nl_resetcnt_boot(void);
int nl_resetcnt_clear(void);
#endif
+1
View File
@@ -33,3 +33,4 @@ nl_test(test_control test_control.c ${NL_SRC}/light/nl_control.c ${NL_SRC}/light
nl_test(test_settings test_settings.c fake_flash.c ${NL_SRC}/config/nl_settings.c ${NL_SRC}/util/nl_crc.c)
nl_test(test_state_log test_state_log.c fake_flash.c ${NL_SRC}/config/nl_state_log.c
${NL_SRC}/light/nl_boot_state.c ${NL_SRC}/util/nl_crc.c)
nl_test(test_reset_counter test_reset_counter.c fake_flash.c ${NL_SRC}/config/nl_reset_counter.c)
+75
View File
@@ -0,0 +1,75 @@
#include "unity.h"
#include "fake_flash.h"
#include "config/nl_flash_layout.h"
#include "config/nl_reset_counter.h"
static uint8_t boot(void)
{
nl_resetcnt_init(NL_FL_RESETCNT);
return nl_resetcnt_boot();
}
void setUp(void) { fake_flash_reset(); }
void tearDown(void)
{
TEST_ASSERT_EQUAL_UINT(0, fake_flash_dirty_writes);
}
static void test_first_boot_is_one(void)
{
TEST_ASSERT_EQUAL_UINT8(1, boot());
}
static void test_fast_boots_count_up(void)
{
for (uint8_t i = 1; i <= 5; i++)
TEST_ASSERT_EQUAL_UINT8(i, boot());
}
static void test_clear_resets(void)
{
boot();
boot();
TEST_ASSERT_EQUAL_INT(0, nl_resetcnt_clear());
TEST_ASSERT_EQUAL_UINT8(1, boot());
}
static void test_clear_twice_writes_once(void)
{
boot();
nl_resetcnt_clear();
nl_resetcnt_clear();
/* slot 0: count 1, slot 1: count 0, slot 2 still free */
TEST_ASSERT_EQUAL_HEX8(0xFF, fake_flash_mem[NL_FL_RESETCNT + 8]);
}
static void test_wraps_after_full_sector(void)
{
for (int i = 0; i < 700; i++) {
boot();
nl_resetcnt_clear();
}
TEST_ASSERT_EQUAL_UINT(1, fake_flash_erases[NL_FL_RESETCNT / NL_FLASH_SECTOR_SIZE]);
TEST_ASSERT_EQUAL_UINT8(1, boot());
TEST_ASSERT_EQUAL_UINT8(2, boot());
}
static void test_garbage_counts_as_zero(void)
{
fake_flash_mem[NL_FL_RESETCNT + 0] = 0x12;
fake_flash_mem[NL_FL_RESETCNT + 3] = 0x00;
TEST_ASSERT_EQUAL_UINT8(1, boot());
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_first_boot_is_one);
RUN_TEST(test_fast_boots_count_up);
RUN_TEST(test_clear_resets);
RUN_TEST(test_clear_twice_writes_once);
RUN_TEST(test_wraps_after_full_sector);
RUN_TEST(test_garbage_counts_as_zero);
return UNITY_END();
}