Skip to content

Commit 3de6842

Browse files
committed
Add tiered map storage for CustomControlMap
Store control maps in NVS when they fit within the 8KB NVS budget, and use filesystem storage when larger maps require SD-backed persistence. - report dynamic max map size based on available storage (8KB NVS, 32KB storage) - load from storage first when available, then fall back to NVS - save small maps to NVS and remove stale storage copies - save large maps to storage and remove stale NVS copies - keep upload-time size validation aligned with the active persistence backend
1 parent ae86508 commit 3de6842

2 files changed

Lines changed: 176 additions & 17 deletions

File tree

Applications/CustomControlMap/CustomControlMap.cpp

Lines changed: 168 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
#include "CustomControlMap.h"
22
#include "UI/UI.h"
33

4+
namespace {
5+
const string c_uad_storage_path = "/map.uad";
6+
}
7+
8+
size_t CustomControlMap::GetCurrentMaxUADSize() const {
9+
#if DEVICE_STORAGE == 1
10+
if (MatrixOS::FileSystem::Available())
11+
{
12+
return MAX_UAD_SIZE_STORAGE;
13+
}
14+
#endif
15+
return MAX_UAD_SIZE_NVS;
16+
}
17+
418
void CustomControlMap::Setup(const vector<string>& args) {
5-
LoadUADfromNVS();
19+
LoadSavedUAD();
620
}
721

