mirror of https://github.com/meshcore-dev/MeshCore
9 changed files with 433 additions and 354 deletions
@ -0,0 +1,306 @@ |
|||
#include <Arduino.h> |
|||
#include "DataStore.h" |
|||
|
|||
DataStore::DataStore(FILESYSTEM& fs) : _fs(&fs), |
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
identity_store(fs, "") |
|||
#elif defined(RP2040_PLATFORM) |
|||
identity_store(fs, "/identity") |
|||
#else |
|||
identity_store(fs, "/identity") |
|||
#endif |
|||
{ |
|||
} |
|||
|
|||
void DataStore::begin() { |
|||
#if defined(RP2040_PLATFORM) |
|||
identity_store.begin(); |
|||
#endif |
|||
|
|||
// init 'blob store' support
|
|||
_fs->mkdir("/bl"); |
|||
} |
|||
|
|||
#if defined(ESP32) |
|||
#include <SPIFFS.h> |
|||
#elif defined(RP2040_PLATFORM) |
|||
#include <LittleFS.h> |
|||
#endif |
|||
|
|||
bool DataStore::formatFileSystem() { |
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
return _fs->format(); |
|||
#elif defined(RP2040_PLATFORM) |
|||
return LittleFS.format(); |
|||
#elif defined(ESP32) |
|||
return ((fs::SPIFFSFS *)_fs)->format(); |
|||
#else |
|||
#error "need to implement format()" |
|||
#endif |
|||
} |
|||
|
|||
bool DataStore::loadMainIdentity(mesh::LocalIdentity &identity) { |
|||
return identity_store.load("_main", identity); |
|||
} |
|||
|
|||
bool DataStore::saveMainIdentity(const mesh::LocalIdentity &identity) { |
|||
return identity_store.save("_main", identity); |
|||
} |
|||
|
|||
void DataStore::loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon) { |
|||
if (_fs->exists("/new_prefs")) { |
|||
loadPrefsInt("/new_prefs", prefs, node_lat, node_lon); // new filename
|
|||
} else if (_fs->exists("/node_prefs")) { |
|||
loadPrefsInt("/node_prefs", prefs, node_lat, node_lon); |
|||
savePrefs(prefs, node_lat, node_lon); // save to new filename
|
|||
_fs->remove("/node_prefs"); // remove old
|
|||
} |
|||
} |
|||
|
|||
void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& node_lat, double& node_lon) { |
|||
#if defined(RP2040_PLATFORM) |
|||
File file = _fs->open(filename, "r"); |
|||
#else |
|||
File file = _fs->open(filename); |
|||
#endif |
|||
if (file) { |
|||
uint8_t pad[8]; |
|||
|
|||
file.read((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0
|
|||
file.read((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4
|
|||
file.read(pad, 4); // 36
|
|||
file.read((uint8_t *)&node_lat, sizeof(node_lat)); // 40
|
|||
file.read((uint8_t *)&node_lon, sizeof(node_lon)); // 48
|
|||
file.read((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
|
|||
file.read((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
|
|||
file.read((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
|
|||
file.read((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
|
|||
file.read((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
|
|||
file.read((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
|
|||
file.read((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
|||
file.read((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
|||
file.read((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
|||
file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
|
|||
file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
|||
file.read(pad, 4); // 76
|
|||
file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
|||
|
|||
file.close(); |
|||
} |
|||
} |
|||
|
|||
void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_lon) { |
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
_fs->remove("/new_prefs"); |
|||
File file = _fs->open("/new_prefs", FILE_O_WRITE); |
|||
#elif defined(RP2040_PLATFORM) |
|||
File file = _fs->open("/new_prefs", "w"); |
|||
#else |
|||
File file = _fs->open("/new_prefs", "w", true); |
|||
#endif |
|||
if (file) { |
|||
uint8_t pad[8]; |
|||
memset(pad, 0, sizeof(pad)); |
|||
|
|||
file.write((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0
|
|||
file.write((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4
|
|||
file.write(pad, 4); // 36
|
|||
file.write((uint8_t *)&node_lat, sizeof(node_lat)); // 40
|
|||
file.write((uint8_t *)&node_lon, sizeof(node_lon)); // 48
|
|||
file.write((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56
|
|||
file.write((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60
|
|||
file.write((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61
|
|||
file.write((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
|
|||
file.write((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63
|
|||
file.write((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64
|
|||
file.write((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
|
|||
file.write((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69
|
|||
file.write((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
|
|||
file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
|
|||
file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
|
|||
file.write(pad, 4); // 76
|
|||
file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
|
|||
|
|||
file.close(); |
|||
} |
|||
} |
|||
|
|||
void DataStore::loadContacts(DataStoreHost* host) { |
|||
if (_fs->exists("/contacts3")) { |
|||
#if defined(RP2040_PLATFORM) |
|||
File file = _fs->open("/contacts3", "r"); |
|||
#else |
|||
File file = _fs->open("/contacts3"); |
|||
#endif |
|||
if (file) { |
|||
bool full = false; |
|||
while (!full) { |
|||
ContactInfo c; |
|||
uint8_t pub_key[32]; |
|||
uint8_t unused; |
|||
|
|||
bool success = (file.read(pub_key, 32) == 32); |
|||
success = success && (file.read((uint8_t *)&c.name, 32) == 32); |
|||
success = success && (file.read(&c.type, 1) == 1); |
|||
success = success && (file.read(&c.flags, 1) == 1); |
|||
success = success && (file.read(&unused, 1) == 1); |
|||
success = success && (file.read((uint8_t *)&c.sync_since, 4) == 4); // was 'reserved'
|
|||
success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1); |
|||
success = success && (file.read((uint8_t *)&c.last_advert_timestamp, 4) == 4); |
|||
success = success && (file.read(c.out_path, 64) == 64); |
|||
success = success && (file.read((uint8_t *)&c.lastmod, 4) == 4); |
|||
success = success && (file.read((uint8_t *)&c.gps_lat, 4) == 4); |
|||
success = success && (file.read((uint8_t *)&c.gps_lon, 4) == 4); |
|||
|
|||
if (!success) break; // EOF
|
|||
|
|||
c.id = mesh::Identity(pub_key); |
|||
if (!host->onContactLoaded(c)) full = true; |
|||
} |
|||
file.close(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void DataStore::saveContacts(DataStoreHost* host) { |
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
_fs->remove("/contacts3"); |
|||
File file = _fs->open("/contacts3", FILE_O_WRITE); |
|||
#elif defined(RP2040_PLATFORM) |
|||
File file = _fs->open("/contacts3", "w"); |
|||
#else |
|||
File file = _fs->open("/contacts3", "w", true); |
|||
#endif |
|||
if (file) { |
|||
uint32_t idx = 0; |
|||
ContactInfo c; |
|||
uint8_t unused = 0; |
|||
|
|||
while (host->getContactForSave(idx, c)) { |
|||
bool success = (file.write(c.id.pub_key, 32) == 32); |
|||
success = success && (file.write((uint8_t *)&c.name, 32) == 32); |
|||
success = success && (file.write(&c.type, 1) == 1); |
|||
success = success && (file.write(&c.flags, 1) == 1); |
|||
success = success && (file.write(&unused, 1) == 1); |
|||
success = success && (file.write((uint8_t *)&c.sync_since, 4) == 4); |
|||
success = success && (file.write((uint8_t *)&c.out_path_len, 1) == 1); |
|||
success = success && (file.write((uint8_t *)&c.last_advert_timestamp, 4) == 4); |
|||
success = success && (file.write(c.out_path, 64) == 64); |
|||
success = success && (file.write((uint8_t *)&c.lastmod, 4) == 4); |
|||
success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4); |
|||
success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4); |
|||
|
|||
if (!success) break; // write failed
|
|||
|
|||
idx++; // advance to next contact
|
|||
} |
|||
file.close(); |
|||
} |
|||
} |
|||
|
|||
void DataStore::loadChannels(DataStoreHost* host) { |
|||
if (_fs->exists("/channels2")) { |
|||
#if defined(RP2040_PLATFORM) |
|||
File file = _fs->open("/channels2", "r"); |
|||
#else |
|||
File file = _fs->open("/channels2"); |
|||
#endif |
|||
if (file) { |
|||
bool full = false; |
|||
uint8_t channel_idx = 0; |
|||
while (!full) { |
|||
ChannelDetails ch; |
|||
uint8_t unused[4]; |
|||
|
|||
bool success = (file.read(unused, 4) == 4); |
|||
success = success && (file.read((uint8_t *)ch.name, 32) == 32); |
|||
success = success && (file.read((uint8_t *)ch.channel.secret, 32) == 32); |
|||
|
|||
if (!success) break; // EOF
|
|||
|
|||
if (host->onChannelLoaded(channel_idx, ch)) { |
|||
channel_idx++; |
|||
} else { |
|||
full = true; |
|||
} |
|||
} |
|||
file.close(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void DataStore::saveChannels(DataStoreHost* host) { |
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
_fs->remove("/channels2"); |
|||
File file = _fs->open("/channels2", FILE_O_WRITE); |
|||
#elif defined(RP2040_PLATFORM) |
|||
File file = _fs->open("/channels2", "w"); |
|||
#else |
|||
File file = _fs->open("/channels2", "w", true); |
|||
#endif |
|||
if (file) { |
|||
uint8_t channel_idx = 0; |
|||
ChannelDetails ch; |
|||
uint8_t unused[4]; |
|||
memset(unused, 0, 4); |
|||
|
|||
while (host->getChannelForSave(channel_idx, ch)) { |
|||
bool success = (file.write(unused, 4) == 4); |
|||
success = success && (file.write((uint8_t *)ch.name, 32) == 32); |
|||
success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); |
|||
|
|||
if (!success) break; // write failed
|
|||
channel_idx++; |
|||
} |
|||
file.close(); |
|||
} |
|||
} |
|||
|
|||
int DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { |
|||
char path[64]; |
|||
char fname[18]; |
|||
|
|||
if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix)
|
|||
mesh::Utils::toHex(fname, key, key_len); |
|||
sprintf(path, "/bl/%s", fname); |
|||
|
|||
if (_fs->exists(path)) { |
|||
#if defined(RP2040_PLATFORM) |
|||
File f = _fs->open(path, "r"); |
|||
#else |
|||
File f = _fs->open(path); |
|||
#endif |
|||
if (f) { |
|||
int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!!
|
|||
f.close(); |
|||
return len; |
|||
} |
|||
} |
|||
return 0; // not found
|
|||
} |
|||
|
|||
bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) { |
|||
char path[64]; |
|||
char fname[18]; |
|||
|
|||
if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix)
|
|||
mesh::Utils::toHex(fname, key, key_len); |
|||
sprintf(path, "/bl/%s", fname); |
|||
|
|||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) |
|||
_fs->remove(path); |
|||
File f = _fs->open(path, FILE_O_WRITE); |
|||
#elif defined(RP2040_PLATFORM) |
|||
File f = _fs->open(path, "w"); |
|||
#else |
|||
File f = _fs->open(path, "w", true); |
|||
#endif |
|||
if (f) { |
|||
int n = f.write(src_buf, len); |
|||
f.close(); |
|||
if (n == len) return true; // success!
|
|||
|
|||
_fs->remove(path); // blob was only partially written!
|
|||
} |
|||
return false; // error
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
#pragma once |
|||
|
|||
#include <helpers/IdentityStore.h> |
|||
#include <helpers/ContactInfo.h> |
|||
#include <helpers/ChannelDetails.h> |
|||
#include "NodePrefs.h" |
|||
|
|||
class DataStoreHost { |
|||
public: |
|||
virtual bool onContactLoaded(const ContactInfo& contact) =0; |
|||
virtual bool getContactForSave(uint32_t idx, ContactInfo& contact) =0; |
|||
virtual bool onChannelLoaded(uint8_t channel_idx, const ChannelDetails& ch) =0; |
|||
virtual bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) =0; |
|||
}; |
|||
|
|||
class DataStore { |
|||
FILESYSTEM* _fs; |
|||
IdentityStore identity_store; |
|||
|
|||
void loadPrefsInt(const char *filename, NodePrefs& prefs, double& node_lat, double& node_lon); |
|||
|
|||
public: |
|||
DataStore(FILESYSTEM& fs); |
|||
void begin(); |
|||
bool formatFileSystem(); |
|||
bool loadMainIdentity(mesh::LocalIdentity &identity); |
|||
bool saveMainIdentity(const mesh::LocalIdentity &identity); |
|||
void loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon); |
|||
void savePrefs(const NodePrefs& prefs, double node_lat, double node_lon); |
|||
void loadContacts(DataStoreHost* host); |
|||
void saveContacts(DataStoreHost* host); |
|||
void loadChannels(DataStoreHost* host); |
|||
void saveChannels(DataStoreHost* host); |
|||
int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]); |
|||
bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len); |
|||
}; |
|||
@ -0,0 +1,9 @@ |
|||
#pragma once |
|||
|
|||
#include <Arduino.h> |
|||
#include <Mesh.h> |
|||
|
|||
struct ChannelDetails { |
|||
mesh::GroupChannel channel; |
|||
char name[32]; |
|||
}; |
|||
@ -0,0 +1,18 @@ |
|||
#pragma once |
|||
|
|||
#include <Arduino.h> |
|||
#include <Mesh.h> |
|||
|
|||
struct ContactInfo { |
|||
mesh::Identity id; |
|||
char name[32]; |
|||
uint8_t type; // on of ADV_TYPE_*
|
|||
uint8_t flags; |
|||
int8_t out_path_len; |
|||
uint8_t out_path[MAX_PATH_SIZE]; |
|||
uint32_t last_advert_timestamp; // by THEIR clock
|
|||
uint8_t shared_secret[PUB_KEY_SIZE]; |
|||
uint32_t lastmod; // by OUR clock
|
|||
int32_t gps_lat, gps_lon; // 6 dec places
|
|||
uint32_t sync_since; |
|||
}; |
|||
Loading…
Reference in new issue