Files
MeshCore/src/helpers/ota/OtaContext.cpp
T

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