save db to flash

1.2-legacy
geeksville 2020-02-07 09:36:15 -08:00
rodzic 2671599b90
commit 3e87e60d43
10 zmienionych plików z 169 dodań i 28 usunięć

Wyświetl plik

@ -4,7 +4,7 @@
* very occasionally send our position and user packet (if for nothing else so that other nodes update last_seen)
* switch to my gui layout manager
* make basic gui. different screens: debug, one page for each user in the user db, last received text message
* save our node db (and any rx packets waiting for phone) to flash - see DeviceState protobuf
* save our node db on entry to sleep
# Medium priority

1
mesh.proto 120000
Wyświetl plik

@ -0,0 +1 @@
../MeshUtil/app/src/main/proto/mesh.proto

Wyświetl plik

@ -12,7 +12,6 @@
// Change to 434.0 or other frequency, must match RX's freq! FIXME, choose a better default value
#define RF95_FREQ_US 902.0f
RadioConfig radioConfig = RadioConfig_init_zero;
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: rf95(NSS_GPIO, DIO0_GPIO),

Wyświetl plik

@ -59,4 +59,4 @@ private:
void handleReceive(MeshPacket *p);
};
extern RadioConfig radioConfig;

Wyświetl plik

@ -53,6 +53,7 @@ void MeshService::sendOurOwner(NodeNum dest)
p->payload.which_variant = SubPacket_user_tag;
User &u = p->payload.variant.user;
u = owner;
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
sendToMesh(p);
}

Wyświetl plik

@ -2,6 +2,9 @@
#include <Arduino.h>
#include <assert.h>
#include "FS.h"
#include "SPIFFS.h"
#include <pb_encode.h>
#include <pb_decode.h>
#include "configuration.h"
@ -9,16 +12,22 @@
#include "NodeDB.h"
#include "GPS.h"
MyNodeInfo myNodeInfo = MyNodeInfo_init_zero;
NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now)
DeviceState devicestate;
MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig &radioConfig = devicestate.radio;
#define FS SPIFFS
/**
*
* Normally userids are unique and start with +country code to look like Signal phone numbers.
* But there are some special ids used when we haven't yet been configured by a user. In that case
* we use !macaddr (no colons).
*/
User owner = {"+1650xxxyyyy", "unset name", "????", {0}};
User &owner = devicestate.owner;
static uint8_t ourMacAddr[6];
@ -35,16 +44,22 @@ static NodeNum getDesiredNodeNum()
return r;
}
NodeDB::NodeDB()
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count)
{
}
void NodeDB::init() {
void NodeDB::init()
{
// Crummy guess at our nodenum
myNodeInfo.my_node_num = getDesiredNodeNum();
// init our devicestate with valid flags so protobuf writing/reading will work
devicestate.has_my_node = true;
devicestate.has_radio = true;
devicestate.has_owner = true;
devicestate.node_db_count = 0;
devicestate.receive_queue_count = 0;
// Init our blank owner info to reasonable defaults
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0],
ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4], ourMacAddr[5]);
@ -59,11 +74,73 @@ void NodeDB::init() {
info->user = owner;
info->has_user = true;
info->last_seen = 0; // haven't heard a real message yet
if (!FS.begin(true)) // FIXME - do this in main?
{
DEBUG_MSG("ERROR SPIFFS Mount Failed\n");
// FIXME - report failure to phone
}
// saveToDisk();
loadFromDisk();
DEBUG_MSG("NODENUM=0x%x, dbsize=%d\n", myNodeInfo.my_node_num, *numNodes);
}
const char *preffile = "/db.proto";
const char *preftmp = "/db.proto.tmp";
void NodeDB::loadFromDisk()
{
File f = FS.open(preffile);
if (f)
{
DEBUG_MSG("Loading saved preferences\n");
pb_istream_t stream = {&readcb, &f, DeviceState_size};
if (!pb_decode(&stream, DeviceState_fields, &devicestate))
{
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
// FIXME - report failure to phone
}
f.close();
}
else
{
DEBUG_MSG("No saved preferences found\n");
}
}
void NodeDB::saveToDisk()
{
File f = FS.open(preftmp, "w");
if (f)
{
DEBUG_MSG("Writing preferences\n");
pb_ostream_t stream = {&writecb, &f, DeviceState_size, 0};
if (!pb_encode(&stream, DeviceState_fields, &devicestate))
{
DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream));
// FIXME - report failure to phone
}
f.close();
// brief window of risk here ;-)
FS.remove(preffile);
FS.rename(preftmp, preffile);
}
else
{
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
}
}
const NodeInfo *NodeDB::readNextInfo()
{
if (readPointer < numNodes)
if (readPointer < *numNodes)
return &nodes[readPointer++];
else
return NULL;
@ -79,10 +156,10 @@ void NodeDB::updateFrom(const MeshPacket &mp)
DEBUG_MSG("Update DB node 0x%x for variant %d\n", mp.from, p.which_variant);
if (p.which_variant != SubPacket_want_node_tag) // we don't create nodeinfo records for someone that is just trying to claim a nodenum
{
int oldNumNodes = numNodes;
int oldNumNodes = *numNodes;
NodeInfo *info = getOrCreateNode(mp.from);
if (oldNumNodes != numNodes)
if (oldNumNodes != *numNodes)
updateGUI = true; // we just created a nodeinfo
info->last_seen = gps.getTime();
@ -96,10 +173,23 @@ void NodeDB::updateFrom(const MeshPacket &mp)
break;
case SubPacket_user_tag:
{
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
bool changed = memcmp(&info->user, &p.variant.user, sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
info->user = p.variant.user;
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
info->has_user = true;
updateGUIforNode = info;
if (changed)
{
// We just created a user for the first time, store our DB
saveToDisk();
}
break;
}
default:
break; // Ignore other packet types
@ -111,7 +201,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
/// Find a node in our DB, return null for missing
NodeInfo *NodeDB::getNode(NodeNum n)
{
for (int i = 0; i < numNodes; i++)
for (int i = 0; i < *numNodes; i++)
if (nodes[i].num == n)
return &nodes[i];
@ -126,8 +216,8 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
if (!info)
{
// add the node
assert(numNodes < MAX_NUM_NODES);
info = &nodes[numNodes++];
assert(*numNodes < MAX_NUM_NODES);
info = &nodes[(*numNodes)++];
// everything is missing except the nodenum
memset(info, 0, sizeof(*info));

Wyświetl plik

@ -6,8 +6,9 @@
#include "mesh-pb-constants.h"
#include "MeshTypes.h"
extern MyNodeInfo myNodeInfo;
extern User owner;
extern MyNodeInfo &myNodeInfo;
extern RadioConfig &radioConfig;
extern User &owner;
class NodeDB
{
@ -16,8 +17,9 @@ class NodeDB
// A NodeInfo for every node we've seen
// Eventually use a smarter datastructure
// HashMap<NodeNum, NodeInfo> nodes;
NodeInfo nodes[MAX_NUM_NODES];
int numNodes = 0;
// Note: these two references just point into our static array we serialize to/from disk
NodeInfo *nodes;
pb_size_t *numNodes;
bool updateGUI = false; // we think the gui should definitely be redrawn
NodeInfo *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
@ -32,6 +34,9 @@ public:
/// Called from service after app start, to do init which can only be done after OS load
void init();
/// write to flash
void saveToDisk();
/// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void updateFrom(const MeshPacket &p);
@ -60,6 +65,9 @@ private:
/// Find a node in our DB, create an empty NodeInfo if missing
NodeInfo *getOrCreateNode(NodeNum n);
/// read our db from flash
void loadFromDisk();
};
extern NodeDB nodeDB;

Wyświetl plik

@ -4,6 +4,7 @@
#include <pb_encode.h>
#include <pb_decode.h>
#include <assert.h>
#include "FS.h"
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
/// returns the encoded packet size
@ -37,3 +38,33 @@ bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msg
return true;
}
}
/// Read from an Arduino File
bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
{
File *file = (File *)stream->state;
bool status;
if (buf == NULL)
{
while (count-- && file->read() != EOF)
;
return count == 0;
}
status = (file->read(buf, count) == count);
if (file->available() == 0)
stream->bytes_left = 0;
return status;
}
/// Write to an arduino file
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
File *file = (File*) stream->state;
return file->write(buf, count) == count;
}

Wyświetl plik

@ -19,4 +19,10 @@
size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct);
/// helper function for decoding a record as a protobuf, we will return false if the decoding failed
bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msgdesc_t *fields, void *dest_struct);
bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msgdesc_t *fields, void *dest_struct);
/// Read from an Arduino File
bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count);
/// Write to an arduino file
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count);

