diff --git a/.gitignore b/.gitignore index 3d500c6..1fcac04 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,4 @@ __pycache__/ .DS_Store Thumbs.db desktop.ini +zephcore/lib/zcpfs/SPEC.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e3a58bc..3fc762b 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -875,7 +875,7 @@ Does not cover the display backlight, which has its own UI brightness setting (` `lora-tx-pwm-led` drives that LED through PWM (`zephcore_led_pwm_write()`), and the PWM alias wins over `led0` / `lora-tx-led`. `CONFIG_ZEPHCORE_LED_PWM` follows the aliases: it selects `CONFIG_PWM` and stops the server and observer mains from configuring `led0` as a GPIO, because that pin belongs to the PWM -driver. Persisted in `NodePrefs.led_brightness` (companion offset 272; repeater offset 311). +driver. Persisted in `prefs.json` as `zc.leds_brightness`; it is not part of the legacy binary files. ### 7.6 WiFi / MQTT / TCP Transports diff --git a/tests/catalog.json b/tests/catalog.json index 4d5cd48..3f456a5 100644 --- a/tests/catalog.json +++ b/tests/catalog.json @@ -374,7 +374,7 @@ }, { "id": "UNIT-PREFS-001", - "name": "Companion prefs encode to the documented 273-byte layout", + "name": "Companion prefs encode to the documented 272-byte layout", "source": "tests/unit/prefs_codec_tests.cpp" }, { @@ -399,7 +399,7 @@ }, { "id": "UNIT-PREFS-006", - "name": "Server prefs encode to the documented 312-byte layout", + "name": "Server prefs encode to the documented 311-byte layout", "source": "tests/unit/prefs_codec_tests.cpp" }, { diff --git a/tests/unit/prefs_codec_tests.cpp b/tests/unit/prefs_codec_tests.cpp index 2ae9699..c8f26d8 100644 --- a/tests/unit/prefs_codec_tests.cpp +++ b/tests/unit/prefs_codec_tests.cpp @@ -13,7 +13,7 @@ namespace { struct Field { size_t file_off; size_t size; size_t struct_off; }; #define F(off, member) { off, sizeof(NodePrefs::member), offsetof(NodePrefs, member) } -// Companion /lfs/new_prefs, 273 bytes. Pads at 36-39 and 79. +// Companion /lfs/new_prefs, 272 bytes. Pads at 36-39 and 79. const Field kCompanion[] = { F(0, airtime_factor), F(4, node_name), F(40, node_lat), F(48, node_lon), F(56, freq), F(60, sf), F(61, cr), F(62, client_repeat), F(63, manual_add_contacts), F(64, bw), @@ -30,10 +30,10 @@ const Field kCompanion[] = { F(158, cad_busycap), F(159, adc_multiplier), F(163, extra_sf), F(166, v_contact_flags), F(167, fem_rxgain), F(168, display_rotate), F(169, input_rotate), F(170, cad_base), F(171, tz_offset), F(172, leds_radio_mode), F(173, leds_hb_mode), F(174, wifi_enabled), - F(175, wifi_ssid), F(208, wifi_pwd), F(272, led_brightness), + F(175, wifi_ssid), F(208, wifi_pwd), }; -// Server /lfs/repeater/prefs, 312 bytes. Offset 120 is leds_disabled as a +// Server /lfs/repeater/prefs, 311 bytes. Offset 120 is leds_disabled as a // magic byte (checked separately); pads at 36-39, 79, 123, 127-151 (bridge), // 153-155. const Field kServer[] = { @@ -50,7 +50,7 @@ const Field kServer[] = { F(295, flood_max_advert), F(296, meshtimesync), F(297, cad_auto), F(298, cad_offset), F(299, probe_interval), F(300, cad_busycap), F(301, extra_sf), F(304, fem_rxgain), F(305, display_rotate), F(306, input_rotate), F(307, cad_base), F(308, tz_offset), - F(309, leds_radio_mode), F(310, leds_hb_mode), F(311, led_brightness), + F(309, leds_radio_mode), F(310, leds_hb_mode), }; #undef F @@ -80,7 +80,7 @@ NodePrefs sample() { p.backoff_multiplier = 0.6f; p.allow_read_only = 1; p.multi_acks = 1; p.flood_max = 20; p.flood_max_unscoped = 10; p.flood_max_advert = 4; p.interference_threshold = 7; p.leds_disabled = 1; p.leds_radio_mode = LEDS_RADIO_RX; - p.leds_hb_mode = LEDS_HB_UNREAD; p.led_brightness = 42; p.powersaving_enabled = 1; p.gps_enabled = 1; + p.leds_hb_mode = LEDS_HB_UNREAD; p.powersaving_enabled = 1; p.gps_enabled = 1; p.gps_interval = 600; p.advert_loc_policy = ADVERT_LOC_SHARE; p.discovery_mod_timestamp = 123456; p.adc_multiplier = 1.25f; strcpy(p.owner_info, "owner info"); p.rx_boost = 0; p.fem_rxgain = 0; p.rx_duty_cycle = 1; @@ -125,7 +125,7 @@ NodePrefs expectShort(const NodePrefs &file_p, size_t len, const Field (&table)[ } // namespace -TEST(prefs_companion_layout, "UNIT-PREFS-001", "Companion prefs encode to the documented 273-byte layout") { +TEST(prefs_companion_layout, "UNIT-PREFS-001", "Companion prefs encode to the documented 272-byte layout") { NodePrefs p = sample(); uint8_t buf[COMPANION_PREFS_SIZE + 8]; std::memset(buf, 0xEE, sizeof(buf)); @@ -154,7 +154,7 @@ TEST(prefs_companion_short, "UNIT-PREFS-003", "Short companion files keep the ca // Every field boundary: each length the format has had ends on one. const size_t lens[] = { 91, 92, 93, 94, 95, 96, 127, 143, 144, 145, 146, 148, 150, 151, 152, 153, 155, 156, 157, 158, 159, 163, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 208, 272, 273 }; + 171, 172, 173, 174, 175, 208, 272 }; for (size_t len : lens) { NodePrefs got = defaults(); CHECK(companionPrefsDecode(got, full, len)); @@ -215,7 +215,7 @@ TEST(prefs_companion_corrupt, "UNIT-PREFS-005", "Corrupt companion bytes fall ba CHECK(got.leds_radio_mode == 0); } -TEST(prefs_server_layout, "UNIT-PREFS-006", "Server prefs encode to the documented 312-byte layout") { +TEST(prefs_server_layout, "UNIT-PREFS-006", "Server prefs encode to the documented 311-byte layout") { NodePrefs p = sample(); uint8_t buf[SERVER_PREFS_SIZE + 8]; std::memset(buf, 0xEE, sizeof(buf)); @@ -248,7 +248,7 @@ TEST(prefs_server_short, "UNIT-PREFS-008", "Short server files keep the caller's uint8_t full[SERVER_PREFS_SIZE]; serverPrefsEncode(p, full, sizeof(full)); // Every length the format has had. - const size_t lens[] = { 290, 292, 294, 296, 297, 300, 301, 304, 305, 307, 308, 309, 311, 312 }; + const size_t lens[] = { 290, 292, 294, 296, 297, 300, 301, 304, 305, 307, 308, 309, 311 }; for (size_t len : lens) { NodePrefs got = defaults(); serverPrefsDecode(got, full, len); diff --git a/tests/unit/prefs_json_tests.cpp b/tests/unit/prefs_json_tests.cpp index 6cd807e..faa8a75 100644 --- a/tests/unit/prefs_json_tests.cpp +++ b/tests/unit/prefs_json_tests.cpp @@ -33,7 +33,7 @@ NodePrefs sample() { p.backoff_multiplier = 0.6f; p.allow_read_only = 1; p.multi_acks = 1; p.flood_max = 20; p.flood_max_unscoped = 10; p.flood_max_advert = 4; p.interference_threshold = 7; p.leds_disabled = 1; p.leds_radio_mode = LEDS_RADIO_RX; - p.leds_hb_mode = LEDS_HB_UNREAD; p.powersaving_enabled = 1; p.gps_enabled = 1; + p.leds_hb_mode = LEDS_HB_UNREAD; p.led_brightness = 42; p.powersaving_enabled = 1; p.gps_enabled = 1; p.gps_interval = 600; p.advert_loc_policy = ADVERT_LOC_SHARE; p.discovery_mod_timestamp = 123456; p.adc_multiplier = 1.25f; strcpy(p.owner_info, "owner info"); p.rx_boost = 0; p.fem_rxgain = 0; p.rx_duty_cycle = 1; @@ -73,6 +73,8 @@ TEST(pjson_companion_roundtrip, "UNIT-PJSON-001", "Companion prefs survive prefs CHECK(companionPrefsFromJson(q, s)); // Every field of the binary layout, as a legacy file migrated to JSON. CHECK(companionBytes(q) == companionBytes(p)); + // prefs.json only: not in the binary layout. + CHECK(q.led_brightness == 42); } TEST(pjson_server_roundtrip, "UNIT-PJSON-002", "Server prefs survive prefs.json field for field") { @@ -82,6 +84,7 @@ TEST(pjson_server_roundtrip, "UNIT-PJSON-002", "Server prefs survive prefs.json NodePrefs q = defaults(); CHECK(serverPrefsFromJson(q, s)); CHECK(serverBytes(q) == serverBytes(p)); + CHECK(q.led_brightness == 42); } TEST(pjson_upstream_file, "UNIT-PJSON-003", "A companion prefs.json as upstream v1.17 writes it loads") { diff --git a/zephcore/helpers/PrefsCodec.cpp b/zephcore/helpers/PrefsCodec.cpp index 9e8b74f..a22984d 100644 --- a/zephcore/helpers/PrefsCodec.cpp +++ b/zephcore/helpers/PrefsCodec.cpp @@ -109,7 +109,6 @@ size_t companionPrefsEncode(const NodePrefs &p, uint8_t *buf, size_t cap) w.put(&p.wifi_enabled, 1); w.put(p.wifi_ssid, sizeof(p.wifi_ssid)); w.put(p.wifi_pwd, sizeof(p.wifi_pwd)); - w.put(&p.led_brightness, 1); return w.off; } @@ -191,8 +190,6 @@ bool companionPrefsDecode(NodePrefs &prefs, const uint8_t *buf, size_t len) r.take(&p.wifi_enabled, 1); r.take(p.wifi_ssid, sizeof(p.wifi_ssid)); r.take(p.wifi_pwd, sizeof(p.wifi_pwd)); - /* led_brightness at offset 272, after wifi_pwd: a 272-byte file leaves it at the initNodePrefs() default. */ - r.take(&p.led_brightness, 1); /* The one validator: bounds, NaNs, and the unterminated char fields */ sanitizeNodePrefs(&p); @@ -283,8 +280,6 @@ size_t serverPrefsEncode(const NodePrefs &prefs, uint8_t *buf, size_t cap) /* LED activity/heartbeat modes (offsets 309-310) */ w.put(&prefs.leds_radio_mode, sizeof(prefs.leds_radio_mode)); w.put(&prefs.leds_hb_mode, sizeof(prefs.leds_hb_mode)); - /* led_brightness at offset 311. */ - w.put(&prefs.led_brightness, sizeof(prefs.led_brightness)); return w.off; } @@ -360,8 +355,6 @@ void serverPrefsDecode(NodePrefs &prefs, const uint8_t *buf, size_t len) r.get(&prefs.tz_offset, sizeof(prefs.tz_offset)); r.get(&prefs.leds_radio_mode, sizeof(prefs.leds_radio_mode)); r.get(&prefs.leds_hb_mode, sizeof(prefs.leds_hb_mode)); - /* led_brightness at offset 311: a shorter file leaves the initNodePrefs() default. */ - r.get(&prefs.led_brightness, sizeof(prefs.led_brightness)); /* Only the explicit "off" magic disables LEDs; a legacy AGC interval or an * unwritten byte both mean "on". */ diff --git a/zephcore/helpers/PrefsCodec.h b/zephcore/helpers/PrefsCodec.h index a92953f..f65745c 100644 --- a/zephcore/helpers/PrefsCodec.h +++ b/zephcore/helpers/PrefsCodec.h @@ -14,8 +14,8 @@ #include #include "NodePrefs.h" -#define COMPANION_PREFS_SIZE 273 -#define SERVER_PREFS_SIZE 312 +#define COMPANION_PREFS_SIZE 272 +#define SERVER_PREFS_SIZE 311 /* Companion file layout, including the fields shared with upstream's former * new_prefs up to offset 92. Returns the byte count (COMPANION_PREFS_SIZE),