2020-11-28 12:10:19 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
2021-03-23 11:44:51 +08:00
|
|
|
#include "mesh/Channels.h"
|
2020-11-28 12:10:19 +08:00
|
|
|
#include "mesh/MeshTypes.h"
|
2021-03-17 10:44:42 -07:00
|
|
|
#include <vector>
|
|
|
|
|
|
2022-07-31 07:11:47 -05:00
|
|
|
#if HAS_SCREEN
|
2021-02-21 16:46:46 -05:00
|
|
|
#include <OLEDDisplay.h>
|
|
|
|
|
#include <OLEDDisplayUi.h>
|
2021-03-17 10:44:42 -07:00
|
|
|
#endif
|
|
|
|
|
|
2025-01-26 20:59:59 +01:00
|
|
|
#define MESHMODULE_MIN_BROADCAST_DELAY_MS 30 * 1000 // Min. delay after boot before sending first broadcast by any module
|
|
|
|
|
#define MESHMODULE_BROADCAST_SPACING_MS 15 * 1000 // Initial spacing between broadcasts of different modules
|
|
|
|
|
|
2021-09-23 04:42:09 +03:00
|
|
|
/** handleReceived return enumeration
|
2023-01-21 14:34:29 +01:00
|
|
|
*
|
2021-09-23 04:42:09 +03:00
|
|
|
* Use ProcessMessage::CONTINUE to allows other modules to process a message.
|
2023-01-21 14:34:29 +01:00
|
|
|
*
|
2021-09-23 04:42:09 +03:00
|
|
|
* Use ProcessMessage::STOP to stop further message processing.
|
|
|
|
|
*/
|
2023-01-21 14:34:29 +01:00
|
|
|
enum class ProcessMessage {
|
|
|
|
|
CONTINUE = 0,
|
|
|
|
|
STOP = 1,
|
2021-09-23 04:42:09 +03:00
|
|
|
};
|
|
|
|
|
|
2022-02-21 06:29:15 +01:00
|
|
|
/**
|
2022-02-27 00:29:05 -08:00
|
|
|
* Used by modules to return the result of the AdminMessage handling.
|
|
|
|
|
* If request is handled, then module should return HANDLED,
|
2022-02-21 06:29:15 +01:00
|
|
|
* If response is also prepared for the request, then HANDLED_WITH_RESPONSE
|
|
|
|
|
* should be returned.
|
|
|
|
|
*/
|
2023-01-21 14:34:29 +01:00
|
|
|
enum class AdminMessageHandleResult {
|
2022-02-21 06:29:15 +01:00
|
|
|
NOT_HANDLED = 0,
|
|
|
|
|
HANDLED = 1,
|
|
|
|
|
HANDLED_WITH_RESPONSE = 2,
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-13 09:19:36 +01:00
|
|
|
/*
|
|
|
|
|
* This struct is used by Screen to figure out whether screen frame should be updated.
|
|
|
|
|
*/
|
2024-07-12 11:51:26 +12:00
|
|
|
struct UIFrameEvent {
|
|
|
|
|
// What do we actually want to happen?
|
|
|
|
|
enum Action {
|
|
|
|
|
REDRAW_ONLY, // Don't change which frames are show, just redraw, asap
|
|
|
|
|
REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus()
|
2024-11-04 12:16:25 -06:00
|
|
|
REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, Attempt to remain on the same frame throughout
|
2024-07-12 11:51:26 +12:00
|
|
|
} action = REDRAW_ONLY;
|
|
|
|
|
|
|
|
|
|
// We might want to pass additional data inside this struct at some point
|
|
|
|
|
};
|
2022-01-13 09:19:36 +01:00
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
/** A baseclass for any mesh "module".
|
2020-11-28 12:10:19 +08:00
|
|
|
*
|
2022-02-27 00:29:05 -08:00
|
|
|
* A module allows you to add new features to meshtastic device code, without needing to know messaging details.
|
2020-11-28 12:10:19 +08:00
|
|
|
*
|
2022-02-27 00:29:05 -08:00
|
|
|
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
|
2020-11-28 12:10:19 +08:00
|
|
|
* and handle.
|
|
|
|
|
*
|
2023-07-14 17:25:20 -04:00
|
|
|
* Internally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
|
2022-02-27 00:29:05 -08:00
|
|
|
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
|
2020-11-28 12:10:19 +08:00
|
|
|
*/
|
2022-03-09 19:01:43 +11:00
|
|
|
class MeshModule
|
2020-11-28 12:10:19 +08:00
|
|
|
{
|
2022-03-09 19:01:43 +11:00
|
|
|
static std::vector<MeshModule *> *modules;
|
2020-11-28 12:10:19 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/** Constructor
|
|
|
|
|
* name is for debugging output
|
|
|
|
|
*/
|
2022-03-09 19:01:43 +11:00
|
|
|
MeshModule(const char *_name);
|
2020-11-28 12:10:19 +08:00
|
|
|
|
2022-03-09 19:01:43 +11:00
|
|
|
virtual ~MeshModule();
|
2020-11-28 12:10:19 +08:00
|
|
|
|
2020-11-28 13:51:51 +08:00
|
|
|
/** For use only by MeshService
|
|
|
|
|
*/
|
2025-08-29 12:09:22 -05:00
|
|
|
static void callModules(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
2020-11-28 13:51:51 +08:00
|
|
|
|
2.7 Miscellaneous Fixes - Week 1 (#7102)
* Update Favorite Node Message Options to unify against other screens
* Rebuild Horizontal Battery, Resolve overlap concerns
* Update positioning on Message frame and fix drawCommonHeader overlay
* Beginnings of creating isHighResolution bool
* Fixup determineResolution()
* Implement isHighResolution in place of SCREEN_WIDTH > 128 checks
* Line Spacing bound to isHighResolution
* Analog Clock for all
* Add AM/PM to Analog Clock if isHighResolution and not TWatch
* Simple Menu Queue, and add time menu
* Fix prompt string for 12/24 hour picker
* More menu banners into functions
* Fix Action Menu on Home frame
* Correct pop-up calculation size and continue to leverage isHighResolution
* Move menu bits to MenuHandler
* Plumb in the digital/analog picker
* Correct Clock Face Picker title
* Clock picker fixes
* Migrate the rest of the menus to MenuHandler.*
* Add compass menu and needle point option
* Minor fix for compass point menu
* Correct Home menu into typical format
* Fix emoji bounce, overlap, and missing commonHeader
* Sanitize long_names and removed unused variables
* Slightly better sanitizeString variation
* Resolved apostrophe being shown as upside down question mark
* Gotta keep height and width in expected order
* Remove Second Hand for Analog Clock on EInk displays
* Fix Clock menu option decision tree
* Improvements to Eink Navigation
* Pause Banner for Eink moved to bottom
* Updated working for 12-/24-hour menu and Added US/Arizona to timezone picker
* Add Adhoc Ping and resolve error with std::string sanitized
* Hide quick toggle as option is available within Action Menu, commented out for the moment
* Remove old battery icon and option, use drawCommonHeader throughout, re-add battery to Clock frames
* fix misc build warnings. NFC
* Update Analog Clock on EInk to show more digits
* Establish Action Menu on all node list screens, add NodeDB reset (with confirmation) option
* Add Toggle Backlight for EInk Displays
* Suppress action screen Full refresh for Eink
* Adjust drawBluetoothConnectedIcon on TWatch
* Maintain clock frame when switching between Clock Faces
* Move modules beyond the clock in navigation
* addressed the conflicts, and changed target branch to 2.7-MiscFixes-Week1
* cleanup, cheers
* Add AM/PM to low resolution clock also
* Small adjustments to AM/PM replacement across various devices
* Resolve dangling pointer issues with sanitize code
* Update comments for Screen.cpp related to module load change
* Trunk runs
* Update message caching to correct aged timestamp
* Menu wording adjustments
* Time Format wording
* Use all the rows on EInk since with autohide the navigation bar
* Finalize Time Format picker word change
* Retired drawFunctionOverlay code
No longer being used
* Actually honor the points-north setting
* Trunk
* Compressed action list
* Update no-op showOverlayBanner function
* trunk
* Correct T_Watch_S3 specific line
* Autosized Action menu per screen
* Finalize Autosized Action menu per screen
* Unify Message Titles
* Reorder Timezones to match expectations
* Adjust text location for pop-ups
* Revert "Actually honor the points-north setting"
This reverts commit 20988aa4fabb0975be644989d556fca7e1176680.
* Make NodeDB sort its internal vector when lastheard is updated. Don't sort in NodeListRenderer
* Update src/graphics/draw/NodeListRenderer.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/mesh/NodeDB.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Pass by reference -- Thanks Copilot!
* Throttle sorting just a touch
* Check more carefully for own node
* Eliminate some now-unneeded sorting
* Move function after include
* Putting Modules back to position 0 and some trunk checks found
* Add Scrollbar for Action menus
* Second attempt to move modules down the navigation bar
* Continue effort of moving modules in the navigation
* Canned Messages tweak
* Replicate Function + Space through the Menu System
* Move init button parameters into config struct (#7145)
* Remove bundling of web-ui from ESP32 devices (#7143)
* Fixed triple click GPS toggle bungle
* Move init button parameters into config struct
* Reapply "Actually honor the points-north setting"
This reverts commit 42c1967e7b3735ec9f5be8acd9582bc9edcbc78a.
* Actually do compass pointings correctly
* Tweak to node bearings
* Menu wording tweaks
* Get the compass_north_top logic right
* Don't jump frames after setting Compass
* Get rid of the extra bearingTo functions
* Don't blink Mail on EInk Clock Screens
* Actually set lat and long
* Calibrate
* Convert Radians to Degrees
* More degree vs radians fixes
* De-duplicate draw arrow function
* Don't advertise compass calibration without an accell thread.
---------
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: csrutil <keming.cao@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-26 22:11:20 -05:00
|
|
|
static std::vector<MeshModule *> GetMeshModulesWithUIFrames(int startIndex);
|
2022-01-13 09:19:36 +01:00
|
|
|
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
|
2024-04-17 00:47:56 +02:00
|
|
|
static AdminMessageHandleResult handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp,
|
2023-01-21 18:39:58 +01:00
|
|
|
meshtastic_AdminMessage *request,
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_AdminMessage *response);
|
2022-07-31 07:11:47 -05:00
|
|
|
#if HAS_SCREEN
|
2024-02-09 20:31:10 -06:00
|
|
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
|
2024-09-25 23:27:04 +12:00
|
|
|
virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset
|
|
|
|
|
virtual bool interceptingKeyboardInput() { return false; } // Can screen use keyboard for nav, or is module handling input?
|
2021-03-17 10:44:42 -07:00
|
|
|
#endif
|
2020-11-28 13:51:51 +08:00
|
|
|
protected:
|
2020-12-03 16:48:44 +08:00
|
|
|
const char *name;
|
|
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
/** Most modules only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific
|
2021-03-11 10:01:57 +08:00
|
|
|
recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those
|
2022-02-27 00:29:05 -08:00
|
|
|
modules can set this to true and their handleReceived() will be called for every packet.
|
2021-02-17 13:06:23 +08:00
|
|
|
*/
|
|
|
|
|
bool isPromiscuous = false;
|
|
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
/** Also receive a copy of LOCALLY GENERATED messages - most modules should leave
|
2021-10-09 14:02:21 +00:00
|
|
|
* this setting disabled - see issue #877 */
|
|
|
|
|
bool loopbackOk = false;
|
|
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
/** Most modules only understand decrypted packets. For modules that also want to see encrypted packets, they should set this
|
2021-04-05 08:44:47 +08:00
|
|
|
* flag */
|
|
|
|
|
bool encryptedOk = false;
|
|
|
|
|
|
2023-02-15 19:31:09 +01:00
|
|
|
/* We allow modules to ignore a request without sending an error if they have a specific reason for it. */
|
|
|
|
|
bool ignoreRequest = false;
|
|
|
|
|
|
2021-03-11 10:01:57 +08:00
|
|
|
/** If a bound channel name is set, we will only accept received packets that come in on that channel.
|
|
|
|
|
* A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface
|
|
|
|
|
* are allowed on any channel (this lets the local user do anything).
|
|
|
|
|
*
|
|
|
|
|
* We will send responses on the same channel that the request arrived on.
|
|
|
|
|
*/
|
|
|
|
|
const char *boundChannel = NULL;
|
|
|
|
|
|
2020-12-13 12:57:37 +08:00
|
|
|
/**
|
2022-02-27 00:29:05 -08:00
|
|
|
* If this module is currently handling a request currentRequest will be preset
|
2020-12-13 12:57:37 +08:00
|
|
|
* to the packet with the request. This is mostly useful for reply handlers.
|
2021-03-11 10:01:57 +08:00
|
|
|
*
|
2020-12-13 12:57:37 +08:00
|
|
|
* Note: this can be static because we are guaranteed to be processing only one
|
2022-02-27 00:29:05 -08:00
|
|
|
* plumodulegin at a time.
|
2020-12-13 12:57:37 +08:00
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
static const meshtastic_MeshPacket *currentRequest;
|
2020-12-13 12:57:37 +08:00
|
|
|
|
2025-01-26 20:59:59 +01:00
|
|
|
// We keep track of the number of modules that send a periodic broadcast to schedule them spaced out over time
|
|
|
|
|
static uint8_t numPeriodicModules;
|
|
|
|
|
|
|
|
|
|
// Set the start delay for module that broadcasts periodically
|
|
|
|
|
int32_t setStartDelay();
|
|
|
|
|
|
2021-04-06 10:34:23 +08:00
|
|
|
/**
|
|
|
|
|
* If your handler wants to send a response, simply set currentReply and it will be sent at the end of response handling.
|
|
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *myReply = NULL;
|
2021-04-06 10:34:23 +08:00
|
|
|
|
2020-11-28 12:10:19 +08:00
|
|
|
/**
|
2022-02-27 00:29:05 -08:00
|
|
|
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
|
2020-11-28 12:10:19 +08:00
|
|
|
* been initialized
|
|
|
|
|
*/
|
2020-11-28 13:25:03 +08:00
|
|
|
virtual void setup();
|
2020-11-28 12:10:19 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return true if you want to receive the specified portnum
|
|
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
virtual bool wantPacket(const meshtastic_MeshPacket *p) = 0;
|
2020-11-28 12:10:19 +08:00
|
|
|
|
|
|
|
|
/** Called to handle a particular incoming message
|
|
|
|
|
|
2023-01-21 14:34:29 +01:00
|
|
|
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
|
|
|
|
|
it
|
2020-11-28 12:10:19 +08:00
|
|
|
*/
|
2024-02-09 20:31:10 -06:00
|
|
|
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) { return ProcessMessage::CONTINUE; }
|
|
|
|
|
|
|
|
|
|
/** Called to change a particular incoming message
|
|
|
|
|
This allows the module to change the message before it is passed through the rest of the call-chain.
|
|
|
|
|
*/
|
|
|
|
|
virtual void alterReceived(meshtastic_MeshPacket &mp) {}
|
2020-12-05 11:15:06 +08:00
|
|
|
|
|
|
|
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
2021-04-06 10:34:23 +08:00
|
|
|
* so that subclasses can (optionally) send a response back to the original sender.
|
|
|
|
|
*
|
|
|
|
|
* Note: most implementers don't need to override this, instead: If while handling a request you have a reply, just set
|
|
|
|
|
* the protected reply field in this instance.
|
|
|
|
|
* */
|
2023-01-21 18:22:19 +01:00
|
|
|
virtual meshtastic_MeshPacket *allocReply();
|
2020-12-07 10:18:11 +08:00
|
|
|
|
2021-02-21 16:46:46 -05:00
|
|
|
/***
|
|
|
|
|
* @return true if you want to be alloced a UI screen frame
|
|
|
|
|
*/
|
2024-02-09 20:31:10 -06:00
|
|
|
virtual bool wantUIFrame() { return false; }
|
|
|
|
|
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() { return NULL; }
|
2021-02-21 16:46:46 -05:00
|
|
|
|
2024-03-08 14:13:57 +01:00
|
|
|
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
2024-11-03 13:21:45 +01:00
|
|
|
uint8_t hopLimit = 0);
|
2021-03-23 11:44:51 +08:00
|
|
|
|
|
|
|
|
/// Send an error response for the specified packet.
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p);
|
2021-03-23 11:44:51 +08:00
|
|
|
|
2023-01-21 14:34:29 +01:00
|
|
|
/**
|
|
|
|
|
* @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request.
|
|
|
|
|
*
|
|
|
|
|
* @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_RESPONSE if a response is also prepared and to be sent.
|
|
|
|
|
*/
|
2023-01-21 18:39:58 +01:00
|
|
|
virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
|
|
|
|
|
meshtastic_AdminMessage *request,
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_AdminMessage *response)
|
2023-01-21 14:34:29 +01:00
|
|
|
{
|
|
|
|
|
return AdminMessageHandleResult::NOT_HANDLED;
|
|
|
|
|
};
|
2022-02-21 06:29:15 +01:00
|
|
|
|
2024-07-12 11:51:26 +12:00
|
|
|
#if HAS_SCREEN
|
|
|
|
|
/** Request that our module's screen frame be focused when Screen::setFrames runs
|
|
|
|
|
* Only considered if Screen::setFrames is triggered via a UIFrameEvent
|
|
|
|
|
*
|
|
|
|
|
* Having this as a separate call, instead of part of the UIFrameEvent, allows the module to delay decision
|
|
|
|
|
* until drawFrame() is called. This required less restructuring.
|
|
|
|
|
*/
|
|
|
|
|
bool _requestingFocus = false;
|
|
|
|
|
void requestFocus() { _requestingFocus = true; }
|
|
|
|
|
#else
|
|
|
|
|
void requestFocus(){}; // No-op
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-12-07 10:18:11 +08:00
|
|
|
private:
|
2021-03-05 11:44:45 +08:00
|
|
|
/**
|
2022-02-27 00:29:05 -08:00
|
|
|
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
|
2022-02-27 01:49:24 -08:00
|
|
|
* the RoutingModule to avoid sending redundant acks
|
2021-03-05 11:44:45 +08:00
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
static meshtastic_MeshPacket *currentReply;
|
2021-04-06 10:34:23 +08:00
|
|
|
|
2021-03-11 10:01:57 +08:00
|
|
|
friend class ReliableRouter;
|
2021-03-05 11:44:45 +08:00
|
|
|
|
2020-12-07 10:18:11 +08:00
|
|
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
|
|
|
|
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
|
|
|
|
|
* to generate the reply message, and if !NULL that message will be delivered to whoever sent req
|
2020-12-05 11:15:06 +08:00
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
void sendResponse(const meshtastic_MeshPacket &req);
|
2020-12-07 10:18:11 +08:00
|
|
|
};
|
|
|
|
|
|
2021-03-11 10:01:57 +08:00
|
|
|
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
2020-12-07 10:18:11 +08:00
|
|
|
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
2021-03-11 10:01:57 +08:00
|
|
|
*/
|
2025-12-12 12:19:32 +01:00
|
|
|
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|