9static const char*
TAG =
"TR01_STORE";
22 static TropicStorage inst;
38 header_.mapSignature = computeMapSignature();
40 cacheValid_ = loadHeader();
46 LOG_W(
TAG,
"Cache header missing or stale - rebuild required");
60 if (!
init())
return false;
95 if (!cb)
return false;
96 if (fromSlot > toSlot)
return false;
102 if (fromSlot == 0 || toSlot == 0xFFFF) {
103 fromSlot = range.
start;
106 if (fromSlot < range.
start) fromSlot = range.
start;
107 if (toSlot > range.
end) toSlot = range.
end;
113 for (uint16_t chunk = startChunk; chunk <= endChunk; chunk++) {
114 if (!loadChunk(chunk, entries)) {
119 uint16_t slot =
static_cast<uint16_t
>(slotBase + i);
120 if (slot < fromSlot || slot > toSlot)
continue;
122 if (!isEntryUsed(entry))
continue;
123 if (!isEntryAllowed(slot, entry.
moduleId))
continue;
125 cb(slot, entry, ctx);
140 if (!cb)
return false;
153 uint32_t slot =
static_cast<uint32_t
>(
start) + index;
154 if (slot > end)
return false;
157 if (!getEntry(
static_cast<uint16_t
>(slot), &entry))
return false;
158 if (!isEntryUsed(entry))
return false;
159 if (!isEntryAllowed(
static_cast<uint16_t
>(slot), entry.
moduleId))
return false;
162 cb(
static_cast<uint16_t
>(slot), entry, ctx);
175 if (!isEntryAllowed(slot,
moduleId)) {
184 entry.
name[
sizeof(entry.
name) - 1] =
'\0';
191 return setEntry(slot, entry);
201 if (!isEntryAllowed(slot,
moduleId)) {
206 return setEntry(slot, entry);
224 if (!secureElement_) {
225 LOG_E(
TAG,
"No secure element set");
228 if (!secureElement_->isSessionActive()) {
229 if (!secureElement_->sessionStart()) {
230 if (logFn) logFn(0xFFFF,
"session start failed", ctx);
236 uint16_t totalChunks =
239 for (uint16_t chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
240 memset(chunk, 0,
sizeof(chunk));
243 uint16_t slot =
static_cast<uint16_t
>(slotBase + i);
244 if (slot == 0)
continue;
246 cdc::hal::ISecureElement::RMemHeader header = {};
247 uint16_t payloadLen = 0;
248 auto res = secureElement_->rmemReadWithHeader(slot, &header,
nullptr, 0, &payloadLen);
250 if (!isEntryAllowed(slot, header.moduleId)) {
251 if (logFn) logFn(slot,
"mismatched module", ctx);
258 strncpy(entry.
name, header.name,
sizeof(entry.
name) - 1);
259 entry.
name[
sizeof(entry.
name) - 1] =
'\0';
260 if (logFn) logFn(slot, entry.
name, ctx);
265 uint16_t readLen = 0;
266 auto rawRes = secureElement_->rmemRead(slot, temp,
sizeof(temp), &readLen);
268 if (logFn) logFn(slot,
"invalid header", ctx);
270 if (logFn) logFn(slot,
"read failed", ctx);
273 if (!saveChunk(chunkIndex, chunk)) {
274 if (logFn) logFn(slotBase,
"nvs write failed", ctx);
279 cacheValid_ = saveHeader();
288 if (!secureElement_) {
289 LOG_E(
TAG,
"No secure element set");
294 uint16_t totalChunks =
297 for (uint16_t chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
298 if (!loadChunk(chunkIndex, entries)) {
302 bool changed =
false;
304 uint16_t slot =
static_cast<uint16_t
>(slotBase + i);
306 if (!isEntryUsed(entry))
continue;
307 if (isEntryAllowed(slot, entry.
moduleId))
continue;
309 LOG_W(
TAG,
"Cleanup: slot %u has mismatched module %u", slot, entry.
moduleId);
310 secureElement_->rmemErase(slot);
311 memset(&entry, 0,
sizeof(entry));
315 if (!saveChunk(chunkIndex, entries)) {
328bool TropicStorage::loadHeader() {
330 if (!nvs)
return false;
331 size_t len =
sizeof(CacheHeader);
332 CacheHeader stored = {};
334 if (err != ESP_OK || len !=
sizeof(CacheHeader)) {
339 stored.entrySize !=
sizeof(CacheEntry)) {
342 if (stored.mapSignature != computeMapSignature()) {
353bool TropicStorage::saveHeader() {
355 if (!nvs)
return false;
356 esp_err_t err = nvs_set_blob(nvs,
NVS_KEY_HEADER, &header_,
sizeof(header_));
357 if (err == ESP_OK) err = nvs.commit();
358 return err == ESP_OK;
367bool TropicStorage::loadChunk(uint16_t chunkIndex, CacheEntry* entries) {
368 if (!entries)
return false;
372 if (!nvs)
return true;
374 snprintf(key,
sizeof(key),
"c%u", chunkIndex);
376 esp_err_t err = nvs_get_blob(nvs, key, entries, &len);
391bool TropicStorage::saveChunk(uint16_t chunkIndex,
const CacheEntry* entries) {
392 if (!entries)
return false;
394 if (!nvs)
return false;
396 snprintf(key,
sizeof(key),
"c%u", chunkIndex);
398 if (err == ESP_OK) err = nvs.commit();
399 return err == ESP_OK;
406uint32_t TropicStorage::computeMapSignature()
const {
419bool TropicStorage::setEntry(uint16_t slot,
const CacheEntry& entry) {
423 if (!loadChunk(chunkIndex, entries))
return false;
424 entries[offset] = entry;
425 return saveChunk(chunkIndex, entries);
434bool TropicStorage::getEntry(uint16_t slot, CacheEntry* entry) {
435 if (!entry)
return false;
439 if (!loadChunk(chunkIndex, entries))
return false;
440 *entry = entries[offset];
449bool TropicStorage::isEntryUsed(
const CacheEntry& entry)
const {
459bool TropicStorage::isEntryAllowed(uint16_t slot, uint8_t
moduleId)
const {
Centralized non-cryptographic hash utilities.
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
Shared RAII wrappers for firmware resources.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
#define LOG_E(tag, fmt,...)
RAII wrapper for an NVS handle.
static TropicSlotMap & instance()
Returns singleton Tropic slot-map instance.
uint16_t rmemMax() const
Returns maximum RMEM slot index.
bool isRmemAllowedForModuleId(uint16_t slot, uint8_t moduleId) const
Checks whether RMEM slot is allowed for given module id.
static constexpr uint16_t CHUNK_SLOTS
bool rebuild()
Rebuilds cache contents from secure-element R-MEM without verbose logging.
void stop() override
Stops cache service.
bool writeSlot(uint8_t moduleId, uint16_t slot, const char *name, uint8_t flags)
Writes or updates cached metadata entry for one slot.
bool eraseSlot(uint8_t moduleId, uint16_t slot)
Clears cached metadata entry for one slot.
static TropicStorage & instance()
Returns singleton instance of TROPIC metadata cache manager.
bool forEachSlot(uint8_t moduleId, SlotCallback cb, void *ctx)
Iterates all cached slots for one module across its allowed range.
void(*)(uint16_t slot, const CacheEntry &entry, void *ctx) SlotCallback
bool getSlot(uint8_t moduleId, uint16_t index, SlotCallback cb, void *ctx)
Resolves one module-relative index to slot entry and invokes callback.
bool start() override
Starts cache service, initializing first if required.
bool init() override
Initializes cache metadata and validates persisted cache header.
void(*)(uint16_t slot, const char *message, void *ctx) RebuildLogFn
static constexpr uint8_t FLAG_USED
bool rebuildVerbose(RebuildLogFn logFn, void *ctx)
Rebuilds cache contents from secure-element R-MEM with optional logging callback.
bool cleanup()
Removes cache entries and chip records that violate slot/module mapping.
static constexpr uint32_t FNV1A_32_OFFSET_BASIS
FNV-1a 32-bit constants (Fowler/Noll/Vo).
void fnv1a_mix_u32(uint32_t &hash, uint32_t value)
Mixes a 32-bit word into a running FNV-1a 32-bit hash.
static constexpr const char * NVS_NAMESPACE
static constexpr uint8_t CACHE_VERSION
static constexpr const char * NVS_KEY_HEADER
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]