diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 86599d5b3e..24d249f072 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1034,7 +1034,7 @@ void Screen::setFrames(FrameFocus focus) indicatorIcons.push_back(icon_compass); } #endif - if (RadioLibInterface::instance && !hiddenFrames.lora) { + if (!RadioLibInterface::instances.empty() && !hiddenFrames.lora) { fsi.positions.lora = numframes; normalFrames[numframes++] = graphics::DebugRenderer::drawLoRaFocused; indicatorIcons.push_back(icon_radio); diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index d098fa304c..03ce7f7448 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -425,7 +425,9 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, // === Fourth Row: Frequency / ChanNum === char frequencyslot[35]; char freqStr[16]; - float freq = RadioLibInterface::instance->getFreq(); + float freq = -1; + if (!RadioLibInterface::instances.empty()) + freq = RadioLibInterface::instances.front()->getFreq(); snprintf(freqStr, sizeof(freqStr), "%.3f", freq); if (config.lora.channel_num == 0) { #if defined(M5STACK_UNITC6L) diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index 9f53b06f4a..dd6b817b10 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -189,7 +189,7 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_LONG_PRESSED: { // Ignore if: TX in progress // Uncommon T-Echo hardware bug, LoRa TX triggers touch button - if (_touchQuirk && RadioLibInterface::instance && RadioLibInterface::instance->isSending()) + if (_touchQuirk && !RadioLibInterface::instances.empty() && RadioLibInterface::instances.front()->isSending()) break; // Check if this is part of a short-press + long-press combination diff --git a/src/main.cpp b/src/main.cpp index 8fec62953c..b3425b16a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -858,11 +858,11 @@ void setup() #else // ESP32 #if defined(HW_SPI1_DEVICE) - SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); + SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, -1); // CS handled by RadioLib LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); SPI1.setFrequency(4000000); #else - SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); + SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, -1); // CS handled by RadioLib LOG_DEBUG("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); SPI.setFrequency(4000000); #endif diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 80e51b8bcb..9be48438e8 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -37,14 +37,25 @@ void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in) RadioLibInterface::RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, PhysicalLayer *_iface) - : NotifiedWorkerThread("RadioIf"), module(hal, cs, irq, rst, busy), iface(_iface) + : NotifiedWorkerThread(strcpy(ifaceName, std::string("RadioIf" + std::to_string(cs)).c_str())), + module(hal, cs, irq, rst, busy), iface(_iface) { - instance = this; + noInterrupts(); + instances.push_back(this); + interrupts(); #if defined(ARCH_STM32WL) && defined(USE_SX1262) module.setCb_digitalWrite(stm32wl_emulate_digitalWrite); module.setCb_digitalRead(stm32wl_emulate_digitalRead); #endif } +RadioLibInterface::~RadioLibInterface() +{ + auto it = std::find(instances.begin(), instances.end(), this); + assert(it != instances.end()); + noInterrupts(); + instances.erase(it); + interrupts(); +} #ifdef ARCH_ESP32 // ESP32 doesn't use that flag @@ -55,15 +66,19 @@ RadioLibInterface::RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE c void INTERRUPT_ATTR RadioLibInterface::isrLevel0Common(PendingISR cause) { - instance->disableInterrupt(); + for (auto instance : instances) { + if (digitalRead(instance->module.getIrq())) { + instance->disableInterrupt(); - BaseType_t xHigherPriorityTaskWoken; - instance->notifyFromISR(&xHigherPriorityTaskWoken, cause, true); + BaseType_t xHigherPriorityTaskWoken; + instance->notifyFromISR(&xHigherPriorityTaskWoken, cause, true); - /* Force a context switch if xHigherPriorityTaskWoken is now set to pdTRUE. - The macro used to do this is dependent on the port and may be called - portEND_SWITCHING_ISR. */ - YIELD_FROM_ISR(xHigherPriorityTaskWoken); + /* Force a context switch if xHigherPriorityTaskWoken is now set to pdTRUE. + The macro used to do this is dependent on the port and may be called + portEND_SWITCHING_ISR. */ + YIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + } } void INTERRUPT_ATTR RadioLibInterface::isrRxLevel0() @@ -78,7 +93,7 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0() /** Our ISR code currently needs this to find our active instance */ -RadioLibInterface *RadioLibInterface::instance; +std::vector RadioLibInterface::instances; /** Could we send right now (i.e. either not actively receiving or transmitting)? */ bool RadioLibInterface::canSendImmediately() diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 833c887108..37a3fd63a9 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -7,12 +7,7 @@ #include #include -// ESP32 has special rules about ISR code -#ifdef ARDUINO_ARCH_ESP32 -#define INTERRUPT_ATTR IRAM_ATTR -#else #define INTERRUPT_ATTR -#endif #define RADIOLIB_PIN_TYPE uint32_t @@ -60,6 +55,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); + char ifaceName[16]; + protected: ModemType_t modemType = RADIOLIB_MODEM_LORA; DataRate_t getDataRate() const { return {.lora = {.spreadingFactor = sf, .bandwidth = bw, .codingRate = cr}}; } @@ -100,7 +97,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified public: /** Our ISR code currently needs this to find our active instance */ - static RadioLibInterface *instance; + static std::vector instances; /** * Glue functions called from ISR land @@ -122,6 +119,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, PhysicalLayer *iface = NULL); + ~RadioLibInterface(); + virtual ErrorCode send(meshtastic_MeshPacket *p) override; /** diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7b7ebb5956..c0a043a490 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -694,8 +694,10 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) // data->radio JSONObject jsonObjRadio; - jsonObjRadio["frequency"] = new JSONValue(RadioLibInterface::instance->getFreq()); - jsonObjRadio["lora_channel"] = new JSONValue((int)RadioLibInterface::instance->getChannelNum() + 1); + if (!RadioLibInterface::instances.empty()) { + jsonObjRadio["frequency"] = new JSONValue(RadioLibInterface::instances.front()->getFreq()); + jsonObjRadio["lora_channel"] = new JSONValue((int)RadioLibInterface::instances.front()->getChannelNum() + 1); + } // collect data to inner data object JSONObject jsonObjInner; diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 066b9361d6..4e2b409641 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -117,12 +117,13 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry() telemetry.variant.local_stats.air_util_tx = airTime->utilizationTXPercent(); telemetry.variant.local_stats.num_online_nodes = numOnlineNodes; telemetry.variant.local_stats.num_total_nodes = nodeDB->getNumMeshNodes(); - if (RadioLibInterface::instance) { - telemetry.variant.local_stats.num_packets_tx = RadioLibInterface::instance->txGood; - telemetry.variant.local_stats.num_packets_rx = RadioLibInterface::instance->rxGood + RadioLibInterface::instance->rxBad; - telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad; - telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay; - telemetry.variant.local_stats.num_tx_dropped = RadioLibInterface::instance->txDrop; + if (!RadioLibInterface::instances.empty()) { + telemetry.variant.local_stats.num_packets_tx = RadioLibInterface::instances.front()->txGood; + telemetry.variant.local_stats.num_packets_rx = + RadioLibInterface::instances.front()->rxGood + RadioLibInterface::instances.front()->rxBad; + telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instances.front()->rxBad; + telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instances.front()->txRelay; + telemetry.variant.local_stats.num_tx_dropped = RadioLibInterface::instances.front()->txDrop; } #ifdef ARCH_PORTDUINO if (SimRadio::instance) { diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 3fe017d5e1..9fd446929f 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -55,6 +55,9 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac); void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault = RADIOLIB_NC); std::string exec(const char *cmd); +#define interrupts() +#define noInterrupts() + extern struct portduino_config_struct { // Lora std::map loraModules = { diff --git a/variants/nrf52840/t-echo/nicheGraphics.h b/variants/nrf52840/t-echo/nicheGraphics.h index c89d816b99..f5b04f305c 100644 --- a/variants/nrf52840/t-echo/nicheGraphics.h +++ b/variants/nrf52840/t-echo/nicheGraphics.h @@ -105,7 +105,7 @@ void setupNicheGraphics() buttons->setHandlerDown(1, [inkhud, backlight]() { // Discard the button press if radio is active // Rare hardware fault: LoRa activity triggers touch button - if (!RadioLibInterface::instance || RadioLibInterface::instance->isSending()) + if (RadioLibInterface::instances.empty() || RadioLibInterface::instances.front()->isSending()) return; // Backlight on (while held)