diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b9107515f..f2139b82b 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -367,7 +367,7 @@ static const char *oemConfigFile = "/oem/oem.proto"; /** Load a protobuf from a file, return true for success */ -bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct) +bool NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct) { bool okay = false; #ifdef FSCom @@ -450,7 +450,7 @@ void NodeDB::loadFromDisk() } /** Save a protobuf from a file, return true for success */ -bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct) +bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct) { bool okay = false; #ifdef FSCom diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 1622a57ff..991e577c7 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -125,6 +125,9 @@ class NodeDB bool factoryReset(); + bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct); + bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct); + private: /// Find a node in our DB, create an empty NodeInfo if missing NodeInfo *getOrCreateNode(NodeNum n); diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 4357ee2ca..c0563f666 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -43,10 +43,6 @@ CannedMessageModuleConfig cannedMessageModuleConfig; CannedMessageModule *cannedMessageModule; -// TODO: move it into NodeDB.h! -extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct); -extern bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct); - CannedMessageModule::CannedMessageModule() : SinglePortModule("canned", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule") { @@ -478,7 +474,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st void CannedMessageModule::loadProtoForModule() { - if (!loadProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessagesConfigFile), + if (!nodeDB.loadProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(CannedMessageModuleConfig), &CannedMessageModuleConfig_msg, &cannedMessageModuleConfig)) { installDefaultCannedMessageModuleConfig(); } @@ -498,7 +494,7 @@ bool CannedMessageModule::saveProtoForModule() FS.mkdir("/prefs"); #endif - okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, + okay &= nodeDB.saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, &CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); return okay; diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index be3e6cd8b..c042aa966 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -5,6 +5,7 @@ #include "Router.h" #include "buzz/buzz.h" #include "configuration.h" +#include "mesh/generated/rtttl.pb.h" #include #ifndef PIN_BUZZER @@ -26,12 +27,16 @@ #define ASCII_BELL 0x07 +RTTTLConfig rtttlConfig; + ExternalNotificationModule *externalNotificationModule; bool externalCurrentState[3] = {}; uint32_t externalTurnedOn[3] = {}; +static const char *rtttlConfigFile = "/prefs/ringtone.proto"; + int32_t ExternalNotificationModule::runOnce() { if (!moduleConfig.external_notification.enabled) { @@ -81,7 +86,7 @@ int32_t ExternalNotificationModule::runOnce() rtttl::play(); } else if (nagCycleCutoff >= millis()) { // start the song again if we have time left - rtttl::begin(config.device.buzzer_gpio, pwmRingtone); + rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); } } #endif @@ -165,6 +170,10 @@ ExternalNotificationModule::ExternalNotificationModule() // moduleConfig.external_notification.nag_timeout = 300; if (moduleConfig.external_notification.enabled) { + if (!nodeDB.loadProto(rtttlConfigFile, RTTTLConfig_size, sizeof(RTTTLConfig), &RTTTLConfig_msg, &rtttlConfig)) { + memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); + strncpy(rtttlConfig.ringtone, "a:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#", sizeof(rtttlConfig.ringtone)); + } DEBUG_MSG("Initializing External Notification Module\n"); @@ -249,7 +258,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) setExternalOn(2); } else { #ifndef ARCH_PORTDUINO - rtttl::begin(config.device.buzzer_gpio, pwmRingtone); + rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); #endif } if (moduleConfig.external_notification.nag_timeout) { @@ -287,7 +296,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) setExternalOn(2); } else { #ifndef ARCH_PORTDUINO - rtttl::begin(config.device.buzzer_gpio, pwmRingtone); + rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone); #endif } if (moduleConfig.external_notification.nag_timeout) { @@ -306,3 +315,61 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) return ProcessMessage::CONTINUE; // Let others look at this message also if they want } + +/** + * @brief An admin message arrived to AdminModule. We are asked whether we want to handle that. + * + * @param mp The mesh packet arrived. + * @param request The AdminMessage request extracted from the packet. + * @param response The prepared response + * @return AdminMessageHandleResult HANDLED if message was handled + * HANDLED_WITH_RESULT if a result is also prepared. + */ +AdminMessageHandleResult ExternalNotificationModule::handleAdminMessageForModule(const MeshPacket &mp, AdminMessage *request, AdminMessage *response) +{ + AdminMessageHandleResult result; + + switch (request->which_payload_variant) { + case AdminMessage_get_ringtone_request_tag: + DEBUG_MSG("Client is getting ringtone\n"); + this->handleGetRingtone(mp, response); + result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE; + break; + + case AdminMessage_set_ringtone_message_tag: + DEBUG_MSG("Client is setting ringtone\n"); + this->handleSetRingtone(request->set_canned_message_module_messages); + result = AdminMessageHandleResult::HANDLED; + break; + + default: + result = AdminMessageHandleResult::NOT_HANDLED; + } + + return result; +} + +void ExternalNotificationModule::handleGetRingtone(const MeshPacket &req, AdminMessage *response) +{ + DEBUG_MSG("*** handleGetRingtone\n"); + assert(req.decoded.want_response); + + response->which_payload_variant = AdminMessage_get_ringtone_response_tag; + strcpy(response->get_ringtone_response, rtttlConfig.ringtone); +} + + +void ExternalNotificationModule::handleSetRingtone(const char *from_msg) +{ + int changed = 0; + + if (*from_msg) { + changed |= strcmp(rtttlConfig.ringtone, from_msg); + strcpy(rtttlConfig.ringtone, from_msg); + DEBUG_MSG("*** from_msg.text:%s\n", from_msg); + } + + if (changed) { + nodeDB.saveProto(rtttlConfigFile, RTTTLConfig_size, &RTTTLConfig_msg, &rtttlConfig); + } +} \ No newline at end of file diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h index 258078357..50af360c1 100644 --- a/src/modules/ExternalNotificationModule.h +++ b/src/modules/ExternalNotificationModule.h @@ -28,7 +28,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency: void stopNow(); - char pwmRingtone[Constants_DATA_PAYLOAD_LEN] = "a:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#"; + void handleGetRingtone(const MeshPacket &req, AdminMessage *response); + void handleSetRingtone(const char *from_msg); protected: /** Called to handle a particular incoming message @@ -37,6 +38,8 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency: virtual ProcessMessage handleReceived(const MeshPacket &mp) override; virtual int32_t runOnce() override; + + virtual AdminMessageHandleResult handleAdminMessageForModule(const MeshPacket &mp, AdminMessage *request, AdminMessage *response) override; }; extern ExternalNotificationModule *externalNotificationModule;