2022-03-09 19:01:43 +11:00
|
|
|
#include "MeshModule.h"
|
2021-03-11 10:01:57 +08:00
|
|
|
#include "Channels.h"
|
2020-12-07 10:18:11 +08:00
|
|
|
#include "MeshService.h"
|
2021-03-05 11:44:45 +08:00
|
|
|
#include "NodeDB.h"
|
2023-01-21 14:34:29 +01:00
|
|
|
#include "configuration.h"
|
2022-02-27 00:18:35 -08:00
|
|
|
#include "modules/RoutingModule.h"
|
2025-01-01 17:25:01 -08:00
|
|
|
#include <algorithm>
|
2020-11-28 12:10:19 +08:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
2022-03-09 19:01:43 +11:00
|
|
|
std::vector<MeshModule *> *MeshModule::modules;
|
2020-11-28 12:10:19 +08:00
|
|
|
|
2023-01-21 18:22:19 +01:00
|
|
|
const meshtastic_MeshPacket *MeshModule::currentRequest;
|
2025-01-26 20:59:59 +01:00
|
|
|
uint8_t MeshModule::numPeriodicModules = 0;
|
2020-12-13 12:57:37 +08:00
|
|
|
|
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
|
2024-04-17 00:47:56 +02:00
|
|
|
* the RoutingModule to avoid sending redundant acks
|
2021-03-05 11:44:45 +08:00
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *MeshModule::currentReply;
|
2021-03-05 11:44:45 +08:00
|
|
|
|
2022-03-09 19:01:43 +11:00
|
|
|
MeshModule::MeshModule(const char *_name) : name(_name)
|
2020-11-28 13:25:03 +08:00
|
|
|
{
|
2023-07-14 17:25:20 -04:00
|
|
|
// Can't trust static initializer order, so we check each time
|
2022-02-27 01:49:24 -08:00
|
|
|
if (!modules)
|
2022-03-09 19:01:43 +11:00
|
|
|
modules = new std::vector<MeshModule *>();
|
2020-11-28 13:25:03 +08:00
|
|
|
|
2022-02-27 01:49:24 -08:00
|
|
|
modules->push_back(this);
|
2020-11-28 13:25:03 +08:00
|
|
|
}
|
|
|
|
|
|
2022-03-09 19:01:43 +11:00
|
|
|
void MeshModule::setup() {}
|
2020-11-28 12:10:19 +08:00
|
|
|
|
2022-03-09 19:01:43 +11:00
|
|
|
MeshModule::~MeshModule()
|
2020-11-28 12:10:19 +08:00
|
|
|
{
|
2025-01-01 17:25:01 -08:00
|
|
|
auto it = std::find(modules->begin(), modules->end(), this);
|
|
|
|
|
assert(it != modules->end());
|
|
|
|
|
modules->erase(it);
|
2020-11-28 12:10:19 +08:00
|
|
|
}
|
|
|
|
|
|
2025-01-26 20:59:59 +01:00
|
|
|
// ⚠️ **Only call once** to set the initial delay before a module starts broadcasting periodically
|
|
|
|
|
int32_t MeshModule::setStartDelay()
|
|
|
|
|
{
|
|
|
|
|
int32_t startDelay = MESHMODULE_MIN_BROADCAST_DELAY_MS + numPeriodicModules * MESHMODULE_BROADCAST_SPACING_MS;
|
|
|
|
|
numPeriodicModules++;
|
|
|
|
|
|
|
|
|
|
return startDelay;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-08 14:13:57 +01:00
|
|
|
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
2024-11-03 13:21:45 +01:00
|
|
|
uint8_t hopLimit)
|
2021-03-23 11:44:51 +08:00
|
|
|
{
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_Routing c = meshtastic_Routing_init_default;
|
2021-03-23 11:44:51 +08:00
|
|
|
|
|
|
|
|
c.error_reason = err;
|
2023-01-21 18:22:19 +01:00
|
|
|
c.which_variant = meshtastic_Routing_error_reason_tag;
|
2021-03-23 11:44:51 +08:00
|
|
|
|
2024-04-17 00:47:56 +02:00
|
|
|
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingModule
|
2021-03-23 11:44:51 +08:00
|
|
|
// So we manually call pb_encode_to_bytes and specify routing port number
|
|
|
|
|
// auto p = allocDataProtobuf(c);
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *p = router->allocForSending();
|
|
|
|
|
p->decoded.portnum = meshtastic_PortNum_ROUTING_APP;
|
2023-01-21 18:39:58 +01:00
|
|
|
p->decoded.payload.size =
|
|
|
|
|
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Routing_msg, &c);
|
2021-03-23 11:44:51 +08:00
|
|
|
|
2023-01-21 18:22:19 +01:00
|
|
|
p->priority = meshtastic_MeshPacket_Priority_ACK;
|
2021-03-23 11:44:51 +08:00
|
|
|
|
2024-11-03 13:21:45 +01:00
|
|
|
p->hop_limit = hopLimit; // Flood ACK back to original sender
|
2021-03-23 11:44:51 +08:00
|
|
|
p->to = to;
|
|
|
|
|
p->decoded.request_id = idFrom;
|
|
|
|
|
p->channel = chIndex;
|
2024-08-13 12:10:46 -05:00
|
|
|
if (err != meshtastic_Routing_Error_NONE)
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_WARN("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x", err, to, idFrom, p->id);
|
2021-03-23 11:44:51 +08:00
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p)
|
2021-03-23 11:44:51 +08:00
|
|
|
{
|
2024-06-09 23:02:52 +02:00
|
|
|
// If the original packet couldn't be decoded, use the primary channel
|
|
|
|
|
uint8_t channelIndex =
|
|
|
|
|
p->which_payload_variant == meshtastic_MeshPacket_decoded_tag ? p->channel : channels.getPrimaryIndex();
|
|
|
|
|
auto r = allocAckNak(err, getFrom(p), p->id, channelIndex);
|
2021-03-23 11:44:51 +08:00
|
|
|
|
|
|
|
|
setReplyTo(r, *p);
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-12 16:08:03 -05:00
|
|
|
void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src, const char *specificModule)
|
2020-11-28 12:10:19 +08:00
|
|
|
{
|
2025-08-12 16:08:03 -05:00
|
|
|
if (specificModule) {
|
|
|
|
|
LOG_DEBUG("Calling specific module: %s", specificModule);
|
|
|
|
|
}
|
2024-10-14 06:11:43 +02:00
|
|
|
// LOG_DEBUG("In call modules");
|
2022-02-27 02:21:02 -08:00
|
|
|
bool moduleFound = false;
|
2021-02-17 19:04:41 +08:00
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
// We now allow **encrypted** packets to pass through the modules
|
2023-01-21 18:22:19 +01:00
|
|
|
bool isDecoded = mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag;
|
2021-02-17 19:04:41 +08:00
|
|
|
|
2021-03-05 11:44:45 +08:00
|
|
|
currentReply = NULL; // No reply yet
|
|
|
|
|
|
2023-02-15 19:31:09 +01:00
|
|
|
bool ignoreRequest = false; // No module asked to ignore the request yet
|
|
|
|
|
|
2021-02-17 19:04:41 +08:00
|
|
|
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
2024-03-21 09:06:37 -05:00
|
|
|
auto ourNodeNum = nodeDB->getNodeNum();
|
2024-10-19 12:48:00 -05:00
|
|
|
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
|
2021-10-09 14:02:21 +00:00
|
|
|
|
2022-02-27 01:49:24 -08:00
|
|
|
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
2020-11-28 13:25:03 +08:00
|
|
|
auto &pi = **i;
|
2020-12-13 12:57:37 +08:00
|
|
|
|
2025-08-12 16:08:03 -05:00
|
|
|
// If specificModule is provided, only call that specific module
|
|
|
|
|
if (specificModule && (!pi.name || strcmp(pi.name, specificModule) != 0)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 12:57:37 +08:00
|
|
|
pi.currentRequest = ∓
|
2021-02-17 19:04:41 +08:00
|
|
|
|
2022-02-27 00:29:05 -08:00
|
|
|
/// We only call modules that are interested in the packet (and the message is destined to us or we are promiscious)
|
2021-04-05 08:44:47 +08:00
|
|
|
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
2021-03-23 12:07:04 +08:00
|
|
|
|
2021-10-09 14:02:21 +00:00
|
|
|
if ((src == RX_SRC_LOCAL) && !(pi.loopbackOk)) {
|
|
|
|
|
// new case, monitor separately for now, then FIXME merge above
|
|
|
|
|
wantsPacket = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-06 10:34:23 +08:00
|
|
|
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
|
|
|
|
|
2021-03-23 12:07:04 +08:00
|
|
|
if (wantsPacket) {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("Module '%s' wantsPacket=%d", pi.name, wantsPacket);
|
2021-05-03 14:46:30 +08:00
|
|
|
|
2022-02-27 02:21:02 -08:00
|
|
|
moduleFound = true;
|
2020-12-13 15:59:26 +08:00
|
|
|
|
2021-04-05 08:44:47 +08:00
|
|
|
/// received channel (or NULL if not decoded)
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL;
|
2021-04-05 08:44:47 +08:00
|
|
|
|
2021-03-23 12:07:04 +08:00
|
|
|
/// Is the channel this packet arrived on acceptable? (security check)
|
2022-02-27 00:29:05 -08:00
|
|
|
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
|
2021-05-03 14:46:30 +08:00
|
|
|
|
2023-01-21 14:34:29 +01:00
|
|
|
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and
|
|
|
|
|
/// it needs to to be able to fetch the initial admin packets without yet knowing any channels.
|
2021-05-03 14:46:30 +08:00
|
|
|
|
2024-06-09 23:02:52 +02:00
|
|
|
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (ch && strcasecmp(ch->settings.name, pi.boundChannel) == 0);
|
2020-12-05 11:15:06 +08:00
|
|
|
|
2021-03-23 12:07:04 +08:00
|
|
|
if (!rxChannelOk) {
|
|
|
|
|
// no one should have already replied!
|
|
|
|
|
assert(!currentReply);
|
2021-02-26 20:10:41 +08:00
|
|
|
|
2024-06-09 23:02:52 +02:00
|
|
|
if (isDecoded && mp.decoded.want_response) {
|
2022-11-23 19:27:57 +01:00
|
|
|
printPacket("packet on wrong channel, returning error", &mp);
|
2023-01-21 18:22:19 +01:00
|
|
|
currentReply = pi.allocErrorResponse(meshtastic_Routing_Error_NOT_AUTHORIZED, &mp);
|
2021-03-23 12:07:04 +08:00
|
|
|
} else
|
2022-11-23 19:27:57 +01:00
|
|
|
printPacket("packet on wrong channel, but can't respond", &mp);
|
2021-03-05 11:44:45 +08:00
|
|
|
} else {
|
2021-09-23 04:42:09 +03:00
|
|
|
ProcessMessage handled = pi.handleReceived(mp);
|
2021-03-23 12:07:04 +08:00
|
|
|
|
2024-02-09 20:31:10 -06:00
|
|
|
pi.alterReceived(mp);
|
|
|
|
|
|
2021-03-23 12:07:04 +08:00
|
|
|
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious
|
2022-02-27 00:29:05 -08:00
|
|
|
// sniffing) also: we only let the one module send a reply, once that happens, remaining modules are not
|
2021-03-23 12:07:04 +08:00
|
|
|
// considered
|
|
|
|
|
|
|
|
|
|
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary
|
|
|
|
|
// because currently when the phone sends things, it sends things using the local node ID as the from address. A
|
|
|
|
|
// better solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like
|
|
|
|
|
// any other node.
|
2024-10-04 13:28:51 +02:00
|
|
|
if (isDecoded && mp.decoded.want_response && toUs && (!isFromUs(&mp) || isToUs(&mp)) && !currentReply) {
|
2021-03-23 12:07:04 +08:00
|
|
|
pi.sendResponse(mp);
|
2023-02-15 19:31:09 +01:00
|
|
|
ignoreRequest = ignoreRequest || pi.ignoreRequest; // If at least one module asks it, we may ignore a request
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_INFO("Asked module '%s' to send a response", pi.name);
|
2021-03-23 12:07:04 +08:00
|
|
|
} else {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("Module '%s' considered", pi.name);
|
2021-03-23 12:07:04 +08:00
|
|
|
}
|
2021-04-06 10:34:23 +08:00
|
|
|
|
|
|
|
|
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
|
|
|
|
|
if (pi.myReply) {
|
2024-11-04 19:15:59 -06:00
|
|
|
LOG_DEBUG("Discard an unneeded response");
|
2021-04-06 10:34:23 +08:00
|
|
|
packetPool.release(pi.myReply);
|
|
|
|
|
pi.myReply = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 04:42:09 +03:00
|
|
|
if (handled == ProcessMessage::STOP) {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("Module '%s' handled and skipped other processing", pi.name);
|
2021-03-23 12:07:04 +08:00
|
|
|
break;
|
|
|
|
|
}
|
2021-02-17 19:04:41 +08:00
|
|
|
}
|
2020-11-28 13:25:03 +08:00
|
|
|
}
|
2021-03-05 11:44:45 +08:00
|
|
|
|
2020-12-13 12:57:37 +08:00
|
|
|
pi.currentRequest = NULL;
|
2020-11-28 12:10:19 +08:00
|
|
|
}
|
2020-12-13 15:59:26 +08:00
|
|
|
|
2024-06-09 23:02:52 +02:00
|
|
|
if (isDecoded && mp.decoded.want_response && toUs) {
|
2021-03-12 14:10:36 +08:00
|
|
|
if (currentReply) {
|
2024-11-04 12:16:25 -06:00
|
|
|
printPacket("Send response", currentReply);
|
2024-08-01 19:29:49 -05:00
|
|
|
service->sendToMesh(currentReply);
|
2021-03-12 14:10:36 +08:00
|
|
|
currentReply = NULL;
|
2023-02-15 19:31:09 +01:00
|
|
|
} else if (mp.from != ourNodeNum && !ignoreRequest) {
|
|
|
|
|
// Note: if the message started with the local node or a module asked to ignore the request, we don't want to send a
|
|
|
|
|
// no response reply
|
2021-05-03 10:53:06 +08:00
|
|
|
|
2023-07-14 17:25:20 -04:00
|
|
|
// No one wanted to reply to this request, tell the requster that happened
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("No one responded, send a nak");
|
2021-04-05 08:56:11 +08:00
|
|
|
|
|
|
|
|
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
|
|
|
|
|
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
|
|
|
|
|
// bad.
|
2024-11-03 13:21:45 +01:00
|
|
|
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
|
|
|
|
|
routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit));
|
2021-03-12 14:10:36 +08:00
|
|
|
}
|
2021-03-05 11:44:45 +08:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 23:02:52 +02:00
|
|
|
if (!moduleFound && isDecoded) {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("No modules interested in portnum=%d, src=%s", mp.decoded.portnum, (src == RX_SRC_LOCAL) ? "LOCAL" : "REMOTE");
|
2023-05-13 13:33:14 +03:00
|
|
|
}
|
2020-12-07 10:18:11 +08:00
|
|
|
}
|
|
|
|
|
|
2023-01-21 18:22:19 +01:00
|
|
|
meshtastic_MeshPacket *MeshModule::allocReply()
|
2021-04-06 10:34:23 +08:00
|
|
|
{
|
|
|
|
|
auto r = myReply;
|
|
|
|
|
myReply = NULL; // Only use each reply once
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
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. Implementing this method
|
|
|
|
|
* is optional
|
|
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
void MeshModule::sendResponse(const meshtastic_MeshPacket &req)
|
2021-03-05 11:44:45 +08:00
|
|
|
{
|
2020-12-07 10:18:11 +08:00
|
|
|
auto r = allocReply();
|
2021-03-05 11:44:45 +08:00
|
|
|
if (r) {
|
2020-12-07 10:18:11 +08:00
|
|
|
setReplyTo(r, req);
|
2021-03-11 10:01:57 +08:00
|
|
|
currentReply = r;
|
2021-03-05 11:44:45 +08:00
|
|
|
} else {
|
2022-02-27 00:29:05 -08:00
|
|
|
// Ignore - this is now expected behavior for routing module (because it ignores some replies)
|
2024-10-14 06:11:43 +02:00
|
|
|
// LOG_WARN("Client requested response but this module did not provide");
|
2020-12-07 10:18:11 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-05 11:44:45 +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-05 11:44:45 +08:00
|
|
|
*/
|
2023-01-21 18:22:19 +01:00
|
|
|
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
|
2021-03-05 11:44:45 +08:00
|
|
|
{
|
2023-01-21 18:22:19 +01:00
|
|
|
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
|
2021-04-06 10:34:23 +08:00
|
|
|
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
|
2021-03-11 10:01:57 +08:00
|
|
|
p->channel = to.channel; // Use the same channel that the request came in on
|
2024-03-08 14:13:57 +01:00
|
|
|
p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
|
2021-03-05 12:37:26 +08:00
|
|
|
|
|
|
|
|
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
|
|
|
|
p->want_ack = (to.from != 0) ? to.want_ack : false;
|
2023-01-21 18:22:19 +01:00
|
|
|
if (p->priority == meshtastic_MeshPacket_Priority_UNSET)
|
|
|
|
|
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
|
2021-02-26 20:36:22 +08:00
|
|
|
p->decoded.request_id = to.id;
|
2021-02-21 16:46:46 -05: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
|
|
|
std::vector<MeshModule *> MeshModule::GetMeshModulesWithUIFrames(int startIndex)
|
2021-03-05 11:44:45 +08:00
|
|
|
{
|
2022-03-09 19:01:43 +11:00
|
|
|
std::vector<MeshModule *> modulesWithUIFrames;
|
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
|
|
|
|
|
|
|
|
// Fill with nullptr up to startIndex
|
|
|
|
|
modulesWithUIFrames.resize(startIndex, nullptr);
|
|
|
|
|
|
2022-02-27 01:49:24 -08:00
|
|
|
if (modules) {
|
|
|
|
|
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
2022-02-21 06:29:15 +01:00
|
|
|
auto &pi = **i;
|
|
|
|
|
if (pi.wantUIFrame()) {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("%s wants a UI Frame", pi.name);
|
2022-02-27 02:21:02 -08:00
|
|
|
modulesWithUIFrames.push_back(&pi);
|
2022-02-21 06:29:15 +01:00
|
|
|
}
|
2021-02-21 16:46:46 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-02-27 02:21:02 -08:00
|
|
|
return modulesWithUIFrames;
|
2021-02-21 16:46:46 -05:00
|
|
|
}
|
2022-01-13 09:19:36 +01:00
|
|
|
|
2023-01-21 14:34:29 +01:00
|
|
|
void MeshModule::observeUIEvents(Observer<const UIFrameEvent *> *observer)
|
2022-01-13 09:19:36 +01:00
|
|
|
{
|
2022-02-27 01:49:24 -08:00
|
|
|
if (modules) {
|
|
|
|
|
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
2022-02-21 06:29:15 +01:00
|
|
|
auto &pi = **i;
|
2023-01-21 14:34:29 +01:00
|
|
|
Observable<const UIFrameEvent *> *observable = pi.getUIFrameObservable();
|
2022-02-21 06:29:15 +01:00
|
|
|
if (observable != NULL) {
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("%s wants a UI Frame", pi.name);
|
2022-02-21 06:29:15 +01:00
|
|
|
observer->observe(observable);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-17 00:47:56 +02:00
|
|
|
AdminMessageHandleResult MeshModule::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-02-21 06:29:15 +01:00
|
|
|
{
|
|
|
|
|
AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED;
|
2022-02-27 01:49:24 -08:00
|
|
|
if (modules) {
|
|
|
|
|
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
2022-02-21 06:29:15 +01:00
|
|
|
auto &pi = **i;
|
2022-02-27 02:21:02 -08:00
|
|
|
AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response);
|
2023-01-21 14:34:29 +01:00
|
|
|
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
|
2022-02-21 06:29:15 +01:00
|
|
|
// In case we have a response it always has priority.
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("Reply prepared by module '%s' of variant: %d", pi.name, response->which_payload_variant);
|
2022-02-21 06:29:15 +01:00
|
|
|
handled = h;
|
2023-01-21 14:34:29 +01:00
|
|
|
} else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) && (h == AdminMessageHandleResult::HANDLED)) {
|
2022-02-21 06:29:15 +01:00
|
|
|
// In case the message is handled it should be populated, but will not overwrite
|
|
|
|
|
// a result with response.
|
|
|
|
|
handled = h;
|
|
|
|
|
}
|
2022-01-13 09:19:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-02-21 06:29:15 +01:00
|
|
|
return handled;
|
2024-07-12 11:51:26 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAS_SCREEN
|
|
|
|
|
// Would our module like its frame to be focused after Screen::setFrames has regenerated the list of frames?
|
|
|
|
|
// Only considered if setFrames is triggered by a UIFrameEvent
|
|
|
|
|
bool MeshModule::isRequestingFocus()
|
|
|
|
|
{
|
|
|
|
|
if (_requestingFocus) {
|
|
|
|
|
_requestingFocus = false; // Consume the request
|
|
|
|
|
return true;
|
|
|
|
|
} else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-03 13:21:45 +01:00
|
|
|
#endif
|