Wyświetl plik

@ -108,6 +108,8 @@ typedef struct _DeviceState {
RadioConfig radio;
bool has_my_node;
MyNodeInfo my_node;
bool has_owner;
User owner;
pb_size_t node_db_count;
NodeInfo node_db[32];
pb_size_t receive_queue_count;
@ -151,7 +153,7 @@ typedef struct _ToRadio {
#define RadioConfig_init_default {0, 0, 0, 0, _RadioConfig_ModemConfig_MIN, {0, {0}}, 0, 0}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}}
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define Position_init_zero {0, 0, 0, 0, 0}
@ -164,7 +166,7 @@ typedef struct _ToRadio {
#define RadioConfig_init_zero {0, 0, 0, 0, _RadioConfig_ModemConfig_MIN, {0, {0}}, 0, 0}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}}
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
@ -208,8 +210,9 @@ typedef struct _ToRadio {
#define MeshPacket_payload_tag 3
#define DeviceState_radio_tag 1
#define DeviceState_my_node_tag 2
#define DeviceState_node_db_tag 3
#define DeviceState_receive_queue_tag 4
#define DeviceState_owner_tag 3
#define DeviceState_node_db_tag 4
#define DeviceState_receive_queue_tag 5
#define FromRadio_packet_tag 2
#define FromRadio_num_tag 1
#define ToRadio_packet_tag 1
@ -303,12 +306,14 @@ X(a, STATIC, SINGULAR, INT32, my_node_num, 1)
#define DeviceState_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, radio, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 3) \
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 4)
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_radio_MSGTYPE RadioConfig
#define DeviceState_my_node_MSGTYPE MyNodeInfo
#define DeviceState_owner_MSGTYPE User
#define DeviceState_node_db_MSGTYPE NodeInfo
#define DeviceState_receive_queue_MSGTYPE MeshPacket
@ -365,7 +370,7 @@ extern const pb_msgdesc_t ToRadio_msg;
#define RadioConfig_size 70
#define NodeInfo_size 151
#define MyNodeInfo_size 11
#define DeviceState_size 9269
#define DeviceState_size 9343
#define FromRadio_size 139
#define ToRadio_size 133