This commit is contained in:
Ben Meadors 2023-01-28 06:39:14 -06:00
parent de82119415
commit e8908784f9
6 changed files with 357 additions and 512 deletions

View File

@ -29,38 +29,29 @@ bool GPS::getACK(uint8_t c, uint8_t i)
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned long startTime = millis();
for (int j = 2; j < 6; j++)
{
for (int j = 2; j < 6; j++) {
buf[8] += buf[j];
buf[9] += buf[8];
}
for (int j = 0; j < 2; j++)
{
for (int j = 0; j < 2; j++) {
buf[6 + j] = ackP[j];
buf[8] += buf[6 + j];
buf[9] += buf[8];
}
while (1)
{
if (ack > 9)
{
while (1) {
if (ack > 9) {
return true;
}
if (millis() - startTime > 1000)
{
if (millis() - startTime > 1000) {
return false;
}
if (_serial_gps->available())
{
if (_serial_gps->available()) {
b = _serial_gps->read();
if (b == buf[ack])
{
if (b == buf[ack]) {
ack++;
}
else
{
} else {
ack = 0;
}
}
@ -82,50 +73,37 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
uint32_t startTime = millis();
uint16_t needRead;
while (millis() - startTime < 800)
{
while (_serial_gps->available())
{
while (millis() - startTime < 800) {
while (_serial_gps->available()) {
int c = _serial_gps->read();
switch (ubxFrameCounter)
{
switch (ubxFrameCounter) {
case 0:
// ubxFrame 'μ'
if (c == 0xB5)
{
if (c == 0xB5) {
ubxFrameCounter++;
}
break;
case 1:
// ubxFrame 'b'
if (c == 0x62)
{
if (c == 0x62) {
ubxFrameCounter++;
}
else
{
} else {
ubxFrameCounter = 0;
}
break;
case 2:
// Class
if (c == requestedClass)
{
if (c == requestedClass) {
ubxFrameCounter++;
}
else
{
} else {
ubxFrameCounter = 0;
}
break;
case 3:
// Message ID
if (c == requestedID)
{
if (c == requestedID) {
ubxFrameCounter++;
}
else
{
} else {
ubxFrameCounter = 0;
}
break;
@ -141,17 +119,13 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
break;
case 6:
// Check for buffer overflow
if (needRead >= size)
{
if (needRead >= size) {
ubxFrameCounter = 0;
break;
}
if (_serial_gps->readBytes(buffer, needRead) != needRead)
{
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
ubxFrameCounter = 0;
}
else
{
} else {
// return payload lenght
return needRead;
}
@ -167,8 +141,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
bool GPS::setupGPS()
{
if (_serial_gps && !didSerialInit)
{
if (_serial_gps && !didSerialInit) {
didSerialInit = true;
#ifdef ARCH_ESP32
@ -200,8 +173,7 @@ bool GPS::setupGPS()
*/
gnssModel = probe();
if (gnssModel == GNSS_MODEL_MTK)
{
if (gnssModel == GNSS_MODEL_MTK) {
/*
* t-beam-s3-core uses the same L76K GNSS module as t-echo.
* Unlike t-echo, L76K uses 9600 baud rate for communication by default.
@ -218,9 +190,7 @@ bool GPS::setupGPS()
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n");
delay(250);
}
else if (gnssModel == GNSS_MODEL_UBLOX)
{
} else if (gnssModel == GNSS_MODEL_UBLOX) {
/*
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
@ -242,8 +212,7 @@ bool GPS::setupGPS()
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GGL.\n");
return true;
}
@ -252,8 +221,7 @@ bool GPS::setupGPS()
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSA.\n");
return true;
}
@ -262,8 +230,7 @@ bool GPS::setupGPS()
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSV.\n");
return true;
}
@ -272,8 +239,7 @@ bool GPS::setupGPS()
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA VTG.\n");
return true;
}
@ -282,8 +248,7 @@ bool GPS::setupGPS()
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA RMC.\n");
return true;
}
@ -292,8 +257,7 @@ bool GPS::setupGPS()
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
if (!getACK(0x06, 0x01))
{
if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA GGA.\n");
}
}
@ -311,8 +275,7 @@ bool GPS::setup()
#endif
#ifdef HAS_PMU
if (config.position.gps_enabled)
{
if (config.position.gps_enabled) {
setGPSPower(true);
}
#endif
@ -326,15 +289,13 @@ bool GPS::setup()
setAwake(true); // Wake GPS power before doing any init
bool ok = setupGPS();
if (ok)
{
if (ok) {
notifySleepObserver.observe(&notifySleep);
notifyDeepSleepObserver.observe(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep);
}
if (config.position.gps_enabled == false && config.position.fixed_position == false)
{
if (config.position.gps_enabled == false && config.position.fixed_position == false) {
setAwake(false);
doGPSpowersave(false);
}
@ -383,8 +344,7 @@ void GPS::sleep()
/// Record that we have a GPS
void GPS::setConnected()
{
if (!hasGPS)
{
if (!hasGPS) {
hasGPS = true;
shouldPublish = true;
}
@ -392,8 +352,7 @@ void GPS::setConnected()
void GPS::setNumSatellites(uint8_t n)
{
if (n != numSatellites)
{
if (n != numSatellites) {
numSatellites = n;
shouldPublish = true;
}
@ -406,22 +365,17 @@ void GPS::setNumSatellites(uint8_t n)
*/
void GPS::setAwake(bool on)
{
if (!wakeAllowed && on)
{
if (!wakeAllowed && on) {
LOG_WARN("Inhibiting because !wakeAllowed\n");
on = false;
}
if (isAwake != on)
{
if (isAwake != on) {
LOG_DEBUG("WANT GPS=%d\n", on);
if (on)
{
if (on) {
lastWakeStartMsec = millis();
wake();
}
else
{
} else {
lastSleepStartMsec = millis();
sleep();
}
@ -460,8 +414,7 @@ uint32_t GPS::getSleepTime() const
void GPS::publishUpdate()
{
if (shouldPublish)
{
if (shouldPublish) {
shouldPublish = false;
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
@ -479,18 +432,13 @@ int32_t GPS::runOnce()
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
disable();
if (whileIdle())
{
if (whileIdle()) {
// if we have received valid NMEA claim we are connected
setConnected();
}
else
{
if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX))
{
} else {
if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) {
// reset the GPS on next bootup
if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow())
{
if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) {
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
devicestate.did_gps_reset = false;
nodeDB.saveDeviceStateToDisk();
@ -503,33 +451,28 @@ int32_t GPS::runOnce()
uint32_t now = millis();
auto sleepTime = getSleepTime();
if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime)
{
if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) {
// We now want to be awake - so wake up the GPS
setAwake(true);
}
// While we are awake
if (isAwake)
{
if (isAwake) {
// LOG_DEBUG("looking for location\n");
if ((now - lastWhileActiveMsec) > 5000)
{
if ((now - lastWhileActiveMsec) > 5000) {
lastWhileActiveMsec = now;
whileActive();
}
// If we've already set time from the GPS, no need to ask the GPS
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
if (!gotTime && lookForTime())
{ // Note: we count on this && short-circuiting and not resetting the RTC time
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
shouldPublish = true;
}
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation)
{ // declare that we have location ASAP
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE\n");
hasValidLocation = true;
shouldPublish = true;
@ -542,14 +485,11 @@ int32_t GPS::runOnce()
// Once we get a location we no longer desperately want an update
// LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
if ((gotLoc && gotTime) || tooLong)
{
if ((gotLoc && gotTime) || tooLong) {
if (tooLong)
{
if (tooLong) {
// we didn't get a location during this ack window, therefore declare loss of lock
if (hasValidLocation)
{
if (hasValidLocation) {
LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
}
p = meshtastic_Position_init_default;
@ -564,12 +504,10 @@ int32_t GPS::runOnce()
// If state has changed do a publish
publishUpdate();
if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation)
{
if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) {
fixeddelayCtr++;
// LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr);
if (fixeddelayCtr >= 20)
{
if (fixeddelayCtr >= 20) {
doGPSpowersave(false);
forceWake(false);
}
@ -581,14 +519,11 @@ int32_t GPS::runOnce()
void GPS::forceWake(bool on)
{
if (on)
{
if (on) {
LOG_DEBUG("Allowing GPS lock\n");
// lastSleepStartMsec = 0; // Force an update ASAP
wakeAllowed = true;
}
else
{
} else {
wakeAllowed = false;
// Note: if the gps was already awake, we DO NOT shut it down, because we want to allow it to complete its lock
@ -643,19 +578,15 @@ GnssModel_t GPS::probe()
// Get version information
_serial_gps->write("$PCAS06,0*1B\r\n");
uint32_t startTimeout = millis() + 500;
while (millis() < startTimeout)
{
if (_serial_gps->available())
{
while (millis() < startTimeout) {
if (_serial_gps->available()) {
String ver = _serial_gps->readStringUntil('\r');
// Get module info , If the correct header is returned,
// it can be determined that it is the MTK chip
int index = ver.indexOf("$");
if (index != -1)
{
if (index != -1) {
ver = ver.substring(index);
if (ver.startsWith("$GPTXT,01,01,02"))
{
if (ver.startsWith("$GPTXT,01,01,02")) {
LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n");
return GNSS_MODEL_MTK;
}
@ -666,8 +597,7 @@ GnssModel_t GPS::probe()
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct
if (!getAck(buffer, 256, 0x06, 0x08))
{
if (!getAck(buffer, 256, 0x06, 0x08)) {
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
return GNSS_MODEL_UNKONW;
}
@ -677,25 +607,20 @@ GnssModel_t GPS::probe()
_serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw));
uint16_t len = getAck(buffer, 256, 0x0A, 0x04);
if (len)
{
if (len) {
uint16_t position = 0;
for (int i = 0; i < 30; i++)
{
for (int i = 0; i < 30; i++) {
info.swVersion[i] = buffer[position];
position++;
}
for (int i = 0; i < 10; i++)
{
for (int i = 0; i < 10; i++) {
info.hwVersion[i] = buffer[position];
position++;
}
while (len >= position + 30)
{
for (int i = 0; i < 30; i++)
{
while (len >= position + 30) {
for (int i = 0; i < 30; i++) {
info.extension[info.extensionNo][i] = buffer[position];
position++;
}
@ -708,30 +633,24 @@ GnssModel_t GPS::probe()
LOG_DEBUG("Soft version: %s\n", info.swVersion);
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
for (int i = 0; i < info.extensionNo; i++)
{
for (int i = 0; i < info.extensionNo; i++) {
LOG_DEBUG(" %s\n", info.extension[i]);
}
memset(buffer, 0, sizeof(buffer));
// tips: extensionNo field is 0 on some 6M GNSS modules
for (int i = 0; i < info.extensionNo; ++i)
{
if (!strncmp(info.extension[i], "OD=", 3))
{
for (int i = 0; i < info.extensionNo; ++i) {
if (!strncmp(info.extension[i], "OD=", 3)) {
strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer));
LOG_DEBUG("GetModel:%s\n", (char *)buffer);
}
}
}
if (strlen((char *)buffer))
{
if (strlen((char *)buffer)) {
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer);
}
else
{
} else {
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
}
@ -749,24 +668,20 @@ GPS *createGps()
#if !HAS_GPS
return nullptr;
#else
if (config.position.gps_enabled)
{
if (config.position.gps_enabled) {
#ifdef GPS_ALTITUDE_HAE
LOG_DEBUG("Using HAE altitude model\n");
#else
LOG_DEBUG("Using MSL altitude model\n");
#endif
if (GPS::_serial_gps)
{
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;
}
}
else
{
} else {
GPS *new_gps = new NMEAGPS();
new_gps->setup();
return new_gps;

View File

@ -18,168 +18,162 @@
*/
class LockingModule : public Module
{
public:
/*!
\brief Extended SPI-based module constructor.
public:
/*!
\brief Extended SPI-based module constructor.
\param cs Arduino pin to be used as chip select.
\param cs Arduino pin to be used as chip select.
\param irq Arduino pin to be used as interrupt/GPIO.
\param irq Arduino pin to be used as interrupt/GPIO.
\param rst Arduino pin to be used as hardware reset for the module.
\param rst Arduino pin to be used as hardware reset for the module.
\param gpio Arduino pin to be used as additional interrupt/GPIO.
\param gpio Arduino pin to be used as additional interrupt/GPIO.
\param spi SPI interface to be used, can also use software SPI implementations.
\param spi SPI interface to be used, can also use software SPI implementations.
\param spiSettings SPI interface settings.
*/
LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi,
SPISettings spiSettings)
: Module(cs, irq, rst, gpio, spi, spiSettings)
{
}
\param spiSettings SPI interface settings.
*/
LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi,
SPISettings spiSettings)
: Module(cs, irq, rst, gpio, spi, spiSettings)
{
}
void SPIbeginTransaction() override;
void SPIendTransaction() override;
void SPIbeginTransaction() override;
void SPIendTransaction() override;
};
class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread
{
/// Used as our notification from the ISR
enum PendingISR
{
ISR_NONE = 0,
ISR_RX,
ISR_TX,
TRANSMIT_DELAY_COMPLETED
};
/// Used as our notification from the ISR
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
/**
* Raw ISR handler that just calls our polymorphic method
*/
static void isrTxLevel0(), isrLevel0Common(PendingISR code);
/**
* Raw ISR handler that just calls our polymorphic method
*/
static void isrTxLevel0(), isrLevel0Common(PendingISR code);
/**
* Debugging counts
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
/**
* Debugging counts
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
protected:
/**
* We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old
* loads 0x14) Note: do not use 0x34 - that is reserved for lorawan
*
* We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with
* this code for a long time.
*/
const uint8_t syncWord = 0x2b;
protected:
/**
* We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old
* loads 0x14) Note: do not use 0x34 - that is reserved for lorawan
*
* We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with
* this code for a long time.
*/
const uint8_t syncWord = 0x2b;
float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset.
float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset.
LockingModule module; // The HW interface to the radio
LockingModule module; // The HW interface to the radio
/**
* provides lowest common denominator RadioLib API
*/
PhysicalLayer *iface;
/**
* provides lowest common denominator RadioLib API
*/
PhysicalLayer *iface;
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving = false;
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
bool isReceiving = false;
public:
/** Our ISR code currently needs this to find our active instance
*/
static RadioLibInterface *instance;
public:
/** Our ISR code currently needs this to find our active instance
*/
static RadioLibInterface *instance;
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() = 0;
/**
* Glue functions called from ISR land
*/
virtual void disableInterrupt() = 0;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*)()) = 0;
/**
* Enable a particular ISR callback glue function
*/
virtual void enableInterrupt(void (*)()) = 0;
public:
RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi,
PhysicalLayer *iface = NULL);
public:
RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi,
PhysicalLayer *iface = NULL);
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
/**
* 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.
*/
virtual bool canSleep() override;
/**
* 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.
*/
virtual bool canSleep() override;
/**
* Start waiting to receive a message
*
* External functions can call this method to wake the device from sleep.
*/
virtual void startReceive() = 0;
/**
* Start waiting to receive a message
*
* External functions can call this method to wake the device from sleep.
*/
virtual void startReceive() = 0;
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() = 0;
/** can we detect a LoRa preamble on the current channel? */
virtual bool isChannelActive() = 0;
/** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call.
*/
virtual bool isActivelyReceiving() = 0;
/** are we actively receiving a packet (only called during receiving state)
* This method is only public to facilitate debugging. Do not call.
*/
virtual bool isActivelyReceiving() = 0;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id) override;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id) override;
private:
/** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually
* doing the transmit */
void setTransmitDelay();
private:
/** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually
* doing the transmit */
void setTransmitDelay();
/** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true);
/** random timer with certain min. and max. settings */
void startTransmitTimer(bool withDelay = true);
/** timer scaled to SNR of to be flooded packet */
void startTransmitTimerSNR(float snr);
/** timer scaled to SNR of to be flooded packet */
void startTransmitTimerSNR(float snr);
void handleTransmitInterrupt();
void handleReceiveInterrupt();
void handleTransmitInterrupt();
void handleReceiveInterrupt();
static void timerCallback(void *p1, uint32_t p2);
static void timerCallback(void *p1, uint32_t p2);
virtual void onNotify(uint32_t notification) override;
virtual void onNotify(uint32_t notification) override;
/** start an immediate transmit
* This method is virtual so subclasses can hook as needed, subclasses should not call directly
*/
virtual void startSend(meshtastic_MeshPacket *txp);
/** start an immediate transmit
* This method is virtual so subclasses can hook as needed, subclasses should not call directly
*/
virtual void startSend(meshtastic_MeshPacket *txp);
meshtastic_QueueStatus getQueueStatus();
meshtastic_QueueStatus getQueueStatus();
protected:
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
virtual void configHardwareForSend() {}
protected:
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
virtual void configHardwareForSend() {}
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
virtual bool canSendImmediately();
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
virtual bool canSendImmediately();
/**
* Raw ISR handler that just calls our polymorphic method
*/
static void isrRxLevel0();
/**
* Raw ISR handler that just calls our polymorphic method
*/
static void isrRxLevel0();
/**
* If a send was in progress finish it and return the buffer to the pool */
void completeSending();
/**
* If a send was in progress finish it and return the buffer to the pool */
void completeSending();
/**
* Add SNR data to received messages
*/
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
/**
* Add SNR data to received messages
*/
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
virtual void setStandby() = 0;
virtual void setStandby() = 0;
};

View File

@ -12,13 +12,11 @@
*/
ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
{
if (p->want_ack)
{
if (p->want_ack) {
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// counts and we want this message to get through the whole mesh, so use the default.
if (p->hop_limit == 0)
{
if (p->hop_limit == 0) {
p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
}
@ -32,8 +30,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
if (p->from == getNodeNum())
{
if (p->from == getNodeNum()) {
printPacket("Rx someone rebroadcasting for us", p);
// We are seeing someone rebroadcast one of our broadcast attempts.
@ -44,17 +41,14 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
// from the intended recipient.
auto key = GlobalPacketId(getFrom(p), p->id);
auto old = findPendingPacket(key);
if (old)
{
if (old) {
LOG_DEBUG("generating implicit ack\n");
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
// marked as wantAck
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
stopRetransmission(key);
}
else
{
} else {
LOG_DEBUG("didn't find pending packet\n");
}
}
@ -63,8 +57,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
* flooding this ACK back to the original sender already adds redundancy. */
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum())
{
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p);
@ -91,10 +84,8 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
{
NodeNum ourNode = getNodeNum();
if (p->to == ourNode)
{ // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
if (p->want_ack)
{
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
if (p->want_ack) {
if (MeshModule::currentReply)
LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n");
else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
@ -111,15 +102,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId)
{
if (ackId)
{
if (ackId || nakId) {
if (ackId) {
LOG_DEBUG("Received an ack for 0x%x, stopping retransmissions\n", ackId);
stopRetransmission(p->to, ackId);
}
else
{
} else {
LOG_DEBUG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
stopRetransmission(p->to, nakId);
}
@ -141,11 +128,9 @@ PendingPacket::PendingPacket(meshtastic_MeshPacket *p)
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
{
auto old = pending.find(key); // If we have an old record, someone messed up because id got reused
if (old != pending.end())
{
if (old != pending.end()) {
return &old->second;
}
else
} else
return NULL;
}
/**
@ -160,14 +145,12 @@ bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id)
bool ReliableRouter::stopRetransmission(GlobalPacketId key)
{
auto old = findPendingPacket(key);
if (old)
{
if (old) {
auto numErased = pending.erase(key);
assert(numErased == 1);
cancelSending(getFrom(old->packet), old->packet->id);
return true;
}
else
} else
return false;
}
@ -197,27 +180,22 @@ int32_t ReliableRouter::doRetransmissions()
// FIXME, we should use a better datastructure rather than walking through this map.
// for(auto el: pending) {
for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt)
{
for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) {
++nextIt; // we use this odd pattern because we might be deleting it...
auto &p = it->second;
bool stillValid = true; // assume we'll keep this record around
// FIXME, handle 51 day rolloever here!!!
if (p.nextTxMsec <= now)
{
if (p.numRetransmissions == 0)
{
if (p.nextTxMsec <= now) {
if (p.numRetransmissions == 0) {
LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
p.packet->id);
sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived
stopRetransmission(it->first);
stillValid = false; // just deleted it
}
else
{
} else {
LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
p.packet->to, p.packet->id, p.numRetransmissions);
@ -231,8 +209,7 @@ int32_t ReliableRouter::doRetransmissions()
}
}
if (stillValid)
{
if (stillValid) {
// Update our desired sleep delay
int32_t t = p.nextTxMsec - now;

View File

@ -8,8 +8,7 @@
#include "main.h"
#include "mesh-pb-constants.h"
#include "modules/RoutingModule.h"
extern "C"
{
extern "C" {
#include "mesh/compression/unishox2.h"
}
@ -26,13 +25,13 @@ extern "C"
*
**/
#define MAX_RX_FROMRADIO \
#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
// And every TX packet might have a retransmission packet or an ack alive at any moment
#define MAX_PACKETS \
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
#define MAX_PACKETS \
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
// static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
@ -65,8 +64,7 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
int32_t Router::runOnce()
{
meshtastic_MeshPacket *mp;
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL)
{
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
// printPacket("handle fromRadioQ", mp);
perhapsHandleReceived(mp);
}
@ -81,14 +79,11 @@ int32_t Router::runOnce()
*/
void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p)
{
if (fromRadioQueue.enqueue(p, 0))
{ // NOWAIT - fixme, if queue is full, delete older messages
if (fromRadioQueue.enqueue(p, 0)) { // NOWAIT - fixme, if queue is full, delete older messages
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
setReceivedMessage();
}
else
{
} else {
printPacket("BUG! fromRadioQueue is full! Discarding!", p);
packetPool.release(p);
}
@ -103,8 +98,7 @@ PacketId generatePacketId()
uint32_t numPacketId = UINT32_MAX;
if (!didInit)
{
if (!didInit) {
didInit = true;
// pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0)
@ -163,25 +157,19 @@ meshtastic_QueueStatus Router::getQueueStatus()
ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
{
// No need to deliver externally if the destination is the local node
if (p->to == nodeDB.getNodeNum())
{
if (p->to == nodeDB.getNodeNum()) {
printPacket("Enqueued local", p);
enqueueReceivedMessage(p);
return ERRNO_OK;
}
else if (!iface)
{
} else if (!iface) {
// We must be sending to remote nodes also, fail if no interface found
abortSendAndNak(meshtastic_Routing_Error_NO_INTERFACE, p);
return ERRNO_NO_INTERFACES;
}
else
{
} else {
// If we are sending a broadcast, we also treat it as if we just received it ourself
// this allows local apps (and PCs) to see broadcasts sourced locally
if (p->to == NODENUM_BROADCAST)
{
if (p->to == NODENUM_BROADCAST) {
handleReceived(p, src);
}
@ -205,34 +193,27 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes)
ErrorCode Router::send(meshtastic_MeshPacket *p)
{
// Skip the normal ceremony for repeaters
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
{
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
assert(iface);
return iface->send(p);
}
if (p->to == nodeDB.getNodeNum())
{
if (p->to == nodeDB.getNodeNum()) {
LOG_ERROR("BUG! send() called with packet destined for local node!\n");
packetPool.release(p);
return meshtastic_Routing_Error_BAD_REQUEST;
} // should have already been handled by sendLocal
// Abort sending if we are violating the duty cycle
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100)
{
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
float hourlyTxPercent = airTime->utilizationTXPercent();
if (hourlyTxPercent > myRegion->dutyCycle)
{
if (hourlyTxPercent > myRegion->dutyCycle) {
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes);
meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT;
if (getFrom(p) == nodeDB.getNodeNum())
{ // only send NAK to API, not to the mesh
if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh
abortSendAndNak(err, p);
}
else
{
} else {
packetPool.release(p);
}
return err;
@ -257,15 +238,13 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
{
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
bool shouldActuallyEncrypt = true;
#if HAS_WIFI || HAS_ETHERNET
if (moduleConfig.mqtt.enabled)
{
if (moduleConfig.mqtt.enabled) {
// check if we should send decrypted packets to mqtt
// truth table:
@ -278,8 +257,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
* => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
*/
if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled)
{
if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
shouldActuallyEncrypt = false;
}
@ -292,15 +270,13 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
#endif
auto encodeResult = perhapsEncode(p);
if (encodeResult != meshtastic_Routing_Error_NONE)
{
if (encodeResult != meshtastic_Routing_Error_NONE) {
abortSendAndNak(encodeResult, p);
return encodeResult; // FIXME - this isn't a valid ErrorCode
}
#if HAS_WIFI || HAS_ETHERNET
if (moduleConfig.mqtt.enabled)
{
if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted.
// check if we should send encrypted packets to mqtt
if (mqtt && shouldActuallyEncrypt)
@ -339,11 +315,9 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
// assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// Try to find a channel that works with this hash
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++)
{
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) {
// Try to use this hash/channel pair
if (channels.decryptForHash(chIndex, p->channel))
{
if (channels.decryptForHash(chIndex, p->channel)) {
// Try to decrypt the packet if we can
size_t rawSize = p->encrypted.size;
assert(rawSize <= sizeof(bytes));
@ -355,23 +329,17 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
// Take those raw bytes and convert them back into a well structured protobuf we can understand
memset(&p->decoded, 0, sizeof(p->decoded));
if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded))
{
if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) {
LOG_ERROR("Invalid protobufs in received mesh packet (bad psk?)!\n");
}
else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP)
{
} else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) {
LOG_ERROR("Invalid portnum (bad psk?)!\n");
}
else
{
} else {
// parsing was successful
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded
p->channel = chIndex; // change to store the index instead of the hash
// Decompress if needed. jm
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP)
{
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
// Decompress the payload
char compressed_in[meshtastic_Constants_DATA_PAYLOAD_LEN] = {};
char decompressed_out[meshtastic_Constants_DATA_PAYLOAD_LEN] = {};
@ -404,14 +372,12 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
{
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
{
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
// Only allow encryption on the text message app.
// TODO: Allow modules to opt into compression.
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP)
{
if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) {
char original_payload[meshtastic_Constants_DATA_PAYLOAD_LEN];
memcpy(original_payload, p->decoded.payload.bytes, p->decoded.payload.size);
@ -426,17 +392,14 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes);
// If the compressed length is greater than or equal to the original size, don't use the compressed form
if (compressed_len >= p->decoded.payload.size)
{
if (compressed_len >= p->decoded.payload.size) {
LOG_DEBUG("Not using compressing message.\n");
// Set the uncompressed payload varient anyway. Shouldn't hurt?
// p->decoded.which_payloadVariant = Data_payload_tag;
// Otherwise we use the compressor
}
else
{
} else {
LOG_DEBUG("Using compressed message.\n");
// Copy the compressed data into the meshpacket
@ -487,8 +450,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
// Take those raw bytes and convert them back into a well structured protobuf we can understand
bool decoded = perhapsDecode(p);
if (decoded)
{
if (decoded) {
// parsing was successful, queue for our recipient
if (src == RX_SRC_LOCAL)
printPacket("handleReceived(LOCAL)", p);
@ -496,9 +458,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
printPacket("handleReceived(USER)", p);
else
printPacket("handleReceived(REMOTE)", p);
}
else
{
} else {
printPacket("packet decoding failed (no PSK?)", p);
}
@ -513,8 +473,7 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
if (ignore)
LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);
else if (ignore |= shouldFilterReceived(p))
{
else if (ignore |= shouldFilterReceived(p)) {
LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from);
}

View File

@ -13,122 +13,122 @@
*/
class Router : protected concurrency::OSThread
{
private:
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
/// forwarded to the phone.
PointerQueue<meshtastic_MeshPacket> fromRadioQueue;
private:
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
/// forwarded to the phone.
PointerQueue<meshtastic_MeshPacket> fromRadioQueue;
protected:
RadioInterface *iface = NULL;
protected:
RadioInterface *iface = NULL;
public:
/**
* Constructor
*
*/
Router();
public:
/**
* Constructor
*
*/
Router();
/**
* Currently we only allow one interface, that may change in the future
*/
void addInterface(RadioInterface *_iface) { iface = _iface; }
/**
* Currently we only allow one interface, that may change in the future
*/
void addInterface(RadioInterface *_iface) { iface = _iface; }
/**
* do idle processing
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
*/
virtual int32_t runOnce() override;
/**
* do idle processing
* Mostly looking in our incoming rxPacket queue and calling handleReceived.
*/
virtual int32_t runOnce() override;
/**
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
* This is the primary method used for sending packets, because it handles both the remote and local cases.
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO);
/**
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
* This is the primary method used for sending packets, because it handles both the remote and local cases.
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO);
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool cancelSending(NodeNum from, PacketId id);
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool cancelSending(NodeNum from, PacketId id);
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
* The returned packet is guaranteed to have a unique packet ID already assigned
*/
meshtastic_MeshPacket *allocForSending();
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
* The returned packet is guaranteed to have a unique packet ID already assigned
*/
meshtastic_MeshPacket *allocForSending();
/** Return Underlying interface's TX queue status */
meshtastic_QueueStatus getQueueStatus();
/** Return Underlying interface's TX queue status */
meshtastic_QueueStatus getQueueStatus();
/**
* @return our local nodenum */
NodeNum getNodeNum();
/**
* @return our local nodenum */
NodeNum getNodeNum();
/** Wake up the router thread ASAP, because we just queued a message for it.
* FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue'
*/
void setReceivedMessage();
/** Wake up the router thread ASAP, because we just queued a message for it.
* FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue'
*/
void setReceivedMessage();
/**
* RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for
* freeing the packet
*/
void enqueueReceivedMessage(meshtastic_MeshPacket *p);
/**
* RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for
* freeing the packet
*/
void enqueueReceivedMessage(meshtastic_MeshPacket *p);
/**
* 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
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
virtual ErrorCode send(meshtastic_MeshPacket *p);
/**
* 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
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
virtual ErrorCode send(meshtastic_MeshPacket *p);
protected:
friend class RoutingModule;
protected:
friend class RoutingModule;
/**
* Should this incoming filter be dropped?
*
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
*
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
*/
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; }
/**
* Should this incoming filter be dropped?
*
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
*
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
*/
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; }
/**
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
*/
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c);
/**
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
*/
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c);
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
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 packet will never be called for messages sent/generated by this node.
* Note: this method will free the provided packet.
*/
void perhapsHandleReceived(meshtastic_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 packet will never be called for messages sent/generated by this node.
* Note: this method will free the provided packet.
*/
void perhapsHandleReceived(meshtastic_MeshPacket *p);
/**
* Called from perhapsHandleReceived() - allows subclass message delivery behavior.
* 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 packet will never be called for messages sent/generated by this node.
* Note: this method will free the provided packet.
*/
void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO);
/**
* Called from perhapsHandleReceived() - allows subclass message delivery behavior.
* 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 packet will never be called for messages sent/generated by this node.
* Note: this method will free the provided packet.
*/
void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO);
/** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */
void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p);
/** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */
void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p);
};
/** FIXME - move this into a mesh packet class

View File

@ -7,25 +7,25 @@
*/
class RepeaterModule : public ProtobufModule<meshtastic_Routing>
{
public:
/** Constructor
* name is for debugging output
*/
RepeaterModule();
public:
/** Constructor
* name is for debugging output
*/
RepeaterModule();
protected:
/** Called to handle a particular incoming message
protected:
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override;
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override;
/** 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. */
virtual meshtastic_MeshPacket *allocReply() override;
/** 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. */
virtual meshtastic_MeshPacket *allocReply() override;
/// Override wantPacket to say we want to see all packets, not just those for our port number
virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; }
/// Override wantPacket to say we want to see all packets, not just those for our port number
virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; }
};
extern RepeaterModule *repeaterModule;