joystick UI: add Path hash bytes setting (System → Device)

prefs.path_hash_mode already exists end-to-end (NodePrefs field,
ZephyrDataStore persists it, CompanionMesh::sendFlood reads it as
the path_hash_size for every outbound flood, and the phone protocol
exposes it). Add a joystick UI control so it can be set locally
without going through the phone app.

System → Device gets a new "Path hash: Nb" item; ENTER cycles
1 → 2 → 3 → 1 (path_hash_mode 0 → 1 → 2 → 0). Save goes through
the existing mesh_save_* deferred-write infrastructure
(UI_ACTION_PATH_HASH_MODE_SAVE, pending_path_hash_mode atomic),
handled in the mesh thread with savePrefs().
This commit is contained in:
liquidraver
2026-05-22 09:24:38 +02:00
parent 072b4edadb
commit 1563658a68
5 changed files with 42 additions and 2 deletions
@@ -951,6 +951,14 @@ void JoystickUITask::adjustScreenOff(int32_t delta_ms)
mesh_save_screen_off_secs((uint16_t)(_screen_off_ms / 1000));
}
void JoystickUITask::cyclePathHashMode()
{
if (!_prefs) return;
uint8_t next = (uint8_t)((_prefs->path_hash_mode + 1) % 3); /* 0→1→2→0 */
_prefs->path_hash_mode = next;
mesh_save_path_hash_mode(next);
}
void JoystickUITask::toggleWakeOnMsg()
{
_wake_on_msg = !_wake_on_msg;
@@ -95,6 +95,10 @@ public:
void adjustBrightness(int delta);
bool getWakeOnMsg() const { return _wake_on_msg; }
void toggleWakeOnMsg();
/* Path-hash-mode: 0/1/2 → 1/2/3 bytes per hop appended to outbound flood
* path. Cycles through the three valid settings; persists to prefs. */
uint8_t getPathHashBytes() const { return _prefs ? (uint8_t)(_prefs->path_hash_mode + 1) : 1; }
void cyclePathHashMode();
bool isBuzzerQuiet() const;
void toggleBuzzer();
bool isGPSAvailable() const;
@@ -21,7 +21,7 @@ static const char * const kSysCatLabels[] = { "Device", "Display", "Info", "Powe
static const int kSysCatCount = 4;
/* Device submenu items */
enum SysDevItem { SYSDEV_BUZZER=0, SYSDEV_BLUETOOTH, SYSDEV_OFFGRID, SYSDEV_LEDS, SYSDEV_BLE_CODE, SYSDEV_DFU, SYSDEV_TELEMETRY, SYSDEV_RENAME, SYSDEV_COUNT };
enum SysDevItem { SYSDEV_BUZZER=0, SYSDEV_BLUETOOTH, SYSDEV_OFFGRID, SYSDEV_LEDS, SYSDEV_BLE_CODE, SYSDEV_PATHHASH, SYSDEV_DFU, SYSDEV_TELEMETRY, SYSDEV_RENAME, SYSDEV_COUNT };
#define DFU_CONFIRM_WINDOW_MS 3000
/* Display submenu items */
@@ -56,11 +56,12 @@ int SystemScreen::render(JoystickDisplay &display)
return 500;
}
if (_mode == SYSMODE_DEVICE) {
char bt_label[24], buz_label[24], og_label[24], led_label[24], dfu_label[24];
char bt_label[24], buz_label[24], og_label[24], led_label[24], dfu_label[24], ph_label[24];
snprintf(buz_label, sizeof(buz_label), "Buzzer: %s", _task->isBuzzerQuiet() ? "OFF" : "ON");
snprintf(bt_label, sizeof(bt_label), "Bluetooth: %s", _task->isSerialEnabled() ? "ON" : "OFF");
snprintf(og_label, sizeof(og_label), "Offgrid: %s", _task->isOffgridEnabled() ? "ON" : "OFF");
snprintf(led_label, sizeof(led_label), "LEDs: %s", _task->isLedsDisabled() ? "OFF" : "ON");
snprintf(ph_label, sizeof(ph_label), "Path hash: %db", (int)_task->getPathHashBytes());
uint32_t now = k_uptime_get_32();
bool dfu_pending = (_dfu_confirm_time != 0 &&
(now - _dfu_confirm_time) <= DFU_CONFIRM_WINDOW_MS);
@@ -69,6 +70,7 @@ int SystemScreen::render(JoystickDisplay &display)
items[SYSDEV_BUZZER] = buz_label;
items[SYSDEV_BLUETOOTH] = bt_label;
items[SYSDEV_BLE_CODE] = "BLE Code";
items[SYSDEV_PATHHASH] = ph_label;
items[SYSDEV_TELEMETRY] = "Telemetry";
items[SYSDEV_RENAME] = "Rename node";
items[SYSDEV_OFFGRID] = og_label;
@@ -159,6 +161,13 @@ bool SystemScreen::handleInput(char c)
_task->toggleLeds();
_task->showAlert(_task->isLedsDisabled() ? "LEDs: OFF" : "LEDs: ON", 1000);
return true;
case SYSDEV_PATHHASH: {
_task->cyclePathHashMode();
char alert[24];
snprintf(alert, sizeof(alert), "Path hash: %db", (int)_task->getPathHashBytes());
_task->showAlert(alert, 1000);
return true;
}
case SYSDEV_DFU: {
uint32_t now = k_uptime_get_32();
if (_dfu_confirm_time != 0 &&
+17
View File
@@ -44,6 +44,7 @@ LOG_MODULE_REGISTER(zephcore_ui_actions, CONFIG_ZEPHCORE_UI_ACTIONS_LOG_LEVEL);
#define UI_ACTION_SAVE_RESTART BIT(8)
#define UI_ACTION_WAKE_ON_MSG_SAVE BIT(9)
#define UI_ACTION_SCREEN_OFF_SAVE BIT(10)
#define UI_ACTION_PATH_HASH_MODE_SAVE BIT(11)
/* Module-local pointers, set by init */
static CompanionMesh *s_mesh;
@@ -68,6 +69,7 @@ static atomic_t pending_ble_disabled;
static atomic_t pending_brightness;
static atomic_t pending_wake_on_msg;
static atomic_t pending_screen_off_secs;
static atomic_t pending_path_hash_mode;
extern "C" void ui_mesh_actions_init(struct k_event *mesh_events,
uint32_t mesh_event_ui_action,
@@ -144,6 +146,13 @@ extern "C" void mesh_save_screen_off_secs(uint16_t secs)
k_event_post(s_mesh_events, s_mesh_event_ui_action);
}
extern "C" void mesh_save_path_hash_mode(uint8_t mode)
{
atomic_set(&pending_path_hash_mode, (atomic_val_t)mode);
atomic_or(&pending_ui_actions, UI_ACTION_PATH_HASH_MODE_SAVE);
k_event_post(s_mesh_events, s_mesh_event_ui_action);
}
extern "C" void mesh_set_buzzer_quiet(bool quiet)
{
/* Defer the flash write (savePrefs) to mesh thread */
@@ -286,6 +295,14 @@ extern "C" void mesh_handle_ui_actions(void)
need_save = true;
}
if (actions & UI_ACTION_PATH_HASH_MODE_SAVE) {
uint8_t mode = (uint8_t)atomic_get(&pending_path_hash_mode);
if (mode > 2) mode = 2; /* clamp to valid range (0-2 → 1-3 bytes) */
s_mesh->prefs.path_hash_mode = mode;
LOG_INF("path_hash_mode=%d (%d bytes per hop)", mode, mode + 1);
need_save = true;
}
if (need_save || (actions & UI_ACTION_SAVE_RESTART)) {
s_data_store->savePrefs(s_mesh->prefs);
LOG_INF("prefs saved (button action)");
+2
View File
@@ -64,6 +64,8 @@ void mesh_save_brightness(uint8_t brightness);
void mesh_save_and_restart(void);
void mesh_set_wake_on_msg(bool enabled);
void mesh_save_screen_off_secs(uint16_t secs);
/* path_hash_mode: 0/1/2 → 1/2/3 bytes per hop appended to outbound flood path */
void mesh_save_path_hash_mode(uint8_t mode);
#ifdef __cplusplus
}