diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 4f5476cf..027b77a0 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -268,6 +268,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no file.read((uint8_t *)_prefs.dm_notif, sizeof(_prefs.dm_notif)); if (file.available()) { file.read((uint8_t *)_prefs.dashboard_fields, sizeof(_prefs.dashboard_fields)); + if (file.available()) { + file.read((uint8_t *)&_prefs.advert_auto_interval_sec, sizeof(_prefs.advert_auto_interval_sec)); + } } } } @@ -342,6 +345,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.buzzer_auto, sizeof(_prefs.buzzer_auto)); file.write((uint8_t *)_prefs.dm_notif, sizeof(_prefs.dm_notif)); file.write((uint8_t *)_prefs.dashboard_fields, sizeof(_prefs.dashboard_fields)); + file.write((uint8_t *)&_prefs.advert_auto_interval_sec, sizeof(_prefs.advert_auto_interval_sec)); file.close(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 5fc8abc9..6071dda4 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -854,6 +854,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe offline_queue_len = 0; app_target_ver = 0; _bot_last_reply_ms = 0; + _next_auto_advert_ms = 0; clearPendingReqs(); next_ack_idx = 0; sign_data = NULL; @@ -2204,6 +2205,11 @@ void MyMesh::loop() { dirty_contacts_expiry = 0; } + if (_prefs.advert_auto_interval_sec > 0 && millisHasNowPassed(_next_auto_advert_ms)) { + advert(); + _next_auto_advert_ms = futureMillis(_prefs.advert_auto_interval_sec * 1000UL); + } + #ifdef DISPLAY_CLASS if (_ui) _ui->setHasConnection(_serial->isConnected()); #endif diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 4b1e73c8..8362878c 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -242,6 +242,7 @@ private: uint32_t sign_data_len; unsigned long dirty_contacts_expiry; unsigned long _bot_last_reply_ms; + unsigned long _next_auto_advert_ms; TransportKey send_scope; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 05fbbd66..94e593c3 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -61,4 +61,5 @@ struct NodePrefs { // persisted to file static const int DM_NOTIF_TABLE_MAX = 16; DmNotifEntry dm_notif[DM_NOTIF_TABLE_MAX]; // 16*5 = 80 bytes uint8_t dashboard_fields[3]; // 0=None,1=Batt,2=Temp,3=Hum,4=Pres,5=GPS,6=Alt,7=Lux,8=CO2,9=Nodes + uint32_t advert_auto_interval_sec; // periodic 0-hop advert with GPS: 0=off, else seconds }; \ No newline at end of file diff --git a/examples/companion_radio/ui-new/AutoAdvertScreen.h b/examples/companion_radio/ui-new/AutoAdvertScreen.h new file mode 100644 index 00000000..c4c1dac6 --- /dev/null +++ b/examples/companion_radio/ui-new/AutoAdvertScreen.h @@ -0,0 +1,68 @@ +#pragma once +// Configures periodic automatic 0-hop advert with GPS position. +// Included by UITask.cpp after DashboardConfigScreen.h. + +class AutoAdvertScreen : public UIScreen { + UITask* _task; + NodePrefs* _prefs; + bool _dirty; + + static const int OPT_COUNT = 7; + static const uint32_t OPTS[OPT_COUNT]; + static const char* OPT_LABELS[OPT_COUNT]; + + int currentIdx() const { + for (int i = 0; i < OPT_COUNT; i++) + if (OPTS[i] == _prefs->advert_auto_interval_sec) return i; + return 0; + } + +public: + AutoAdvertScreen(UITask* task, NodePrefs* prefs) : _task(task), _prefs(prefs) {} + + void enter() { _dirty = false; } + + int render(DisplayDriver& display) override { + display.setTextSize(1); + display.setColor(DisplayDriver::LIGHT); + display.drawTextCentered(display.width() / 2, 0, "AUTO-ADVERT"); + display.fillRect(0, 10, display.width(), 1); + + display.setCursor(2, 14); + display.print("Interval:"); + + int idx = currentIdx(); + display.setColor(DisplayDriver::LIGHT); + display.fillRect(0, 24, display.width(), 12); + display.setColor(DisplayDriver::DARK); + display.drawTextCentered(display.width() / 2, 25, OPT_LABELS[idx]); + display.setColor(DisplayDriver::LIGHT); + + display.setCursor(2, 40); + display.print("< > to change"); + display.setCursor(2, 51); + display.print("[Esc] to save"); + return 500; + } + + bool handleInput(char c) override { + if (c == KEY_CANCEL || c == KEY_CONTEXT_MENU) { + if (_dirty) the_mesh.savePrefs(); + _task->gotoToolsScreen(); + return true; + } + bool right = (c == KEY_RIGHT || c == KEY_NEXT || c == KEY_ENTER); + bool left = (c == KEY_LEFT || c == KEY_PREV); + if (right || left) { + int idx = currentIdx(); + idx = right ? (idx + 1) % OPT_COUNT : (idx + OPT_COUNT - 1) % OPT_COUNT; + _prefs->advert_auto_interval_sec = OPTS[idx]; + _dirty = true; + return true; + } + return false; + } +}; + +const uint32_t AutoAdvertScreen::OPTS[AutoAdvertScreen::OPT_COUNT] = { 0, 60, 120, 300, 600, 1800, 3600 }; +const char* AutoAdvertScreen::OPT_LABELS[AutoAdvertScreen::OPT_COUNT] = { "off", "1min", "2min", "5min", "10min", "30min", "1h" }; diff --git a/examples/companion_radio/ui-new/ToolsScreen.h b/examples/companion_radio/ui-new/ToolsScreen.h index 2bb600ee..f738718a 100644 --- a/examples/companion_radio/ui-new/ToolsScreen.h +++ b/examples/companion_radio/ui-new/ToolsScreen.h @@ -6,7 +6,7 @@ class ToolsScreen : public UIScreen { UITask* _task; int _sel; - static const int ITEM_COUNT = 3; + static const int ITEM_COUNT = 4; static const char* ITEMS[ITEM_COUNT]; public: @@ -42,11 +42,12 @@ public: if (c == KEY_DOWN && _sel < ITEM_COUNT - 1) { _sel++; return true; } if (c == KEY_CANCEL || c == KEY_CONTEXT_MENU) { _task->gotoHomeScreen(); return true; } if (c == KEY_ENTER) { - if (_sel == 0) { _task->gotoRingtoneEditor(); return true; } - if (_sel == 1) { _task->gotoBotScreen(); return true; } - if (_sel == 2) { _task->gotoNearbyScreen(); return true; } + if (_sel == 0) { _task->gotoRingtoneEditor(); return true; } + if (_sel == 1) { _task->gotoBotScreen(); return true; } + if (_sel == 2) { _task->gotoNearbyScreen(); return true; } + if (_sel == 3) { _task->gotoAutoAdvertScreen(); return true; } } return false; } }; -const char* ToolsScreen::ITEMS[3] = { "Ringtone Editor", "Auto-Reply Bot", "Nearby Nodes" }; +const char* ToolsScreen::ITEMS[4] = { "Ringtone Editor", "Auto-Reply Bot", "Nearby Nodes", "Auto-Advert" }; diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index eb4701b5..77b015f2 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -1594,6 +1594,7 @@ public: #include "BotScreen.h" #include "NearbyScreen.h" #include "DashboardConfigScreen.h" +#include "AutoAdvertScreen.h" #include "ToolsScreen.h" // ── HomeScreen ──────────────────────────────────────────────────────────────── @@ -2252,6 +2253,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no bot_screen = new BotScreen(this, node_prefs); nearby_screen = new NearbyScreen(this); dashboard_config = new DashboardConfigScreen(this, node_prefs); + auto_advert_screen = new AutoAdvertScreen(this, node_prefs); setCurrScreen(splash); applyBrightness(); @@ -2286,6 +2288,11 @@ void UITask::gotoDashboardConfig() { setCurrScreen(dashboard_config); } +void UITask::gotoAutoAdvertScreen() { + ((AutoAdvertScreen*)auto_advert_screen)->enter(); + setCurrScreen(auto_advert_screen); +} + void UITask::playMelody(const char* melody) { #ifdef PIN_BUZZER buzzer.playForced(melody); diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 388500b7..c96711dc 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -65,6 +65,7 @@ class UITask : public AbstractUITask { UIScreen* bot_screen; UIScreen* nearby_screen; UIScreen* dashboard_config; + UIScreen* auto_advert_screen; UIScreen* curr; void userLedHandler(); @@ -102,6 +103,7 @@ public: void gotoBotScreen(); void gotoNearbyScreen(); void gotoDashboardConfig(); + void gotoAutoAdvertScreen(); void playMelody(const char* melody); void stopMelody(); bool isMelodyPlaying();