mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-30 06:31:01 +00:00
* If a packet is heard multiple times, rebroadcast using the highest hop limit Sometimes a packet will be in the TX queue waiting to be transmitted, when it is overheard being rebroadcast by another node, with a higher hop limit remaining. When this occurs, modify the pending packet in the TX queue to avoid unnecessarily wasting hops. * Reprocess instead of modifying queued packet In order to ensure that the traceroute module works correctly, rather than modifying the hop limnit of the existing queued version of the packet, simply drop it ifrom the queue and reprocess the version of the packet with the superior hop limit. * Update protobufs submodule * Merge upstream/develop into overheard-hoptimisation branch Resolved conflicts in: - src/mesh/FloodingRouter.cpp: Integrated hop limit optimization with refactored duplicate handling - src/mesh/MeshPacketQueue.h: Kept both hop_limit_lt parameter and new find() method * Improve method naming and code clarity - Rename findPacket() to getPacketFromQueue() for better clarity - Make code DRY by having find() use getPacketFromQueue() internally - Resolves method overloading conflict with clearer naming * If a packet is heard multiple times, rebroadcast using the highest hop limit Sometimes a packet will be in the TX queue waiting to be transmitted, when it is overheard being rebroadcast by another node, with a higher hop limit remaining. When this occurs, modify the pending packet in the TX queue to avoid unnecessarily wasting hops. * Improve router role checking using IS_ONE_OF macro - Replace multiple individual role checks with cleaner IS_ONE_OF macro - Add CLIENT_BASE support as suggested in PR #7992 - Include MeshTypes.h for IS_ONE_OF macro - Makes code more maintainable and consistent with other parts of codebase * Apply IS_ONE_OF improvement to NextHopRouter.cpp - Replace multiple individual role checks with cleaner IS_ONE_OF macro - Add CLIENT_BASE support for consistency - Include MeshTypes.h for IS_ONE_OF macro - Matches the pattern used in FloodingRouter.cpp * Create and apply IS_ROUTER_ROLE() macro across codebase - Add IS_ROUTER_ROLE() macro to meshUtils.h for consistent router role checking - Update FloodingRouter.cpp to use macro in multiple locations - Update NextHopRouter.cpp to use macro - Include CLIENT_BASE role support * Core Changes: - Add hop_limit field to PacketRecord (17B→20B due to alignment) - Extend wasSeenRecently() with wasUpgraded parameter - Enable router optimization without duplicate app delivery - Handle ROUTER_LATE delayed transmission properly Technical Details: - Memory overhead: ~4000 bytes for 1000 records - Prevents duplicate message delivery while enabling routing optimization - Maintains protocol integrity for ACK/NAK handling - Supports upgrade from hop_limit=0 to hop_limit>0 scenarios * Delete files accdentally added for merge * Trunk formatting * Packets are supposed to be unsigned. Thankfully, it's only a log message. * Upgrade all packets, not just 0 hop packets. * Not just unsigned, but hex. Updating packet log IDs. * Fixed order of operations issue that prevented packetrs from being removed from the queue * Fixing some bugs after testing. Only storing the maximum hop value in PacketRecord which makes sense. Also, updating messaging to make more sense in the logs. * Fixed flow logic about how to handle re-inserting duplicate packets. Removed IS_ROUTER_ROLE macro and replaced it with better isRebroadcaster(). * Add logic to re-run modules, but avoid re-sending to phone. * Refactor how to process the new packet with hops. Only update nodeDB and traceRouteModule. * - Apply changes to both FloodingRouter and NextHopRouter classes to make packets mutable for traceroute - MESHTASTIC_EXCLUDE_TRACEROUTE guard for when we don't want traceroute * Allow MeshPacket to be modified in-place in processUpgradePacket * let's not make a copy where a copy is unncessary. --------- Co-authored-by: Clive Blackledge <clive@ansible.org> Co-authored-by: Clive Blackledge <git@ansible.org> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
194 lines
7.9 KiB
C++
194 lines
7.9 KiB
C++
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
#include <assert.h>
|
|
#include <string>
|
|
|
|
#include "GPSStatus.h"
|
|
#include "MemoryPool.h"
|
|
#include "MeshRadio.h"
|
|
#include "MeshTypes.h"
|
|
#include "Observer.h"
|
|
#ifdef ARCH_PORTDUINO
|
|
#include "PointerQueue.h"
|
|
#else
|
|
#include "StaticPointerQueue.h"
|
|
#endif
|
|
#include "mesh-pb-constants.h"
|
|
#if defined(ARCH_PORTDUINO)
|
|
#include "../platform/portduino/SimRadio.h"
|
|
#endif
|
|
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
|
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
|
#include "modules/StoreForwardModule.h"
|
|
#endif
|
|
#endif
|
|
|
|
extern Allocator<meshtastic_QueueStatus> &queueStatusPool;
|
|
extern Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool;
|
|
extern Allocator<meshtastic_ClientNotification> &clientNotificationPool;
|
|
|
|
/**
|
|
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
|
*
|
|
*/
|
|
class MeshService
|
|
{
|
|
#if HAS_GPS
|
|
CallbackObserver<MeshService, const meshtastic::GPSStatus *> gpsObserver =
|
|
CallbackObserver<MeshService, const meshtastic::GPSStatus *>(this, &MeshService::onGPSChanged);
|
|
#endif
|
|
/// received packets waiting for the phone to process them
|
|
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
|
|
/// we never hang because android hasn't been there in a while
|
|
/// FIXME - save this to flash on deep sleep
|
|
#ifdef ARCH_PORTDUINO
|
|
PointerQueue<meshtastic_MeshPacket> toPhoneQueue;
|
|
#else
|
|
StaticPointerQueue<meshtastic_MeshPacket, MAX_RX_TOPHONE> toPhoneQueue;
|
|
#endif
|
|
|
|
// keep list of QueueStatus packets to be send to the phone
|
|
#ifdef ARCH_PORTDUINO
|
|
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
|
|
#else
|
|
StaticPointerQueue<meshtastic_QueueStatus, MAX_RX_QUEUESTATUS_TOPHONE> toPhoneQueueStatusQueue;
|
|
#endif
|
|
|
|
// keep list of MqttClientProxyMessages to be send to the client for delivery
|
|
#ifdef ARCH_PORTDUINO
|
|
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
|
|
#else
|
|
StaticPointerQueue<meshtastic_MqttClientProxyMessage, MAX_RX_MQTTPROXY_TOPHONE> toPhoneMqttProxyQueue;
|
|
#endif
|
|
|
|
// keep list of ClientNotifications to be send to the client (phone)
|
|
#ifdef ARCH_PORTDUINO
|
|
PointerQueue<meshtastic_ClientNotification> toPhoneClientNotificationQueue;
|
|
#else
|
|
StaticPointerQueue<meshtastic_ClientNotification, MAX_RX_NOTIFICATION_TOPHONE> toPhoneClientNotificationQueue;
|
|
#endif
|
|
|
|
// This holds the last QueueStatus send
|
|
meshtastic_QueueStatus lastQueueStatus;
|
|
|
|
/// The current nonce for the newest packet which has been queued for the phone
|
|
uint32_t fromNum = 0;
|
|
|
|
/// Updated in loop() to detect when fromNum changes
|
|
uint32_t oldFromNum = 0;
|
|
|
|
public:
|
|
static bool isTextPayload(const meshtastic_MeshPacket *p)
|
|
{
|
|
if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
|
|
return true;
|
|
}
|
|
return p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
|
|
p->decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP ||
|
|
p->decoded.portnum == meshtastic_PortNum_ALERT_APP;
|
|
}
|
|
/// Called when some new packets have arrived from one of the radios
|
|
Observable<uint32_t> fromNumChanged;
|
|
|
|
/// Called when radio config has changed (radios should observe this and set their hardware as required)
|
|
Observable<void *> configChanged;
|
|
|
|
MeshService();
|
|
|
|
void init();
|
|
|
|
/// Do idle processing (mostly processing messages which have been queued from the radio)
|
|
void loop();
|
|
|
|
/// Return the next packet destined to the phone. FIXME, somehow use fromNum to allow the phone to retry the
|
|
/// last few packets if needs to.
|
|
meshtastic_MeshPacket *getForPhone() { return toPhoneQueue.dequeuePtr(0); }
|
|
|
|
/// Allows the bluetooth handler to free packets after they have been sent
|
|
void releaseToPool(meshtastic_MeshPacket *p) { packetPool.release(p); }
|
|
|
|
/// Return the next QueueStatus packet destined to the phone.
|
|
meshtastic_QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
|
|
|
|
/// Return the next MqttClientProxyMessage packet destined to the phone.
|
|
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
|
|
|
|
/// Return the next ClientNotification packet destined to the phone.
|
|
meshtastic_ClientNotification *getClientNotificationForPhone() { return toPhoneClientNotificationQueue.dequeuePtr(0); }
|
|
|
|
// search the queue for a request id and return the matching nodenum
|
|
NodeNum getNodenumFromRequestId(uint32_t request_id);
|
|
|
|
// Release QueueStatus packet to pool
|
|
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
|
|
|
|
// Release MqttClientProxyMessage packet to pool
|
|
void releaseMqttClientProxyMessageToPool(meshtastic_MqttClientProxyMessage *p) { mqttClientProxyMessagePool.release(p); }
|
|
|
|
/// Release the next ClientNotification packet to pool.
|
|
void releaseClientNotificationToPool(meshtastic_ClientNotification *p) { clientNotificationPool.release(p); }
|
|
|
|
/**
|
|
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
|
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep
|
|
* a reference
|
|
*/
|
|
void handleToRadio(meshtastic_MeshPacket &p);
|
|
|
|
/** The radioConfig object just changed, call this to force the hw to change to the new settings
|
|
* @return true if client devices should be sent a new set of radio configs
|
|
*/
|
|
void reloadConfig(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
|
|
|
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
|
void reloadOwner(bool shouldSave = true);
|
|
|
|
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
|
|
/// sends our nodeinfo
|
|
/// returns true if we sent a position
|
|
bool trySendPosition(NodeNum dest, bool wantReplies = false);
|
|
|
|
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
|
|
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
|
|
/// cache
|
|
void sendToMesh(meshtastic_MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false);
|
|
|
|
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
|
|
bool cancelSending(PacketId id);
|
|
|
|
/// Pull the latest power and time info into my nodeinfo
|
|
meshtastic_NodeInfoLite *refreshLocalMeshNode();
|
|
|
|
/// Send a packet to the phone
|
|
void sendToPhone(meshtastic_MeshPacket *p);
|
|
|
|
/// Send an MQTT message to the phone for client proxying
|
|
virtual void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m);
|
|
|
|
/// Send a ClientNotification to the phone
|
|
virtual void sendClientNotification(meshtastic_ClientNotification *cn);
|
|
|
|
/// Send an error response to the phone
|
|
void sendRoutingErrorResponse(meshtastic_Routing_Error error, const meshtastic_MeshPacket *mp);
|
|
|
|
bool isToPhoneQueueEmpty();
|
|
|
|
ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
|
|
|
|
uint32_t GetTimeSinceMeshPacket(const meshtastic_MeshPacket *mp);
|
|
|
|
private:
|
|
#if HAS_GPS
|
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
|
/// returns 0 to allow further processing
|
|
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
|
#endif
|
|
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it
|
|
/// needs to keep the packet around it makes a copy
|
|
int handleFromRadio(const meshtastic_MeshPacket *p);
|
|
friend class RoutingModule;
|
|
};
|
|
|
|
extern MeshService *service;
|