mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-08 14:12:05 +00:00
Cannedmessagemodule.h cleanup
This commit is contained in:
parent
b2663d4b19
commit
e974a58d18
@ -3,6 +3,10 @@
|
|||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
#include "input/InputBroker.h"
|
#include "input/InputBroker.h"
|
||||||
|
|
||||||
|
// ============================
|
||||||
|
// Enums & Defines
|
||||||
|
// ============================
|
||||||
|
|
||||||
enum cannedMessageModuleRunState {
|
enum cannedMessageModuleRunState {
|
||||||
CANNED_MESSAGE_RUN_STATE_DISABLED,
|
CANNED_MESSAGE_RUN_STATE_DISABLED,
|
||||||
CANNED_MESSAGE_RUN_STATE_INACTIVE,
|
CANNED_MESSAGE_RUN_STATE_INACTIVE,
|
||||||
@ -25,6 +29,17 @@ enum cannedMessageDestinationType {
|
|||||||
|
|
||||||
enum CannedMessageModuleIconType { shift, backspace, space, enter };
|
enum CannedMessageModuleIconType { shift, backspace, space, enter };
|
||||||
|
|
||||||
|
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
|
||||||
|
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
|
||||||
|
|
||||||
|
#ifndef CANNED_MESSAGE_MODULE_ENABLE
|
||||||
|
#define CANNED_MESSAGE_MODULE_ENABLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ============================
|
||||||
|
// Data Structures
|
||||||
|
// ============================
|
||||||
|
|
||||||
struct Letter {
|
struct Letter {
|
||||||
String character;
|
String character;
|
||||||
float width;
|
float width;
|
||||||
@ -34,90 +49,57 @@ struct Letter {
|
|||||||
int rectHeight;
|
int rectHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
|
|
||||||
/**
|
|
||||||
* Sum of CannedMessageModuleConfig part sizes.
|
|
||||||
*/
|
|
||||||
#define CANNED_MESSAGE_MODULE_MESSAGES_SIZE 800
|
|
||||||
|
|
||||||
#ifndef CANNED_MESSAGE_MODULE_ENABLE
|
|
||||||
#define CANNED_MESSAGE_MODULE_ENABLE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct NodeEntry {
|
struct NodeEntry {
|
||||||
meshtastic_NodeInfoLite *node;
|
meshtastic_NodeInfoLite *node;
|
||||||
uint32_t lastHeard;
|
uint32_t lastHeard;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CannedMessageModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
|
// ============================
|
||||||
{
|
// Main Class
|
||||||
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =
|
// ============================
|
||||||
CallbackObserver<CannedMessageModule, const InputEvent *>(this, &CannedMessageModule::handleInputEvent);
|
|
||||||
private:
|
class CannedMessageModule : public SinglePortModule,
|
||||||
int displayHeight = 64; // Default to a common value, update dynamically
|
public Observable<const UIFrameEvent *>,
|
||||||
int destIndex = 0; // Tracks currently selected node/channel in selection mode
|
private concurrency::OSThread {
|
||||||
int scrollIndex = 0; // Tracks scrolling position in node selection grid
|
public:
|
||||||
int visibleRows = 0;
|
|
||||||
bool needsUpdate = true;
|
|
||||||
String searchQuery;
|
|
||||||
std::vector<uint8_t> activeChannelIndices;
|
|
||||||
bool shouldRedraw = false;
|
|
||||||
unsigned long lastUpdateMillis = 0;
|
|
||||||
uint8_t lastAckHopStart = 0;
|
|
||||||
uint8_t lastAckHopLimit = 0;
|
|
||||||
public:
|
|
||||||
CannedMessageModule();
|
CannedMessageModule();
|
||||||
|
|
||||||
|
// === Message navigation ===
|
||||||
const char *getCurrentMessage();
|
const char *getCurrentMessage();
|
||||||
const char *getPrevMessage();
|
const char *getPrevMessage();
|
||||||
const char *getNextMessage();
|
const char *getNextMessage();
|
||||||
const char *getMessageByIndex(int index);
|
const char *getMessageByIndex(int index);
|
||||||
const char *getNodeName(NodeNum node);
|
const char *getNodeName(NodeNum node);
|
||||||
|
|
||||||
|
// === State/UI ===
|
||||||
bool shouldDraw();
|
bool shouldDraw();
|
||||||
bool hasMessages();
|
bool hasMessages();
|
||||||
// void eventUp();
|
|
||||||
// void eventDown();
|
|
||||||
// void eventSelect();
|
|
||||||
|
|
||||||
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
|
||||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
|
||||||
|
|
||||||
void showTemporaryMessage(const String &message);
|
void showTemporaryMessage(const String &message);
|
||||||
void resetSearch();
|
void resetSearch();
|
||||||
void updateFilteredNodes();
|
void updateFilteredNodes();
|
||||||
std::vector<NodeEntry> filteredNodes;
|
|
||||||
String nodeSelectionInput;
|
|
||||||
String drawWithCursor(String text, int cursor);
|
String drawWithCursor(String text, int cursor);
|
||||||
|
|
||||||
|
// === Admin Handlers ===
|
||||||
|
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||||
|
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||||
|
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
cannedMessageModuleRunState getRunState() const { return runState; }
|
cannedMessageModuleRunState getRunState() const { return runState; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
// === Packet Interest Filter ===
|
||||||
-Override the wantPacket method. We need the Routing Messages to look for ACKs.
|
virtual bool wantPacket(const meshtastic_MeshPacket *p) override {
|
||||||
*/
|
if (p->rx_rssi != 0) lastRxRssi = p->rx_rssi;
|
||||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
if (p->rx_snr > 0) lastRxSnr = p->rx_snr;
|
||||||
{
|
return (p->decoded.portnum == meshtastic_PortNum_ROUTING_APP) ? waitingForAck : false;
|
||||||
if (p->rx_rssi != 0) {
|
|
||||||
this->lastRxRssi = p->rx_rssi;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->rx_snr > 0) {
|
|
||||||
this->lastRxSnr = p->rx_snr;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (p->decoded.portnum) {
|
|
||||||
case meshtastic_PortNum_ROUTING_APP:
|
|
||||||
return waitingForAck;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// === Thread Entry Point ===
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
// === Transmission ===
|
||||||
void sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies);
|
void sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies);
|
||||||
|
|
||||||
int splitConfiguredMessages();
|
int splitConfiguredMessages();
|
||||||
int getNextIndex();
|
int getNextIndex();
|
||||||
int getPrevIndex();
|
int getPrevIndex();
|
||||||
@ -125,60 +107,81 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
|||||||
#if defined(USE_VIRTUAL_KEYBOARD)
|
#if defined(USE_VIRTUAL_KEYBOARD)
|
||||||
void drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
void drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
String keyForCoordinates(uint x, uint y);
|
String keyForCoordinates(uint x, uint y);
|
||||||
bool shift = false;
|
|
||||||
int charSet = 0;
|
|
||||||
void drawShiftIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
void drawShiftIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
||||||
void drawBackspaceIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
void drawBackspaceIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
||||||
void drawEnterIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
void drawEnterIcon(OLEDDisplay *display, int x, int y, float scale = 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char highlight = 0x00;
|
// === Input Handling ===
|
||||||
|
|
||||||
int handleInputEvent(const InputEvent *event);
|
int handleInputEvent(const InputEvent *event);
|
||||||
virtual bool wantUIFrame() override { return this->shouldDraw(); }
|
virtual bool wantUIFrame() override { return shouldDraw(); }
|
||||||
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() override { return this; }
|
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() override { return this; }
|
||||||
virtual bool interceptingKeyboardInput() override;
|
virtual bool interceptingKeyboardInput() override;
|
||||||
#if !HAS_TFT
|
#if !HAS_TFT
|
||||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
|
||||||
#endif
|
#endif
|
||||||
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
virtual AdminMessageHandleResult handleAdminMessageForModule(
|
||||||
meshtastic_AdminMessage *request,
|
const meshtastic_MeshPacket &mp,
|
||||||
meshtastic_AdminMessage *response) override;
|
meshtastic_AdminMessage *request,
|
||||||
|
meshtastic_AdminMessage *response) override;
|
||||||
|
|
||||||
/** Called to handle a particular incoming message
|
|
||||||
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered
|
|
||||||
* for it
|
|
||||||
*/
|
|
||||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||||
|
|
||||||
void loadProtoForModule();
|
void loadProtoForModule();
|
||||||
bool saveProtoForModule();
|
bool saveProtoForModule();
|
||||||
|
|
||||||
void installDefaultCannedMessageModuleConfig();
|
void installDefaultCannedMessageModuleConfig();
|
||||||
|
|
||||||
int currentMessageIndex = -1;
|
private:
|
||||||
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
// === Input Observers ===
|
||||||
char payload = 0x00;
|
CallbackObserver<CannedMessageModule, const InputEvent *> inputObserver =
|
||||||
unsigned int cursor = 0;
|
CallbackObserver<CannedMessageModule, const InputEvent *>(this, &CannedMessageModule::handleInputEvent);
|
||||||
String freetext = ""; // Text Buffer for Freetext Editor
|
|
||||||
NodeNum dest = NODENUM_BROADCAST;
|
|
||||||
ChannelIndex channel = 0;
|
|
||||||
cannedMessageDestinationType destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
|
||||||
uint8_t numChannels = 0;
|
|
||||||
ChannelIndex indexChannels[MAX_NUM_CHANNELS] = {0};
|
|
||||||
NodeNum incoming = NODENUM_BROADCAST;
|
|
||||||
NodeNum lastSentNode = 0; // Tracks who the message was sent to (for ACK screen)
|
|
||||||
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
|
|
||||||
bool waitingForAck = false; // Are currently interested in routing packets?
|
|
||||||
bool lastAckWasRelayed = false;
|
|
||||||
float lastRxSnr = 0;
|
|
||||||
int32_t lastRxRssi = 0;
|
|
||||||
|
|
||||||
|
// === Display and UI ===
|
||||||
|
int displayHeight = 64;
|
||||||
|
int destIndex = 0;
|
||||||
|
int scrollIndex = 0;
|
||||||
|
int visibleRows = 0;
|
||||||
|
bool needsUpdate = true;
|
||||||
|
bool shouldRedraw = false;
|
||||||
|
unsigned long lastUpdateMillis = 0;
|
||||||
|
String searchQuery;
|
||||||
|
String nodeSelectionInput;
|
||||||
|
String freetext;
|
||||||
|
String temporaryMessage;
|
||||||
|
|
||||||
|
// === Message Storage ===
|
||||||
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1];
|
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1];
|
||||||
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
||||||
int messagesCount = 0;
|
int messagesCount = 0;
|
||||||
|
int currentMessageIndex = -1;
|
||||||
|
|
||||||
|
// === Routing & Acknowledgment ===
|
||||||
|
NodeNum dest = NODENUM_BROADCAST; // Destination node for outgoing messages (default: broadcast)
|
||||||
|
NodeNum incoming = NODENUM_BROADCAST; // Source node from which last ACK/NACK was received
|
||||||
|
NodeNum lastSentNode = 0; // Tracks the most recent node we sent a message to (for UI display)
|
||||||
|
ChannelIndex channel = 0; // Channel index used when sending a message
|
||||||
|
uint8_t numChannels = 0; // Total number of channels available for selection
|
||||||
|
ChannelIndex indexChannels[MAX_NUM_CHANNELS] = {0}; // Cached channel indices available for this node
|
||||||
|
|
||||||
|
bool ack = false; // True = ACK received, False = NACK or failed
|
||||||
|
bool waitingForAck = false; // True if we're expecting an ACK and should monitor routing packets
|
||||||
|
bool lastAckWasRelayed = false; // True if the ACK was relayed through intermediate nodes
|
||||||
|
uint8_t lastAckHopStart = 0; // Hop start value from the received ACK packet
|
||||||
|
uint8_t lastAckHopLimit = 0; // Hop limit value from the received ACK packet
|
||||||
|
|
||||||
|
float lastRxSnr = 0; // SNR from last received ACK (used for diagnostics/UI)
|
||||||
|
int32_t lastRxRssi = 0; // RSSI from last received ACK (used for diagnostics/UI)
|
||||||
|
|
||||||
|
// === State Tracking ===
|
||||||
|
cannedMessageModuleRunState runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||||
|
cannedMessageDestinationType destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||||
|
char highlight = 0x00;
|
||||||
|
char payload = 0x00;
|
||||||
|
unsigned int cursor = 0;
|
||||||
unsigned long lastTouchMillis = 0;
|
unsigned long lastTouchMillis = 0;
|
||||||
String temporaryMessage;
|
std::vector<uint8_t> activeChannelIndices;
|
||||||
|
std::vector<NodeEntry> filteredNodes;
|
||||||
|
|
||||||
|
|
||||||
#if defined(USE_VIRTUAL_KEYBOARD)
|
#if defined(USE_VIRTUAL_KEYBOARD)
|
||||||
Letter keyboard[2][4][10] = {{{{"Q", 20, 0, 0, 0, 0},
|
Letter keyboard[2][4][10] = {{{{"Q", 20, 0, 0, 0, 0},
|
||||||
|
Loading…
Reference in New Issue
Block a user