Make Trunk happy

This commit is contained in:
GUVWAF 2023-01-21 13:01:19 +01:00
parent c628c70db2
commit bcf24b8187

View File

@ -3,8 +3,8 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "SPILock.h" #include "SPILock.h"
#include "configuration.h" #include "configuration.h"
#include "main.h"
#include "error.h" #include "error.h"
#include "main.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include <pb_decode.h> #include <pb_decode.h>
#include <pb_encode.h> #include <pb_encode.h>
@ -134,29 +134,29 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
#endif #endif
// Sometimes when testing it is useful to be able to never turn on the xmitter // Sometimes when testing it is useful to be able to never turn on the xmitter
#ifndef LORA_DISABLE_SENDING #ifndef LORA_DISABLE_SENDING
printPacket("enqueuing for send", p); printPacket("enqueuing for send", p);
LOG_DEBUG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); LOG_DEBUG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
return res;
}
// set (random) transmit delay to let others reconfigure their radio,
// to avoid collisions and implement timing-based flooding
// LOG_DEBUG("Set random delay before transmitting.\n");
setTransmitDelay();
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
return res; return res;
}
// set (random) transmit delay to let others reconfigure their radio,
// to avoid collisions and implement timing-based flooding
// LOG_DEBUG("Set random delay before transmitting.\n");
setTransmitDelay();
return res;
#else #else
packetPool.release(p); packetPool.release(p);
return ERRNO_DISABLED; return ERRNO_DISABLED;
#endif #endif
} }
QueueStatus RadioLibInterface::getQueueStatus() QueueStatus RadioLibInterface::getQueueStatus()
{ {
@ -169,246 +169,247 @@ QueueStatus RadioLibInterface::getQueueStatus()
return qs; return qs;
} }
bool RadioLibInterface::canSleep() bool RadioLibInterface::canSleep()
{ {
bool res = txQueue.empty(); bool res = txQueue.empty();
if (!res) // only print debug messages if we are vetoing sleep if (!res) // only print debug messages if we are vetoing sleep
LOG_DEBUG("radio wait to sleep, txEmpty=%d\n", res); LOG_DEBUG("radio wait to sleep, txEmpty=%d\n", res);
return res; return res;
} }
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
{ {
auto p = txQueue.remove(from, id); auto p = txQueue.remove(from, id);
if (p) if (p)
packetPool.release(p); // free the packet we just removed packetPool.release(p); // free the packet we just removed
bool result = (p != NULL); bool result = (p != NULL);
LOG_DEBUG("cancelSending id=0x%x, removed=%d\n", id, result); LOG_DEBUG("cancelSending id=0x%x, removed=%d\n", id, result);
return result; return result;
} }
/** radio helper thread callback. /** radio helper thread callback.
We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of
'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision. 'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision.
The CW size is determined by setTransmitDelay() and depends either on the current channel utilization or SNR in case The CW size is determined by setTransmitDelay() and depends either on the current channel utilization or SNR in case
of a flooding message. After this, we perform channel activity detection (CAD) and reset the transmit delay if it is of a flooding message. After this, we perform channel activity detection (CAD) and reset the transmit delay if it is
currently active. currently active.
*/ */
void RadioLibInterface::onNotify(uint32_t notification) void RadioLibInterface::onNotify(uint32_t notification)
{ {
switch (notification) { switch (notification) {
case ISR_TX: case ISR_TX:
handleTransmitInterrupt(); handleTransmitInterrupt();
startReceive(); startReceive();
// LOG_DEBUG("tx complete - starting timer\n"); // LOG_DEBUG("tx complete - starting timer\n");
startTransmitTimer(); startTransmitTimer();
break; break;
case ISR_RX: case ISR_RX:
handleReceiveInterrupt(); handleReceiveInterrupt();
startReceive(); startReceive();
// LOG_DEBUG("rx complete - starting timer\n"); // LOG_DEBUG("rx complete - starting timer\n");
startTransmitTimer(); startTransmitTimer();
break; break;
case TRANSMIT_DELAY_COMPLETED: case TRANSMIT_DELAY_COMPLETED:
// LOG_DEBUG("delay done\n"); // LOG_DEBUG("delay done\n");
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread // If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode? // has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
if (!txQueue.empty()) { if (!txQueue.empty()) {
if (!canSendImmediately()) { if (!canSendImmediately()) {
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay\n"); // LOG_DEBUG("Currently Rx/Tx-ing: set random delay\n");
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
} else {
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
// LOG_DEBUG("Channel is active: set random delay\n");
setTransmitDelay(); // reset random delay
} else { } else {
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel // Send any outgoing packets we have ready
// LOG_DEBUG("Channel is active: set random delay\n"); MeshPacket *txp = txQueue.dequeue();
setTransmitDelay(); // reset random delay assert(txp);
} else { startSend(txp);
// Send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
// Packet has been sent, count it toward our TX airtime utilization. // Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = getPacketTime(txp); uint32_t xmitMsec = getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec); airTime->logAirtime(TX_LOG, xmitMsec);
}
} }
} else {
// LOG_DEBUG("done with txqueue\n");
} }
break;
default:
assert(0); // We expected to receive a valid notification from the ISR
}
}
void RadioLibInterface::setTransmitDelay()
{
MeshPacket *p = txQueue.getFront();
// We want all sending/receiving to be done by our daemon thread.
// We use a delay here because this packet might have been sent in response to a packet we just received.
// So we want to make sure the other side has had a chance to reconfigure its radio.
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else { } else {
// If there is a SNR, start a timer scaled based on that SNR. // LOG_DEBUG("done with txqueue\n");
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
startTransmitTimerSNR(p->rx_snr);
} }
break;
default:
assert(0); // We expected to receive a valid notification from the ISR
}
}
void RadioLibInterface::setTransmitDelay()
{
MeshPacket *p = txQueue.getFront();
// We want all sending/receiving to be done by our daemon thread.
// We use a delay here because this packet might have been sent in response to a packet we just received.
// So we want to make sure the other side has had a chance to reconfigure its radio.
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
* This assumption is valid because of the offset generated by the radio to account for the noise
* floor.
*/
if (p->rx_snr == 0 && p->rx_rssi == 0) {
startTransmitTimer(true);
} else {
// If there is a SNR, start a timer scaled based on that SNR.
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
startTransmitTimerSNR(p->rx_snr);
}
}
void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// LOG_DEBUG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::startTransmitTimerSNR(float snr)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = getTxDelayMsecWeighted(snr);
// LOG_DEBUG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::handleTransmitInterrupt()
{
// LOG_DEBUG("handling lora TX interrupt\n");
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
}
void RadioLibInterface::completeSending()
{
// We are careful to clear sending packet before calling printPacket because
// that can take a long time
auto p = sendingPacket;
sendingPacket = NULL;
if (p) {
txGood++;
printPacket("Completed sending", p);
// We are done sending that packet, release it
packetPool.release(p);
// LOG_DEBUG("Done with send\n");
}
}
void RadioLibInterface::handleReceiveInterrupt()
{
uint32_t xmitMsec;
// when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race
// Condition?
if (!isReceiving) {
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode\n");
return;
} }
void RadioLibInterface::startTransmitTimer(bool withDelay) isReceiving = false;
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// LOG_DEBUG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::startTransmitTimerSNR(float snr) // read the number of actually received bytes
{ size_t length = iface->getPacketLength();
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.empty()) {
uint32_t delay = getTxDelayMsecWeighted(snr);
// LOG_DEBUG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
}
void RadioLibInterface::handleTransmitInterrupt() xmitMsec = getPacketTime(length);
{
// LOG_DEBUG("handling lora TX interrupt\n");
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
}
void RadioLibInterface::completeSending() int state = iface->readData(radiobuf, length);
{ if (state != RADIOLIB_ERR_NONE) {
// We are careful to clear sending packet before calling printPacket because LOG_ERROR("ignoring received packet due to error=%d\n", state);
// that can take a long time rxBad++;
auto p = sendingPacket;
sendingPacket = NULL;
if (p) { airTime->logAirtime(RX_ALL_LOG, xmitMsec);
txGood++;
printPacket("Completed sending", p);
// We are done sending that packet, release it } else {
packetPool.release(p); // Skip the 4 headers that are at the beginning of the rxBuf
// LOG_DEBUG("Done with send\n"); int32_t payloadLen = length - sizeof(PacketHeader);
} const uint8_t *payload = radiobuf + sizeof(PacketHeader);
}
void RadioLibInterface::handleReceiveInterrupt() // check for short packets
{ if (payloadLen < 0) {
uint32_t xmitMsec; LOG_WARN("ignoring received packet too short\n");
// when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race Condition?
if (!isReceiving) {
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode\n");
return;
}
isReceiving = false;
// read the number of actually received bytes
size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length);
int state = iface->readData(radiobuf, length);
if (state != RADIOLIB_ERR_NONE) {
LOG_ERROR("ignoring received packet due to error=%d\n", state);
rxBad++; rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec); airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else { } else {
// Skip the 4 headers that are at the beginning of the rxBuf const PacketHeader *h = (PacketHeader *)radiobuf;
int32_t payloadLen = length - sizeof(PacketHeader); rxGood++;
const uint8_t *payload = radiobuf + sizeof(PacketHeader); // altered packet with "from == 0" can do Remote Node Administration without permission
if (h->from == 0) {
// check for short packets LOG_WARN("ignoring received packet without sender\n");
if (payloadLen < 0) { return;
LOG_WARN("ignoring received packet too short\n");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
const PacketHeader *h = (PacketHeader *)radiobuf;
rxGood++;
// altered packet with "from == 0" can do Remote Node Administration without permission
if (h->from == 0) {
LOG_WARN("ignoring received packet without sender\n");
return;
}
// Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
// This allows the router and other apps on our node to sniff packets (usually routing) between other
// nodes.
MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
addReceiveMetadata(mp);
mp->which_payload_variant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
airTime->logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
}
}
}
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket * txp)
{
printPacket("Starting low level send", txp);
if (disabled || !config.lora.tx_enabled) {
LOG_WARN("startSend is dropping tx packet because we are disabled\n");
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
if (res != RADIOLIB_ERR_NONE) {
LOG_ERROR("startTransmit failed, error=%d\n", res);
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
// This send failed, but make sure to 'complete' it properly
completeSending();
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
} }
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register // Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
// bits // This allows the router and other apps on our node to sniff packets (usually routing) between other
enableInterrupt(isrTxLevel0); // nodes.
MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
addReceiveMetadata(mp);
mp->which_payload_variant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
airTime->logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
} }
} }
}
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket *txp)
{
printPacket("Starting low level send", txp);
if (disabled || !config.lora.tx_enabled) {
LOG_WARN("startSend is dropping tx packet because we are disabled\n");
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
if (res != RADIOLIB_ERR_NONE) {
LOG_ERROR("startTransmit failed, error=%d\n", res);
RECORD_CRITICALERROR(CriticalErrorCode_RADIO_SPI_BUG);
// This send failed, but make sure to 'complete' it properly
completeSending();
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
}
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
// bits
enableInterrupt(isrTxLevel0);
}
}