mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-10 03:47:39 +00:00
massive WIP updates to create a clean Router abstraction for mesh
This commit is contained in:
@@ -11,10 +11,7 @@
|
||||
#define MAX_RHPACKETLEN 251
|
||||
static uint8_t radiobuf[MAX_RHPACKETLEN];
|
||||
|
||||
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
||||
: RH_RF95(NSS_GPIO, RF95_IRQ_GPIO), RadioInterface(_pool, _rxDest), txQueue(MAX_TX_QUEUE)
|
||||
{
|
||||
}
|
||||
CustomRF95::CustomRF95() : RH_RF95(NSS_GPIO, RF95_IRQ_GPIO), txQueue(MAX_TX_QUEUE) {}
|
||||
|
||||
bool CustomRF95::canSleep()
|
||||
{
|
||||
@@ -58,7 +55,7 @@ ErrorCode CustomRF95::send(MeshPacket *p)
|
||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (res != ERRNO_OK) // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
pool.release(p);
|
||||
packetPool.release(p);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -76,7 +73,7 @@ void CustomRF95::handleInterrupt()
|
||||
if (sendingPacket) // Were we sending?
|
||||
{
|
||||
// We are done sending that packet, release it
|
||||
pool.releaseFromISR(sendingPacket, &higherPriWoken);
|
||||
packetPool.releaseFromISR(sendingPacket, &higherPriWoken);
|
||||
sendingPacket = NULL;
|
||||
// DEBUG_MSG("Done with send\n");
|
||||
}
|
||||
@@ -94,7 +91,7 @@ void CustomRF95::handleInterrupt()
|
||||
// DEBUG_MSG("Received packet from mesh src=0x%x,dest=0x%x,id=%d,len=%d rxGood=%d,rxBad=%d,freqErr=%d,snr=%d\n",
|
||||
// srcaddr, destaddr, id, rxlen, rf95.rxGood(), rf95.rxBad(), freqerr, snr);
|
||||
|
||||
MeshPacket *mp = pool.allocZeroed();
|
||||
MeshPacket *mp = packetPool.allocZeroed();
|
||||
|
||||
SubPacket *p = &mp->payload;
|
||||
|
||||
@@ -113,12 +110,12 @@ void CustomRF95::handleInterrupt()
|
||||
}
|
||||
|
||||
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p)) {
|
||||
pool.releaseFromISR(mp, &higherPriWoken);
|
||||
packetPool.releaseFromISR(mp, &higherPriWoken);
|
||||
} else {
|
||||
// parsing was successful, queue for our recipient
|
||||
mp->has_payload = true;
|
||||
|
||||
assert(rxDest.enqueueFromISR(mp, &higherPriWoken)); // NOWAIT - fixme, if queue is full, delete older messages
|
||||
deliverToReceiverISR(mp, &higherPriWoken);
|
||||
}
|
||||
|
||||
clearRxBuf(); // This message accepted and cleared
|
||||
|
||||
@@ -19,7 +19,7 @@ class CustomRF95 : public RH_RF95, public RadioInterface
|
||||
/** pool is the pool we will alloc our rx packets from
|
||||
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
||||
*/
|
||||
CustomRF95(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
|
||||
CustomRF95();
|
||||
|
||||
/**
|
||||
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
|
||||
|
||||
@@ -31,6 +31,7 @@ template <class T> class MemoryPool
|
||||
~MemoryPool() { delete[] buf; }
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||
/// Note: this method is safe to call from regular OR ISR code
|
||||
T *allocZeroed()
|
||||
{
|
||||
T *p = allocZeroed(0);
|
||||
@@ -40,7 +41,7 @@ template <class T> class MemoryPool
|
||||
}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably
|
||||
/// don't want this version)
|
||||
/// don't want this version).
|
||||
T *allocZeroed(TickType_t maxWait)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
@@ -65,7 +66,7 @@ template <class T> class MemoryPool
|
||||
{
|
||||
assert(dead.enqueue(p, 0));
|
||||
assert(p >= buf &&
|
||||
(size_t) (p - buf) <
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ template <class T> class MemoryPool
|
||||
{
|
||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||
assert(p >= buf &&
|
||||
(size_t) (p - buf) <
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,14 +2,21 @@
|
||||
#include "NodeDB.h"
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
RadioInterface::RadioInterface(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : pool(_pool), rxDest(_rxDest) {}
|
||||
RadioInterface::RadioInterface() {}
|
||||
|
||||
ErrorCode SimRadio::send(MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("SimRadio.send\n");
|
||||
pool.release(p);
|
||||
packetPool.release(p);
|
||||
return ERRNO_OK;
|
||||
}
|
||||
|
||||
void RadioInterface::deliverToReceiverISR(MeshPacket *p, BaseType_t *higherPriWoken)
|
||||
{
|
||||
assert(rxDest);
|
||||
assert(rxDest->enqueueFromISR(p, higherPriWoken)); // NOWAIT - fixme, if queue is full, delete older messages
|
||||
}
|
||||
@@ -16,43 +16,38 @@
|
||||
class RadioInterface
|
||||
{
|
||||
friend class MeshRadio; // for debugging we let that class touch pool
|
||||
PointerQueue<MeshPacket> *rxDest = NULL;
|
||||
|
||||
protected:
|
||||
MemoryPool<MeshPacket> &pool;
|
||||
PointerQueue<MeshPacket> &rxDest;
|
||||
|
||||
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
||||
|
||||
/**
|
||||
* Enqueue a received packet for the registered receiver
|
||||
*/
|
||||
void deliverToReceiverISR(MeshPacket *p, BaseType_t *higherPriWoken);
|
||||
|
||||
public:
|
||||
/** pool is the pool we will alloc our rx packets from
|
||||
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
||||
*/
|
||||
RadioInterface(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
|
||||
RadioInterface();
|
||||
|
||||
/**
|
||||
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
|
||||
*
|
||||
* This method must be used before putting the CPU into deep or light sleep.
|
||||
* Set where to deliver received packets. This method should only be used by the Router class
|
||||
*/
|
||||
virtual bool canSleep() { return true; }
|
||||
void setReceiver(PointerQueue<MeshPacket> *_rxDest) { rxDest = _rxDest; }
|
||||
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
/// return true for success
|
||||
virtual bool sleep() { return true; }
|
||||
|
||||
/// Send a packet (possibly by enquing in a private fifo). This routine will
|
||||
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
|
||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||
/**
|
||||
* Send a packet (possibly by enquing in a private fifo). This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p) = 0;
|
||||
};
|
||||
|
||||
class SimRadio : public RadioInterface
|
||||
{
|
||||
public:
|
||||
/** pool is the pool we will alloc our rx packets from
|
||||
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
||||
*/
|
||||
SimRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : RadioInterface(_pool, _rxDest) {}
|
||||
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
|
||||
// methods from radiohead
|
||||
|
||||
72
src/rf95/Router.cpp
Normal file
72
src/rf95/Router.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
|
||||
/**
|
||||
* Router todo
|
||||
*
|
||||
* Implement basic interface and use it elsewhere in app
|
||||
* Add naive flooding mixin (& drop duplicate rx broadcasts), add tools for sending broadcasts with incrementing sequence #s
|
||||
* Add an optional adjacent node only 'send with ack' mixin. If we timeout waiting for the ack, call handleAckTimeout(packet)
|
||||
* Add DSR mixin
|
||||
*
|
||||
**/
|
||||
|
||||
#define MAX_RX_FROMRADIO \
|
||||
4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
|
||||
|
||||
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
|
||||
#define MAX_PACKETS \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
|
||||
MemoryPool<MeshPacket> packetPool(MAX_PACKETS);
|
||||
|
||||
Router router;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Currently we only allow one interface, that may change in the future
|
||||
*/
|
||||
Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO) {}
|
||||
|
||||
/**
|
||||
* do idle processing
|
||||
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
|
||||
*/
|
||||
void Router::loop()
|
||||
{
|
||||
MeshPacket *mp;
|
||||
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
||||
handleReceived(mp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet on a suitable interface. This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
ErrorCode Router::send(MeshPacket *p)
|
||||
{
|
||||
assert(iface);
|
||||
return iface->send(p);
|
||||
}
|
||||
|
||||
#include "GPS.h"
|
||||
|
||||
/**
|
||||
* Handle any packet that is received by an interface on this node.
|
||||
* Note: some packets may merely being passed through this node and will be forwarded elsewhere.
|
||||
*/
|
||||
void Router::handleReceived(MeshPacket *p)
|
||||
{
|
||||
// FIXME, this class shouldn't EVER need to know about the GPS, move getValidTime() into a non gps dependent function
|
||||
// Also, we should set the time from the ISR and it should have msec level resolution
|
||||
p->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone
|
||||
|
||||
DEBUG_MSG("Notifying observers of received packet\n");
|
||||
notifyPacketReceived.notifyObservers(p);
|
||||
packetPool.release(p);
|
||||
}
|
||||
70
src/rf95/Router.h
Normal file
70
src/rf95/Router.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryPool.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "Observer.h"
|
||||
#include "PointerQueue.h"
|
||||
#include "RadioInterface.h"
|
||||
#include "mesh.pb.h"
|
||||
#include <RH_RF95.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mesh aware router that supports multiple interfaces.
|
||||
*/
|
||||
class Router
|
||||
{
|
||||
private:
|
||||
RadioInterface *iface;
|
||||
|
||||
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
|
||||
/// forwarded to the phone.
|
||||
PointerQueue<MeshPacket> fromRadioQueue;
|
||||
|
||||
public:
|
||||
/// Local services that want to see _every_ packet this node receives can observe this.
|
||||
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting
|
||||
/// freed)
|
||||
Observable<const MeshPacket *> notifyPacketReceived;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
Router();
|
||||
|
||||
/**
|
||||
* Currently we only allow one interface, that may change in the future
|
||||
*/
|
||||
void addInterface(RadioInterface *_iface)
|
||||
{
|
||||
iface = _iface;
|
||||
iface->setReceiver(&fromRadioQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* do idle processing
|
||||
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
|
||||
*/
|
||||
void loop();
|
||||
|
||||
/**
|
||||
* Send a packet on a suitable interface. This routine will
|
||||
* later free() the packet to pool. This routine is not allowed to stall.
|
||||
* If the txmit queue is full it might return an error
|
||||
*/
|
||||
virtual ErrorCode send(MeshPacket *p);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called from loop()
|
||||
* Handle any packet that is received by an interface on this node.
|
||||
* Note: some packets may merely being passed through this node and will be forwarded elsewhere.
|
||||
*
|
||||
* Note: this method will free the provided packet
|
||||
*/
|
||||
void handleReceived(MeshPacket *p);
|
||||
};
|
||||
|
||||
extern Router router;
|
||||
Reference in New Issue
Block a user