From f861b68a092a3b899a3a01ffb8bca7b9347e87c8 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 23 Mar 2025 17:36:31 +1100 Subject: [PATCH 1/5] * refactor: ESP32 OTA lib-deps now selectively added --- platformio.ini | 3 ++- src/helpers/ESP32Board.cpp | 9 +++++++++ variants/heltec_v2/platformio.ini | 6 ++++++ variants/heltec_v3/platformio.ini | 12 ++++++++++++ variants/lilygo_t3s3/platformio.ini | 6 ++++++ variants/lilygo_tlora_v2_1/platformio.ini | 6 ++++++ variants/station_g2/platformio.ini | 6 ++++++ variants/xiao_c3/platformio.ini | 6 ++++++ variants/xiao_s3_wio/platformio.ini | 3 +++ 9 files changed, 56 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index c2940f44..3bd80b57 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,8 +40,9 @@ extra_scripts = merge-bin.py build_flags = ${arduino_base.build_flags} ; -D ESP32_CPU_FREQ=80 ; change it to your need build_src_filter = ${arduino_base.build_src_filter} + +[esp32_ota] lib_deps = - ${arduino_base.lib_deps} me-no-dev/ESPAsyncWebServer @ ^3.6.0 file://arch/esp32/AsyncElegantOTA diff --git a/src/helpers/ESP32Board.cpp b/src/helpers/ESP32Board.cpp index 1eb1cdb9..57838d32 100644 --- a/src/helpers/ESP32Board.cpp +++ b/src/helpers/ESP32Board.cpp @@ -1,6 +1,8 @@ #ifdef ESP_PLATFORM #include "ESP32Board.h" + +#if defined(ADMIN_PASSWORD) // Repeater or Room Server only #include #include #include @@ -29,4 +31,11 @@ bool ESP32Board::startOTAUpdate(const char* id, char reply[]) { return true; } + +#else +bool ESP32Board::startOTAUpdate(const char* id, char reply[]) { + return false; // not supported +} +#endif + #endif diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index 117432bf..cfca7fee 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -33,6 +33,9 @@ build_flags = build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<../examples/simple_repeater> + +lib_deps = + ${Heltec_lora32_v2.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_v2_room_server] extends = Heltec_lora32_v2 @@ -49,6 +52,9 @@ build_flags = build_src_filter = ${Heltec_lora32_v2.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${Heltec_lora32_v2.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_v2_terminal_chat] extends = Heltec_lora32_v2 diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index bfd7accb..cfe8f264 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -36,6 +36,9 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${Heltec_lora32_v3.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_v3_room_server] extends = Heltec_lora32_v3 @@ -52,6 +55,9 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${Heltec_lora32_v3.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_v3_terminal_chat] extends = Heltec_lora32_v3 @@ -140,6 +146,9 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_repeater> +lib_deps = + ${Heltec_lora32_v3.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_WSL3_room_server] extends = Heltec_lora32_v3 @@ -154,6 +163,9 @@ build_flags = -D ROOM_PASSWORD='"hello"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${Heltec_lora32_v3.lib_deps} + ${esp32_ota.lib_deps} [env:Heltec_WSL3_companion_radio_ble] extends = Heltec_lora32_v3 diff --git a/variants/lilygo_t3s3/platformio.ini b/variants/lilygo_t3s3/platformio.ini index 698d7c86..59ed60b4 100644 --- a/variants/lilygo_t3s3/platformio.ini +++ b/variants/lilygo_t3s3/platformio.ini @@ -47,6 +47,9 @@ build_flags = build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${LilyGo_T3S3_sx1262.lib_deps} + ${esp32_ota.lib_deps} [env:LilyGo_T3S3_sx1262_terminal_chat] extends = LilyGo_T3S3_sx1262 @@ -77,6 +80,9 @@ build_flags = build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${LilyGo_T3S3_sx1262.lib_deps} + ${esp32_ota.lib_deps} [env:LilyGo_T3S3_sx1262_companion_radio_usb] extends = LilyGo_T3S3_sx1262 diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index 017857d6..f7485f9c 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -45,6 +45,9 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 ; -D CORE_DEBUG_LEVEL=3 +lib_deps = + ${LilyGo_TLora_V2_1_1_6.lib_deps} + ${esp32_ota.lib_deps} [env:LilyGo_TLora_V2_1_1_6_terminal_chat] extends = LilyGo_TLora_V2_1_1_6 @@ -112,3 +115,6 @@ build_flags = -D ROOM_PASSWORD='"hello"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${LilyGo_TLora_V2_1_1_6.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/station_g2/platformio.ini b/variants/station_g2/platformio.ini index e11cb0a1..96eca1c4 100644 --- a/variants/station_g2/platformio.ini +++ b/variants/station_g2/platformio.ini @@ -34,6 +34,9 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Station_G2.build_src_filter} +<../examples/simple_repeater> +lib_deps = + ${Station_G2.lib_deps} + ${esp32_ota.lib_deps} [env:Station_G2_room_server] extends = Station_G2 @@ -48,3 +51,6 @@ build_flags = -D ROOM_PASSWORD='"hello"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${Station_G2.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/xiao_c3/platformio.ini b/variants/xiao_c3/platformio.ini index b66c238f..77c9eae7 100644 --- a/variants/xiao_c3/platformio.ini +++ b/variants/xiao_c3/platformio.ini @@ -35,6 +35,9 @@ build_flags = -D ADMIN_PASSWORD='"password"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} [env:Xiao_C3_Repeater_sx1268] extends = Xiao_esp32_C3 @@ -51,3 +54,6 @@ build_flags = -D ADMIN_PASSWORD='"password"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index 7255f8f2..083f8a16 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -35,6 +35,9 @@ build_flags = -D ADMIN_PASSWORD='"password"' ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_S3_WIO.lib_deps} + ${esp32_ota.lib_deps} [env:Xiao_S3_WIO_terminal_chat] extends = Xiao_S3_WIO From 7010123619ed2b4ac8b2277567fab49d20cb5f96 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 23 Mar 2025 20:25:03 +1100 Subject: [PATCH 2/5] * companion: CMD_SEND_TXT_MSG fix for attempt number --- examples/companion_radio/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 994a90c0..58709d0e 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -907,7 +907,7 @@ public: memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4; uint8_t* pub_key_prefix = &cmd_frame[i]; i += 6; ContactInfo* recipient = lookupContactByPubKey(pub_key_prefix, 6); - if (recipient && attempt < 4 && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) { + if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) { char *text = (char *) &cmd_frame[i]; int tlen = len - i; uint32_t est_timeout; From 39a447619492f2fa7da7ff6099a9b671bf90a7e2 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 23 Mar 2025 23:23:02 +1100 Subject: [PATCH 3/5] * repeater & room server: new config "flood.advert.interval" --- examples/simple_repeater/main.cpp | 29 ++++++++++++++++++++-------- examples/simple_room_server/main.cpp | 26 ++++++++++++++++++------- src/helpers/CommonCLI.cpp | 18 +++++++++++++++-- src/helpers/CommonCLI.h | 5 +++-- 4 files changed, 59 insertions(+), 19 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index f3467a8a..c24227df 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -112,7 +112,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { FILESYSTEM* _fs; RADIO_CLASS* _phy; mesh::MainBoard* _board; - unsigned long next_local_advert; + unsigned long next_local_advert, next_flood_advert; bool _logging; NodePrefs _prefs; CommonCLI _cli; @@ -480,7 +480,7 @@ public: { my_radio = &radio; memset(known_clients, 0, sizeof(known_clients)); - next_local_advert = 0; + next_local_advert = next_flood_advert = 0; _logging = false; // defaults @@ -498,6 +498,7 @@ public: _prefs.cr = LORA_CR; _prefs.tx_power_dbm = LORA_TX_POWER; _prefs.advert_interval = 1; // default to 2 minutes for NEW installs + _prefs.flood_advert_interval = 3; // 3 hours _prefs.flood_max = 64; } @@ -516,6 +517,7 @@ public: _phy->setOutputPower(_prefs.tx_power_dbm); updateAdvertTimer(); + updateFloodAdvertTimer(); } const char* getFirmwareVer() override { return FIRMWARE_VERSION; } @@ -548,11 +550,18 @@ public: void updateAdvertTimer() override { if (_prefs.advert_interval > 0) { // schedule local advert timer - next_local_advert = futureMillis((uint32_t)_prefs.advert_interval * 2 * 60 * 1000); + next_local_advert = futureMillis( ((uint32_t)_prefs.advert_interval) * 2 * 60 * 1000); } else { next_local_advert = 0; // stop the timer } } + void updateFloodAdvertTimer() override { + if (_prefs.flood_advert_interval > 0) { // schedule flood advert timer + next_flood_advert = futureMillis( ((uint32_t)_prefs.flood_advert_interval) * 60 * 60 * 1000); + } else { + next_flood_advert = 0; // stop the timer + } + } void setLoggingOn(bool enable) override { _logging = enable; } @@ -579,11 +588,15 @@ public: void loop() { mesh::Mesh::loop(); - if (next_local_advert && millisHasNowPassed(next_local_advert)) { + if (next_flood_advert && millisHasNowPassed(next_flood_advert)) { mesh::Packet* pkt = createSelfAdvert(); - if (pkt) { - sendZeroHop(pkt); - } + if (pkt) sendFlood(pkt); + + updateFloodAdvertTimer(); // schedule next flood advert + updateAdvertTimer(); // also schedule local advert (so they don't overlap) + } else if (next_local_advert && millisHasNowPassed(next_local_advert)) { + mesh::Packet* pkt = createSelfAdvert(); + if (pkt) sendZeroHop(pkt); updateAdvertTimer(); // schedule next local advert } @@ -657,7 +670,7 @@ void setup() { #endif // send out initial Advertisement to the mesh - the_mesh.sendSelfAdvertisement(2000); + the_mesh.sendSelfAdvertisement(16000); } void loop() { diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 4cef1365..7aa495e1 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -139,7 +139,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { FILESYSTEM* _fs; RADIO_CLASS* _phy; mesh::MainBoard* _board; - unsigned long next_local_advert; + unsigned long next_local_advert, next_flood_advert; NodePrefs _prefs; CommonCLI _cli; uint8_t reply_data[MAX_PACKET_PAYLOAD]; @@ -584,7 +584,7 @@ public: _phy(&phy), _board(&board), _cli(board, this, &_prefs, this) { my_radio = &radio; - next_local_advert = 0; + next_local_advert = next_flood_advert = 0; // defaults memset(&_prefs, 0, sizeof(_prefs)); @@ -602,6 +602,7 @@ public: _prefs.tx_power_dbm = LORA_TX_POWER; _prefs.disable_fwd = 1; _prefs.advert_interval = 1; // default to 2 minutes for NEW installs + _prefs.flood_advert_interval = 3; // 3 hours _prefs.flood_max = 64; #ifdef ROOM_PASSWORD StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password)); @@ -667,6 +668,13 @@ public: next_local_advert = 0; // stop the timer } } + void updateFloodAdvertTimer() override { + if (_prefs.flood_advert_interval > 0) { // schedule flood advert timer + next_flood_advert = futureMillis( ((uint32_t)_prefs.flood_advert_interval) * 60 * 60 * 1000); + } else { + next_flood_advert = 0; // stop the timer + } + } void setLoggingOn(bool enable) override { /* no-op */ } void eraseLogFile() override { /* no-op */ } @@ -711,11 +719,15 @@ public: next_push = futureMillis(SYNC_PUSH_INTERVAL); } - if (next_local_advert && millisHasNowPassed(next_local_advert)) { + if (next_flood_advert && millisHasNowPassed(next_flood_advert)) { mesh::Packet* pkt = createSelfAdvert(); - if (pkt) { - sendZeroHop(pkt); - } + if (pkt) sendFlood(pkt); + + updateFloodAdvertTimer(); // schedule next flood advert + updateAdvertTimer(); // also schedule local advert (so they don't overlap) + } else if (next_local_advert && millisHasNowPassed(next_local_advert)) { + mesh::Packet* pkt = createSelfAdvert(); + if (pkt) sendZeroHop(pkt); updateAdvertTimer(); // schedule next local advert } @@ -791,7 +803,7 @@ void setup() { #endif // send out initial Advertisement to the mesh - the_mesh.sendSelfAdvertisement(2000); + the_mesh.sendSelfAdvertisement(16000); } void loop() { diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 457816a4..b9950dd1 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -29,7 +29,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) { file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76 file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77 file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78 - file.read((uint8_t *) &_prefs->unused, sizeof(_prefs->unused)); // 79 + file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 79 file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80 file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84 file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88 @@ -80,7 +80,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76 file.write((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77 file.write((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78 - file.write((uint8_t *) &_prefs->unused, sizeof(_prefs->unused)); // 79 + file.write((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 79 file.write((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80 file.write((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84 file.write((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88 @@ -155,6 +155,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch const char* config = &command[4]; if (memcmp(config, "af", 2) == 0) { sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor)); + } else if (memcmp(config, "flood.advert.interval", 21) == 0) { + sprintf(reply, "> %d", ((uint32_t) _prefs->flood_advert_interval)); } else if (memcmp(config, "advert.interval", 15) == 0) { sprintf(reply, "> %d", ((uint32_t) _prefs->advert_interval) * 2); } else if (memcmp(config, "guest.password", 14) == 0) { @@ -193,6 +195,18 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _prefs->airtime_factor = atof(&config[3]); savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "flood.advert.interval ", 22) == 0) { + int hours = _atoi(&config[22]); + if (hours > 0 && hours < 3) { + sprintf(reply, "Error: min is 3 hours"); + } else if (hours > 48) { + strcpy(reply, "Error: max is 48 hours"); + } else { + _prefs->flood_advert_interval = (uint8_t)(hours); + _callbacks->updateFloodAdvertTimer(); + savePrefs(); + strcpy(reply, "OK"); + } } else if (memcmp(config, "advert.interval ", 16) == 0) { int mins = _atoi(&config[16]); if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 5538f339..309ee134 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -11,8 +11,8 @@ struct NodePrefs { // persisted to file float freq; uint8_t tx_power_dbm; uint8_t disable_fwd; - uint8_t advert_interval; // minutes - uint8_t unused; + uint8_t advert_interval; // minutes / 2 + uint8_t flood_advert_interval; // hours float rx_delay_base; float tx_delay_factor; char guest_password[16]; @@ -34,6 +34,7 @@ public: virtual bool formatFileSystem() = 0; virtual void sendSelfAdvertisement(int delay_millis) = 0; virtual void updateAdvertTimer() = 0; + virtual void updateFloodAdvertTimer() = 0; virtual void setLoggingOn(bool enable) = 0; virtual void eraseLogFile() = 0; virtual void dumpLogFile() = 0; From d07abc39b6bb402dea3ee1643ae0297c647fd226 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 24 Mar 2025 00:25:36 +1100 Subject: [PATCH 4/5] * room server: new config "allow.read.only" --- examples/simple_room_server/main.cpp | 38 +++++++++++++++++++--------- src/helpers/CommonCLI.cpp | 10 ++++++-- src/helpers/CommonCLI.h | 2 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 7aa495e1..12a576d2 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -79,6 +79,12 @@ /* ------------------------------ Code -------------------------------- */ +enum RoomPermission { + ADMIN, + GUEST, + READ_ONLY +}; + struct ClientInfo { mesh::Identity id; uint32_t last_timestamp; // by THEIR clock @@ -87,7 +93,7 @@ struct ClientInfo { uint32_t pending_ack; uint32_t push_post_timestamp; unsigned long ack_timeout; - bool is_admin; + RoomPermission permission; uint8_t push_failures; uint8_t secret[PUB_KEY_SIZE]; int out_path_len; @@ -299,13 +305,16 @@ protected: memcpy(&sender_timestamp, data, 4); memcpy(&sender_sync_since, &data[4], 4); // sender's "sync messags SINCE x" timestamp - bool is_admin; + RoomPermission perm; data[len] = 0; // ensure null terminator if (strcmp((char *) &data[8], _prefs.password) == 0) { // check for valid admin password - is_admin = true; + perm = RoomPermission::ADMIN; } else { - is_admin = false; - if (strcmp((char *) &data[8], _prefs.guest_password) != 0) { // check the room/public password + if (strcmp((char *) &data[8], _prefs.guest_password) == 0) { // check the room/public password + perm = RoomPermission::GUEST; + } else if (_prefs.allow_read_only) { + perm = RoomPermission::READ_ONLY; + } else { MESH_DEBUG_PRINTLN("Incorrect room password"); return; // no response. Client will timeout } @@ -318,7 +327,7 @@ protected: } MESH_DEBUG_PRINTLN("Login success!"); - client->is_admin = is_admin; + client->permission = perm; client->last_timestamp = sender_timestamp; client->sync_since = sender_sync_since; client->pending_ack = 0; @@ -332,7 +341,7 @@ protected: // TODO: maybe reply with count of messages waiting to be synced for THIS client? reply_data[4] = RESP_SERVER_LOGIN_OK; reply_data[5] = (CLIENT_KEEP_ALIVE_SECS >> 4); // NEW: recommended keep-alive interval (secs / 16) - reply_data[6] = is_admin ? 1 : 0; + reply_data[6] = (perm == RoomPermission::ADMIN ? 1 : (perm == RoomPermission::GUEST ? 0 : 2)); reply_data[7] = 0; // FUTURE: reserved memcpy(&reply_data[8], "OK", 2); // REVISIT: not really needed @@ -409,7 +418,7 @@ protected: uint8_t temp[166]; bool send_ack; if (flags == TXT_TYPE_CLI_DATA) { - if (client->is_admin) { + if (client->permission == RoomPermission::ADMIN) { if (is_retry) { temp[5] = 0; // no reply } else { @@ -422,11 +431,16 @@ protected: send_ack = false; // and no ACK... user shoudn't be sending these } } else { // TXT_TYPE_PLAIN - if (!is_retry) { - addPost(client, (const char *) &data[5]); + if (client->permission == RoomPermission::READ_ONLY) { + temp[5] = 0; // no reply + send_ack = false; // no ACK + } else { + if (!is_retry) { + addPost(client, (const char *) &data[5]); + } + temp[5] = 0; // no reply (ACK is enough) + send_ack = true; } - temp[5] = 0; // no reply (ACK is enough) - send_ack = true; } uint32_t delay_millis; diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index b9950dd1..b83bb26d 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -37,7 +37,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) { file.read(pad, 4); // 108 file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112 file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113 - file.read((uint8_t *) &_prefs->reserved1, sizeof(_prefs->reserved1)); // 114 + file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114 file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115 file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116 file.read(pad, 4); // 120 @@ -88,7 +88,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write(pad, 4); // 108 file.write((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112 file.write((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113 - file.write((uint8_t *) &_prefs->reserved1, sizeof(_prefs->reserved1)); // 114 + file.write((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114 file.write((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115 file.write((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116 file.write(pad, 4); // 120 @@ -155,6 +155,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch const char* config = &command[4]; if (memcmp(config, "af", 2) == 0) { sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor)); + } else if (memcmp(config, "allow.read.only", 15) == 0) { + sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off"); } else if (memcmp(config, "flood.advert.interval", 21) == 0) { sprintf(reply, "> %d", ((uint32_t) _prefs->flood_advert_interval)); } else if (memcmp(config, "advert.interval", 15) == 0) { @@ -195,6 +197,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _prefs->airtime_factor = atof(&config[3]); savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "allow.read.only ", 16) == 0) { + _prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0; + savePrefs(); + strcpy(reply, "OK"); } else if (memcmp(config, "flood.advert.interval ", 22) == 0) { int hours = _atoi(&config[22]); if (hours > 0 && hours < 3) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 309ee134..4a6a6454 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -20,7 +20,7 @@ struct NodePrefs { // persisted to file uint32_t guard; uint8_t sf; uint8_t cr; - uint8_t reserved1; + uint8_t allow_read_only; uint8_t reserved2; float bw; uint8_t flood_max; From edb201ccbe4388dbd9b45b40dc6602fd082cca9a Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 24 Mar 2025 00:50:28 +1100 Subject: [PATCH 5/5] * repeater & room server: "node_prefs" -> "com_prefs" migration --- src/helpers/CommonCLI.cpp | 90 +++++++++++++++++++++------------------ src/helpers/CommonCLI.h | 2 + 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index b83bb26d..a9345ece 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -14,57 +14,65 @@ static uint32_t _atoi(const char* sp) { } void CommonCLI::loadPrefs(FILESYSTEM* fs) { - if (fs->exists("/node_prefs")) { - File file = fs->open("/node_prefs"); - if (file) { - uint8_t pad[8]; + if (fs->exists("/com_prefs")) { + loadPrefsInt(fs, "/com_prefs"); // new filename + } else if (fs->exists("/node_prefs")) { + loadPrefsInt(fs, "/node_prefs"); + savePrefs(fs); // save to new filename + fs->remove("/node_prefs"); // remove old + } +} - file.read((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0 - file.read((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4 - file.read(pad, 4); // 36 - file.read((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40 - file.read((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48 - file.read((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56 - file.read((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72 - file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76 - file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77 - file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78 - file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 79 - file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80 - file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84 - file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88 - file.read((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104 - file.read(pad, 4); // 108 - file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112 - file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113 - file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114 - file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115 - file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116 - file.read(pad, 4); // 120 - file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124 +void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { + File file = fs->open(filename); + if (file) { + uint8_t pad[8]; - // sanitise bad pref values - _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); - _prefs->tx_delay_factor = constrain(_prefs->tx_delay_factor, 0, 2.0f); - _prefs->direct_tx_delay_factor = constrain(_prefs->direct_tx_delay_factor, 0, 2.0f); - _prefs->airtime_factor = constrain(_prefs->airtime_factor, 0, 9.0f); - _prefs->freq = constrain(_prefs->freq, 400.0f, 2500.0f); - _prefs->bw = constrain(_prefs->bw, 62.5f, 500.0f); - _prefs->sf = constrain(_prefs->sf, 7, 12); - _prefs->cr = constrain(_prefs->cr, 5, 8); - _prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30); + file.read((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0 + file.read((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4 + file.read(pad, 4); // 36 + file.read((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40 + file.read((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48 + file.read((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56 + file.read((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72 + file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76 + file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77 + file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78 + file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 79 + file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80 + file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84 + file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88 + file.read((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104 + file.read(pad, 4); // 108 + file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112 + file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113 + file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114 + file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115 + file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116 + file.read(pad, 4); // 120 + file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124 - file.close(); - } + // sanitise bad pref values + _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); + _prefs->tx_delay_factor = constrain(_prefs->tx_delay_factor, 0, 2.0f); + _prefs->direct_tx_delay_factor = constrain(_prefs->direct_tx_delay_factor, 0, 2.0f); + _prefs->airtime_factor = constrain(_prefs->airtime_factor, 0, 9.0f); + _prefs->freq = constrain(_prefs->freq, 400.0f, 2500.0f); + _prefs->bw = constrain(_prefs->bw, 62.5f, 500.0f); + _prefs->sf = constrain(_prefs->sf, 7, 12); + _prefs->cr = constrain(_prefs->cr, 5, 8); + _prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30); + + file.close(); } } void CommonCLI::savePrefs(FILESYSTEM* fs) { #if defined(NRF52_PLATFORM) - File file = fs->open("/node_prefs", FILE_O_WRITE); + File file = fs->open("/com_prefs", FILE_O_WRITE); if (file) { file.seek(0); file.truncate(); } #else - File file = fs->open("/node_prefs", "w", true); + File file = fs->open("/com_prefs", "w", true); #endif if (file) { uint8_t pad[8]; diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 4a6a6454..a31eefa5 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -53,6 +53,8 @@ class CommonCLI { void checkAdvertInterval(); + void loadPrefsInt(FILESYSTEM* _fs, const char* filename); + public: CommonCLI(mesh::MainBoard& board, mesh::Mesh* mesh, NodePrefs* prefs, CommonCLICallbacks* callbacks) : _board(&board), _mesh(mesh), _prefs(prefs), _callbacks(callbacks) { }