kopia lustrzana https://github.com/meshtastic/firmware
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 optionalpull/5499/head
rodzic
d00e0f6911
commit
57ea6a265e
|
@ -82,7 +82,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
|||
#include "STM32WLE5JCInterface.h"
|
||||
#endif
|
||||
|
||||
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
#include "platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
|
||||
|
@ -896,7 +896,7 @@ void setup()
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
if (!rIf) {
|
||||
rIf = new SimRadio;
|
||||
if (!rIf->init()) {
|
||||
|
|
|
@ -166,27 +166,10 @@ NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id)
|
|||
*/
|
||||
void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
||||
{
|
||||
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
|
||||
// Simulates device received a packet via the LoRa chip
|
||||
if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) {
|
||||
// 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
|
||||
SimRadio::instance->startReceive(&p);
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
if (SimRadio::instance && p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) {
|
||||
// Simulates device received a packet via the LoRa chip
|
||||
SimRadio::instance->unpackAndReceive(p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "MeshTypes.h"
|
||||
#include "Observer.h"
|
||||
#include "PointerQueue.h"
|
||||
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
#include "../platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||
|
@ -165,4 +165,4 @@ class MeshService
|
|||
friend class RoutingModule;
|
||||
};
|
||||
|
||||
extern MeshService *service;
|
||||
extern MeshService *service;
|
|
@ -613,13 +613,14 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
|
|||
{
|
||||
printPacket("PACKET FROM PHONE", &p);
|
||||
|
||||
// For use with the simulator, we should not ignore duplicate packets
|
||||
#if !(defined(ARCH_PORTDUINO) && !HAS_RADIO)
|
||||
if (p.id > 0 && wasSeenRecently(p.id)) {
|
||||
LOG_DEBUG("Ignore packet from phone, already seen recently");
|
||||
return false;
|
||||
}
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
// For use with the simulator, we should not ignore duplicate packets from the phone
|
||||
if (SimRadio::instance == nullptr)
|
||||
#endif
|
||||
if (p.id > 0 && wasSeenRecently(p.id)) {
|
||||
LOG_DEBUG("Ignore packet from phone, already seen recently");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] &&
|
||||
Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) {
|
||||
|
@ -656,4 +657,4 @@ int PhoneAPI::onNotify(uint32_t newValue)
|
|||
}
|
||||
|
||||
return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "detect/LoRaRadioType.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "meshUtils.h"
|
||||
|
@ -491,6 +492,8 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
|
|||
// is not in the local nodedb
|
||||
// First, only PKC encrypt packets we are originating
|
||||
if (isFromUs(p) &&
|
||||
// Don't use PKC with simulator
|
||||
radioType != SIM_RADIO &&
|
||||
// Don't use PKC with Ham mode
|
||||
!owner.is_licensed &&
|
||||
// Don't use PKC if it's not explicitly requested and a non-primary channel is requested
|
||||
|
|
|
@ -130,6 +130,14 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry()
|
|||
telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad;
|
||||
telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay;
|
||||
}
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (SimRadio::instance) {
|
||||
telemetry.variant.local_stats.num_packets_tx = SimRadio::instance->txGood;
|
||||
telemetry.variant.local_stats.num_packets_rx = SimRadio::instance->rxGood + SimRadio::instance->rxBad;
|
||||
telemetry.variant.local_stats.num_packets_rx_bad = SimRadio::instance->rxBad;
|
||||
telemetry.variant.local_stats.num_tx_relay = SimRadio::instance->txRelay;
|
||||
}
|
||||
#endif
|
||||
if (router) {
|
||||
telemetry.variant.local_stats.num_rx_dupe = router->rxDupe;
|
||||
telemetry.variant.local_stats.num_tx_relay_canceled = router->txRelayCanceled;
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue