feat: Flash-HAL-Interface und Settings-Store mit A/B-Slots
Implementiert: - Flash HAL (nl_flash_read/write/erase_sector) Interfaces - Flash Layout mit A/B-Settings Slots und weiteren Regions - Test-Fake für Flash mit Fehlerinjection (Stromausfall-Simulation) - Settings-Store mit CRC32 Recovery und Slot-Alternierung - Vollständige Test-Suite mit Corruption/Power-Loss-Tests
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "fake_flash.h"
|
||||
#include "config/nl_flash_layout.h"
|
||||
#include "config/nl_settings.h"
|
||||
#include "light/nl_light_types.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
fake_flash_reset();
|
||||
nl_settings_init(NL_FL_SETTINGS_A, NL_FL_SETTINGS_B);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_UINT(0, fake_flash_dirty_writes);
|
||||
}
|
||||
|
||||
static nl_settings_t sample(const char *name)
|
||||
{
|
||||
nl_settings_t s;
|
||||
nl_settings_defaults(&s);
|
||||
strcpy(s.wifi_ssid, "ninHome");
|
||||
strcpy(s.wifi_pass, "secret");
|
||||
strcpy(s.name, name);
|
||||
s.auth_all = 1;
|
||||
s.power_on_behaviour = NL_POB_ON;
|
||||
s.fade_in_ms = 1200;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void test_defaults(void)
|
||||
{
|
||||
nl_settings_t s;
|
||||
TEST_ASSERT_FALSE(nl_settings_load(&s));
|
||||
TEST_ASSERT_EQUAL_STRING("", s.wifi_ssid);
|
||||
TEST_ASSERT_EQUAL_STRING("aabbccddeeff0011223344", s.token);
|
||||
TEST_ASSERT_EQUAL_STRING("", s.name);
|
||||
TEST_ASSERT_EQUAL_UINT8(0, s.auth_all);
|
||||
TEST_ASSERT_EQUAL_UINT8(NL_POB_LAST, s.power_on_behaviour);
|
||||
TEST_ASSERT_EQUAL_UINT16(500, s.fade_in_ms);
|
||||
TEST_ASSERT_EQUAL_UINT16(500, s.fade_out_ms);
|
||||
}
|
||||
|
||||
static void test_save_and_load(void)
|
||||
{
|
||||
nl_settings_t in = sample("Wohnzimmer"), out;
|
||||
TEST_ASSERT_EQUAL_INT(0, nl_settings_save(&in));
|
||||
TEST_ASSERT_TRUE(nl_settings_load(&out));
|
||||
TEST_ASSERT_EQUAL_MEMORY(&in, &out, sizeof in);
|
||||
}
|
||||
|
||||
static void test_alternates_slots(void)
|
||||
{
|
||||
nl_settings_t s, out;
|
||||
s = sample("a"); nl_settings_save(&s);
|
||||
s = sample("b"); nl_settings_save(&s);
|
||||
s = sample("c"); nl_settings_save(&s);
|
||||
TEST_ASSERT_EQUAL_UINT(2, fake_flash_erases[0]);
|
||||
TEST_ASSERT_EQUAL_UINT(1, fake_flash_erases[1]);
|
||||
TEST_ASSERT_TRUE(nl_settings_load(&out));
|
||||
TEST_ASSERT_EQUAL_STRING("c", out.name);
|
||||
}
|
||||
|
||||
static void test_power_loss_keeps_previous(void)
|
||||
{
|
||||
nl_settings_t s = sample("old"), out;
|
||||
nl_settings_save(&s);
|
||||
s = sample("new");
|
||||
fake_flash_fail_after(50);
|
||||
TEST_ASSERT_NOT_EQUAL(0, nl_settings_save(&s));
|
||||
fake_flash_fail_after(-1);
|
||||
TEST_ASSERT_TRUE(nl_settings_load(&out));
|
||||
TEST_ASSERT_EQUAL_STRING("old", out.name);
|
||||
}
|
||||
|
||||
static void test_corrupt_newest_falls_back(void)
|
||||
{
|
||||
nl_settings_t s, out;
|
||||
s = sample("first"); nl_settings_save(&s); /* slot A */
|
||||
s = sample("second"); nl_settings_save(&s); /* slot B */
|
||||
fake_flash_mem[NL_FL_SETTINGS_B + 40] ^= 0x01;
|
||||
TEST_ASSERT_TRUE(nl_settings_load(&out));
|
||||
TEST_ASSERT_EQUAL_STRING("first", out.name);
|
||||
}
|
||||
|
||||
static void test_erase(void)
|
||||
{
|
||||
nl_settings_t s = sample("x"), out;
|
||||
nl_settings_save(&s);
|
||||
TEST_ASSERT_EQUAL_INT(0, nl_settings_erase());
|
||||
TEST_ASSERT_FALSE(nl_settings_load(&out));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_defaults);
|
||||
RUN_TEST(test_save_and_load);
|
||||
RUN_TEST(test_alternates_slots);
|
||||
RUN_TEST(test_power_loss_keeps_previous);
|
||||
RUN_TEST(test_corrupt_newest_falls_back);
|
||||
RUN_TEST(test_erase);
|
||||
return UNITY_END();
|
||||
}
|
||||
Reference in New Issue
Block a user