mirror of
https://github.com/markqvist/RNode_Firmware.git
synced 2026-04-27 22:35:36 +00:00
Add Settings screen with display timeout, beacon, and GPS controls
Replaces the "Coming soon" placeholder with working LVGL settings: - Display timeout: slider 5-60s, updates display_blanking_timeout - Beacon enable: switch, gates beacon_update() - Beacon interval: roller (10s/30s/1m/5m/10m), replaces #define - GPS dynamic model: roller (Portable/Stationary/Pedestrian/Automotive), sends UBX-CFG-VALSET to MIA-M10Q All settings persist to EEPROM config region (addresses 0x91-0x94) and reload on boot. Callbacks save immediately on change.
This commit is contained in:
parent
0cf5faa01f
commit
2bf457e2ba
5 changed files with 179 additions and 6 deletions
10
Beacon.h
10
Beacon.h
|
|
@ -19,9 +19,14 @@
|
|||
#if HAS_GPS == true
|
||||
|
||||
// Beacon interval and timing
|
||||
#define BEACON_INTERVAL_MS 30000 // 30 seconds between beacons
|
||||
uint32_t beacon_interval_ms = 30000; // Default 30s, configurable via Settings
|
||||
#define BEACON_STARTUP_DELAY_MS 10000 // Wait 10s after boot before first beacon
|
||||
// BEACON_NO_HOST_TIMEOUT_MS and last_host_activity defined in GPS.h
|
||||
bool beacon_enabled = true; // Configurable via Settings
|
||||
|
||||
// Beacon interval options (ms) — indexed by roller selection
|
||||
const uint32_t beacon_interval_options[] = { 10000, 30000, 60000, 300000, 600000 };
|
||||
#define BEACON_INTERVAL_OPTIONS_COUNT 5
|
||||
|
||||
// Beacon radio parameters — must match the router's LoRa interface
|
||||
#define BEACON_FREQ 868000000
|
||||
|
|
@ -69,6 +74,7 @@ void beacon_check_host_activity() {
|
|||
}
|
||||
|
||||
void beacon_update() {
|
||||
if (!beacon_enabled) { beacon_gate = 0; return; }
|
||||
// Don't beacon if host has been active recently
|
||||
if (last_host_activity > 0 &&
|
||||
(millis() - last_host_activity < BEACON_NO_HOST_TIMEOUT_MS)) {
|
||||
|
|
@ -115,7 +121,7 @@ void beacon_update() {
|
|||
|
||||
// Respect beacon interval
|
||||
if (last_beacon_tx > 0 &&
|
||||
(millis() - last_beacon_tx < BEACON_INTERVAL_MS)) {
|
||||
(millis() - last_beacon_tx < beacon_interval_ms)) {
|
||||
beacon_gate = 5;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
32
GPS.h
32
GPS.h
|
|
@ -111,6 +111,38 @@ void gps_setup() {
|
|||
gps_ready = true;
|
||||
}
|
||||
|
||||
// GPS dynamic model options — indexed by roller selection
|
||||
const uint8_t gps_model_ubx[] = { 0, 2, 3, 4 }; // Portable, Stationary, Pedestrian, Automotive
|
||||
#define GPS_MODEL_OPTIONS_COUNT 4
|
||||
uint8_t gps_dynamic_model = 0; // Current model index (default: Portable)
|
||||
|
||||
#if BOARD_MODEL == BOARD_TWATCH_ULT
|
||||
void gps_set_dynamic_model(uint8_t model_index) {
|
||||
if (model_index >= GPS_MODEL_OPTIONS_COUNT) return;
|
||||
uint8_t dyn = gps_model_ubx[model_index];
|
||||
gps_dynamic_model = model_index;
|
||||
uint8_t msg[] = {
|
||||
0xB5, 0x62, 0x06, 0x8A, 0x09, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x21, 0x00, 0x11, 0x20,
|
||||
dyn, 0x00, 0x00
|
||||
};
|
||||
uint8_t ck_a = 0, ck_b = 0;
|
||||
for (int i = 2; i < (int)sizeof(msg) - 2; i++) { ck_a += msg[i]; ck_b += ck_a; }
|
||||
msg[sizeof(msg) - 2] = ck_a;
|
||||
msg[sizeof(msg) - 1] = ck_b;
|
||||
gps_serial.write(msg, sizeof(msg));
|
||||
}
|
||||
#else
|
||||
void gps_set_dynamic_model(uint8_t model_index) {
|
||||
if (model_index >= GPS_MODEL_OPTIONS_COUNT) return;
|
||||
gps_dynamic_model = model_index;
|
||||
const char *cmds[] = { "$PCAS11,0*1D\r\n", "$PCAS11,1*1C\r\n",
|
||||
"$PCAS11,2*1F\r\n", "$PCAS11,3*1E\r\n" };
|
||||
gps_serial.print(cmds[model_index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void gps_update() {
|
||||
if (!gps_ready) return;
|
||||
|
||||
|
|
|
|||
122
Gui.h
122
Gui.h
|
|
@ -434,11 +434,127 @@ static void gui_create_msg_screen(lv_obj_t *parent) {
|
|||
// ---------------------------------------------------------------------------
|
||||
// Screen: Settings (bottom tile — swipe up from watch face)
|
||||
// ---------------------------------------------------------------------------
|
||||
static lv_obj_t *gui_set_disp_slider = NULL;
|
||||
static lv_obj_t *gui_set_disp_val = NULL;
|
||||
static lv_obj_t *gui_set_bcn_roller = NULL;
|
||||
static lv_obj_t *gui_set_gps_roller = NULL;
|
||||
static lv_obj_t *gui_set_bcn_sw = NULL;
|
||||
|
||||
static void gui_set_disp_cb(lv_event_t *e) {
|
||||
lv_obj_t *slider = (lv_obj_t *)lv_event_get_target(e);
|
||||
int32_t val = lv_slider_get_value(slider);
|
||||
display_blanking_timeout = (uint32_t)val * 1000;
|
||||
char buf[8]; snprintf(buf, sizeof(buf), "%lds", (long)val);
|
||||
lv_label_set_text(gui_set_disp_val, buf);
|
||||
EEPROM.write(config_addr(ADDR_CONF_DISP_TIMEOUT), (uint8_t)val);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
static void gui_set_bcn_en_cb(lv_event_t *e) {
|
||||
lv_obj_t *sw = (lv_obj_t *)lv_event_get_target(e);
|
||||
beacon_enabled = lv_obj_has_state(sw, LV_STATE_CHECKED);
|
||||
EEPROM.write(config_addr(ADDR_CONF_BCN_EN), beacon_enabled ? 1 : 0);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
static void gui_set_bcn_int_cb(lv_event_t *e) {
|
||||
lv_obj_t *roller = (lv_obj_t *)lv_event_get_target(e);
|
||||
uint16_t idx = lv_roller_get_selected(roller);
|
||||
if (idx < BEACON_INTERVAL_OPTIONS_COUNT) {
|
||||
beacon_interval_ms = beacon_interval_options[idx];
|
||||
EEPROM.write(config_addr(ADDR_CONF_BCN_INT), (uint8_t)idx);
|
||||
EEPROM.commit();
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_set_gps_model_cb(lv_event_t *e) {
|
||||
lv_obj_t *roller = (lv_obj_t *)lv_event_get_target(e);
|
||||
uint16_t idx = lv_roller_get_selected(roller);
|
||||
if (idx < GPS_MODEL_OPTIONS_COUNT) {
|
||||
gps_set_dynamic_model(idx);
|
||||
EEPROM.write(config_addr(ADDR_CONF_GPS_MODEL), (uint8_t)idx);
|
||||
EEPROM.commit();
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_create_settings_screen(lv_obj_t *parent) {
|
||||
gui_style_black_container(parent);
|
||||
gui_label_at(parent, &lv_font_montserrat_14, GUI_COL_DIM, "SETTINGS", GUI_PAD, 12);
|
||||
lv_obj_t *lbl = gui_label(parent, &font_mid, GUI_COL_MID, "Coming soon");
|
||||
lv_obj_align(lbl, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Child container for settings content — do NOT set flex on the tile itself
|
||||
lv_obj_t *cont = lv_obj_create(parent);
|
||||
lv_obj_remove_style_all(cont);
|
||||
lv_obj_set_size(cont, GUI_W, GUI_H);
|
||||
lv_obj_set_style_bg_color(cont, lv_color_hex(GUI_COL_BLACK), 0);
|
||||
lv_obj_set_style_bg_opa(cont, LV_OPA_COVER, 0);
|
||||
lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
// Title
|
||||
gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_DIM, "SETTINGS", GUI_PAD, 12);
|
||||
|
||||
// --- Row 1: Display timeout (y=50) ---
|
||||
gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_MID, "Display timeout", GUI_PAD, 55);
|
||||
gui_set_disp_slider = lv_slider_create(cont);
|
||||
lv_obj_set_size(gui_set_disp_slider, 180, 12);
|
||||
lv_obj_set_pos(gui_set_disp_slider, GUI_PAD, 80);
|
||||
lv_slider_set_range(gui_set_disp_slider, 5, 60);
|
||||
lv_slider_set_value(gui_set_disp_slider, (int32_t)(display_blanking_timeout / 1000), LV_ANIM_OFF);
|
||||
lv_obj_set_style_bg_color(gui_set_disp_slider, lv_color_hex(GUI_COL_DIM), 0);
|
||||
lv_obj_set_style_bg_color(gui_set_disp_slider, lv_color_hex(GUI_COL_AMBER), LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_color(gui_set_disp_slider, lv_color_hex(GUI_COL_WHITE), LV_PART_KNOB);
|
||||
lv_obj_set_style_pad_all(gui_set_disp_slider, 4, LV_PART_KNOB);
|
||||
lv_obj_add_event_cb(gui_set_disp_slider, gui_set_disp_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
char disp_buf[8]; snprintf(disp_buf, sizeof(disp_buf), "%lds", (long)(display_blanking_timeout / 1000));
|
||||
gui_set_disp_val = gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_WHITE, disp_buf, GUI_PAD + 200, 75);
|
||||
|
||||
gui_create_rule(cont, 110);
|
||||
|
||||
// --- Row 2: Beacon enable (y=120) ---
|
||||
gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_MID, "Beacon", GUI_PAD, 125);
|
||||
gui_set_bcn_sw = lv_switch_create(cont);
|
||||
lv_obj_set_pos(gui_set_bcn_sw, GUI_W - GUI_PAD - 50, 120);
|
||||
lv_obj_set_size(gui_set_bcn_sw, 50, 26);
|
||||
if (beacon_enabled) lv_obj_add_state(gui_set_bcn_sw, LV_STATE_CHECKED);
|
||||
lv_obj_set_style_bg_color(gui_set_bcn_sw, lv_color_hex(GUI_COL_DIM), 0);
|
||||
lv_obj_set_style_bg_color(gui_set_bcn_sw, lv_color_hex(GUI_COL_AMBER), LV_PART_INDICATOR | LV_STATE_CHECKED);
|
||||
lv_obj_add_event_cb(gui_set_bcn_sw, gui_set_bcn_en_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
gui_create_rule(cont, 160);
|
||||
|
||||
// --- Row 3: Beacon interval (y=170) ---
|
||||
gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_MID, "Beacon interval", GUI_PAD, 175);
|
||||
gui_set_bcn_roller = lv_roller_create(cont);
|
||||
lv_roller_set_options(gui_set_bcn_roller, "10s\n30s\n1min\n5min\n10min", LV_ROLLER_MODE_NORMAL);
|
||||
lv_obj_set_pos(gui_set_bcn_roller, GUI_W - GUI_PAD - 100, 170);
|
||||
lv_obj_set_size(gui_set_bcn_roller, 100, 60);
|
||||
lv_obj_set_style_bg_color(gui_set_bcn_roller, lv_color_hex(GUI_COL_BLACK), 0);
|
||||
lv_obj_set_style_text_color(gui_set_bcn_roller, lv_color_hex(GUI_COL_WHITE), 0);
|
||||
lv_obj_set_style_text_font(gui_set_bcn_roller, &lv_font_montserrat_14, 0);
|
||||
lv_obj_set_style_bg_color(gui_set_bcn_roller, lv_color_hex(GUI_COL_AMBER), LV_PART_SELECTED);
|
||||
lv_obj_set_style_text_color(gui_set_bcn_roller, lv_color_hex(GUI_COL_BLACK), LV_PART_SELECTED);
|
||||
// Set initial selection from current beacon_interval_ms
|
||||
for (uint8_t i = 0; i < BEACON_INTERVAL_OPTIONS_COUNT; i++) {
|
||||
if (beacon_interval_options[i] == beacon_interval_ms) {
|
||||
lv_roller_set_selected(gui_set_bcn_roller, i, LV_ANIM_OFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lv_obj_add_event_cb(gui_set_bcn_roller, gui_set_bcn_int_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
gui_create_rule(cont, 245);
|
||||
|
||||
// --- Row 4: GPS dynamic model (y=255) ---
|
||||
gui_label_at(cont, &lv_font_montserrat_14, GUI_COL_MID, "GPS model", GUI_PAD, 260);
|
||||
gui_set_gps_roller = lv_roller_create(cont);
|
||||
lv_roller_set_options(gui_set_gps_roller, "Portable\nStationary\nPedestrian\nAutomotive", LV_ROLLER_MODE_NORMAL);
|
||||
lv_obj_set_pos(gui_set_gps_roller, GUI_W - GUI_PAD - 140, 255);
|
||||
lv_obj_set_size(gui_set_gps_roller, 140, 60);
|
||||
lv_obj_set_style_bg_color(gui_set_gps_roller, lv_color_hex(GUI_COL_BLACK), 0);
|
||||
lv_obj_set_style_text_color(gui_set_gps_roller, lv_color_hex(GUI_COL_WHITE), 0);
|
||||
lv_obj_set_style_text_font(gui_set_gps_roller, &lv_font_montserrat_14, 0);
|
||||
lv_obj_set_style_bg_color(gui_set_gps_roller, lv_color_hex(GUI_COL_AMBER), LV_PART_SELECTED);
|
||||
lv_obj_set_style_text_color(gui_set_gps_roller, lv_color_hex(GUI_COL_BLACK), LV_PART_SELECTED);
|
||||
lv_roller_set_selected(gui_set_gps_roller, gps_dynamic_model, LV_ANIM_OFF);
|
||||
lv_obj_add_event_cb(gui_set_gps_roller, gui_set_gps_model_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -423,6 +423,19 @@ void setup() {
|
|||
lxmf_init_identity();
|
||||
// Initialize IFAC authentication (load from NVS if provisioned)
|
||||
ifac_init();
|
||||
// Load user settings from config EEPROM
|
||||
uint8_t s_disp = EEPROM.read(config_addr(ADDR_CONF_DISP_TIMEOUT));
|
||||
if (s_disp != 0xFF && s_disp >= 5 && s_disp <= 60)
|
||||
display_blanking_timeout = (uint32_t)s_disp * 1000;
|
||||
uint8_t s_bcn_int = EEPROM.read(config_addr(ADDR_CONF_BCN_INT));
|
||||
if (s_bcn_int != 0xFF && s_bcn_int < BEACON_INTERVAL_OPTIONS_COUNT)
|
||||
beacon_interval_ms = beacon_interval_options[s_bcn_int];
|
||||
uint8_t s_gps_model = EEPROM.read(config_addr(ADDR_CONF_GPS_MODEL));
|
||||
if (s_gps_model != 0xFF && s_gps_model < GPS_MODEL_OPTIONS_COUNT)
|
||||
gps_set_dynamic_model(s_gps_model);
|
||||
uint8_t s_bcn_en = EEPROM.read(config_addr(ADDR_CONF_BCN_EN));
|
||||
if (s_bcn_en != 0xFF)
|
||||
beacon_enabled = (s_bcn_en != 0);
|
||||
#endif
|
||||
|
||||
if (console_active) {
|
||||
|
|
@ -2309,7 +2322,7 @@ void twatch_enter_deep_sleep(bool beacon_timer) {
|
|||
// 6. Configure wakeup sources
|
||||
esp_sleep_enable_ext1_wakeup(1ULL << PMU_IRQ, ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
if (beacon_timer) {
|
||||
esp_sleep_enable_timer_wakeup((uint64_t)BEACON_INTERVAL_MS * 1000ULL);
|
||||
esp_sleep_enable_timer_wakeup((uint64_t)beacon_interval_ms * 1000ULL);
|
||||
}
|
||||
|
||||
// 7. Enter deep sleep (does not return)
|
||||
|
|
|
|||
6
ROM.h
6
ROM.h
|
|
@ -66,6 +66,12 @@
|
|||
#define ADDR_BCN_KEY 0x51 // Collector X25519 public key — 32 bytes (0x51-0x70)
|
||||
#define ADDR_BCN_IHASH 0x71 // Collector identity hash — 16 bytes (0x71-0x80)
|
||||
#define ADDR_BCN_DHASH 0x81 // Collector dest hash — 16 bytes (0x81-0x90)
|
||||
|
||||
// User settings — stored in config region via config_addr()
|
||||
#define ADDR_CONF_DISP_TIMEOUT 0x91 // Display blank timeout in seconds — 1 byte
|
||||
#define ADDR_CONF_BCN_INT 0x92 // Beacon interval index — 1 byte
|
||||
#define ADDR_CONF_GPS_MODEL 0x93 // GPS dynamic model index — 1 byte
|
||||
#define ADDR_CONF_BCN_EN 0x94 // Beacon enable (0=off, 1=on) — 1 byte
|
||||
//////////////////////////////////
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue