Preserve unread messages when the OTA wizard borrows queue space
This commit is contained in:
1 parent
02d15876e6
commit
d64a4ef234
5 files changed
+64
-5
No files matched your search
+4
-1
@@ -30,7 +30,10 @@ version 2 direct admin support. An older Full Companion may serve OTA files but
|
||||
provide this guarded admin connection; the wizard will ask for a source
|
||||
firmware upgrade instead of proceeding with that connection.
|
||||
Check `get ota.direct` from its USB console for `v=2`. Update replies use a
|
||||
separate mailbox; ordinary queued messages and saved contact routes stay intact.
|
||||
separate mailbox; the wizard does not consume ordinary queued messages or change
|
||||
saved contact routes. Some Full Companion boards borrow queue space for OTA and
|
||||
retain up to 128 unread messages during an update. If more are waiting, sync them
|
||||
with an app first; the wizard refuses to discard them to make room.
|
||||
|
||||
For this wizard, use an ESP32 source instead of RAK4631 Full. The RAK image's
|
||||
current flash limit prevents adding the new direct admin helper. RAK4631
|
||||
|
||||
@@ -3738,7 +3738,11 @@ bool MyMesh::scheduleTempRadio(float freq, float bw, uint8_t sf, uint8_t cr,
|
||||
}
|
||||
#if defined(OTA_SHARED_COMPANION_QUEUE)
|
||||
uint16_t drained = 0;
|
||||
if (!mesh::ota::ota_acquire_context(reply, reply_size, true, &drained)) return false;
|
||||
bool drain_queue = true;
|
||||
#if COMPANION_FEATURE_DIRECT_OTA_ADMIN
|
||||
drain_queue = !_ota_direct_admin.active(_ms->getMillis());
|
||||
#endif
|
||||
if (!mesh::ota::ota_acquire_context(reply, reply_size, drain_queue, &drained)) return false;
|
||||
mesh::ota::ota_ctx().release_when_idle = false;
|
||||
#endif
|
||||
_temp_radio_freq = freq;
|
||||
@@ -5185,7 +5189,7 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply,
|
||||
while (*action == ' ') ++action;
|
||||
// Only an explicit transfer, catalog search, or source attach may evict
|
||||
// unread offline frames. Read-only OTA queries leave the queue intact.
|
||||
bool const drain_queue = strcmp(action, "folder on") == 0
|
||||
bool drain_queue = strcmp(action, "folder on") == 0
|
||||
|| strcmp(action, "ls") == 0 || strncmp(action, "ls ", 3) == 0
|
||||
|| strncmp(action, "pull ", 5) == 0
|
||||
|| strncmp(action, "get ", 4) == 0
|
||||
@@ -5195,6 +5199,9 @@ bool MyMesh::handleLocalControlCommand(const char* command, char* reply,
|
||||
|| strcmp(action, "applydelta") == 0
|
||||
|| strncmp(action, "bootloader install ", 19) == 0
|
||||
|| strncmp(action, "rescue install ", 15) == 0;
|
||||
#if COMPANION_FEATURE_DIRECT_OTA_ADMIN
|
||||
if (_ota_direct_admin.active(_ms->getMillis())) drain_queue = false;
|
||||
#endif
|
||||
uint16_t drained = 0;
|
||||
if (!mesh::ota::ota_acquire_context(ota_reply, sizeof(ota_reply), drain_queue, &drained)) {
|
||||
snprintf(reply, reply_size, "%s", ota_reply);
|
||||
|
||||
+32
-2
@@ -1,6 +1,7 @@
|
||||
#include <helpers/BorrowableFrameBuffer.h>
|
||||
#include <helpers/ota/OtaContext.h>
|
||||
#include <helpers/CompanionMotaControl.h>
|
||||
#include <helpers/CLICommandUtils.h>
|
||||
#include <helpers/ota/MotaStreamWritePolicy.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@@ -42,6 +43,21 @@ struct Queue {
|
||||
}
|
||||
};
|
||||
|
||||
#define COMPANION_FEATURE_DIRECT_OTA_ADMIN 1
|
||||
struct MyMesh {
|
||||
struct Guard { bool enabled = false; bool active(uint32_t) const { return enabled; } } _ota_direct_admin;
|
||||
struct Timer { uint32_t getMillis() const { return 100; } } timer;
|
||||
Timer* _ms = &timer;
|
||||
bool _primary_radio_blocked = false;
|
||||
float _temp_radio_freq = 0, _temp_radio_bw = 0;
|
||||
uint8_t _temp_radio_sf = 0, _temp_radio_cr = 0, _temp_radio_failures = 0;
|
||||
uint32_t _temp_radio_set_at = 0, _temp_radio_revert_at = 0, _temp_radio_retry_at = 0;
|
||||
uint32_t futureMillis(uint32_t delay) const { return _ms->getMillis() + delay; }
|
||||
void appendRxPowerSavingAdjustmentNote(char*, size_t, uint8_t, float) {}
|
||||
bool scheduleTempRadio(float, float, uint8_t, uint8_t, uint32_t, char*, size_t);
|
||||
};
|
||||
#include "temp_radio_under_test.h"
|
||||
|
||||
class Folder : public MotaSource {
|
||||
public:
|
||||
uint8_t count() override { return 1; }
|
||||
@@ -162,11 +178,25 @@ int main() {
|
||||
assert(strstr(reply, "sync unread messages"));
|
||||
assert(q.head == 191 && q.count == 129 && q.buffer.capacity() == 256);
|
||||
check_messages();
|
||||
MyMesh companion;
|
||||
companion._ota_direct_admin.enabled = true;
|
||||
assert(!companion.scheduleTempRadio(910.525f, 62.5f, 7, 5, 60, reply, sizeof reply));
|
||||
assert(strstr(reply, "sync unread messages"));
|
||||
assert(q.head == 191 && q.count == 129 && q.buffer.capacity() == 256);
|
||||
assert(!companion._temp_radio_set_at && !ota_context_if_active());
|
||||
check_messages();
|
||||
companion._ota_direct_admin.enabled = false;
|
||||
uint16_t drained = 0;
|
||||
assert(ota_acquire_context(reply, sizeof reply, true, &drained));
|
||||
assert(drained == 1 && q.count == 128 && q.head == 0);
|
||||
assert(companion.scheduleTempRadio(910.525f, 62.5f, 7, 5, 60, reply, sizeof reply));
|
||||
assert(strstr(reply, "OTA cleared 1 oldest queued messages"));
|
||||
assert(q.count == 128 && q.head == 0);
|
||||
first_retained = 1;
|
||||
check_messages();
|
||||
companion._ota_direct_admin.enabled = true;
|
||||
assert(companion.scheduleTempRadio(910.525f, 62.5f, 7, 5, 60, reply, sizeof reply));
|
||||
assert(!strstr(reply, "cleared") && q.count == 128);
|
||||
check_messages();
|
||||
ota_ctx().release_when_idle = true;
|
||||
|
||||
for (unsigned cycle = 0; cycle < 8; ++cycle) {
|
||||
assert(ota_acquire_context(reply, sizeof reply));
|
||||
|
||||
@@ -81,6 +81,11 @@ static bool handle_ota_command(const char* command, char* reply, int) {
|
||||
return config(rest, reply, context);
|
||||
}
|
||||
} }
|
||||
#if COMPANION_FEATURE_DIRECT_OTA_ADMIN
|
||||
static struct Guard { bool enabled=false; bool active(uint32_t) const { return enabled; } } _ota_direct_admin;
|
||||
static struct Timer { uint32_t getMillis() const { return 100; } } timer;
|
||||
static Timer* _ms=&timer;
|
||||
#endif
|
||||
static bool companion(const char* command, char* reply, size_t reply_size) {
|
||||
int board=0;
|
||||
@WRAPPER@
|
||||
@@ -124,6 +129,14 @@ int main() {
|
||||
reboot(fs);
|
||||
command("ota folder on", "OK folder attached");
|
||||
assert(drain_requested);
|
||||
#if COMPANION_FEATURE_DIRECT_OTA_ADMIN
|
||||
_ota_direct_admin.enabled=true;
|
||||
command("ota folder on", "OK folder attached");
|
||||
assert(!drain_requested);
|
||||
_ota_direct_admin.enabled=false;
|
||||
command("ota folder on", "OK folder attached");
|
||||
assert(drain_requested);
|
||||
#endif
|
||||
command("ota config", "ota config: speed=1x packet=0.5x");
|
||||
assert(!drain_requested);
|
||||
for (const auto* setting : {"hops", "checkpoint", "advert"}) {
|
||||
@@ -295,6 +308,8 @@ class CompanionOtaConfigTest(unittest.TestCase):
|
||||
for platform in ("ESP32_PLATFORM", "NRF52_PLATFORM", "STM32_PLATFORM")
|
||||
for seeder in ([], ["-DOTA_SEEDER_ONLY=1"])]
|
||||
variants.append(("ESP32_PLATFORM", [], "-DCOMPANION_FEATURE_OTA_CLI=1"))
|
||||
variants.append(("ESP32_PLATFORM", ["-DCOMPANION_FEATURE_DIRECT_OTA_ADMIN=1"],
|
||||
"-DCOMPANION_RADIO_FULL=1"))
|
||||
for platform, seeder, capability in variants:
|
||||
with self.subTest(platform=platform, seeder=seeder, capability=capability):
|
||||
binary = Path(directory) / "config"
|
||||
|
||||
@@ -24,6 +24,9 @@ class SharedMotaQueueTest(unittest.TestCase):
|
||||
control = method((ROOT / "examples/companion_radio/main.cpp").read_text(),
|
||||
"class Nrf52BleMotaSourceControl")
|
||||
(Path(temp) / "ble_control_under_test.h").write_text(control + ";\n")
|
||||
(Path(temp) / "temp_radio_under_test.h").write_text(method(
|
||||
(ROOT / "examples/companion_radio/MyMesh.cpp").read_text(),
|
||||
"bool MyMesh::scheduleTempRadio("))
|
||||
subprocess.run([
|
||||
"cc", "-DENABLE_OTA=1", "-fsanitize=address,undefined", "-g",
|
||||
"-c", str(ROOT / "src/helpers/ota/OtaTinf.c"), "-o", str(tinf),
|
||||
@@ -45,6 +48,7 @@ class SharedMotaQueueTest(unittest.TestCase):
|
||||
"c++", "-std=c++17", "-fsanitize=address,undefined", "-g",
|
||||
*flags, "-DOTA_SEEDER_ONLY=1",
|
||||
"-DCOMPANION_RADIO_FULL=1", "-DOTA_SHARED_COMPANION_QUEUE=1",
|
||||
"-DMESH_ENABLE_HOST_KISS=0",
|
||||
"-DENABLE_OTA=1", "-I", str(ROOT / "src"),
|
||||
"-I", str(ROOT / "test/fixtures/shared_mota_queue/mocks"),
|
||||
"-I", str(ROOT / "test/mocks"), "-I", temp,
|
||||
|
||||
Reference in new issue
Block a user