diff --git a/protobufs b/protobufs index da9bba9c5..24874086e 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit da9bba9c5dd43a98d431cb7a95159b145f0483c4 +Subproject commit 24874086e392b0ec504f9f89137e7b7f8b5bfcbd diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index d5c7c4a19..b4a4a171f 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -104,16 +104,17 @@ bool MeshService::reloadConfig(int saveWhat) } /// The owner User record just got updated, update our node DB and broadcast the info into the mesh -void MeshService::reloadOwner() +void MeshService::reloadOwner(bool shouldSave) { // DEBUG_MSG("reloadOwner()\n"); // update our local data directly nodeDB.updateUser(nodeDB.getNodeNum(), owner); assert(nodeInfoModule); - // update everyone else - if (nodeInfoModule) + // update everyone else and save to disk + if (nodeInfoModule && shouldSave) { nodeInfoModule->sendOurNodeInfo(); - nodeDB.saveToDisk(SEGMENT_DEVICESTATE); + nodeDB.saveToDisk(SEGMENT_DEVICESTATE); + } } /** diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 24ec1c0bc..c3b3c95d9 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -69,7 +69,7 @@ class MeshService bool reloadConfig(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); /// The owner User record just got updated, update our node DB and broadcast the info into the mesh - void reloadOwner(); + void reloadOwner(bool shouldSave = true); /// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least /// sends our owner diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index dcd518191..6e79ea9e4 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -58,7 +58,7 @@ class NodeDB void init(); /// write to flash - void saveToDisk(int saveWhat=SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk(); + void saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS), saveChannelsToDisk(), saveDeviceStateToDisk(); /** Reinit radio config if needed, because either: * a) sometimes a buggy android app might send us bogus settings or diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index b5dc769ca..4257405fa 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -82,10 +82,11 @@ typedef struct _AdminMessage { ModuleConfig set_module_config; /* Set the Canned Message Module messages text. */ char set_canned_message_module_messages[201]; - /* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */ - bool confirm_set_config; - /* Sent immediatly after a config change has been sent to ensure comms, if this is not recieved, the config will be reverted after 10 mins */ - bool confirm_set_module_config; + /* Begins an edit transaction for config, module config, owner, and channel settings changes + This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ + bool begin_edit_settings; + /* Commits an open transaction for any edits made to config, module config, owner, and channel settings */ + bool commit_edit_settings; /* Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again. Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes. If you fail to do so, the radio will assume loss of comms and revert your changes. @@ -147,8 +148,8 @@ extern "C" { #define AdminMessage_set_config_tag 34 #define AdminMessage_set_module_config_tag 35 #define AdminMessage_set_canned_message_module_messages_tag 36 -#define AdminMessage_confirm_set_config_tag 64 -#define AdminMessage_confirm_set_module_config_tag 65 +#define AdminMessage_begin_edit_settings_tag 64 +#define AdminMessage_commit_edit_settings_tag 65 #define AdminMessage_confirm_set_channel_tag 66 #define AdminMessage_confirm_set_radio_tag 67 #define AdminMessage_reboot_ota_seconds_tag 95 @@ -177,8 +178,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 3 X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_module_config,set_module_config), 35) \ X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_messages,set_canned_message_module_messages), 36) \ -X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_config,confirm_set_config), 64) \ -X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_module_config,confirm_set_module_config), 65) \ +X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ +X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 4a76faf6f..8176955c7 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -13,7 +13,10 @@ #include "unistd.h" #endif +#define DEFAULT_REBOOT_SECONDS 5 + AdminModule *adminModule; +bool hasOpenEditTransaction; /// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead. /// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want @@ -133,13 +136,18 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r) case AdminMessage_factory_reset_tag: { DEBUG_MSG("Initiating factory reset\n"); nodeDB.factoryReset(); - reboot(5); + reboot(DEFAULT_REBOOT_SECONDS); break; } - case AdminMessage_nodedb_reset_tag: { - DEBUG_MSG("Initiating node-db reset\n"); - nodeDB.resetNodes(); - reboot(5); + case AdminMessage_begin_edit_settings_tag: { + DEBUG_MSG("Beginning transaction for editing settings\n"); + hasOpenEditTransaction = true; + break; + } + case AdminMessage_commit_edit_settings_tag: { + DEBUG_MSG("Committing transaction for edited settings\n"); + hasOpenEditTransaction = false; + saveChanges(SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); break; } #ifdef ARCH_PORTDUINO @@ -192,9 +200,8 @@ void AdminModule::handleSetOwner(const User &o) } if (changed) { // If nothing really changed, don't broadcast on the network or write to flash - service.reloadOwner(); - DEBUG_MSG("Rebooting due to owner changes\n"); - reboot(5); + service.reloadOwner(!hasOpenEditTransaction); + saveChanges(SEGMENT_DEVICESTATE); } } @@ -220,7 +227,7 @@ void AdminModule::handleSetConfig(const Config &c) config.has_position = true; config.position = c.payload_variant.position; // Save nodedb as well in case we got a fixed position packet - nodeDB.saveToDisk(SEGMENT_DEVICESTATE); + saveChanges(SEGMENT_DEVICESTATE, false); break; case Config_power_tag: DEBUG_MSG("Setting config: Power\n"); @@ -252,9 +259,8 @@ void AdminModule::handleSetConfig(const Config &c) config.bluetooth = c.payload_variant.bluetooth; break; } - - service.reloadConfig(SEGMENT_CONFIG); - reboot(5); + + saveChanges(SEGMENT_CONFIG); } void AdminModule::handleSetModuleConfig(const ModuleConfig &c) @@ -302,15 +308,14 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c) break; } - service.reloadConfig(SEGMENT_MODULECONFIG); - reboot(5); + saveChanges(SEGMENT_MODULECONFIG); } void AdminModule::handleSetChannel(const Channel &cc) { channels.setChannel(cc); channels.onConfigChanged(); // tell the radios about this change - nodeDB.saveChannelsToDisk(); + saveChanges(SEGMENT_CHANNELS, false); } /** @@ -479,6 +484,17 @@ void AdminModule::reboot(int32_t seconds) rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); } +void AdminModule::saveChanges(int saveWhat, bool shouldReboot) +{ + if (!hasOpenEditTransaction) { + service.reloadConfig(saveWhat); // Calls saveToDisk among other things + } + if (shouldReboot) + { + reboot(DEFAULT_REBOOT_SECONDS); + } +} + AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields) { // restrict to the admin channel for rx diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index dd81c3218..3afbfa133 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -20,6 +20,9 @@ class AdminModule : public ProtobufModule virtual bool handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *p) override; private: + bool hasOpenEditTransaction = false; + + void saveChanges(int saveWhat, bool shouldReboot = true); /** * Getters */