mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 18:31:58 +00:00
/prefs holds a header (magic, format version, size, CRC-32), the node's position and NodePrefs as it is in memory, in place of /new_prefs' two hand-kept field lists and 0xC0DE00xx schema bumps. A new field goes at the end of the struct; moving one bumps PREFS_VERSION. sanitize() keeps every value in range. The first boot after an update from before 2.0 imports only the first block of the old file, laid out the same in upstream MeshCore and Solo (name, position, radio, BLE PIN, scope), then deletes it; everything else starts from the defaults. Contacts, channels, scopes, waypoints and trails are untouched. Gone: the page-order and GPS-interval migrations, the unused trail_interval_idx / trail_units_idx / repeat_extra_scopes; fav_sort_off and msg_wake_screen_off become fav_sort and msg_wake (on by default). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.8 KiB
C++
85 lines
3.8 KiB
C++
#pragma once
|
|
|
|
#include <helpers/IdentityStore.h>
|
|
#include <helpers/ContactInfo.h>
|
|
#include <helpers/ChannelDetails.h>
|
|
#include "NodePrefs.h"
|
|
#include "ScopeList.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;
|
|
FILESYSTEM* _fsExtra;
|
|
mesh::RTCClock* _clock;
|
|
IdentityStore identity_store;
|
|
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
void checkAdvBlobFile();
|
|
#endif
|
|
|
|
public:
|
|
DataStore(FILESYSTEM& fs, mesh::RTCClock& clock);
|
|
DataStore(FILESYSTEM& fs, FILESYSTEM& fsExtra, mesh::RTCClock& clock);
|
|
void begin();
|
|
bool formatFileSystem();
|
|
FILESYSTEM* getPrimaryFS() const { return _fs; }
|
|
FILESYSTEM* getSecondaryFS() const { return _fsExtra; }
|
|
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, bool (*filter)(const ContactInfo& c) = NULL);
|
|
// Returns true if a channels file (current or legacy) existed and was
|
|
// loaded -- false only on a genuinely fresh device with neither file, so
|
|
// the caller knows whether it's safe to seed default channels (see
|
|
// MyMesh::begin()'s addChannel("Public", ...) -- seeding unconditionally
|
|
// would resurrect a channel the user had deliberately deleted, since a
|
|
// deleted slot is simply absent from the file, not written as empty).
|
|
bool loadChannels(DataStoreHost* host);
|
|
void saveChannels(DataStoreHost* host);
|
|
// /scopes1: the shared named-scope list (see ScopeList.h). `prefs` is only
|
|
// read, for a one-time migration of a pre-existing single
|
|
// default_scope_name/key into list entry 1 -- the file is authoritative
|
|
// once it exists.
|
|
//
|
|
// Returns true ONLY when that legacy migration just ran, i.e. this boot is
|
|
// the first on a device that had a Scope configured the old way. The caller
|
|
// uses that to seed the channels that already exist with the migrated entry
|
|
// (see MyMesh::begin) -- channels carry their own scope now, so without the
|
|
// seed an upgrader's channel traffic would silently drop to unscoped even
|
|
// though their DMs kept the old scope. Returns false when /scopes1 was
|
|
// already there, and on a genuinely fresh device with nothing to migrate
|
|
// (list left empty, default_idx 0 == "*").
|
|
bool loadScopeList(ScopeList& list, const NodePrefs& prefs);
|
|
void saveScopeList(const ScopeList& list);
|
|
void migrateToSecondaryFS();
|
|
uint8_t 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[], uint8_t len);
|
|
bool deleteBlobByKey(const uint8_t key[], int key_len);
|
|
File openRead(const char* filename);
|
|
File openRead(FILESYSTEM* fs, const char* filename);
|
|
File openWrite(const char* filename);
|
|
// Atomically replace final_path with a fully-written temp file (see
|
|
// openWrite()). Use for small custom records that want the same crash-safety
|
|
// as contacts/channels: write everything to a .tmp, then commit. Returns
|
|
// false if the swap fails (the previous good file is left untouched).
|
|
bool commitFile(const char* tmp_path, const char* final_path);
|
|
bool removeFile(const char* filename);
|
|
bool removeFile(FILESYSTEM* fs, const char* filename);
|
|
uint32_t getStorageUsedKb() const;
|
|
uint32_t getStorageTotalKb() const;
|
|
void saveRTCTime();
|
|
void restoreRTCTime();
|
|
|
|
private:
|
|
FILESYSTEM* _getContactsChannelsFS() const { if (_fsExtra) return _fsExtra; return _fs;};
|
|
};
|