mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-22 10:42:49 +00:00
SimRadio: clean-up and emulate collisions (#5487)
* Clean up SimRadio and don't let it use PKC * Add collision emulation for SimRadio * Add stats from SimRadio to LocalStats * Make emulating collisions optional
This commit is contained in:
@@ -73,6 +73,10 @@ void SimRadio::handleTransmitInterrupt()
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
completeSending();
|
||||
|
||||
isReceiving = true;
|
||||
if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
|
||||
handleReceiveInterrupt();
|
||||
}
|
||||
|
||||
void SimRadio::completeSending()
|
||||
@@ -84,6 +88,8 @@ void SimRadio::completeSending()
|
||||
|
||||
if (p) {
|
||||
txGood++;
|
||||
if (!isFromUs(p))
|
||||
txRelay++;
|
||||
printPacket("Completed sending", p);
|
||||
|
||||
// We are done sending that packet, release it
|
||||
@@ -113,12 +119,12 @@ bool SimRadio::canSendImmediately()
|
||||
|
||||
bool SimRadio::isActivelyReceiving()
|
||||
{
|
||||
return false; // TODO check how this should be simulated
|
||||
return receivingPacket != nullptr;
|
||||
}
|
||||
|
||||
bool SimRadio::isChannelActive()
|
||||
{
|
||||
return false; // TODO ask simulator
|
||||
return receivingPacket != nullptr;
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
@@ -142,10 +148,16 @@ void SimRadio::onNotify(uint32_t notification)
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
handleReceiveInterrupt();
|
||||
// LOG_DEBUG("rx complete - starting timer");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
if (receivingPacket) { // This happens when we had a timer pending and we started receiving
|
||||
handleReceiveInterrupt();
|
||||
startTransmitTimer();
|
||||
break;
|
||||
}
|
||||
LOG_DEBUG("delay done");
|
||||
|
||||
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||
@@ -183,6 +195,7 @@ void SimRadio::onNotify(uint32_t notification)
|
||||
void SimRadio::startSend(meshtastic_MeshPacket *txp)
|
||||
{
|
||||
printPacket("Start low level send", txp);
|
||||
isReceiving = false;
|
||||
size_t numbytes = beginSending(txp);
|
||||
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
|
||||
perhapsDecode(p);
|
||||
@@ -201,15 +214,64 @@ void SimRadio::startSend(meshtastic_MeshPacket *txp)
|
||||
|
||||
service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
|
||||
service->sendToPhone(p); // Sending back to simulator
|
||||
service->loop(); // Process the send immediately
|
||||
}
|
||||
|
||||
// Simulates device received a packet via the LoRa chip
|
||||
void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p)
|
||||
{
|
||||
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
|
||||
meshtastic_Compressed scratch;
|
||||
meshtastic_Compressed *decoded = NULL;
|
||||
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
p.decoded.payload.size =
|
||||
pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
|
||||
if (p.decoded.payload.size) {
|
||||
decoded = &scratch;
|
||||
// Extract the original payload and replace
|
||||
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
|
||||
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
|
||||
p.decoded.portnum = decoded->portnum;
|
||||
} else
|
||||
LOG_ERROR("Error decoding proto for simulator message!");
|
||||
}
|
||||
// Let SimRadio receive as if it did via its LoRa chip
|
||||
startReceive(&p);
|
||||
}
|
||||
|
||||
void SimRadio::startReceive(meshtastic_MeshPacket *p)
|
||||
{
|
||||
#ifdef USERPREFS_SIMRADIO_EMULATE_COLLISIONS
|
||||
if (isActivelyReceiving()) {
|
||||
LOG_WARN("Collision detected, dropping current and previous packet!");
|
||||
rxBad++;
|
||||
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket));
|
||||
packetPool.release(receivingPacket);
|
||||
receivingPacket = nullptr;
|
||||
return;
|
||||
} else if (sendingPacket) {
|
||||
uint32_t airtimeLeft = tillRun(millis());
|
||||
if (airtimeLeft <= 0) {
|
||||
LOG_WARN("Transmitting packet was already done");
|
||||
handleTransmitInterrupt(); // Finish sending first
|
||||
} else if ((interval - airtimeLeft) > preambleTimeMsec) {
|
||||
// Only if transmitting for longer than preamble there is a collision
|
||||
// (channel should actually be detected as active otherwise)
|
||||
LOG_WARN("Collision detected during transmission!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
isReceiving = true;
|
||||
size_t length = getPacketLength(p);
|
||||
uint32_t xmitMsec = getPacketTime(length);
|
||||
delay(xmitMsec); // Model the time it is busy receiving
|
||||
handleReceiveInterrupt(p);
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
uint32_t airtimeMsec = getPacketTime(p);
|
||||
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
|
||||
#else
|
||||
isReceiving = true;
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
handleReceiveInterrupt(); // Simulate receiving the packet immediately
|
||||
startTransmitTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
meshtastic_QueueStatus SimRadio::getQueueStatus()
|
||||
@@ -223,28 +285,27 @@ meshtastic_QueueStatus SimRadio::getQueueStatus()
|
||||
return qs;
|
||||
}
|
||||
|
||||
void SimRadio::handleReceiveInterrupt(meshtastic_MeshPacket *p)
|
||||
void SimRadio::handleReceiveInterrupt()
|
||||
{
|
||||
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
|
||||
uint32_t xmitMsec;
|
||||
if (receivingPacket == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isReceiving) {
|
||||
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
|
||||
return;
|
||||
}
|
||||
|
||||
isReceiving = false;
|
||||
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
|
||||
rxGood++;
|
||||
|
||||
// read the number of actually received bytes
|
||||
size_t length = getPacketLength(p);
|
||||
xmitMsec = getPacketTime(length);
|
||||
// LOG_DEBUG("Payload size %d vs length (includes header) %d", p->decoded.payload.size, length);
|
||||
|
||||
meshtastic_MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packetPool
|
||||
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
|
||||
packetPool.release(receivingPacket); // release the original
|
||||
receivingPacket = nullptr;
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||
airTime->logAirtime(RX_LOG, getPacketTime(mp));
|
||||
|
||||
deliverToReceiver(mp);
|
||||
}
|
||||
@@ -265,4 +326,4 @@ int16_t SimRadio::readData(uint8_t *data, size_t len)
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,6 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
|
||||
{
|
||||
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
|
||||
|
||||
/**
|
||||
* Debugging counts
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
|
||||
|
||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||
|
||||
public:
|
||||
@@ -47,9 +42,17 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
|
||||
|
||||
meshtastic_QueueStatus getQueueStatus() override;
|
||||
|
||||
// Convert Compressed_msg to normal msg and receive it
|
||||
void unpackAndReceive(meshtastic_MeshPacket &p);
|
||||
|
||||
/**
|
||||
* Debugging counts
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
|
||||
|
||||
protected:
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving = false;
|
||||
bool isReceiving = true;
|
||||
|
||||
private:
|
||||
void setTransmitDelay();
|
||||
@@ -61,7 +64,7 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
|
||||
void startTransmitTimerSNR(float snr);
|
||||
|
||||
void handleTransmitInterrupt();
|
||||
void handleReceiveInterrupt(meshtastic_MeshPacket *p);
|
||||
void handleReceiveInterrupt();
|
||||
|
||||
void onNotify(uint32_t notification);
|
||||
|
||||
@@ -73,6 +76,8 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
|
||||
|
||||
int16_t readData(uint8_t *str, size_t len);
|
||||
|
||||
meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
|
||||
|
||||
protected:
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
virtual bool canSendImmediately();
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#ifndef HAS_WIFI
|
||||
#define HAS_WIFI 1
|
||||
#endif
|
||||
#ifndef HAS_RADIO
|
||||
#define HAS_RADIO 1
|
||||
#endif
|
||||
#ifndef HAS_RTC
|
||||
#define HAS_RTC 1
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user