Canned Messages via InkHUD menu (#7096)

* Allow observers to respond to AdminMessage requests
Ground work for CannedMessage getters and setters

* Enable CannedMessage config in apps for InkHUD devices

* Migrate the InkHUD::Events AdminModule observer
Use the new AdminModule_ObserverData struct

* Bare-bones NicheGraphics util to access canned messages
Handles loading and parsing. Handle admin messages for setting and getting.

* Send canned messages via on-screen menu

* Change ThreadedMessageApplet from Observer to Module API
Allows us to intercept locally generated packets ('loopbackOK = true'), to handle outgoing canned messages.

* Fix: crash getting empty canned message string via Client API

* Move file into Utils subdir

* Move an include statement from .cpp to .h

* Limit strncpy size of dest, not source
Wasn't critical in ths specific case, but definitely a mistake.
This commit is contained in:
todd-herbert
2025-06-25 23:04:18 +12:00
committed by GitHub
parent 91bcf072a0
commit ecfaf3a095
17 changed files with 498 additions and 54 deletions

View File

@@ -470,22 +470,38 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
setPassKey(&res);
myReply = allocDataProtobuf(res);
} else if (mp.decoded.want_response) {
LOG_DEBUG("Did not responded to a request that wanted a respond. req.variant=%d", r->which_payload_variant);
LOG_DEBUG("Module API did not respond to admin message. req.variant=%d", r->which_payload_variant);
} else if (handleResult != AdminMessageHandleResult::HANDLED) {
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
LOG_DEBUG("Ignore irrelevant admin %d", r->which_payload_variant);
LOG_DEBUG("Module API did not handle admin message %d", r->which_payload_variant);
}
break;
}
// Allow any observers (e.g. the UI) to handle/respond
AdminMessageHandleResult observerResult = AdminMessageHandleResult::NOT_HANDLED;
meshtastic_AdminMessage observerResponse = meshtastic_AdminMessage_init_default;
AdminModule_ObserverData observerData = {
.request = r,
.response = &observerResponse,
.result = &observerResult,
};
notifyObservers(&observerData);
if (observerResult == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
setPassKey(&observerResponse);
myReply = allocDataProtobuf(observerResponse);
LOG_DEBUG("Observer responded to admin message");
} else if (observerResult == AdminMessageHandleResult::HANDLED) {
LOG_DEBUG("Observer handled admin message");
}
// If asked for a response and it is not yet set, generate an 'ACK' response
if (mp.decoded.want_response && !myReply) {
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
}
// Allow any observers (e.g. the UI) to respond to this event
notifyObservers(r);
return handled;
}

View File

@@ -6,10 +6,19 @@
#include "mesh/wifi/WiFiAPClient.h"
#endif
/**
* Datatype passed to Observers by AdminModule, to allow external handling of admin messages
*/
struct AdminModule_ObserverData {
const meshtastic_AdminMessage *request;
meshtastic_AdminMessage *response;
AdminMessageHandleResult *result;
};
/**
* Admin module for admin messages
*/
class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Observable<const meshtastic_AdminMessage *>
class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Observable<AdminModule_ObserverData *>
{
public:
/** Constructor