From 124936b6cfc848483df69d0eacd0dcfd7fb34a12 Mon Sep 17 00:00:00 2001 From: Eric Severance Date: Sun, 12 Jan 2025 10:05:04 -0800 Subject: [PATCH 1/5] Avoid a potential NULL pointer reference in nrf52/BluetoothPhoneAPI (#5830) --- src/platform/nrf52/NRF52Bluetooth.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 31bbc7fa9..541e90ab2 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -44,11 +44,7 @@ class BluetoothPhoneAPI : public PhoneAPI } /// Check the current underlying physical link to see if the client is currently connected - virtual bool checkIsConnected() override - { - BLEConnection *connection = Bluefruit.Connection(connectionHandle); - return connection->connected(); - } + virtual bool checkIsConnected() override { return Bluefruit.connected(connectionHandle); } }; static BluetoothPhoneAPI *bluetoothPhoneAPI; From 0cf4a2951a7eccf390c52c5adf49e6196b2cae82 Mon Sep 17 00:00:00 2001 From: Erayd Date: Mon, 13 Jan 2025 07:05:51 +1300 Subject: [PATCH 2/5] Bugfix for low-priority packet replacement when TX queue is full (#5827) * Correct function comment * Enqueue the intended packet, not the pointer to what we just dropped! * Add some log output when we drop packets due to a full queue * Make it clear when a non-late packet is dropped * Remove from queue before release, not after * Erase dropped packet from queue * Declared type * Log TX queue length after every send * Fix operand order * Add worst-case cap on TX delay vs current time --- protobufs | 2 +- src/mesh/MeshPacketQueue.cpp | 22 +++++++++++++++++----- src/mesh/RadioLibInterface.cpp | 5 +++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/protobufs b/protobufs index 76f806e1b..c55f120a9 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 76f806e1bb1e2a7b157a14fadd095775f63db5e4 +Subproject commit c55f120a9c1ce90c85e4826907a0b9bcb2d5f5a2 diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index d7ee65800..7dd84639d 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -69,7 +69,11 @@ bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p) { // no space - try to replace a lower priority packet in the queue if (queue.size() >= maxLen) { - return replaceLowerPriorityPacket(p); + bool replaced = replaceLowerPriorityPacket(p); + if (!replaced) { + LOG_WARN("TX queue is full, and there is no lower-priority packet available to evict in favour of 0x%08x", p->id); + } + return replaced; } // Find the correct position using upper_bound to maintain a stable order @@ -113,7 +117,10 @@ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool t return NULL; } -/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ +/** + * Attempt to find a lower-priority packet in the queue and replace it with the provided one. + * @return True if the replacement succeeded, false otherwise + */ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) { @@ -122,11 +129,12 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) } // Check if the packet at the back has a lower priority than the new packet - auto &backPacket = queue.back(); + auto *backPacket = queue.back(); if (!backPacket->tx_after && backPacket->priority < p->priority) { + LOG_WARN("Dropping packet 0x%08x to make room in the TX queue for higher-priority packet 0x%08x", backPacket->id, p->id); // Remove the back packet - packetPool.release(backPacket); queue.pop_back(); + packetPool.release(backPacket); // Insert the new packet in the correct order enqueue(p); return true; @@ -139,8 +147,12 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) for (; refPacket->tx_after && it != queue.begin(); refPacket = *--it) ; if (!refPacket->tx_after && refPacket->priority < p->priority) { + LOG_WARN("Dropping non-late packet 0x%08x to make room in the TX queue for higher-priority packet 0x%08x", + refPacket->id, p->id); + queue.erase(it); packetPool.release(refPacket); - enqueue(refPacket); + // Insert the new packet in the correct order + enqueue(p); return true; } } diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 0a047a660..e31f0b3e2 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -271,6 +271,7 @@ void RadioLibInterface::onNotify(uint32_t notification) uint32_t xmitMsec = getPacketTime(txp); airTime->logAirtime(TX_LOG, xmitMsec); } + LOG_DEBUG("%d packets remain in the TX queue", txQueue.getMaxLen() - txQueue.getFree()); } } } @@ -297,8 +298,8 @@ void RadioLibInterface::setTransmitDelay() if (p->tx_after) { unsigned long add_delay = p->rx_rssi ? getTxDelayMsecWeighted(p->rx_snr) : getTxDelayMsec(); unsigned long now = millis(); - p->tx_after = max(p->tx_after + add_delay, now + add_delay); - notifyLater(now - p->tx_after, TRANSMIT_DELAY_COMPLETED, false); + p->tx_after = min(max(p->tx_after + add_delay, now + add_delay), now + 2 * getTxDelayMsecWeightedWorst(p->rx_snr)); + notifyLater(p->tx_after - now, TRANSMIT_DELAY_COMPLETED, false); } else if (p->rx_snr == 0 && p->rx_rssi == 0) { /* 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 From 70296b47bc9b4a026f3aceb73d8afb8448249160 Mon Sep 17 00:00:00 2001 From: Patrick Siegl <3261314+psiegl@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:40:25 +0100 Subject: [PATCH 3/5] Multi gpiochip support for native environment (#5743) * For each GPIO PIN, allow to specify gpiochip and line * Added support for LLCC68 in native env. * Removed one if by employing && * Fix for log, as std::string and not const char* * Remove CH341 flag, enabling it for all LoRa chips * Provide a default example --------- Co-authored-by: Ben Meadors Co-authored-by: Jonathan Bennett --- bin/config-dist.yaml | 45 +++++- src/main.cpp | 141 ++++++------------- src/mesh/RF95Interface.cpp | 22 +-- src/mesh/SX126xInterface.cpp | 12 +- src/mesh/SX128xInterface.cpp | 42 +++--- src/platform/portduino/PortduinoGlue.cpp | 167 ++++++++++++----------- src/platform/portduino/PortduinoGlue.h | 37 +++-- 7 files changed, 237 insertions(+), 229 deletions(-) diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index e68b01ba3..c8f181308 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -23,6 +23,47 @@ Lora: # Busy: 20 # Reset: 18 +### The Radxa Zero 3E/W employs multiple gpio chips. +### Each gpio pin must be unique, but can be assigned to a specific gpio chip and line. +### In case solely a no. is given, the default gpio chip and pin == line will be employed. +### +# Module: sx1262 # Radxa Zero 3E/W + Ebyte E22-900M30S +# DIO2_AS_RF_SWITCH: true +# DIO3_TCXO_VOLTAGE: 1.8 +# CS: # NSS PIN_24 -> chip 4, line 22 +# pin: 24 +# gpiochip: 4 +# line: 22 +# SCK: # SCK PIN_23 -> chip 4, line 18 +# pin: 23 +# gpiochip: 4 +# line: 18 +# Busy: # BUSY PIN_29 -> chip 3!, line 11 +# pin: 29 +# gpiochip: 3 +# line: 11 +# MOSI: # MOSI PIN_19 -> chip 4, line 19 +# pin: 19 +# gpiochip: 4 +# line: 19 +# MISO: # MISO PIN_21 -> chip 4, line 21 +# pin: 21 +# gpiochip: 4 +# line: 21 +# Reset: # NRST PIN_27 -> chip 4, line 10 +# pin: 27 +# gpiochip: 4 +# line: 10 +# IRQ: # DIO1 PIN_28 -> chip 4, line 11 +# pin: 28 +# gpiochip: 4 +# line: 11 +# RXen: # RXEN PIN_22 -> chip 3!, line 17 +# pin: 22 +# gpiochip: 3 +# line: 17 +# TXen: RADIOLIB_NC # TXEN no PIN, no line, fallback to default gpio chip + # Module: sx1268 # SX1268-based modules, tested with Ebyte E22 400M33S # CS: 21 # IRQ: 16 @@ -39,7 +80,7 @@ Lora: # spiSpeed: 2000000 -### Set gpio chip to use in /dev/. Defaults to 0. +### Set default/fallback gpio chip to use in /dev/. Defaults to 0. ### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4 # gpiochip: 4 @@ -147,4 +188,4 @@ General: MaxMessageQueue: 100 ConfigDirectory: /etc/meshtasticd/config.d/ # MACAddress: AA:BB:CC:DD:EE:FF -# MACAddressSource: eth0 \ No newline at end of file +# MACAddressSource: eth0 diff --git a/src/main.cpp b/src/main.cpp index 4a642ef6d..338fca5c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -826,116 +826,61 @@ void setup() #endif #ifdef ARCH_PORTDUINO - if (settingsMap[use_sx1262]) { - if (!rIf) { - LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str()); + const struct { configNames cfgName; + std::string strName; + } loraModules[] = { + { use_rf95, "RF95" }, + { use_sx1262, "sx1262" }, + { use_sx1268, "sx1268" }, + { use_sx1280, "sx1280" }, + { use_lr1110, "lr1110" }, + { use_lr1120, "lr1120" }, + { use_lr1121, "lr1121" }, + { use_llcc68, "LLCC68" } + }; + // as one can't use a function pointer to the class constructor: + auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) { + switch (cfgName) { + case use_rf95: + return (RadioInterface*)new RF95Interface(hal, cs, irq, rst, busy); + case use_sx1262: + return (RadioInterface*)new SX1262Interface(hal, cs, irq, rst, busy); + case use_sx1268: + return (RadioInterface*)new SX1268Interface(hal, cs, irq, rst, busy); + case use_sx1280: + return (RadioInterface*)new SX1280Interface(hal, cs, irq, rst, busy); + case use_lr1110: + return (RadioInterface*)new LR1110Interface(hal, cs, irq, rst, busy); + case use_lr1120: + return (RadioInterface*)new LR1120Interface(hal, cs, irq, rst, busy); + case use_lr1121: + return (RadioInterface*)new LR1121Interface(hal, cs, irq, rst, busy); + case use_llcc68: + return (RadioInterface*)new LLCC68Interface(hal, cs, irq, rst, busy); + default: + assert(0); // shouldn't happen + return (RadioInterface*)nullptr; + } + }; + for (auto& loraModule : loraModules) { + if (settingsMap[loraModule.cfgName] && !rIf) { + LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str()); if (settingsStrings[spidev] == "ch341") { RadioLibHAL = ch341Hal; } else { RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); } - rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); + rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin], settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]); if (!rIf->init()) { - LOG_WARN("No SX1262 radio"); - delete rIf; - exit(EXIT_FAILURE); - } else { - LOG_INFO("SX1262 init success"); - } - } - } else if (settingsMap[use_rf95]) { - if (!rIf) { - LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str()); - RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No RF95 radio"); + LOG_WARN("No %s radio", loraModule.strName.c_str()); delete rIf; rIf = NULL; exit(EXIT_FAILURE); } else { - LOG_INFO("RF95 init success"); - } - } - } else if (settingsMap[use_sx1280]) { - if (!rIf) { - LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str()); - RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No SX1280 radio"); - delete rIf; - rIf = NULL; - exit(EXIT_FAILURE); - } else { - LOG_INFO("SX1280 init success"); - } - } - } else if (settingsMap[use_lr1110]) { - if (!rIf) { - LOG_DEBUG("Activate lr1110 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new LR1110Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No LR1110 radio"); - delete rIf; - rIf = NULL; - exit(EXIT_FAILURE); - } else { - LOG_INFO("LR1110 init success"); - } - } - } else if (settingsMap[use_lr1120]) { - if (!rIf) { - LOG_DEBUG("Activate lr1120 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new LR1120Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No LR1120 radio"); - delete rIf; - rIf = NULL; - exit(EXIT_FAILURE); - } else { - LOG_INFO("LR1120 init success"); - } - } - } else if (settingsMap[use_lr1121]) { - if (!rIf) { - LOG_DEBUG("Activate lr1121 radio on SPI port %s", settingsStrings[spidev].c_str()); - LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new LR1121Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No LR1121 radio"); - delete rIf; - rIf = NULL; - exit(EXIT_FAILURE); - } else { - LOG_INFO("LR1121 init success"); - } - } - } else if (settingsMap[use_sx1268]) { - if (!rIf) { - LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str()); - RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); - rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], - settingsMap[busy]); - if (!rIf->init()) { - LOG_WARN("No SX1268 radio"); - delete rIf; - rIf = NULL; - exit(EXIT_FAILURE); - } else { - LOG_INFO("SX1268 init success"); + LOG_INFO("%s init success", loraModule.strName.c_str()); } } } - #elif defined(HW_SPI1_DEVICE) LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings); #else // HW_SPI1_DEVICE @@ -1280,4 +1225,4 @@ void loop() mainDelay.delay(delayMsec); } } -#endif \ No newline at end of file +#endif diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index 9ef045099..d4d9ad23c 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -91,16 +91,16 @@ void RF95Interface::setTransmitEnable(bool txon) #ifdef RF95_TXEN digitalWrite(RF95_TXEN, txon ? 1 : 0); #elif ARCH_PORTDUINO - if (settingsMap[txen] != RADIOLIB_NC) { - digitalWrite(settingsMap[txen], txon ? 1 : 0); + if (settingsMap[txen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[txen_pin], txon ? 1 : 0); } #endif #ifdef RF95_RXEN digitalWrite(RF95_RXEN, txon ? 0 : 1); #elif ARCH_PORTDUINO - if (settingsMap[rxen] != RADIOLIB_NC) { - digitalWrite(settingsMap[rxen], txon ? 0 : 1); + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[rxen_pin], txon ? 0 : 1); } #endif } @@ -164,13 +164,13 @@ bool RF95Interface::init() digitalWrite(RF95_RXEN, 1); #endif #if ARCH_PORTDUINO - if (settingsMap[txen] != RADIOLIB_NC) { - pinMode(settingsMap[txen], OUTPUT); - digitalWrite(settingsMap[txen], 0); + if (settingsMap[txen_pin] != RADIOLIB_NC) { + pinMode(settingsMap[txen_pin], OUTPUT); + digitalWrite(settingsMap[txen_pin], 0); } - if (settingsMap[rxen] != RADIOLIB_NC) { - pinMode(settingsMap[rxen], OUTPUT); - digitalWrite(settingsMap[rxen], 0); + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + pinMode(settingsMap[rxen_pin], OUTPUT); + digitalWrite(settingsMap[rxen_pin], 0); } #endif setTransmitEnable(false); @@ -337,4 +337,4 @@ bool RF95Interface::sleep() return true; } -#endif \ No newline at end of file +#endif diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index ed0267c5b..b13bb6faf 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -51,9 +51,9 @@ template bool SX126xInterface::init() #if ARCH_PORTDUINO float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000; - if (settingsMap[sx126x_ant_sw] != RADIOLIB_NC) { - digitalWrite(settingsMap[sx126x_ant_sw], HIGH); - pinMode(settingsMap[sx126x_ant_sw], OUTPUT); + if (settingsMap[sx126x_ant_sw_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[sx126x_ant_sw_pin], HIGH); + pinMode(settingsMap[sx126x_ant_sw_pin], OUTPUT); } // FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE #elif !defined(SX126X_DIO3_TCXO_VOLTAGE) @@ -121,8 +121,8 @@ template bool SX126xInterface::init() // no effect #if ARCH_PORTDUINO if (res == RADIOLIB_ERR_NONE) { - LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen], settingsMap[txen]); - lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]); + LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen_pin], settingsMap[txen_pin]); + lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]); } #else #ifndef SX126X_RXEN @@ -341,4 +341,4 @@ template bool SX126xInterface::sleep() return true; } -#endif \ No newline at end of file +#endif diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 013164bca..ee3408456 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -38,13 +38,13 @@ template bool SX128xInterface::init() #endif #if ARCH_PORTDUINO - if (settingsMap[rxen] != RADIOLIB_NC) { - pinMode(settingsMap[rxen], OUTPUT); - digitalWrite(settingsMap[rxen], LOW); // Set low before becoming an output + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + pinMode(settingsMap[rxen_pin], OUTPUT); + digitalWrite(settingsMap[rxen_pin], LOW); // Set low before becoming an output } - if (settingsMap[txen] != RADIOLIB_NC) { - pinMode(settingsMap[txen], OUTPUT); - digitalWrite(settingsMap[txen], LOW); // Set low before becoming an output + if (settingsMap[txen_pin] != RADIOLIB_NC) { + pinMode(settingsMap[txen_pin], OUTPUT); + digitalWrite(settingsMap[txen_pin], LOW); // Set low before becoming an output } #else #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode @@ -93,8 +93,8 @@ template bool SX128xInterface::init() lora.setRfSwitchPins(SX128X_RXEN, SX128X_TXEN); } #elif ARCH_PORTDUINO - if (res == RADIOLIB_ERR_NONE && settingsMap[rxen] != RADIOLIB_NC && settingsMap[txen] != RADIOLIB_NC) { - lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]); + if (res == RADIOLIB_ERR_NONE && settingsMap[rxen_pin] != RADIOLIB_NC && settingsMap[txen_pin] != RADIOLIB_NC) { + lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]); } #endif @@ -174,11 +174,11 @@ template void SX128xInterface::setStandby() LOG_ERROR("SX128x standby %s%d", radioLibErr, err); assert(err == RADIOLIB_ERR_NONE); #if ARCH_PORTDUINO - if (settingsMap[rxen] != RADIOLIB_NC) { - digitalWrite(settingsMap[rxen], LOW); + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[rxen_pin], LOW); } - if (settingsMap[txen] != RADIOLIB_NC) { - digitalWrite(settingsMap[txen], LOW); + if (settingsMap[txen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[txen_pin], LOW); } #else #if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power @@ -210,11 +210,11 @@ template void SX128xInterface::addReceiveMetadata(meshtastic_Mes template void SX128xInterface::configHardwareForSend() { #if ARCH_PORTDUINO - if (settingsMap[txen] != RADIOLIB_NC) { - digitalWrite(settingsMap[txen], HIGH); + if (settingsMap[txen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[txen_pin], HIGH); } - if (settingsMap[rxen] != RADIOLIB_NC) { - digitalWrite(settingsMap[rxen], LOW); + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[rxen_pin], LOW); } #else @@ -241,11 +241,11 @@ template void SX128xInterface::startReceive() setStandby(); #if ARCH_PORTDUINO - if (settingsMap[rxen] != RADIOLIB_NC) { - digitalWrite(settingsMap[rxen], HIGH); + if (settingsMap[rxen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[rxen_pin], HIGH); } - if (settingsMap[txen] != RADIOLIB_NC) { - digitalWrite(settingsMap[txen], LOW); + if (settingsMap[txen_pin] != RADIOLIB_NC) { + digitalWrite(settingsMap[txen_pin], LOW); } #else @@ -315,4 +315,4 @@ template bool SX128xInterface::sleep() return true; } -#endif \ No newline at end of file +#endif diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index b042510f5..e75112235 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -134,13 +134,13 @@ void portduinoSetup() { printf("Set up Meshtastic on Portduino...\n"); int max_GPIO = 0; - const configNames GPIO_lines[] = {cs, - irq, - busy, - reset, - sx126x_ant_sw, - txen, - rxen, + const configNames GPIO_lines[] = {cs_pin, + irq_pin, + busy_pin, + reset_pin, + sx126x_ant_sw_pin, + txen_pin, + rxen_pin, displayDC, displayCS, displayBacklight, @@ -247,7 +247,7 @@ void portduinoSetup() // Rather important to set this, if not running simulated. randomSeed(time(NULL)); - gpioChipName += std::to_string(settingsMap[gpiochip]); + std::string defaultGpioChipName = gpioChipName + std::to_string(settingsMap[default_gpiochip]); for (configNames i : GPIO_lines) { if (settingsMap.count(i) && settingsMap[i] > max_GPIO) @@ -260,62 +260,46 @@ void portduinoSetup() // TODO: Can we do this in the for loop above? // TODO: If one of these fails, we should log and terminate if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) { + if (initGPIOPin(settingsMap[user], defaultGpioChipName, settingsMap[user]) != ERRNO_OK) { settingsMap[user] = RADIOLIB_NC; } } if (settingsMap[displayPanel] != no_screen) { if (settingsMap[displayCS] > 0) - initGPIOPin(settingsMap[displayCS], gpioChipName); + initGPIOPin(settingsMap[displayCS], defaultGpioChipName, settingsMap[displayCS]); if (settingsMap[displayDC] > 0) - initGPIOPin(settingsMap[displayDC], gpioChipName); + initGPIOPin(settingsMap[displayDC], defaultGpioChipName, settingsMap[displayDC]); if (settingsMap[displayBacklight] > 0) - initGPIOPin(settingsMap[displayBacklight], gpioChipName); + initGPIOPin(settingsMap[displayBacklight], defaultGpioChipName, settingsMap[displayBacklight]); if (settingsMap[displayReset] > 0) - initGPIOPin(settingsMap[displayReset], gpioChipName); + initGPIOPin(settingsMap[displayReset], defaultGpioChipName, settingsMap[displayReset]); } if (settingsMap[touchscreenModule] != no_touchscreen) { if (settingsMap[touchscreenCS] > 0) - initGPIOPin(settingsMap[touchscreenCS], gpioChipName); + initGPIOPin(settingsMap[touchscreenCS], defaultGpioChipName, settingsMap[touchscreenCS]); if (settingsMap[touchscreenIRQ] > 0) - initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName); + initGPIOPin(settingsMap[touchscreenIRQ], defaultGpioChipName, settingsMap[touchscreenIRQ]); } // Only initialize the radio pins when dealing with real, kernel controlled SPI hardware if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") { - if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) { - settingsMap[cs] = RADIOLIB_NC; - } - } - if (settingsMap.count(irq) > 0 && settingsMap[irq] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[irq], gpioChipName) != ERRNO_OK) { - settingsMap[irq] = RADIOLIB_NC; - } - } - if (settingsMap.count(busy) > 0 && settingsMap[busy] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[busy], gpioChipName) != ERRNO_OK) { - settingsMap[busy] = RADIOLIB_NC; - } - } - if (settingsMap.count(reset) > 0 && settingsMap[reset] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[reset], gpioChipName) != ERRNO_OK) { - settingsMap[reset] = RADIOLIB_NC; - } - } - if (settingsMap.count(sx126x_ant_sw) > 0 && settingsMap[sx126x_ant_sw] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[sx126x_ant_sw], gpioChipName) != ERRNO_OK) { - settingsMap[sx126x_ant_sw] = RADIOLIB_NC; - } - } - if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) { - settingsMap[rxen] = RADIOLIB_NC; - } - } - if (settingsMap.count(txen) > 0 && settingsMap[txen] != RADIOLIB_NC) { - if (initGPIOPin(settingsMap[txen], gpioChipName) != ERRNO_OK) { - settingsMap[txen] = RADIOLIB_NC; + const struct { configNames pin; configNames gpiochip; configNames line; } pinMappings[] = { + { cs_pin, cs_gpiochip, cs_line }, + { irq_pin, irq_gpiochip, irq_line }, + { busy_pin, busy_gpiochip, busy_line }, + { reset_pin, reset_gpiochip, reset_line }, + { rxen_pin, rxen_gpiochip, rxen_line }, + { txen_pin, txen_gpiochip, txen_line }, + { sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line } + }; + for (auto& pinMap : pinMappings) { + auto setMapIter = settingsMap.find(pinMap.pin); + if (setMapIter != settingsMap.end() && setMapIter->second != RADIOLIB_NC) { + if (initGPIOPin(setMapIter->second, gpioChipName + std::to_string(settingsMap[pinMap.gpiochip]), settingsMap[pinMap.line] ) != ERRNO_OK) { + settingsMap[pinMap.pin] = RADIOLIB_NC; + settingsMap[pinMap.gpiochip] = RADIOLIB_NC; + settingsMap[pinMap.line] = RADIOLIB_NC; + } } } SPI.begin(settingsStrings[spidev].c_str()); @@ -332,13 +316,13 @@ void portduinoSetup() return; } -int initGPIOPin(int pinNum, const std::string gpioChipName) +int initGPIOPin(int pinNum, const std::string gpioChipName, int line) { #ifdef PORTDUINO_LINUX_HARDWARE std::string gpio_name = "GPIO" + std::to_string(pinNum); try { GPIOPin *csPin; - csPin = new LinuxGPIOPin(pinNum, gpioChipName.c_str(), pinNum, gpio_name.c_str()); + csPin = new LinuxGPIOPin(pinNum, gpioChipName.c_str(), line, gpio_name.c_str()); csPin->setSilent(); gpioBind(csPin); return ERRNO_OK; @@ -376,42 +360,65 @@ bool loadConfig(const char *configPath) } } if (yamlConfig["Lora"]) { - settingsMap[use_sx1262] = false; - settingsMap[use_rf95] = false; - settingsMap[use_sx1280] = false; - settingsMap[use_lr1110] = false; - settingsMap[use_lr1120] = false; - settingsMap[use_lr1121] = false; - settingsMap[use_sx1268] = false; - - if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1262") { - settingsMap[use_sx1262] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "RF95") { - settingsMap[use_rf95] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1280") { - settingsMap[use_sx1280] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1110") { - settingsMap[use_lr1110] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1120") { - settingsMap[use_lr1120] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1121") { - settingsMap[use_lr1121] = true; - } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1268") { - settingsMap[use_sx1268] = true; + const struct { configNames cfgName; std::string strName; } loraModules[] = { + { use_rf95, "RF95" }, + { use_sx1262, "sx1262" }, + { use_sx1268, "sx1268" }, + { use_sx1280, "sx1280" }, + { use_lr1110, "lr1110" }, + { use_lr1120, "lr1120" }, + { use_lr1121, "lr1121" }, + { use_llcc68, "LLCC68" } + }; + for (auto& loraModule : loraModules) { + settingsMap[loraModule.cfgName] = false; } + if (yamlConfig["Lora"]["Module"]) { + for (auto& loraModule : loraModules) { + if (yamlConfig["Lora"]["Module"].as("") == loraModule.strName) { + settingsMap[loraModule.cfgName] = true; + break; + } + } + } + settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as(false); settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(0) * 1000; if (settingsMap[dio3_tcxo_voltage] == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false)) { settingsMap[dio3_tcxo_voltage] = 1800; // default millivolts for "true" } - settingsMap[cs] = yamlConfig["Lora"]["CS"].as(RADIOLIB_NC); - settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as(RADIOLIB_NC); - settingsMap[busy] = yamlConfig["Lora"]["Busy"].as(RADIOLIB_NC); - settingsMap[reset] = yamlConfig["Lora"]["Reset"].as(RADIOLIB_NC); - settingsMap[txen] = yamlConfig["Lora"]["TXen"].as(RADIOLIB_NC); - settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as(RADIOLIB_NC); - settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as(RADIOLIB_NC); - settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as(0); + + // backwards API compatibility and to globally set gpiochip once + int defaultGpioChip = settingsMap[default_gpiochip] = yamlConfig["Lora"]["gpiochip"].as(0); + + const struct { configNames pin; + configNames gpiochip; + configNames line; + std::string strName; } pinMappings[] = { + { cs_pin, cs_gpiochip, cs_line, "CS" }, + { irq_pin, irq_gpiochip, irq_line, "IRQ" }, + { busy_pin, busy_gpiochip, busy_line, "Busy" }, + { reset_pin, reset_gpiochip, reset_line, "Reset" }, + { txen_pin, txen_gpiochip, txen_line, "TXen" }, + { rxen_pin, rxen_gpiochip, rxen_line, "RXen" }, + { sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line, "SX126X_ANT_SW" }, + }; + for (auto& pinMap : pinMappings) { + if (yamlConfig["Lora"][pinMap.strName].IsMap() + && (yamlConfig["Lora"][pinMap.strName]["pin"] + || yamlConfig["Lora"][pinMap.strName]["line"] + || yamlConfig["Lora"][pinMap.strName]["gpiochip"])) { + settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName]["pin"].as(RADIOLIB_NC); + settingsMap[pinMap.line] = yamlConfig["Lora"][pinMap.strName]["line"].as(settingsMap[pinMap.pin]); + settingsMap[pinMap.gpiochip] = yamlConfig["Lora"][pinMap.strName]["gpiochip"].as(defaultGpioChip); + } + else { // backwards API compatibility + settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName].as(RADIOLIB_NC); + settingsMap[pinMap.line] = settingsMap[pinMap.pin]; + settingsMap[pinMap.gpiochip] = defaultGpioChip; + } + } + settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as(2000000); settingsStrings[lora_usb_serial_num] = yamlConfig["Lora"]["USB_Serialnum"].as(""); settingsMap[lora_usb_pid] = yamlConfig["Lora"]["USB_PID"].as(0x5512); diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 5bc07df6a..d1e91956d 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -5,27 +5,42 @@ #include "platform/portduino/USBHal.h" enum configNames { - use_sx1262, - cs, - irq, - busy, - reset, - sx126x_ant_sw, - txen, - rxen, + default_gpiochip, + cs_pin, + cs_line, + cs_gpiochip, + irq_pin, + irq_line, + irq_gpiochip, + busy_pin, + busy_line, + busy_gpiochip, + reset_pin, + reset_line, + reset_gpiochip, + txen_pin, + txen_line, + txen_gpiochip, + rxen_pin, + rxen_line, + rxen_gpiochip, + sx126x_ant_sw_pin, + sx126x_ant_sw_line, + sx126x_ant_sw_gpiochip, dio2_as_rf_switch, dio3_tcxo_voltage, use_rf95, + use_sx1262, + use_sx1268, use_sx1280, use_lr1110, use_lr1120, use_lr1121, - use_sx1268, + use_llcc68, lora_usb_serial_num, lora_usb_pid, lora_usb_vid, user, - gpiochip, spidev, spiSpeed, i2cdev, @@ -75,7 +90,7 @@ extern std::map settingsMap; extern std::map settingsStrings; extern std::ofstream traceFile; extern Ch341Hal *ch341Hal; -int initGPIOPin(int pinNum, std::string gpioChipname); +int initGPIOPin(int pinNum, std::string gpioChipname, int line); bool loadConfig(const char *configPath); static bool ends_with(std::string_view str, std::string_view suffix); void getMacAddr(uint8_t *dmac); From 6b1c01ce02e57788873a9f36197e46885b8f11fc Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 12 Jan 2025 15:10:50 -0600 Subject: [PATCH 4/5] Trunk n stuff (#5833) * Trunk * Allow new gpio syntax with defaults * Exit on pin init failure --- src/main.cpp | 67 +++++++------- src/mesh/SX126xInterface.cpp | 3 +- src/platform/portduino/PortduinoGlue.cpp | 106 ++++++++++------------- 3 files changed, 78 insertions(+), 98 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 338fca5c1..fc9d24e37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -826,43 +826,37 @@ void setup() #endif #ifdef ARCH_PORTDUINO - const struct { configNames cfgName; - std::string strName; - } loraModules[] = { - { use_rf95, "RF95" }, - { use_sx1262, "sx1262" }, - { use_sx1268, "sx1268" }, - { use_sx1280, "sx1280" }, - { use_lr1110, "lr1110" }, - { use_lr1120, "lr1120" }, - { use_lr1121, "lr1121" }, - { use_llcc68, "LLCC68" } - }; + const struct { + configNames cfgName; + std::string strName; + } loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"}, + {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}}; // as one can't use a function pointer to the class constructor: - auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) { - switch (cfgName) { - case use_rf95: - return (RadioInterface*)new RF95Interface(hal, cs, irq, rst, busy); - case use_sx1262: - return (RadioInterface*)new SX1262Interface(hal, cs, irq, rst, busy); - case use_sx1268: - return (RadioInterface*)new SX1268Interface(hal, cs, irq, rst, busy); - case use_sx1280: - return (RadioInterface*)new SX1280Interface(hal, cs, irq, rst, busy); - case use_lr1110: - return (RadioInterface*)new LR1110Interface(hal, cs, irq, rst, busy); - case use_lr1120: - return (RadioInterface*)new LR1120Interface(hal, cs, irq, rst, busy); - case use_lr1121: - return (RadioInterface*)new LR1121Interface(hal, cs, irq, rst, busy); - case use_llcc68: - return (RadioInterface*)new LLCC68Interface(hal, cs, irq, rst, busy); - default: - assert(0); // shouldn't happen - return (RadioInterface*)nullptr; - } + auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, + RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) { + switch (cfgName) { + case use_rf95: + return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy); + case use_sx1262: + return (RadioInterface *)new SX1262Interface(hal, cs, irq, rst, busy); + case use_sx1268: + return (RadioInterface *)new SX1268Interface(hal, cs, irq, rst, busy); + case use_sx1280: + return (RadioInterface *)new SX1280Interface(hal, cs, irq, rst, busy); + case use_lr1110: + return (RadioInterface *)new LR1110Interface(hal, cs, irq, rst, busy); + case use_lr1120: + return (RadioInterface *)new LR1120Interface(hal, cs, irq, rst, busy); + case use_lr1121: + return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy); + case use_llcc68: + return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy); + default: + assert(0); // shouldn't happen + return (RadioInterface *)nullptr; + } }; - for (auto& loraModule : loraModules) { + for (auto &loraModule : loraModules) { if (settingsMap[loraModule.cfgName] && !rIf) { LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str()); if (settingsStrings[spidev] == "ch341") { @@ -870,7 +864,8 @@ void setup() } else { RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); } - rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin], settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]); + rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin], + settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]); if (!rIf->init()) { LOG_WARN("No %s radio", loraModule.strName.c_str()); delete rIf; diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index b13bb6faf..8a7bc7670 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -121,7 +121,8 @@ template bool SX126xInterface::init() // no effect #if ARCH_PORTDUINO if (res == RADIOLIB_ERR_NONE) { - LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen_pin], settingsMap[txen_pin]); + LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen_pin], + settingsMap[txen_pin]); lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]); } #else diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index e75112235..ce2418e86 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -134,21 +134,10 @@ void portduinoSetup() { printf("Set up Meshtastic on Portduino...\n"); int max_GPIO = 0; - const configNames GPIO_lines[] = {cs_pin, - irq_pin, - busy_pin, - reset_pin, - sx126x_ant_sw_pin, - txen_pin, - rxen_pin, - displayDC, - displayCS, - displayBacklight, - displayBacklightPWMChannel, - displayReset, - touchscreenCS, - touchscreenIRQ, - user}; + const configNames GPIO_lines[] = { + cs_pin, irq_pin, busy_pin, reset_pin, sx126x_ant_sw_pin, txen_pin, + rxen_pin, displayDC, displayCS, displayBacklight, displayBacklightPWMChannel, displayReset, + touchscreenCS, touchscreenIRQ, user}; std::string gpioChipName = "gpiochip"; settingsStrings[i2cdev] = ""; @@ -257,7 +246,6 @@ void portduinoSetup() gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need. // Need to bind all the configured GPIO pins so they're not simulated - // TODO: Can we do this in the for loop above? // TODO: If one of these fails, we should log and terminate if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) { if (initGPIOPin(settingsMap[user], defaultGpioChipName, settingsMap[user]) != ERRNO_OK) { @@ -283,22 +271,25 @@ void portduinoSetup() // Only initialize the radio pins when dealing with real, kernel controlled SPI hardware if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") { - const struct { configNames pin; configNames gpiochip; configNames line; } pinMappings[] = { - { cs_pin, cs_gpiochip, cs_line }, - { irq_pin, irq_gpiochip, irq_line }, - { busy_pin, busy_gpiochip, busy_line }, - { reset_pin, reset_gpiochip, reset_line }, - { rxen_pin, rxen_gpiochip, rxen_line }, - { txen_pin, txen_gpiochip, txen_line }, - { sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line } - }; - for (auto& pinMap : pinMappings) { + const struct { + configNames pin; + configNames gpiochip; + configNames line; + } pinMappings[] = {{cs_pin, cs_gpiochip, cs_line}, + {irq_pin, irq_gpiochip, irq_line}, + {busy_pin, busy_gpiochip, busy_line}, + {reset_pin, reset_gpiochip, reset_line}, + {rxen_pin, rxen_gpiochip, rxen_line}, + {txen_pin, txen_gpiochip, txen_line}, + {sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line}}; + for (auto &pinMap : pinMappings) { auto setMapIter = settingsMap.find(pinMap.pin); if (setMapIter != settingsMap.end() && setMapIter->second != RADIOLIB_NC) { - if (initGPIOPin(setMapIter->second, gpioChipName + std::to_string(settingsMap[pinMap.gpiochip]), settingsMap[pinMap.line] ) != ERRNO_OK) { - settingsMap[pinMap.pin] = RADIOLIB_NC; - settingsMap[pinMap.gpiochip] = RADIOLIB_NC; - settingsMap[pinMap.line] = RADIOLIB_NC; + if (initGPIOPin(setMapIter->second, gpioChipName + std::to_string(settingsMap[pinMap.gpiochip]), + settingsMap[pinMap.line]) != ERRNO_OK) { + printf("Error setting pin number %d. It may not exist, or may already be in use.\n", + settingsMap[pinMap.line]); + exit(EXIT_FAILURE); } } } @@ -360,21 +351,16 @@ bool loadConfig(const char *configPath) } } if (yamlConfig["Lora"]) { - const struct { configNames cfgName; std::string strName; } loraModules[] = { - { use_rf95, "RF95" }, - { use_sx1262, "sx1262" }, - { use_sx1268, "sx1268" }, - { use_sx1280, "sx1280" }, - { use_lr1110, "lr1110" }, - { use_lr1120, "lr1120" }, - { use_lr1121, "lr1121" }, - { use_llcc68, "LLCC68" } - }; - for (auto& loraModule : loraModules) { + const struct { + configNames cfgName; + std::string strName; + } loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"}, + {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}}; + for (auto &loraModule : loraModules) { settingsMap[loraModule.cfgName] = false; } if (yamlConfig["Lora"]["Module"]) { - for (auto& loraModule : loraModules) { + for (auto &loraModule : loraModules) { if (yamlConfig["Lora"]["Module"].as("") == loraModule.strName) { settingsMap[loraModule.cfgName] = true; break; @@ -391,28 +377,26 @@ bool loadConfig(const char *configPath) // backwards API compatibility and to globally set gpiochip once int defaultGpioChip = settingsMap[default_gpiochip] = yamlConfig["Lora"]["gpiochip"].as(0); - const struct { configNames pin; - configNames gpiochip; - configNames line; - std::string strName; } pinMappings[] = { - { cs_pin, cs_gpiochip, cs_line, "CS" }, - { irq_pin, irq_gpiochip, irq_line, "IRQ" }, - { busy_pin, busy_gpiochip, busy_line, "Busy" }, - { reset_pin, reset_gpiochip, reset_line, "Reset" }, - { txen_pin, txen_gpiochip, txen_line, "TXen" }, - { rxen_pin, rxen_gpiochip, rxen_line, "RXen" }, - { sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line, "SX126X_ANT_SW" }, + const struct { + configNames pin; + configNames gpiochip; + configNames line; + std::string strName; + } pinMappings[] = { + {cs_pin, cs_gpiochip, cs_line, "CS"}, + {irq_pin, irq_gpiochip, irq_line, "IRQ"}, + {busy_pin, busy_gpiochip, busy_line, "Busy"}, + {reset_pin, reset_gpiochip, reset_line, "Reset"}, + {txen_pin, txen_gpiochip, txen_line, "TXen"}, + {rxen_pin, rxen_gpiochip, rxen_line, "RXen"}, + {sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line, "SX126X_ANT_SW"}, }; - for (auto& pinMap : pinMappings) { - if (yamlConfig["Lora"][pinMap.strName].IsMap() - && (yamlConfig["Lora"][pinMap.strName]["pin"] - || yamlConfig["Lora"][pinMap.strName]["line"] - || yamlConfig["Lora"][pinMap.strName]["gpiochip"])) { + for (auto &pinMap : pinMappings) { + if (yamlConfig["Lora"][pinMap.strName].IsMap()) { settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName]["pin"].as(RADIOLIB_NC); settingsMap[pinMap.line] = yamlConfig["Lora"][pinMap.strName]["line"].as(settingsMap[pinMap.pin]); settingsMap[pinMap.gpiochip] = yamlConfig["Lora"][pinMap.strName]["gpiochip"].as(defaultGpioChip); - } - else { // backwards API compatibility + } else { // backwards API compatibility settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName].as(RADIOLIB_NC); settingsMap[pinMap.line] = settingsMap[pinMap.pin]; settingsMap[pinMap.gpiochip] = defaultGpioChip; @@ -584,4 +568,4 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac) } else { return false; } -} +} \ No newline at end of file From e0f97c930648e8adf71af3a279c8ee79da1f2dca Mon Sep 17 00:00:00 2001 From: Austin Date: Sun, 12 Jan 2025 23:24:05 -0500 Subject: [PATCH 5/5] rpkg Fedora packaging (#5735) --- .github/workflows/hook_copr.yml | 73 +++++++++++++++ ...ghtly_debian.yml => nightly_packaging.yml} | 12 ++- .github/workflows/release_channels.yml | 7 ++ bin/rpkg.macros | 12 +++ meshtasticd.spec.rpkg | 91 +++++++++++++++++++ rpkg.conf | 2 + 6 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/hook_copr.yml rename .github/workflows/{nightly_debian.yml => nightly_packaging.yml} (75%) create mode 100644 bin/rpkg.macros create mode 100644 meshtasticd.spec.rpkg create mode 100644 rpkg.conf diff --git a/.github/workflows/hook_copr.yml b/.github/workflows/hook_copr.yml new file mode 100644 index 000000000..c7b6b8d79 --- /dev/null +++ b/.github/workflows/hook_copr.yml @@ -0,0 +1,73 @@ +name: Trigger COPR build + +on: + workflow_call: + secrets: + COPR_HOOK_DAILY: + COPR_HOOK_ALPHA: + COPR_HOOK_BETA: + inputs: + copr_project: + description: COPR project to target + required: true + type: string + +permissions: read-all + +jobs: + build-copr-hook: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + ref: ${{ github.ref }} + repository: ${{ github.repository }} + + - name: Install Python dependencies + run: | + pip install requests + + - name: Trigger COPR build + shell: python + run: | + import requests + + project_name = "${{ inputs.copr_project }}" + if project_name == "daily": + hook_secret = "${{ secrets.COPR_HOOK_DAILY }}" + project_id = 160277 + elif project_name == "alpha": + hook_secret = "${{ secrets.COPR_HOOK_ALPHA }}" + project_id = 160278 + elif project_name == "beta": + hook_secret = "${{ secrets.COPR_HOOK_BETA }}" + project_id = 160279 + else: + raise ValueError(f"Unknown COPR project: {project_name}") + + webhook_url = f"https://copr.fedorainfracloud.org/webhooks/github/{project_id}/{hook_secret}/meshtasticd/" + copr_payload = { + "event": "push", + "payload": { + "ref": "${{ github.ref }}", + "after": "${{ github.sha }}", + "repository": { + "id": "${{ github.repository_id }}", + "full_name": "${{ github.repository }}", + "git_url": "${{ github.repositoryUrl }}", + "owner": { + "name": "${{ github.repository_owner }}" + } + }, + "pusher": { + "name": "${{ github.actor }}" + }, + "sender": { + "login": "github-actions[bot]" + } + } + } + r = requests.post(webhook_url, json=copr_payload) + r.raise_for_status() diff --git a/.github/workflows/nightly_debian.yml b/.github/workflows/nightly_packaging.yml similarity index 75% rename from .github/workflows/nightly_debian.yml rename to .github/workflows/nightly_packaging.yml index aa001854e..e477fe194 100644 --- a/.github/workflows/nightly_debian.yml +++ b/.github/workflows/nightly_packaging.yml @@ -1,4 +1,4 @@ -name: Nightly Debian Packaging +name: Nightly Packaging on: schedule: - cron: 0 9 * * * @@ -8,10 +8,12 @@ on: - master paths: - debian/** - - .github/workflows/nightly_debian.yml + - "*.rpkg" + - .github/workflows/nightly_packaging.yml - .github/workflows/build_debian_src.yml - .github/workflows/package_ppa.yml - .github/workflows/package_obs.yml + - .github/workflows/hook_copr.yml permissions: contents: write @@ -35,3 +37,9 @@ jobs: obs_project: home:meshtastic:daily series: unstable secrets: inherit + + hook-copr: + uses: ./.github/workflows/hook_copr.yml + with: + copr_project: daily + secrets: inherit diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml index 34673f0c7..8891826d2 100644 --- a/.github/workflows/release_channels.yml +++ b/.github/workflows/release_channels.yml @@ -27,3 +27,10 @@ jobs: series: |- ${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }} secrets: inherit + + # hook-copr: + # uses: ./.github/workflows/hook_copr.yml + # with: + # copr_project: |- + # ${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }} + # secrets: inherit diff --git a/bin/rpkg.macros b/bin/rpkg.macros new file mode 100644 index 000000000..2bbb203de --- /dev/null +++ b/bin/rpkg.macros @@ -0,0 +1,12 @@ +function meshtastic_version { + meshtastic_version=$(python3 bin/buildinfo.py short) + echo -n "$meshtastic_version" +} +function git_commits_num { + total_commits=$(git rev-list --all --count) + echo -n "$total_commits" +} +function git_commit_sha { + commit_sha=$(git rev-parse --short HEAD) + echo -n "$commit_sha" +} \ No newline at end of file diff --git a/meshtasticd.spec.rpkg b/meshtasticd.spec.rpkg new file mode 100644 index 000000000..1819897b0 --- /dev/null +++ b/meshtasticd.spec.rpkg @@ -0,0 +1,91 @@ +# meshtasticd spec file for RPM-based distributions +# +# Build locally with: +# ``` +# sudo dnf install rpkg-util +# rpkg local +# ``` +# +# See: +# - https://docs.pagure.org/rpkg-util/v3/index.html +# - https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/ + +Name: meshtasticd +# Version Ex: 2.5.19 +Version: {{{ meshtastic_version }}} +# Release Ex: 9127.daily.gitd7f5f620.fc41 +Release: {{{ git_commits_num }}}%{?copr_projectname:.%{copr_projectname}}.git{{{ git_commit_sha }}}%{?dist} +VCS: {{{ git_dir_vcs }}} +Summary: Meshtastic daemon for communicating with Meshtastic devices + +License: GPL-3.0 +URL: https://github.com/meshtastic/firmware +Source0: {{{ git_dir_pack }}} +Source1: https://github.com/meshtastic/web/releases/download/latest/build.tar + +BuildRequires: systemd-rpm-macros +BuildRequires: python3-devel +BuildRequires: platformio +BuildRequires: python3dist(protobuf) +BuildRequires: python3dist(grpcio[protobuf]) +BuildRequires: python3dist(grpcio-tools) +BuildRequires: git-core +BuildRequires: gcc-c++ +BuildRequires: pkgconfig(yaml-cpp) +BuildRequires: pkgconfig(libgpiod) +BuildRequires: pkgconfig(bluez) +BuildRequires: pkgconfig(libusb-1.0) +BuildRequires: libi2c-devel +# Web components: +BuildRequires: pkgconfig(openssl) +BuildRequires: pkgconfig(liborcania) +BuildRequires: pkgconfig(libyder) +BuildRequires: pkgconfig(libulfius) + +%description +Meshtastic daemon for controlling Meshtastic devices. Meshtastic is an off-grid +text communication platform that uses inexpensive LoRa radios. + +%prep +{{{ git_dir_setup_macro }}} +# Unpack the web files +mkdir -p web +tar -xf %{SOURCE1} -C web +gzip -dr web + +%build +# Use the “native” environment from platformio to build a Linux binary +platformio run -e native + +%install +mkdir -p %{buildroot}%{_sbindir} +install -m 0755 .pio/build/native/program %{buildroot}%{_sbindir}/meshtasticd + +mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd +install -m 0644 bin/config-dist.yaml %{buildroot}%{_sysconfdir}/meshtasticd/config.yaml +mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/config.d +mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/available.d +cp -r bin/config.d/* %{buildroot}%{_sysconfdir}/meshtasticd/available.d + +install -D -m 0644 bin/meshtasticd.service %{buildroot}%{_unitdir}/meshtasticd.service + +# Install the web files under /usr/share/meshtasticd/web +mkdir -p %{buildroot}%{_datadir}/meshtasticd/web +cp -r web/* %{buildroot}%{_datadir}/meshtasticd/web + +%files +%license LICENSE +%doc README.md +%{_sbindir}/meshtasticd +%dir %{_sysconfdir}/meshtasticd +%dir %{_sysconfdir}/meshtasticd/config.d +%dir %{_sysconfdir}/meshtasticd/available.d +%config(noreplace) %{_sysconfdir}/meshtasticd/config.yaml +%config %{_sysconfdir}/meshtasticd/available.d/* +%{_unitdir}/meshtasticd.service +%dir %{_datadir}/meshtasticd +%dir %{_datadir}/meshtasticd/web +%{_datadir}/meshtasticd/web/* + +%changelog +%autochangelog \ No newline at end of file diff --git a/rpkg.conf b/rpkg.conf new file mode 100644 index 000000000..f574f9a13 --- /dev/null +++ b/rpkg.conf @@ -0,0 +1,2 @@ +[rpkg] +user_macros = "${git_props:root}/bin/rpkg.macros"