diff --git a/platformio.ini b/platformio.ini index d5fbc07f..aa8e3eb8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here ;default_envs = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] @@ -65,7 +65,7 @@ lib_deps = 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad - https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c + https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206 https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 Wire ; explicitly needed here because the AXP202 library forgets to add it diff --git a/src/configuration.h b/src/configuration.h index 4f59c840..cb88ed81 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -394,7 +394,7 @@ along with this program. If not, see . #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module -#define LORA_RESET 23 +#define LORA_RESET RADIOLIB_NC #define LORA_DIO1 33 // Not really used #define LORA_DIO2 32 // Not really used diff --git a/src/esp32/WiFiServerAPI.cpp b/src/esp32/WiFiServerAPI.cpp index 3b11c2ae..fac955cc 100644 --- a/src/esp32/WiFiServerAPI.cpp +++ b/src/esp32/WiFiServerAPI.cpp @@ -28,18 +28,19 @@ void WiFiServerAPI::onConnectionChanged(bool connected) } } -void WiFiServerAPI::loop() +/// override close to also shutdown the TCP link +void WiFiServerAPI::close() { + client.stop(); // drop tcp connection + StreamAPI::close(); +} + +bool WiFiServerAPI::loop() { if (client.connected()) { StreamAPI::loop(); - } else if(isConnected) { - // If our API link was up, shut it down - - DEBUG_MSG("Client dropped connection, closing API client\n"); - // Note: we can't call delete here because this object includes other state - // besides the stream API. Instead kill it later when we start a new instance - // delete this; - close(); + return true; + } else { + return false; } } @@ -58,15 +59,25 @@ int32_t WiFiServerPort::runOnce() auto client = available(); if (client) { // Close any previous connection (see FIXME in header file) - if (openAPI) + if (openAPI) { + DEBUG_MSG("Force closing previous TCP connection\n"); delete openAPI; + } openAPI = new WiFiServerAPI(client); } if (openAPI) { // Allow idle processing so the API can read from its incoming stream - openAPI->loop(); + if(!openAPI->loop()) { + // If our API link was up, shut it down + + DEBUG_MSG("Client dropped connection, closing API client\n"); + // Note: we can't call delete here because this object includes other state + // besides the stream API. Instead kill it later when we start a new instance + delete openAPI; + openAPI = NULL; + } return 0; // run fast while our API server is running } else return 100; // only check occasionally for incoming connections diff --git a/src/esp32/WiFiServerAPI.h b/src/esp32/WiFiServerAPI.h index 19f99cbc..96380020 100644 --- a/src/esp32/WiFiServerAPI.h +++ b/src/esp32/WiFiServerAPI.h @@ -18,7 +18,11 @@ class WiFiServerAPI : public StreamAPI virtual ~WiFiServerAPI(); - virtual void loop(); // Check for dropped client connections + /// @return true if we want to keep running, or false if we are ready to be destroyed + virtual bool loop(); // Check for dropped client connections + + /// override close to also shutdown the TCP link + virtual void close(); protected: /// Hookable to find out when connection changes diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index c0e336f0..04aa2c7a 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -239,6 +239,7 @@ int32_t GPS::runOnce() } // We've been awake too long - force sleep + now = millis(); auto wakeTime = getWakeTime(); bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index a0cad427..545ef2b9 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -21,11 +21,17 @@ void PhoneAPI::init() observe(&service.fromNumChanged); } +PhoneAPI::~PhoneAPI() { + close(); +} + void PhoneAPI::close() { unobserve(); state = STATE_SEND_NOTHING; + bool oldConnected = isConnected; isConnected = false; - onConnectionChanged(isConnected); + if(oldConnected != isConnected) + onConnectionChanged(isConnected); } void PhoneAPI::checkConnectionTimeout() diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 202f7fa2..3cfd9744 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -55,12 +55,15 @@ class PhoneAPI public: PhoneAPI(); + /// Destructor - calls close() + virtual ~PhoneAPI(); + /// Do late init that can't happen at constructor time virtual void init(); // Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING - // Unregisters our observer - void close(); + // Unregisters our observer. A closed connection **can** be reopened by calling init again. + virtual void close(); /** * Handle a ToRadio protobuf diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index 60596468..a94a8d12 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -12,7 +12,7 @@ #define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi) - : RadioLibInterface(cs, irq, rst, 0, spi) + : RadioLibInterface(cs, irq, rst, RADIOLIB_NC, spi) { // FIXME - we assume devices never get destroyed } diff --git a/src/mesh/RF95Interface.h b/src/mesh/RF95Interface.h index 91f5728c..ebebe3c7 100644 --- a/src/mesh/RF95Interface.h +++ b/src/mesh/RF95Interface.h @@ -14,6 +14,9 @@ class RF95Interface : public RadioLibInterface public: RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi); + /// Some boards (Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers + bool isIRQPending() { return lora->getPendingIRQ(); } + /// Initialise the Driver transport hardware and software. /// Make sure the Driver is properly configured before calling init(). /// \return true if initialisation succeeded. diff --git a/src/portduino/PortduinoGlue.cpp b/src/portduino/PortduinoGlue.cpp index 0862e33f..6af00666 100644 --- a/src/portduino/PortduinoGlue.cpp +++ b/src/portduino/PortduinoGlue.cpp @@ -1,8 +1,12 @@ #include "CryptoEngine.h" #include "target_specific.h" -#include +#include "PortduinoGPIO.h" +#include "mesh/RF95Interface.h" #include "sleep.h" +#include +#include + // FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class uint32_t hwId; // fixme move into portduino @@ -34,4 +38,60 @@ void cpuDeepSleep(uint64_t msecs) { // FIXME - implement real crypto for linux CryptoEngine *crypto = new CryptoEngine(); -void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); \ No newline at end of file +void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); + +/** Dear pinetab hardware geeks! + * + * The current pinetab lora module has a slight bug. The ch341 part only provides ISR assertions on edges. + * This makes sense because USB interrupts happen through fast/repeated special irq urbs that are constantly + * chattering on the USB bus. + * + * But this isn't sufficient for level triggered ISR sources like the sx127x radios. The common way that seems to + * be addressed by cs341 users is to **always** connect the INT# (pin 26 on the ch341f) signal to one of the GPIO signals + * on the part. I'd recommend connecting that LORA_DIO0/INT# line to pin 19 (data 4) on the pinetab board. This would + * provide an efficent mechanism so that the (kernel) code in the cs341 driver that I've slightly hacked up to see the + * current state of LORA_DIO0. Without that access, I can't know if the interrupt is still pending - which would create + * race conditions in packet handling. + * + * My workaround is to poll the status register internally to the sx127x. Which is expensive because it involves a number of + * i2c transactions and many trips back and forth between kernel and my userspace app. I think shipping the current version + * of the pinetab lora device would be fine because I can poll slowly (because lora is slow). But if you ever have cause to + * rev this board. I highly encourage this small change. + * + * Btw - your little "USB lora dongle" is really neat. I encourage you to sell it, because even non pinetab customers could + * use it to easily add lora to rasberry pi, desktop pcs etc... + * + * Porduino helper class to do this i2c based polling: + */ +class R595PolledIrqPin : public GPIOPin { +public: + R595PolledIrqPin() : GPIOPin(LORA_DIO0, "LORA_DIO0") {} + + /// Read the low level hardware for this pin + virtual PinStatus readPinHardware() + { + if(isrPinStatus < 0) + return LOW; // No interrupt handler attached, don't bother polling i2c right now + else { + extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this + + assert(rIf); + RF95Interface *rIf95 = static_cast(rIf); + bool p = rIf95->isIRQPending(); + // log(SysGPIO, LogDebug, "R595PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p); + return p ? HIGH : LOW; + } + } +}; + + +/** apps run under portduino can optionally define a portduinoSetup() to + * use portduino specific init code (such as gpioBind) to setup portduino on their host machine, + * before running 'arduino' code. + */ +void portduinoSetup() { + printf("Setting up Meshtastic on Porduino...\n"); + gpioBind(new R595PolledIrqPin()); + // gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET"))); + gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent()); +} diff --git a/version.properties b/version.properties index dc155e20..79a74c10 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 30 +build = 31