#include #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 #elif defined(RP2040_PLATFORM) #include #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 }