mirror of
https://github.com/meshtastic/firmware.git
synced 2025-02-26 22:33:24 +00:00
Change RF95 to deliver packets straight from ISR and no polling for anything
This commit is contained in:
parent
bf491efddf
commit
acce254685
13
TODO.md
13
TODO.md
@ -15,6 +15,7 @@ Items to complete before the first alpha release.
|
||||
# Medium priority
|
||||
Items to complete before the first beta release.
|
||||
|
||||
* GUI on oled hangs for a few seconds occasionally, but comes back
|
||||
* assign every "channel" a random shared 8 bit sync word (per 4.2.13.6 of datasheet) - use that word to filter packets before even checking CRC. This will ensure our CPU will only wake for packets on our "channel"
|
||||
* Note: we do not do address filtering at the chip level, because we might need to route for the mesh
|
||||
* Use the Periodic class for both position and user periodic broadcasts
|
||||
@ -38,14 +39,12 @@ Items to complete before the first beta release.
|
||||
General ideas to hit the power draws our spreadsheet predicts. Do the easy ones before beta, the last 15% can be done after 1.0.
|
||||
|
||||
* lower BT announce interval to save battery
|
||||
* change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet)
|
||||
* we currently poll the lora radio from loop(), which is really bad because it means we run loop every 10ms. Instead have the rf95 driver enqueue received messages from the ISR.
|
||||
* change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet) - I think this is already the case
|
||||
* have mesh service run in a thread that stays blocked until a packet arrives from the RF95
|
||||
* platformio sdkconfig CONFIG_PM and turn on modem sleep mode
|
||||
* keep cpu 100% in deepsleep until irq from radio wakes it. Then stay awake for 30 secs to attempt delivery to phone.
|
||||
* have radiohead ISR send messages to RX queue directly, to allow that thread to block until we have something to send
|
||||
* use https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/ association sleep pattern to save power - but see https://github.com/espressif/esp-idf/issues/2070 and https://esp32.com/viewtopic.php?f=13&t=12182 it seems with BLE on the 'easy' draw people are getting is 80mA
|
||||
* stop using loop() instead use a job queue and let cpu sleep
|
||||
* move lora rx/tx to own thread and block on IO
|
||||
* measure power consumption and calculate battery life assuming no deep sleep
|
||||
* do lowest sleep level possible where BT still works during normal sleeping, make sure cpu stays in that mode unless lora rx packet happens, bt rx packet happens or button press happens
|
||||
* optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature
|
||||
@ -56,6 +55,8 @@ General ideas to hit the power draws our spreadsheet predicts. Do the easy ones
|
||||
# Pre-beta priority
|
||||
During the beta timeframe the following improvements 'would be nice' (and yeah - I guess some of these items count as features, but it is a hobby project ;-) )
|
||||
|
||||
* fix the frequency error reading in the RF95 RX code (can't do floating point math in an ISR ;-)
|
||||
* See CustomRF95::send and fix the problem of dropping partially received packets if we want to start sending
|
||||
* swap out speck for hw-accelerated full AES https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/esp32/hwcrypto/aes.h
|
||||
* use variable length arduino Strings in protobufs (instead of current fixed buffers)
|
||||
* don't even power on bluetooth until we have some data to send to the android phone. Most of the time we should be sleeping in a lowpower "listening for lora" only mode. Once we have some packets for the phone, then power on bluetooth
|
||||
@ -146,4 +147,6 @@ Items after the first final candidate release.
|
||||
* add receive timestamps to messages, inserted by esp32 when message is received but then shown on the phone
|
||||
* update build to generate both board types
|
||||
* have node info screen show real info (including distance and heading)
|
||||
* blink the power led less often
|
||||
* blink the power led less often
|
||||
* have radiohead ISR send messages to RX queue directly, to allow that thread to block until we have something to send
|
||||
* move lora rx/tx to own thread and block on IO
|
168
src/CustomRF95.cpp
Normal file
168
src/CustomRF95.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
#include "CustomRF95.h"
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include "configuration.h"
|
||||
#include "assert.h"
|
||||
#include "NodeDB.h"
|
||||
|
||||
#define MAX_TX_QUEUE 8 // max number of packets which can be waiting for transmission
|
||||
|
||||
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
||||
#define MAX_RHPACKETLEN 251
|
||||
static uint8_t radiobuf[MAX_RHPACKETLEN];
|
||||
|
||||
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
||||
: RH_RF95(NSS_GPIO, DIO0_GPIO),
|
||||
pool(_pool),
|
||||
rxDest(_rxDest),
|
||||
txQueue(MAX_TX_QUEUE),
|
||||
sendingPacket(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
bool CustomRF95::init()
|
||||
{
|
||||
bool ok = RH_RF95::init();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/// 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
|
||||
ErrorCode CustomRF95::send(MeshPacket *p)
|
||||
{
|
||||
// FIXME - we currently just slam over into send mode if the RF95 is in RX mode. This is _probably_ safe given
|
||||
// how quiet our network is, bu it would be better to wait _if_ we are partially though receiving a packet (rather than
|
||||
// just merely waiting for one).
|
||||
// This is doubly bad because not only do we drop the packet that was on the way in, we almost certainly guarantee no one
|
||||
// outside will like the packet we are sending.
|
||||
if (_mode == RHModeIdle || _mode == RHModeRx)
|
||||
{
|
||||
// if the radio is idle, we can send right away
|
||||
DEBUG_MSG("immedate send on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", txGood(), rxGood(), rxBad());
|
||||
startSend(p);
|
||||
return ERRNO_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG("enquing packet for send from=0x%x, to=0x%x\n", p->from, p->to);
|
||||
return txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN; // nowait
|
||||
}
|
||||
}
|
||||
|
||||
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
|
||||
void CustomRF95::handleInterrupt()
|
||||
{
|
||||
RH_RF95::handleInterrupt();
|
||||
|
||||
BaseType_t higherPriWoken = false;
|
||||
if (_mode == RHModeIdle) // We are now done sending or receiving
|
||||
{
|
||||
if (sendingPacket) // Were we sending?
|
||||
{
|
||||
// We are done sending that packet, release it
|
||||
pool.releaseFromISR(sendingPacket, &higherPriWoken);
|
||||
sendingPacket = NULL;
|
||||
// DEBUG_MSG("Done with send\n");
|
||||
}
|
||||
|
||||
// If we just finished receiving a packet, forward it into a queue
|
||||
if (_rxBufValid)
|
||||
{
|
||||
// We received a packet
|
||||
|
||||
// Skip the 4 headers that are at the beginning of the rxBuf
|
||||
size_t payloadLen = _bufLen - RH_RF95_HEADER_LEN;
|
||||
uint8_t *payload = _buf + RH_RF95_HEADER_LEN;
|
||||
|
||||
// FIXME - throws exception if called in ISR context: frequencyError() - probably the floating point math
|
||||
int32_t freqerr = -1, snr = lastSNR();
|
||||
//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();
|
||||
|
||||
SubPacket *p = &mp->payload;
|
||||
|
||||
mp->from = _rxHeaderFrom;
|
||||
mp->to = _rxHeaderTo;
|
||||
//_rxHeaderId = _buf[2];
|
||||
//_rxHeaderFlags = _buf[3];
|
||||
|
||||
// If we already have an entry in the DB for this nodenum, goahead and hide the snr/freqerr info there.
|
||||
// Note: we can't create it at this point, because it might be a bogus User node allocation. But odds are we will
|
||||
// already have a record we can hide this debugging info in.
|
||||
NodeInfo *info = nodeDB.getNode(mp->from);
|
||||
if (info)
|
||||
{
|
||||
info->snr = snr;
|
||||
info->frequency_error = freqerr;
|
||||
}
|
||||
|
||||
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p))
|
||||
{
|
||||
pool.releaseFromISR(mp, &higherPriWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// parsing was successful, queue for our recipient
|
||||
mp->has_payload = true;
|
||||
|
||||
int res = rxDest.enqueueFromISR(mp, &higherPriWoken); // NOWAIT - fixme, if queue is full, delete older messages
|
||||
assert(res == pdTRUE);
|
||||
}
|
||||
|
||||
clearRxBuf(); // This message accepted and cleared
|
||||
}
|
||||
|
||||
higherPriWoken |= handleIdleISR();
|
||||
}
|
||||
|
||||
// If we call this _IT WILL NOT RETURN_
|
||||
if (higherPriWoken)
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
/// Return true if a higher pri task has woken
|
||||
bool CustomRF95::handleIdleISR()
|
||||
{
|
||||
BaseType_t higherPriWoken = false;
|
||||
|
||||
// First send any outgoing packets we have ready
|
||||
MeshPacket *txp = txQueue.dequeuePtrFromISR(0);
|
||||
if (txp)
|
||||
startSend(txp);
|
||||
else
|
||||
{
|
||||
// Nothing to send, let's switch back to receive mode
|
||||
setModeRx();
|
||||
}
|
||||
|
||||
return higherPriWoken;
|
||||
}
|
||||
|
||||
/// This routine might be called either from user space or ISR
|
||||
void CustomRF95::startSend(MeshPacket *txp)
|
||||
{
|
||||
assert(!sendingPacket);
|
||||
|
||||
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
|
||||
assert(txp->has_payload);
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(radiobuf, sizeof(radiobuf), SubPacket_fields, &txp->payload);
|
||||
|
||||
sendingPacket = txp;
|
||||
|
||||
setHeaderTo(txp->to);
|
||||
setHeaderFrom(nodeDB.getNodeNum()); // We must do this before each send, because we might have just changed our nodenum
|
||||
|
||||
// setHeaderId(0);
|
||||
|
||||
assert(numbytes <= 251); // Make sure we don't overflow the tiny max packet size
|
||||
|
||||
// uint32_t start = millis(); // FIXME, store this in the class
|
||||
|
||||
int res = RH_RF95::send(radiobuf, numbytes);
|
||||
assert(res);
|
||||
}
|
43
src/CustomRF95.h
Normal file
43
src/CustomRF95.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <RH_RF95.h>
|
||||
#include <RHMesh.h>
|
||||
#include "MemoryPool.h"
|
||||
#include "mesh.pb.h"
|
||||
#include "PointerQueue.h"
|
||||
#include "MeshTypes.h"
|
||||
|
||||
/**
|
||||
* A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!)
|
||||
*/
|
||||
class CustomRF95 : public RH_RF95
|
||||
{
|
||||
MemoryPool<MeshPacket> &pool;
|
||||
PointerQueue<MeshPacket> &rxDest;
|
||||
PointerQueue<MeshPacket> txQueue;
|
||||
|
||||
MeshPacket *sendingPacket; // The packet we are currently sending
|
||||
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
|
||||
*/
|
||||
CustomRF95(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
|
||||
|
||||
/// 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
|
||||
ErrorCode send(MeshPacket *p);
|
||||
|
||||
bool init();
|
||||
|
||||
protected:
|
||||
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
|
||||
virtual void handleInterrupt();
|
||||
|
||||
private:
|
||||
/// Send a new packet - this low level call can be called from either ISR or userspace
|
||||
void startSend(MeshPacket *txp);
|
||||
|
||||
/// Return true if a higher pri task has woken
|
||||
bool handleIdleISR();
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
@ -10,58 +10,72 @@
|
||||
*
|
||||
* Eventually this routine will even be safe for ISR use...
|
||||
*/
|
||||
template <class T> class MemoryPool {
|
||||
template <class T>
|
||||
class MemoryPool
|
||||
{
|
||||
PointerQueue<T> dead;
|
||||
|
||||
T *buf; // our large raw block of memory
|
||||
|
||||
size_t maxElements;
|
||||
|
||||
public:
|
||||
MemoryPool(size_t _maxElements): dead(_maxElements), maxElements(_maxElements) {
|
||||
MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
|
||||
{
|
||||
buf = new T[maxElements];
|
||||
|
||||
|
||||
// prefill dead
|
||||
for(int i = 0; i < maxElements; i++)
|
||||
for (int i = 0; i < maxElements; i++)
|
||||
release(&buf[i]);
|
||||
}
|
||||
|
||||
~MemoryPool() {
|
||||
~MemoryPool()
|
||||
{
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||
T *allocZeroed() {
|
||||
T *allocZeroed()
|
||||
{
|
||||
T *p = allocZeroed(0);
|
||||
|
||||
|
||||
assert(p); // FIXME panic instead
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably don't want this version)
|
||||
T *allocZeroed(TickType_t maxWait) {
|
||||
T *allocZeroed(TickType_t maxWait)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
|
||||
if(p)
|
||||
|
||||
if (p)
|
||||
memset(p, 0, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Return a queable object which is a copy of some other object
|
||||
T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY) {
|
||||
T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
|
||||
if(p)
|
||||
|
||||
if (p)
|
||||
*p = src;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/// Return a buffer for use by others
|
||||
void release(T *p) {
|
||||
void release(T *p)
|
||||
{
|
||||
int res = dead.enqueue(p, 0);
|
||||
assert(res == pdTRUE);
|
||||
assert(p >= buf && (p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
}
|
||||
};
|
||||
|
||||
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
||||
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
||||
{
|
||||
int res = dead.enqueueFromISR(p, higherPriWoken);
|
||||
assert(res == pdTRUE);
|
||||
assert(p >= buf && (p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
}
|
||||
};
|
||||
|
@ -11,9 +11,8 @@
|
||||
|
||||
#define DEFAULT_CHANNEL_NUM 3 // we randomly pick one
|
||||
|
||||
|
||||
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
|
||||
static const uint8_t defaultpsk[] = { 0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf };
|
||||
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
|
||||
|
||||
/**
|
||||
* ## LoRaWAN for North America
|
||||
@ -27,11 +26,8 @@ Channel zero starts at 903.08 MHz center frequency.
|
||||
*/
|
||||
|
||||
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
||||
: rf95(NSS_GPIO, DIO0_GPIO),
|
||||
manager(rf95),
|
||||
pool(_pool),
|
||||
rxDest(_rxDest),
|
||||
txQueue(MAX_TX_QUEUE)
|
||||
: rf95(_pool, _rxDest),
|
||||
manager(rf95)
|
||||
{
|
||||
myNodeInfo.num_channels = NUM_CHANNELS;
|
||||
|
||||
@ -81,15 +77,15 @@ bool MeshRadio::init()
|
||||
|
||||
void MeshRadio::reloadConfig()
|
||||
{
|
||||
rf95.setModeIdle();
|
||||
rf95.setModeIdle(); // Need to be idle before doing init
|
||||
|
||||
// Set up default configuration
|
||||
// No Sync Words in LORA mode.
|
||||
rf95.setModemConfig((RH_RF95::ModemConfigChoice)channelSettings.modem_config); // Radio default
|
||||
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
|
||||
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
|
||||
// rf95.setPreambleLength(8); // Default is 8
|
||||
|
||||
assert(channelSettings.channel_num < NUM_CHANNELS); // If the phone tries to tell us to use an illegal channel then panic
|
||||
assert(channelSettings.channel_num < NUM_CHANNELS); // If the phone tries to tell us to use an illegal channel then panic
|
||||
|
||||
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
|
||||
float center_freq = CH0 + CH_SPACING * channelSettings.channel_num;
|
||||
@ -108,11 +104,14 @@ void MeshRadio::reloadConfig()
|
||||
rf95.setTxPower(channelSettings.tx_power, false);
|
||||
|
||||
DEBUG_MSG("Set radio: name=%s. config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config, channelSettings.channel_num, channelSettings.tx_power);
|
||||
|
||||
// Done with init tell radio to start receiving
|
||||
rf95.setModeRx();
|
||||
}
|
||||
|
||||
|
||||
void MeshRadio::sleep() {
|
||||
// we no longer care about interrupts from this device
|
||||
void MeshRadio::sleep()
|
||||
{
|
||||
// we no longer care about interrupts from this device
|
||||
rf95.prepareDeepSleep();
|
||||
|
||||
// FIXME - leave the device state in rx mode instead
|
||||
@ -121,10 +120,15 @@ void MeshRadio::sleep() {
|
||||
|
||||
ErrorCode MeshRadio::send(MeshPacket *p)
|
||||
{
|
||||
#if 1
|
||||
return rf95.send(p);
|
||||
#else
|
||||
DEBUG_MSG("enquing packet for send from=0x%x, to=0x%x\n", p->from, p->to);
|
||||
return txQueue.enqueue(p, 0); // nowait
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
ErrorCode MeshRadio::sendTo(NodeNum dest, const uint8_t *buf, size_t len)
|
||||
{
|
||||
// We must do this before each send, because we might have just changed our nodenum
|
||||
@ -154,6 +158,7 @@ void MeshRadio::handleReceive(MeshPacket *mp)
|
||||
int res = rxDest.enqueue(mp, 0); // NOWAIT - fixme, if queue is full, delete older messages
|
||||
assert(res == pdTRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MeshRadio::loop()
|
||||
{
|
||||
@ -168,8 +173,9 @@ static int16_t packetnum = 0; // packet counter, we increment per xmission
|
||||
assert(sendTo(NODENUM_BROADCAST, (uint8_t *)radiopacket, sizeof(radiopacket)) == ERRNO_OK);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
||||
#define MAX_RHPACKETLEN 251
|
||||
#define MAX_RHPACKETLEN 251
|
||||
static uint8_t radiobuf[MAX_RHPACKETLEN];
|
||||
uint8_t rxlen;
|
||||
uint8_t srcaddr, destaddr, id, flags;
|
||||
@ -213,7 +219,9 @@ static int16_t packetnum = 0; // packet counter, we increment per xmission
|
||||
handleReceive(mp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Poll to see if we need to send any packets
|
||||
MeshPacket *txp = txQueue.dequeuePtr(0); // nowait
|
||||
if (txp)
|
||||
@ -234,4 +242,5 @@ static int16_t packetnum = 0; // packet counter, we increment per xmission
|
||||
|
||||
DEBUG_MSG("Done with send\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <RH_RF95.h>
|
||||
#include "CustomRF95.h"
|
||||
#include <RHMesh.h>
|
||||
#include "MemoryPool.h"
|
||||
#include "mesh.pb.h"
|
||||
@ -80,17 +80,13 @@ public:
|
||||
void reloadConfig();
|
||||
|
||||
private:
|
||||
RH_RF95 rf95; // the raw radio interface
|
||||
CustomRF95 rf95; // the raw radio interface
|
||||
|
||||
// RHDatagram manager;
|
||||
// RHReliableDatagram manager; // don't use mesh yet
|
||||
RHMesh manager;
|
||||
// MeshRXHandler rxHandler;
|
||||
|
||||
MemoryPool<MeshPacket> &pool;
|
||||
PointerQueue<MeshPacket> &rxDest;
|
||||
PointerQueue<MeshPacket> txQueue;
|
||||
|
||||
/// low level send, might block for mutiple seconds
|
||||
ErrorCode sendTo(NodeNum dest, const uint8_t *buf, size_t len);
|
||||
|
||||
|
@ -218,7 +218,7 @@ void MeshService::handleToRadio(std::string s)
|
||||
void MeshService::sendToMesh(MeshPacket *p)
|
||||
{
|
||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||
assert(radio.send(p) == pdTRUE);
|
||||
assert(radio.send(p) == ERRNO_OK);
|
||||
}
|
||||
|
||||
MeshPacket *MeshService::allocForSending()
|
||||
|
@ -292,6 +292,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
||||
}
|
||||
|
||||
/// Find a node in our DB, return null for missing
|
||||
/// NOTE: This function might be called from an ISR
|
||||
NodeInfo *NodeDB::getNode(NodeNum n)
|
||||
{
|
||||
for (int i = 0; i < *numNodes; i++)
|
||||
|
@ -1,21 +1,31 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "TypedQueue.h"
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper for freertos queues that assumes each element is a pointer
|
||||
*/
|
||||
template <class T> class PointerQueue: public TypedQueue<T *> {
|
||||
template <class T>
|
||||
class PointerQueue : public TypedQueue<T *>
|
||||
{
|
||||
public:
|
||||
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {
|
||||
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements)
|
||||
{
|
||||
}
|
||||
|
||||
// preturns a ptr or null if the queue was empty
|
||||
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY) {
|
||||
// returns a ptr or null if the queue was empty
|
||||
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p;
|
||||
|
||||
return this->dequeue(&p, maxWait) == pdTRUE ? p : NULL;
|
||||
|
||||
return this->dequeue(&p, maxWait) == pdTRUE ? p : NULL;
|
||||
}
|
||||
|
||||
// returns a ptr or null if the queue was empty
|
||||
T *dequeuePtrFromISR(BaseType_t *higherPriWoken)
|
||||
{
|
||||
T *p;
|
||||
|
||||
return this->dequeueFromISR(&p, higherPriWoken) == pdTRUE ? p : NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <assert.h>
|
||||
@ -7,29 +7,47 @@
|
||||
* A wrapper for freertos queues. Note: each element object must be quite small, so T should be only
|
||||
* pointer types or ints
|
||||
*/
|
||||
template <class T> class TypedQueue {
|
||||
template <class T>
|
||||
class TypedQueue
|
||||
{
|
||||
QueueHandle_t h;
|
||||
|
||||
public:
|
||||
TypedQueue(int maxElements) {
|
||||
TypedQueue(int maxElements)
|
||||
{
|
||||
h = xQueueCreate(maxElements, sizeof(T));
|
||||
assert(h);
|
||||
}
|
||||
|
||||
~TypedQueue() {
|
||||
~TypedQueue()
|
||||
{
|
||||
vQueueDelete(h);
|
||||
}
|
||||
|
||||
int numFree() {
|
||||
int numFree()
|
||||
{
|
||||
return uxQueueSpacesAvailable(h);
|
||||
}
|
||||
|
||||
// pdTRUE for success else failure
|
||||
BaseType_t enqueue(T x, TickType_t maxWait = portMAX_DELAY) {
|
||||
BaseType_t enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
return xQueueSendToBack(h, &x, maxWait);
|
||||
}
|
||||
|
||||
BaseType_t enqueueFromISR(T x, BaseType_t *higherPriWoken)
|
||||
{
|
||||
return xQueueSendToBackFromISR(h, &x, higherPriWoken);
|
||||
}
|
||||
|
||||
// pdTRUE for success else failure
|
||||
BaseType_t dequeue(T *p, TickType_t maxWait = portMAX_DELAY) {
|
||||
BaseType_t dequeue(T *p, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
return xQueueReceive(h, p, maxWait);
|
||||
}
|
||||
|
||||
BaseType_t dequeueFromISR(T *p, BaseType_t *higherPriWoken)
|
||||
{
|
||||
return xQueueReceiveFromISR(h, p, higherPriWoken);
|
||||
}
|
||||
};
|
||||
|
@ -43,8 +43,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Select which board is being used. If the outside build environment has sent a choice, just use that
|
||||
#if !defined(T_BEAM_V10) && !defined(HELTEC_LORA32)
|
||||
#define T_BEAM_V10 // AKA Rev1 (second board released)
|
||||
//#define HELTEC_LORA32
|
||||
//#define T_BEAM_V10 // AKA Rev1 (second board released)
|
||||
#define HELTEC_LORA32
|
||||
|
||||
#define HW_VERSION_US // We encode the hardware freq range in the hw version string, so sw update can eventually install the correct build
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user