822
void CustomControlMap::Loop() {
@@ -13,39 +27,116 @@ void CustomControlMap::Loop() {
1327
HIDReportHandler();
1428
}
1529

30+
void CustomControlMap::LoadSavedUAD() {
31+
#if DEVICE_STORAGE == 1
32+
if (MatrixOS::FileSystem::Available() && LoadUADfromStorage())
33+
{
34+
return;
35+
}
36+
#endif
37+
38+
LoadUADfromNVS();
39+
}
40+
41+
#if DEVICE_STORAGE == 1
42+
bool CustomControlMap::LoadUADfromStorage() {
43+
if (!MatrixOS::FileSystem::Available())
44+
{
45+
return false;
46+
}
47+
48+
if (!MatrixOS::FileSystem::Exists(c_uad_storage_path))
49+
{
50+
MLOGD("CustomControlMap", "No map found in storage");
51+
return false;
52+
}
53+
54+
uadRT.UnloadUAD();
55+
vPortFree(uadData);
56+
uadData = nullptr;
57+
58+
uadSize = 0;
59+
60+
File file = MatrixOS::FileSystem::Open(c_uad_storage_path, "rb");
61+
size_t new_uad_size = file.Size();
62+
MLOGD("CustomControlMap", "Storage map size: %d", new_uad_size);
63+
if (new_uad_size == 0 || new_uad_size > MAX_UAD_SIZE_STORAGE)
64+
{
65+
MLOGE("CustomControlMap", "Invalid map size in storage (%d bytes)", new_uad_size);
66+
file.Close();
67+
return false;
68+
}
69+
70+
uadData = (uint8_t*)pvPortMalloc(new_uad_size);
71+
if (uadData == nullptr)
72+
{
73+
MLOGE("CustomControlMap", "Failed to allocate memory for map from storage (%d bytes requested, %d bytes free)", new_uad_size, xPortGetFreeHeapSize());
74+
file.Close();
75+
return false;
76+
}
77+
78+
if (file.Read(uadData, new_uad_size) != new_uad_size)
79+
{
80+
MLOGE("CustomControlMap", "Failed to read map from storage");
81+
file.Close();
82+
vPortFree(uadData);
83+
uadData = nullptr;
84+
return false;
85+
}
86+
file.Close();
87+
88+
if (!uadRT.LoadUAD(uadData, new_uad_size))
89+
{
90+
MLOGE("CustomControlMap", "Failed to load map from storage");
91+
vPortFree(uadData);
92+
uadData = nullptr;
93+
return false;
94+
}
95+
96+
uadSize = new_uad_size;
97+
return true;
98+
}
99+
#endif
100+
16101
void CustomControlMap::LoadUADfromNVS() {
17102
uadRT.UnloadUAD();
18103
vPortFree(uadData);
104+
uadData = nullptr;
19105

20106
uadSize = 0;
21107

22108
size_t new_uad_size = MatrixOS::NVS::GetSize(UAD_NVS_HASH);
23109

24-
MLOGD("CustomControlMap", "NVS UAD Size: %d", new_uad_size);
110+
MLOGD("CustomControlMap", "NVS map size: %d", new_uad_size);
25111
if (new_uad_size == -1 || new_uad_size == 0)
26112
{
27-
MLOGD("CustomControlMap", "No UAD found in NVS");
113+
MLOGD("CustomControlMap", "No map found in NVS");
114+
return;
115+
}
116+
if (new_uad_size > MAX_UAD_SIZE_NVS)
117+
{
118+
MLOGE("CustomControlMap", "Map in NVS exceeds NVS limit (%d > %d)", new_uad_size, MAX_UAD_SIZE_NVS);
28119
return;
29120
}
30121

31122
uadData = (uint8_t*)pvPortMalloc(new_uad_size);
32123
if (uadData == nullptr)
33124
{
34-
MLOGE("CustomControlMap", "Failed to allocate memory for UAD (%d bytes requested, %d bytes free)", new_uad_size, xPortGetFreeHeapSize());
125+
MLOGE("CustomControlMap", "Failed to allocate memory for map from NVS (%d bytes requested, %d bytes free)", new_uad_size, xPortGetFreeHeapSize());
35126
return;
36127
}
37128

38129
if (MatrixOS::NVS::GetVariable(UAD_NVS_HASH, uadData, new_uad_size) != 0)
39130
{
40-
MLOGE("CustomControlMap", "Failed to read UAD from NVS");
131+
MLOGE("CustomControlMap", "Failed to read map from NVS");
41132
vPortFree(uadData);
42133
uadData = nullptr;
43134
return;
44135
}
45136

46137
if (!uadRT.LoadUAD(uadData, new_uad_size))
47138
{
48-
MLOGE("CustomControlMap", "Failed to load UAD");
139+
MLOGE("CustomControlMap", "Failed to load map from NVS");
49140
vPortFree(uadData);
50141
uadData = nullptr;
51142
return;
@@ -54,6 +145,26 @@ void CustomControlMap::LoadUADfromNVS() {
54145
uadSize = new_uad_size;
55146
}
56147

148+
#if DEVICE_STORAGE == 1
149+
bool CustomControlMap::SaveUADtoStorage() {
150+
if (!MatrixOS::FileSystem::Available())
151+
{
152+
return false;
153+
}
154+
155+
File file = MatrixOS::FileSystem::Open(c_uad_storage_path, "wb");
156+
if (file.Write(uadData, uadSize) != uadSize)
157+
{
158+
file.Close();
159+
return false;
160+
}
161+
162+
bool flush_ok = file.Flush();
163+
file.Close();
164+
return flush_ok;
165+
}
166+
#endif
167+
57168
bool CustomControlMap::SaveUADtoNVS() {
58169
return MatrixOS::NVS::SetVariable(UAD_NVS_HASH, uadData, uadSize);
59170
}
@@ -124,11 +235,12 @@ void CustomControlMap::HIDReportHandler() {
124235

125236
void CustomControlMap::PrepNewUAD(const uint8_t* report) {
126237
uint32_t new_uad_size = (report[2] << 24) | (report[3] << 16) | (report[4] << 8) | report[5];
238+
size_t max_uad_size = GetCurrentMaxUADSize();
127239
MLOGD("CustomControlMap", "Prep New UAD with Size: %d", new_uad_size);
128240

129-
if (new_uad_size > MAX_UAD_SIZE)
241+
if (new_uad_size > max_uad_size)
130242
{
131-
MLOGE("CustomControlMap", "UAD size exceeds limit (%d > %d)", new_uad_size, MAX_UAD_SIZE);
243+
MLOGE("CustomControlMap", "UAD size exceeds limit (%d > %d)", new_uad_size, max_uad_size);
132244
SendError(report[0], 3); // UAD Size too large
133245
return;
134246
}
@@ -196,18 +308,57 @@ void CustomControlMap::SaveUAD() {
196308
return;
197309
}
198310

199-
if (!SaveUADtoNVS())
311+
bool save_ok = false;
312+
if (uadSize <= MAX_UAD_SIZE_NVS)
200313
{
201-
MLOGE("CustomControlMap", "Failed to save UAD to NVS (%d bytes)", uadSize);
202-
SendError(UAD_SAVE, 3); // Failed to save UAD to NVS
314+
save_ok = SaveUADtoNVS();
315+
if (!save_ok)
316+
{
317+
MLOGE("CustomControlMap", "Failed to save map to NVS (%d bytes)", uadSize);
318+
}
319+
#if DEVICE_STORAGE == 1
320+
else if (MatrixOS::FileSystem::Available() && MatrixOS::FileSystem::Exists(c_uad_storage_path))
321+
{
322+
if (!MatrixOS::FileSystem::Remove(c_uad_storage_path))
323+
{
324+
MLOGE("CustomControlMap", "Failed to remove stale map from storage");
325+
}
326+
}
327+
#endif
328+
}
329+
else
330+
{
331+
#if DEVICE_STORAGE == 1
332+
if (MatrixOS::FileSystem::Available())
333+
{
334+
save_ok = SaveUADtoStorage();
335+
if (!save_ok)
336+
{
337+
MLOGE("CustomControlMap", "Failed to save map to storage (%d bytes)", uadSize);
338+
}
339+
else if (MatrixOS::NVS::GetSize(UAD_NVS_HASH) > 0 && !MatrixOS::NVS::DeleteVariable(UAD_NVS_HASH))
340+
{
341+
MLOGE("CustomControlMap", "Failed to remove stale map from NVS");
342+
}
343+
}
344+
#endif
345+
if (!save_ok)
346+
{
347+
MLOGE("CustomControlMap", "Map exceeds NVS limit and no storage is available (%d bytes)", uadSize);
348+
}
349+
}
350+
351+
if (!save_ok)
352+
{
353+
SendError(UAD_SAVE, 3); // Failed to save map
203354
return;
204355
}
205356

206357
SendAck(UAD_SAVE | HID_RESPONSE);
207358
}
208359

209360
void CustomControlMap::LoadUAD() {
210-
LoadUADfromNVS();
361+
LoadSavedUAD();
211362
SendAck(UAD_LOAD | HID_RESPONSE);
212363
}
213364

@@ -234,6 +385,7 @@ void CustomControlMap::BeginUAD() {
234385
}
235386

236387
void CustomControlMap::SendDeviceDescriptor() {
388+
size_t max_uad_size = GetCurrentMaxUADSize();
237389
MLOGD("CustomControlMap", "Send Device Descriptor");
238390
vector<uint8_t> payload = {
239391
DEVICE_DESCRIPTOR | HID_RESPONSE, // Response to DEVICE_DESCRIPTOR
@@ -248,10 +400,10 @@ void CustomControlMap::SendDeviceDescriptor() {
248400
Device::x_size, // Device X 8
249401
Device::y_size, // Device Y 8
250402
MAX_UAD_LAYER, // Max Layers
251-
(uint8_t)((MAX_UAD_SIZE >> 24) & 0xFF), // UAD Size MSB1
252-
(uint8_t)((MAX_UAD_SIZE >> 16) & 0xFF), // UAD Size MSB2
253-
(uint8_t)((MAX_UAD_SIZE >> 8) & 0xFF), // UAD Size MSB3
254-
(uint8_t)((MAX_UAD_SIZE) & 0xFF), // UAD Size MSB4
403+
(uint8_t)((max_uad_size >> 24) & 0xFF), // UAD Size MSB1
404+
(uint8_t)((max_uad_size >> 16) & 0xFF), // UAD Size MSB2
405+
(uint8_t)((max_uad_size >> 8) & 0xFF), // UAD Size MSB3
406+
(uint8_t)((max_uad_size) & 0xFF), // UAD Size MSB4
255407
(uint8_t)MAX_HID_TRANSFER_SIZE, // Max HID Transfer Size
256408
};
257409

Applications/CustomControlMap/CustomControlMap.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class CustomControlMap : public Application {
1919
void Loop() override;
2020

2121
const uint8_t MAX_UAD_LAYER = 16;
22-
const size_t MAX_UAD_SIZE = 8196; // 8KB
22+
const size_t MAX_UAD_SIZE_NVS = 8196; // 8KB
23+
const size_t MAX_UAD_SIZE_STORAGE = 32768; // 32KB
2324
const uint32_t UAD_NVS_HASH = StaticHash("CustomControlMap-UAD");
2425
const uint16_t MAX_HID_TRANSFER_SIZE = 28; // 28 bytes
2526
private:
@@ -31,7 +32,13 @@ class CustomControlMap : public Application {
3132
void KeyEventHandler(KeyEvent& keyEvent);
3233
void Reload();
3334
void ActionMenu();
35+
size_t GetCurrentMaxUADSize() const;
3436

37+
void LoadSavedUAD();
38+
#if DEVICE_STORAGE == 1
39+
bool LoadUADfromStorage();
40+
bool SaveUADtoStorage();
41+
#endif
3542
void LoadUADfromNVS();
3643
bool SaveUADtoNVS();
3744

0 commit comments

Comments
 (0)