From ddac13ae80c74960a0879975741236f9021dc2cd Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Thu, 6 Nov 2025 21:40:52 +1100 Subject: [PATCH] * repeater: CLI, added "region put" and "region remove" commands --- examples/simple_repeater/MyMesh.cpp | 29 ++++++++++++++++++++++++----- src/helpers/RegionMap.cpp | 13 ++++++++++++- src/helpers/RegionMap.h | 2 ++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index a996cbf6..b06ae42a 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -890,10 +890,6 @@ void MyMesh::clearStats() { ((SimpleMeshTables *)getTables())->resetStats(); } -static bool is_name_char(char c) { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' || c == '#'; -} - void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply) { if (region_load_active) { if (*command == 0) { // empty line, signal to terminate 'load' operation @@ -907,7 +903,7 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply int indent = np - command; char *ep = np; - while (is_name_char(*ep)) ep++; + while (RegionMap::is_name_char(*ep)) ep++; if (*ep) { *ep++ = 0; } // set null terminator for end of name while (*ep && *ep != 'F') ep++; // look for (optional) flags @@ -1022,6 +1018,29 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply } else if (n == 2 && strcmp(parts[1], "home") == 0) { auto home = region_map.getHomeRegion(); sprintf(reply, " home is %s", home ? home->name : "*"); + } else if (n >= 3 && strcmp(parts[1], "put") == 0) { + auto parent = n >= 4 ? region_map.findByNamePrefix(parts[3]) : ®ion_map.getWildcard(); + if (parent == NULL) { + strcpy(reply, "Err - unknown parent"); + } else { + auto region = region_map.putRegion(parts[2], parent->id); + if (region == NULL) { + strcpy(reply, "Err - unable to put"); + } else { + strcpy(reply, "OK"); + } + } + } else if (n >= 3 && strcmp(parts[1], "remove") == 0) { + auto region = region_map.findByName(parts[2]); + if (region) { + if (region_map.removeRegion(*region)) { + strcpy(reply, "OK"); + } else { + strcpy(reply, "Err - not empty"); + } + } else { + strcpy(reply, "Err - not found"); + } } else { strcpy(reply, "Err - ??"); } diff --git a/src/helpers/RegionMap.cpp b/src/helpers/RegionMap.cpp index c6221db0..7d1c08e6 100644 --- a/src/helpers/RegionMap.cpp +++ b/src/helpers/RegionMap.cpp @@ -9,6 +9,10 @@ RegionMap::RegionMap(TransportKeyStore& store) : _store(&store) { strcpy(wildcard.name, "*"); } +bool RegionMap::is_name_char(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' || c == '#'; +} + static File openWrite(FILESYSTEM* _fs, const char* filename) { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove(filename); @@ -93,6 +97,12 @@ bool RegionMap::save(FILESYSTEM* _fs) { } RegionEntry* RegionMap::putRegion(const char* name, uint16_t parent_id, uint16_t id) { + const char* sp = name; // check for illegal name chars + while (*sp) { + if (!is_name_char(*sp)) return NULL; // error + sp++; + } + auto region = findByName(name); if (region) { if (region->id == parent_id) return NULL; // ERROR: invalid parent! @@ -187,8 +197,9 @@ bool RegionMap::removeRegion(const RegionEntry& region) { if (i >= num_regions) return false; // failed (not found) num_regions--; // remove from regions array - while (i + 1 < num_regions) { + while (i < num_regions) { regions[i] = regions[i + 1]; + i++; } return true; // success } diff --git a/src/helpers/RegionMap.h b/src/helpers/RegionMap.h index c3f897c5..50513be1 100644 --- a/src/helpers/RegionMap.h +++ b/src/helpers/RegionMap.h @@ -30,6 +30,8 @@ class RegionMap { public: RegionMap(TransportKeyStore& store); + static bool is_name_char(char c); + bool load(FILESYSTEM* _fs); bool save(FILESYSTEM* _fs);