Skip to content

Commit 6e0b505

Browse files
author
Scott Powell
committed
* companion: refactor of all filesystem access to new DataStore module
1 parent 93e584f commit 6e0b505

File tree

9 files changed

+433
-354
lines changed

9 files changed

+433
-354
lines changed
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
#include <Arduino.h>
2+
#include "DataStore.h"
3+
4+
DataStore::DataStore(FILESYSTEM& fs) : _fs(&fs),
5+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
6+
identity_store(fs, "")
7+
#elif defined(RP2040_PLATFORM)
8+
identity_store(fs, "/identity")
9+
#else
10+
identity_store(fs, "/identity")
11+
#endif
12+
{
13+
}
14+
15+
void DataStore::begin() {
16+
#if defined(RP2040_PLATFORM)
17+
identity_store.begin();
18+
#endif
19+
20+
// init 'blob store' support
21+
_fs->mkdir("/bl");
22+
}
23+
24+
#if defined(ESP32)
25+
#include <SPIFFS.h>
26+
#elif defined(RP2040_PLATFORM)
27+
#include <LittleFS.h>
28+
#endif
29+
30+
bool DataStore::formatFileSystem() {
31+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
32+
return _fs->format();
33+
#elif defined(RP2040_PLATFORM)
34+
return LittleFS.format();
35+
#elif defined(ESP32)
36+
return ((fs::SPIFFSFS *)_fs)->format();
37+
#else
38+
#error "need to implement format()"
39+
#endif
40+
}
41+
42+
bool DataStore::loadMainIdentity(mesh::LocalIdentity &identity) {
43+
return identity_store.load("_main", identity);
44+
}
45+
46+
bool DataStore::saveMainIdentity(const mesh::LocalIdentity &identity) {
47+
return identity_store.save("_main", identity);
48+
}
49+
50+
void DataStore::loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon) {
51+
if (_fs->exists("/new_prefs")) {
52+
loadPrefsInt("/new_prefs", prefs, node_lat, node_lon); // new filename
53+
} else if (_fs->exists("/node_prefs")) {
54+
loadPrefsInt("/node_prefs", prefs, node_lat, node_lon);
55+
savePrefs(prefs, node_lat, node_lon); // save to new filename
56+
_fs->remove("/node_prefs"); // remove old
57+
}
58+
}
59+
60+
void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& node_lat, double& node_lon) {
61+
#if defined(RP2040_PLATFORM)
62+
File file = _fs->open(filename, "r");
63+
#else
64+
File file = _fs->open(filename);
65+
#endif
66+
if (file) {
67+
uint8_t pad[8];
68+
69+
file.read((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0
70+
file.read((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4
71+
file.read(pad, 4); // 36
72+
file.read((uint8_t *)&node_lat, sizeof(node_lat)); // 40
73+
file.read((uint8_t *)&node_lon, sizeof(node_lon)); // 48
74+
file.read((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
75+
file.read((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
76+
file.read((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
77+
file.read((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
78+
file.read((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
79+
file.read((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
80+
file.read((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
81+
file.read((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
82+
file.read((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
83+
file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
84+
file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
85+
file.read(pad, 4); // 76
86+
file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
87+
88+
file.close();
89+
}
90+
}
91+
92+
void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_lon) {
93+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
94+
_fs->remove("/new_prefs");
95+
File file = _fs->open("/new_prefs", FILE_O_WRITE);
96+
#elif defined(RP2040_PLATFORM)
97+
File file = _fs->open("/new_prefs", "w");
98+
#else
99+
File file = _fs->open("/new_prefs", "w", true);
100+
#endif
101+
if (file) {
102+
uint8_t pad[8];
103+
memset(pad, 0, sizeof(pad));
104+
105+
file.write((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0
106+
file.write((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4
107+
file.write(pad, 4); // 36
108+
file.write((uint8_t *)&node_lat, sizeof(node_lat)); // 40
109+
file.write((uint8_t *)&node_lon, sizeof(node_lon)); // 48
110+
file.write((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
111+
file.write((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
112+
file.write((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
113+
file.write((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
114+
file.write((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
115+
file.write((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
116+
file.write((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
117+
file.write((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
118+
file.write((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
119+
file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
120+
file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
121+
file.write(pad, 4); // 76
122+
file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
123+
124+
file.close();
125+
}
126+
}
127+
128+
void DataStore::loadContacts(DataStoreHost* host) {
129+
if (_fs->exists("/contacts3")) {
130+
#if defined(RP2040_PLATFORM)
131+
File file = _fs->open("/contacts3", "r");
132+
#else
133+
File file = _fs->open("/contacts3");
134+
#endif
135+
if (file) {
136+
bool full = false;
137+
while (!full) {
138+
ContactInfo c;
139+
uint8_t pub_key[32];
140+
uint8_t unused;
141+
142+
bool success = (file.read(pub_key, 32) == 32);
143+
success = success && (file.read((uint8_t *)&c.name, 32) == 32);
144+
success = success && (file.read(&c.type, 1) == 1);
145+
success = success && (file.read(&c.flags, 1) == 1);
146+
success = success && (file.read(&unused, 1) == 1);
147+
success = success && (file.read((uint8_t *)&c.sync_since, 4) == 4); // was 'reserved'
148+
success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1);
149+
success = success && (file.read((uint8_t *)&c.last_advert_timestamp, 4) == 4);
150+
success = success && (file.read(c.out_path, 64) == 64);
151+
success = success && (file.read((uint8_t *)&c.lastmod, 4) == 4);
152+
success = success && (file.read((uint8_t *)&c.gps_lat, 4) == 4);
153+
success = success && (file.read((uint8_t *)&c.gps_lon, 4) == 4);
154+
155+
if (!success) break; // EOF
156+
157+
c.id = mesh::Identity(pub_key);
158+
if (!host->onContactLoaded(c)) full = true;
159+
}
160+
file.close();
161+
}
162+
}
163+
}
164+
165+
void DataStore::saveContacts(DataStoreHost* host) {
166+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
167+
_fs->remove("/contacts3");
168+
File file = _fs->open("/contacts3", FILE_O_WRITE);
169+
#elif defined(RP2040_PLATFORM)
170+
File file = _fs->open("/contacts3", "w");
171+
#else
172+
File file = _fs->open("/contacts3", "w", true);
173+
#endif
174+
if (file) {
175+
uint32_t idx = 0;
176+
ContactInfo c;
177+
uint8_t unused = 0;
178+
179+
while (host->getContactForSave(idx, c)) {
180+
bool success = (file.write(c.id.pub_key, 32) == 32);
181+
success = success && (file.write((uint8_t *)&c.name, 32) == 32);
182+
success = success && (file.write(&c.type, 1) == 1);
183+
success = success && (file.write(&c.flags, 1) == 1);
184+
success = success && (file.write(&unused, 1) == 1);
185+
success = success && (file.write((uint8_t *)&c.sync_since, 4) == 4);
186+
success = success && (file.write((uint8_t *)&c.out_path_len, 1) == 1);
187+
success = success && (file.write((uint8_t *)&c.last_advert_timestamp, 4) == 4);
188+
success = success && (file.write(c.out_path, 64) == 64);
189+
success = success && (file.write((uint8_t *)&c.lastmod, 4) == 4);
190+
success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4);
191+
success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4);
192+
193+
if (!success) break; // write failed
194+
195+
idx++; // advance to next contact
196+
}
197+
file.close();
198+
}
199+
}
200+
201+
void DataStore::loadChannels(DataStoreHost* host) {
202+
if (_fs->exists("/channels2")) {
203+
#if defined(RP2040_PLATFORM)
204+
File file = _fs->open("/channels2", "r");
205+
#else
206+
File file = _fs->open("/channels2");
207+
#endif
208+
if (file) {
209+
bool full = false;
210+
uint8_t channel_idx = 0;
211+
while (!full) {
212+
ChannelDetails ch;
213+
uint8_t unused[4];
214+
215+
bool success = (file.read(unused, 4) == 4);
216+
success = success && (file.read((uint8_t *)ch.name, 32) == 32);
217+
success = success && (file.read((uint8_t *)ch.channel.secret, 32) == 32);
218+
219+
if (!success) break; // EOF
220+
221+
if (host->onChannelLoaded(channel_idx, ch)) {
222+
channel_idx++;
223+
} else {
224+
full = true;
225+
}
226+
}
227+
file.close();
228+
}
229+
}
230+
}
231+
232+
void DataStore::saveChannels(DataStoreHost* host) {
233+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
234+
_fs->remove("/channels2");
235+
File file = _fs->open("/channels2", FILE_O_WRITE);
236+
#elif defined(RP2040_PLATFORM)
237+
File file = _fs->open("/channels2", "w");
238+
#else
239+
File file = _fs->open("/channels2", "w", true);
240+
#endif
241+
if (file) {
242+
uint8_t channel_idx = 0;
243+
ChannelDetails ch;
244+
uint8_t unused[4];
245+
memset(unused, 0, 4);
246+
247+
while (host->getChannelForSave(channel_idx, ch)) {
248+
bool success = (file.write(unused, 4) == 4);
249+
success = success && (file.write((uint8_t *)ch.name, 32) == 32);
250+
success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32);
251+
252+
if (!success) break; // write failed
253+
channel_idx++;
254+
}
255+
file.close();
256+
}
257+
}
258+
259+
int DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) {
260+
char path[64];
261+
char fname[18];
262+
263+
if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix)
264+
mesh::Utils::toHex(fname, key, key_len);
265+
sprintf(path, "/bl/%s", fname);
266+
267+
if (_fs->exists(path)) {
268+
#if defined(RP2040_PLATFORM)
269+
File f = _fs->open(path, "r");
270+
#else
271+
File f = _fs->open(path);
272+
#endif
273+
if (f) {
274+
int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!!
275+
f.close();
276+
return len;
277+
}
278+
}
279+
return 0; // not found
280+
}
281+
282+
bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) {
283+
char path[64];
284+
char fname[18];
285+
286+
if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix)
287+
mesh::Utils::toHex(fname, key, key_len);
288+
sprintf(path, "/bl/%s", fname);
289+
290+
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
291+
_fs->remove(path);
292+
File f = _fs->open(path, FILE_O_WRITE);
293+
#elif defined(RP2040_PLATFORM)
294+
File f = _fs->open(path, "w");
295+
#else
296+
File f = _fs->open(path, "w", true);
297+
#endif
298+
if (f) {
299+
int n = f.write(src_buf, len);
300+
f.close();
301+
if (n == len) return true; // success!
302+
303+
_fs->remove(path); // blob was only partially written!
304+
}
305+
return false; // error
306+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <helpers/IdentityStore.h>
4+
#include <helpers/ContactInfo.h>
5+
#include <helpers/ChannelDetails.h>
6+
#include "NodePrefs.h"
7+
8+
class DataStoreHost {
9+
public:
10+
virtual bool onContactLoaded(const ContactInfo& contact) =0;
11+
virtual bool getContactForSave(uint32_t idx, ContactInfo& contact) =0;
12+
virtual bool onChannelLoaded(uint8_t channel_idx, const ChannelDetails& ch) =0;
13+
virtual bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) =0;
14+
};
15+
16+
class DataStore {
17+
FILESYSTEM* _fs;
18+
IdentityStore identity_store;
19+
20+
void loadPrefsInt(const char *filename, NodePrefs& prefs, double& node_lat, double& node_lon);
21+
22+
public:
23+
DataStore(FILESYSTEM& fs);
24+
void begin();
25+
bool formatFileSystem();
26+
bool loadMainIdentity(mesh::LocalIdentity &identity);
27+
bool saveMainIdentity(const mesh::LocalIdentity &identity);
28+
void loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon);
29+
void savePrefs(const NodePrefs& prefs, double node_lat, double node_lon);
30+
void loadContacts(DataStoreHost* host);
31+
void saveContacts(DataStoreHost* host);
32+
void loadChannels(DataStoreHost* host);
33+
void saveChannels(DataStoreHost* host);
34+
int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]);
35+
bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len);
36+
};

0 commit comments

Comments
 (0)