117 lines
3.9 KiB
C++
117 lines
3.9 KiB
C++
#include "OtaContext.h"
|
|
#include <assert.h>
|
|
|
|
namespace mesh {
|
|
namespace ota {
|
|
|
|
#if defined(OTA_SHARED_COMPANION_QUEUE)
|
|
namespace {
|
|
OtaContext* active_context = nullptr;
|
|
void* storage_owner = nullptr;
|
|
OtaContext* (*acquire_storage)(void*) = nullptr;
|
|
void (*release_storage)(void*) = nullptr;
|
|
OtaSend saved_send = nullptr;
|
|
void* saved_send_ctx = nullptr;
|
|
uint32_t saved_target = 0;
|
|
char saved_hw[33] = {0};
|
|
uint8_t saved_seeder_id[4] = {0};
|
|
// Keep user policy across workspace reuse; discovered catalogs and transfers
|
|
// belong to the temporary mOTA session. No allocation is needed while idle.
|
|
SignerAllowlist saved_allow;
|
|
uint8_t saved_autofetch = OtaManager::AUTOFETCH_OFF;
|
|
uint8_t saved_autoinstall = OtaContext::AUTOINSTALL_OFF;
|
|
uint8_t saved_hops = OTA_HOP_LIMIT_DEFAULT;
|
|
uint16_t saved_checkpoint = OTA_CHECKPOINT_BLOCKS;
|
|
uint16_t saved_advert = OTA_ADVERT_INTERVAL_MINS;
|
|
}
|
|
|
|
void ota_set_context_storage(void* owner, OtaContext* (*acquire)(void*),
|
|
void (*release)(void*)) {
|
|
assert(!active_context);
|
|
storage_owner = owner;
|
|
acquire_storage = acquire;
|
|
release_storage = release;
|
|
}
|
|
|
|
OtaContext& ota_ctx() {
|
|
assert(active_context); // Only explicit OTA entry points acquire storage.
|
|
return *active_context;
|
|
}
|
|
|
|
OtaContext* ota_context_if_active() { return active_context; }
|
|
|
|
void ota_begin_context(uint32_t target, OtaSend send, void* ctx,
|
|
const char* hw, const uint8_t* seeder_id) {
|
|
saved_target = target;
|
|
saved_send = send;
|
|
saved_send_ctx = ctx;
|
|
strncpy(saved_hw, hw ? hw : "", sizeof(saved_hw) - 1);
|
|
saved_hw[sizeof(saved_hw) - 1] = 0;
|
|
if (seeder_id) memcpy(saved_seeder_id, seeder_id, sizeof(saved_seeder_id));
|
|
}
|
|
|
|
bool ota_acquire_context(char* reply, size_t cap) {
|
|
if (active_context) return true;
|
|
if (!acquire_storage || !release_storage || !saved_send) {
|
|
if (reply && cap) snprintf(reply, cap, "ERR mOTA storage is not ready");
|
|
return false;
|
|
}
|
|
active_context = acquire_storage(storage_owner);
|
|
if (!active_context) {
|
|
if (reply && cap) snprintf(reply, cap,
|
|
"ERR mOTA needs 128 free queue slots; sync unread messages with an app first");
|
|
return false;
|
|
}
|
|
OtaContext& c = *active_context;
|
|
c.begin(saved_target, saved_send, saved_send_ctx, saved_hw);
|
|
c.manager.set_seeder_id(saved_seeder_id);
|
|
c.manager.set_autofetch(saved_autofetch);
|
|
c.manager.set_checkpoint_blocks(saved_checkpoint);
|
|
c.manager.set_advert_mins(saved_advert);
|
|
c.manager.set_max_hops(saved_hops);
|
|
c.autoinstall = saved_autoinstall;
|
|
c.allow = saved_allow;
|
|
return true;
|
|
}
|
|
|
|
uint8_t ota_hop_limit() {
|
|
return active_context ? active_context->manager.max_hops() : saved_hops;
|
|
}
|
|
|
|
void ota_release_context_if_idle(bool temporary_radio_active) {
|
|
if (!active_context) return;
|
|
OtaContext& c = *active_context;
|
|
if (c.folder_active || c.folder_dest || c.serving || c.apply_pending) return;
|
|
if (temporary_radio_active && !c.release_when_idle) return;
|
|
// No host source/destination remains. Discard pending transfer work before
|
|
// the queue reuses these bytes, including dynamic discovery/diff buffers.
|
|
saved_autofetch = c.manager.autofetch();
|
|
saved_checkpoint = c.manager.checkpoint_blocks();
|
|
saved_advert = c.manager.advert_mins();
|
|
saved_hops = c.manager.max_hops();
|
|
saved_autoinstall = c.autoinstall;
|
|
saved_allow = c.allow;
|
|
c.manager.clearPendingEgress();
|
|
c.manager.reset_session();
|
|
active_context = nullptr;
|
|
release_storage(storage_owner);
|
|
}
|
|
#else
|
|
OtaContext& ota_ctx() {
|
|
static OtaContext ctx;
|
|
return ctx;
|
|
}
|
|
|
|
OtaContext* ota_context_if_active() { return &ota_ctx(); }
|
|
bool ota_acquire_context(char*, size_t) { return true; }
|
|
void ota_begin_context(uint32_t target, OtaSend send, void* ctx,
|
|
const char* hw, const uint8_t* seeder_id) {
|
|
ota_ctx().begin(target, send, ctx, hw);
|
|
ota_ctx().manager.set_seeder_id(seeder_id);
|
|
}
|
|
uint8_t ota_hop_limit() { return ota_ctx().manager.max_hops(); }
|
|
#endif
|
|
|
|
} // namespace ota
|
|
} // namespace mesh
|