feat(cv): add CVTuning struct and NVS persistence scaffolding

Adds CVTuning to CVState, populates defaults from existing file-scope
constants in cv_init, and introduces config_load_tuning/config_save_tuning
backed by the doorcounter NVS namespace. No runtime behavior change yet;
CV code still reads the existing constants (Task 2 will migrate reads).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 15:45:53 -07:00
parent 9d5b588231
commit e28a4c1863
5 changed files with 92 additions and 0 deletions

View File

@@ -135,6 +135,26 @@ void test_blob_crossing_line_bottom_to_top_is_exit() {
TEST_ASSERT_EQUAL_INT(1, r.exits_delta);
}
void test_cv_init_populates_tuning_defaults() {
CVState state;
// Pre-pollute to make sure cv_init overwrites
state.tuning.diff_thresh = 0;
state.tuning.min_blob_px = 0;
state.tuning.max_move = 0.0f;
state.tuning.max_missed = 0;
state.tuning.line_offset = 0;
state.tuning.cfg_version = 0xDEADBEEF;
cv_init(state);
TEST_ASSERT_EQUAL_UINT8(CV_DIFF_THRESH, state.tuning.diff_thresh);
TEST_ASSERT_EQUAL_INT(CV_MIN_BLOB_PX, state.tuning.min_blob_px);
TEST_ASSERT_EQUAL_FLOAT(CV_MAX_MOVE, state.tuning.max_move);
TEST_ASSERT_EQUAL_INT(CV_MAX_MISSED, state.tuning.max_missed);
TEST_ASSERT_EQUAL_UINT8(50, state.tuning.line_offset);
TEST_ASSERT_EQUAL_UINT32(0, state.tuning.cfg_version);
}
void test_no_crossing_same_side_no_count() {
CVState state;
cv_init(state);
@@ -162,5 +182,6 @@ int main() {
RUN_TEST(test_blob_crossing_line_top_to_bottom_is_entry);
RUN_TEST(test_blob_crossing_line_bottom_to_top_is_exit);
RUN_TEST(test_no_crossing_same_side_no_count);
RUN_TEST(test_cv_init_populates_tuning_defaults);
return UNITY_END();
}