From 5cec370cf5ac667811c1aff1b666adb2f45feb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 11:28:21 +0100 Subject: [PATCH 01/16] getByName was not used anywhere in the code so that change is safe. Please TEST this as i don't have a working Json setup in mqtt at the moment. --- src/mesh/Channels.cpp | 2 +- src/mqtt/MQTT.cpp | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 97f2c1448..bfd46091f 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -199,7 +199,7 @@ Channel &Channels::getByIndex(ChannelIndex chIndex) Channel &Channels::getByName(const char* chName) { for (ChannelIndex i = 0; i < getNumChannels(); i++) { - if (strcasecmp(channelFile.channels[i].settings.name, chName) == 0) { + if (strcasecmp(getGlobalId(i), chName) == 0) { return channelFile.channels[i]; } } diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index f4004139a..e66b942e9 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -43,9 +43,20 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) JSONValue *json_value = JSON::Parse(payloadStr); if (json_value != NULL) { LOG_INFO("JSON Received on MQTT, parsing..\n"); + // check if it is a valid envelope JSONObject json; json = json_value->AsObject(); + + // parse the channel name from the topic string + char *ptr = strtok(topic, "/"); + for (int i = 0; i < 3; i++) { + ptr = strtok(NULL, "/"); + } + LOG_DEBUG("Looking for Channel name: %s\n", ptr); + Channel sendChannel = channels.getByName(ptr); + LOG_DEBUG("Found Channel name: %s (Index %d)\n", channels.getGlobalId(sendChannel.settings.channel_num), sendChannel.settings.channel_num); + if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) && (json.find("type") != json.end()) && json["type"]->IsString() && (json["type"]->AsString().compare("sendtext") == 0)) { // this is a valid envelope if (json["payload"]->IsString() && json["type"]->IsString() && (json["sender"]->AsString().compare(owner.id) != 0)) { @@ -55,13 +66,18 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) // construct protobuf data packet using TEXT_MESSAGE, send it to the mesh MeshPacket *p = router->allocForSending(); p->decoded.portnum = PortNum_TEXT_MESSAGE_APP; - if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { - memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); - p->decoded.payload.size = jsonPayloadStr.length(); - MeshPacket *packet = packetPool.allocCopy(*p); - service.sendToMesh(packet, RX_SRC_LOCAL); + p->channel = sendChannel.settings.channel_num; + if (sendChannel.settings.downlink_enabled) { + if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { + memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); + p->decoded.payload.size = jsonPayloadStr.length(); + MeshPacket *packet = packetPool.allocCopy(*p); + service.sendToMesh(packet, RX_SRC_LOCAL); + } else { + LOG_WARN("Received MQTT json payload too long, dropping\n"); + } } else { - LOG_WARN("Received MQTT json payload too long, dropping\n"); + LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n", sendChannel.settings.name); } } else { LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n"); @@ -80,9 +96,13 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length) // construct protobuf data packet using POSITION, send it to the mesh MeshPacket *p = router->allocForSending(); p->decoded.portnum = PortNum_POSITION_APP; - p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Position_msg, &pos); //make the Data protobuf from position - service.sendToMesh(p, RX_SRC_LOCAL); - + p->channel = sendChannel.settings.channel_num; + if (sendChannel.settings.downlink_enabled) { + p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Position_msg, &pos); //make the Data protobuf from position + service.sendToMesh(p, RX_SRC_LOCAL); + } else { + LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n", sendChannel.settings.name); + } } else { LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n"); } From 5fd00b253849791b3758e37465bc6737c0b9f16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 17:03:52 +0100 Subject: [PATCH 02/16] - make a template class for API Server - Skip a lot of duplicate code - add a hexDump output - might come in handy - refactor directory names - remove unused debugOut that was generating template errors --- arch/nrf52/nrf52.ini | 2 +- arch/rp2040/rp2040.ini | 2 +- arch/stm32/stm32wl5e.ini | 2 +- src/RedirectablePrint.cpp | 33 ++++++-- src/RedirectablePrint.h | 2 + src/main.cpp | 4 +- src/mesh/InterfacesTemplates.cpp | 14 ++++ src/mesh/PhoneAPI.h | 3 - src/mesh/api/ServerAPI.cpp | 67 +++++++++++++++ .../{wifi/WiFiServerAPI.h => api/ServerAPI.h} | 22 ++--- src/mesh/api/WiFiServerAPI.cpp | 25 ++++++ src/mesh/api/WiFiServerAPI.h | 25 ++++++ src/mesh/api/ethServerAPI.cpp | 27 ++++++ src/mesh/api/ethServerAPI.h | 25 ++++++ src/mesh/eth/ethClient.cpp | 2 +- src/mesh/eth/ethServerAPI.cpp | 82 ------------------- src/mesh/eth/ethServerAPI.h | 58 ------------- src/mesh/http/WiFiAPClient.cpp | 2 +- src/mesh/wifi/WiFiServerAPI.cpp | 82 ------------------- variants/rak4631/platformio.ini | 2 +- 20 files changed, 230 insertions(+), 251 deletions(-) create mode 100644 src/mesh/api/ServerAPI.cpp rename src/mesh/{wifi/WiFiServerAPI.h => api/ServerAPI.h} (72%) create mode 100644 src/mesh/api/WiFiServerAPI.cpp create mode 100644 src/mesh/api/WiFiServerAPI.h create mode 100644 src/mesh/api/ethServerAPI.cpp create mode 100644 src/mesh/api/ethServerAPI.h delete mode 100644 src/mesh/eth/ethServerAPI.cpp delete mode 100644 src/mesh/eth/ethServerAPI.h delete mode 100644 src/mesh/wifi/WiFiServerAPI.cpp diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 46f946530..9ee2c37b5 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -8,7 +8,7 @@ build_flags = ${arduino_base.build_flags} -Wno-unused-variable -Isrc/platform/nrf52 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - lib_ignore = BluetoothOTA diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index cf898a60f..f30a94d3d 100644 --- a/arch/rp2040/rp2040.ini +++ b/arch/rp2040/rp2040.ini @@ -12,7 +12,7 @@ build_flags = -D__PLAT_RP2040__ # -D _POSIX_THREADS build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - lib_ignore = BluetoothOTA lib_deps = diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index 3fc7583ad..a38fb65e8 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -10,7 +10,7 @@ build_flags = # Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support # -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - - - lib_deps = ${env.lib_deps} https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index e7f305e19..28ae3e635 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -3,7 +3,6 @@ #include "RTC.h" #include "NodeDB.h" #include "concurrency/OSThread.h" -// #include "wifi/WiFiServerAPI.h" #include #include #include @@ -27,10 +26,6 @@ size_t RedirectablePrint::write(uint8_t c) SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif - // FIXME - clean this up, the whole relationship of this class to SerialConsole to TCP/bluetooth debug log output is kinda messed up. But for now, just have this hack to - // optionally send chars to TCP also - //WiFiServerPort::debugOut(c); - if (!config.has_lora || config.device.serial_enabled) dest->write(c); @@ -108,3 +103,31 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) return r; } + +void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) { + char alphabet[17] = "0123456789abcdef"; + log(logLevel, " +------------------------------------------------+ +----------------+\n"); + log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n"); + for (uint16_t i = 0; i < len; i += 16) { + if (i % 128 == 0) + log(logLevel, " +------------------------------------------------+ +----------------+\n"); + char s[] = "| | | |\n"; + uint8_t ix = 1, iy = 52; + for (uint8_t j = 0; j < 16; j++) { + if (i + j < len) { + uint8_t c = buf[i + j]; + s[ix++] = alphabet[(c >> 4) & 0x0F]; + s[ix++] = alphabet[c & 0x0F]; + ix++; + if (c > 31 && c < 128) s[iy++] = c; + else s[iy++] = '.'; + } + } + uint8_t index = i / 16; + if (i < 256) log(logLevel, " "); + log(logLevel, "%02x",index); + log(logLevel, "."); + log(logLevel, s); + } + log(logLevel, " +------------------------------------------------+ +----------------+\n"); +} diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 8fabd4a72..7aaeb4a47 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -38,6 +38,8 @@ class RedirectablePrint : public Print /** like printf but va_list based */ size_t vprintf(const char *format, va_list arg); + + void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); }; class NoopPrint : public Print diff --git a/src/main.cpp b/src/main.cpp index af7f28b50..47236bf7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,12 +36,12 @@ #endif #if HAS_WIFI -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #endif #if HAS_ETHERNET -#include "mesh/eth/ethServerAPI.h" +#include "mesh/api/ethServerAPI.h" #include "mqtt/MQTT.h" #endif diff --git a/src/mesh/InterfacesTemplates.cpp b/src/mesh/InterfacesTemplates.cpp index 0d2246428..d8f84c487 100644 --- a/src/mesh/InterfacesTemplates.cpp +++ b/src/mesh/InterfacesTemplates.cpp @@ -2,9 +2,23 @@ #include "SX126xInterface.cpp" #include "SX128xInterface.h" #include "SX128xInterface.cpp" +#include "api/ServerAPI.h" +#include "api/ServerAPI.cpp" // We need this declaration for proper linking in derived classes template class SX126xInterface; template class SX126xInterface; template class SX126xInterface; template class SX128xInterface; + +#if HAS_ETHERNET +#include "api/ethServerAPI.h" +template class ServerAPI; +template class APIServerPort; +#endif + +#if HAS_WIFI +#include "api/WiFiServerAPI.h" +template class ServerAPI; +template class APIServerPort; +#endif \ No newline at end of file diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 2f2695807..aa190ae37 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -86,9 +86,6 @@ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting void setInitialState() { state = STATE_SEND_MY_INFO; } - /// emit a debugging log character, FIXME - implement - void debugOut(char c) { } - protected: /// Our fromradio packet while it is being assembled FromRadio fromRadioScratch = {}; diff --git a/src/mesh/api/ServerAPI.cpp b/src/mesh/api/ServerAPI.cpp new file mode 100644 index 000000000..e35455063 --- /dev/null +++ b/src/mesh/api/ServerAPI.cpp @@ -0,0 +1,67 @@ +#include "ServerAPI.h" +#include "configuration.h" +#include + +template +ServerAPI::ServerAPI(T &_client) : StreamAPI(&client), concurrency::OSThread("ServerAPI"), client(_client) +{ + LOG_INFO("Incoming wifi connection\n"); +} + +template +ServerAPI::~ServerAPI() +{ + client.stop(); +} + +template +void ServerAPI::close() +{ + client.stop(); // drop tcp connection + StreamAPI::close(); +} + +/// Check the current underlying physical link to see if the client is currently connected +template +bool ServerAPI::checkIsConnected() +{ + return client.connected(); +} + +template +int32_t ServerAPI::runOnce() +{ + if (client.connected()) { + return StreamAPI::runOncePart(); + } else { + LOG_INFO("Client dropped connection, suspending API service\n"); + enabled = false; // we no longer need to run + return 0; + } +} + +template +APIServerPort::APIServerPort(int port) : U(port), concurrency::OSThread("ApiServer") {} + +template +void APIServerPort::init() +{ + U::begin(); +} + +template +int32_t APIServerPort::runOnce() +{ + auto client = U::available(); + if (client) { + // Close any previous connection (see FIXME in header file) + if (openAPI) { + LOG_INFO("Force closing previous TCP connection\n"); + delete openAPI; + } + + openAPI = new T(client); + } + + return 100; // only check occasionally for incoming connections +} diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/api/ServerAPI.h similarity index 72% rename from src/mesh/wifi/WiFiServerAPI.h rename to src/mesh/api/ServerAPI.h index 812408818..174aa774f 100644 --- a/src/mesh/wifi/WiFiServerAPI.h +++ b/src/mesh/api/ServerAPI.h @@ -1,21 +1,21 @@ #pragma once #include "StreamAPI.h" -#include /** * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). */ -class WiFiServerAPI : public StreamAPI, private concurrency::OSThread +template +class ServerAPI : public StreamAPI, private concurrency::OSThread { private: - WiFiClient client; + T client; public: - explicit WiFiServerAPI(WiFiClient &_client); + explicit ServerAPI(T &_client); - virtual ~WiFiServerAPI(); + virtual ~ServerAPI(); /// override close to also shutdown the TCP link virtual void close(); @@ -34,25 +34,21 @@ class WiFiServerAPI : public StreamAPI, private concurrency::OSThread /** * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed */ -class WiFiServerPort : public WiFiServer, private concurrency::OSThread +template +class APIServerPort : public U, private concurrency::OSThread { /** The currently open port * * FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to * delegate to the worker. Once coroutines are implemented we can relax this restriction. */ - WiFiServerAPI *openAPI = NULL; + T *openAPI = NULL; public: - explicit WiFiServerPort(int port); + explicit APIServerPort(int port); void init(); - /// If an api server is running, we try to spit out debug 'serial' characters there - static void debugOut(char c); - protected: int32_t runOnce() override; }; - -void initApiServer(int port=4403); diff --git a/src/mesh/api/WiFiServerAPI.cpp b/src/mesh/api/WiFiServerAPI.cpp new file mode 100644 index 000000000..5f86dbe85 --- /dev/null +++ b/src/mesh/api/WiFiServerAPI.cpp @@ -0,0 +1,25 @@ +#include "configuration.h" +#include + +#if HAS_WIFI +#include "WiFiServerAPI.h" + +static WiFiServerPort *apiPort; + +void initApiServer(int port) +{ + // Start API server on port 4403 + if (!apiPort) { + apiPort = new WiFiServerPort(port); + LOG_INFO("API server listening on TCP port %d\n", port); + apiPort->init(); + } +} + +WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client) +{ + LOG_INFO("Incoming wifi connection\n"); +} + +WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {} +#endif diff --git a/src/mesh/api/WiFiServerAPI.h b/src/mesh/api/WiFiServerAPI.h new file mode 100644 index 000000000..279ee0f3f --- /dev/null +++ b/src/mesh/api/WiFiServerAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ServerAPI.h" +#include + +/** + * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs + * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). + */ +class WiFiServerAPI : public ServerAPI +{ + public: + explicit WiFiServerAPI(WiFiClient &_client); +}; + +/** + * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed + */ +class WiFiServerPort : public APIServerPort +{ + public: + explicit WiFiServerPort(int port); +}; + +void initApiServer(int port=4403); diff --git a/src/mesh/api/ethServerAPI.cpp b/src/mesh/api/ethServerAPI.cpp new file mode 100644 index 000000000..3badcdfde --- /dev/null +++ b/src/mesh/api/ethServerAPI.cpp @@ -0,0 +1,27 @@ +#include "configuration.h" +#include + +#if HAS_ETHERNET + +#include "ethServerAPI.h" + +static ethServerPort *apiPort; + +void initApiServer(int port) +{ + // Start API server on port 4403 + if (!apiPort) { + apiPort = new ethServerPort(port); + LOG_INFO("API server listening on TCP port %d\n", port); + apiPort->init(); + } +} + +ethServerAPI::ethServerAPI(EthernetClient &_client) : ServerAPI(_client) +{ + LOG_INFO("Incoming ethernet connection\n"); +} + +ethServerPort::ethServerPort(int port) : APIServerPort(port) {} + +#endif \ No newline at end of file diff --git a/src/mesh/api/ethServerAPI.h b/src/mesh/api/ethServerAPI.h new file mode 100644 index 000000000..36f363f70 --- /dev/null +++ b/src/mesh/api/ethServerAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ServerAPI.h" +#include + +/** + * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs + * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). + */ +class ethServerAPI : public ServerAPI +{ + public: + explicit ethServerAPI(EthernetClient &_client); +}; + +/** + * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed + */ +class ethServerPort : public APIServerPort +{ + public: + explicit ethServerPort(int port); +}; + +void initApiServer(int port=4403); diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 4ac9bd9ad..dce04b191 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -5,7 +5,7 @@ #include #include #include "target_specific.h" -#include "mesh/eth/ethServerAPI.h" +#include "mesh/api/ethServerAPI.h" #include "mqtt/MQTT.h" #ifndef DISABLE_NTP diff --git a/src/mesh/eth/ethServerAPI.cpp b/src/mesh/eth/ethServerAPI.cpp deleted file mode 100644 index d91b798a0..000000000 --- a/src/mesh/eth/ethServerAPI.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "ethServerAPI.h" -#include "configuration.h" -#include - -static ethServerPort *apiPort; - -void initApiServer(int port) -{ - // Start API server on port 4403 - if (!apiPort) { - apiPort = new ethServerPort(port); - LOG_INFO("API server listening on TCP port %d\n", port); - apiPort->init(); - } -} - -ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), concurrency::OSThread("ethServerAPI"), client(_client) -{ - LOG_INFO("Incoming ethernet connection\n"); -} - -ethServerAPI::~ethServerAPI() -{ - client.stop(); - - // FIXME - delete this if the client dropps the connection! -} - -/// override close to also shutdown the TCP link -void ethServerAPI::close() -{ - client.stop(); // drop tcp connection - StreamAPI::close(); -} - -/// Check the current underlying physical link to see if the client is currently connected -bool ethServerAPI::checkIsConnected() -{ - return client.connected(); -} - -int32_t ethServerAPI::runOnce() -{ - if (client.connected()) { - return StreamAPI::runOncePart(); - } else { - LOG_INFO("Client dropped connection, suspending API service\n"); - enabled = false; // we no longer need to run - return 0; - } -} - -/// If an api server is running, we try to spit out debug 'serial' characters there -void ethServerPort::debugOut(char c) -{ - if (apiPort && apiPort->openAPI) - apiPort->openAPI->debugOut(c); -} - - -ethServerPort::ethServerPort(int port) : EthernetServer(port), concurrency::OSThread("ApiServer") {} - -void ethServerPort::init() -{ - begin(); -} - -int32_t ethServerPort::runOnce() -{ - auto client = available(); - if (client) { - // Close any previous connection (see FIXME in header file) - if (openAPI) { - LOG_WARN("Force closing previous TCP connection\n"); - delete openAPI; - } - - openAPI = new ethServerAPI(client); - } - - return 100; // only check occasionally for incoming connections -} diff --git a/src/mesh/eth/ethServerAPI.h b/src/mesh/eth/ethServerAPI.h deleted file mode 100644 index 962841c80..000000000 --- a/src/mesh/eth/ethServerAPI.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "StreamAPI.h" -#include - -/** - * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs - * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). - */ -class ethServerAPI : public StreamAPI, private concurrency::OSThread -{ - private: - EthernetClient client; - - public: - explicit ethServerAPI(EthernetClient &_client); - - virtual ~ethServerAPI(); - - /// override close to also shutdown the TCP link - virtual void close(); - - protected: - /// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to - /// stay in the POWERED state to prevent disabling wifi) - virtual void onConnectionChanged(bool connected) override {} - - virtual int32_t runOnce() override; // Check for dropped client connections - - /// Check the current underlying physical link to see if the client is currently connected - virtual bool checkIsConnected() override; -}; - -/** - * Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed - */ -class ethServerPort : public EthernetServer, private concurrency::OSThread -{ - /** The currently open port - * - * FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to - * delegate to the worker. Once coroutines are implemented we can relax this restriction. - */ - ethServerAPI *openAPI = NULL; - - public: - explicit ethServerPort(int port); - - void init(); - - /// If an api server is running, we try to spit out debug 'serial' characters there - static void debugOut(char c); - - protected: - int32_t runOnce() override; -}; - -void initApiServer(int port=4403); diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index ec34f9927..d8f3570c2 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -5,7 +5,7 @@ #include "configuration.h" #include "main.h" #include "mesh/http/WebServer.h" -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #include "target_specific.h" #include diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp deleted file mode 100644 index 136dfadb7..000000000 --- a/src/mesh/wifi/WiFiServerAPI.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "WiFiServerAPI.h" -#include "configuration.h" -#include - -static WiFiServerPort *apiPort; - -void initApiServer(int port) -{ - // Start API server on port 4403 - if (!apiPort) { - apiPort = new WiFiServerPort(port); - LOG_INFO("API server listening on TCP port %d\n", port); - apiPort->init(); - } -} - -WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), concurrency::OSThread("WiFiServerAPI"), client(_client) -{ - LOG_INFO("Incoming wifi connection\n"); -} - -WiFiServerAPI::~WiFiServerAPI() -{ - client.stop(); - - // FIXME - delete this if the client dropps the connection! -} - -/// override close to also shutdown the TCP link -void WiFiServerAPI::close() -{ - client.stop(); // drop tcp connection - StreamAPI::close(); -} - -/// Check the current underlying physical link to see if the client is currently connected -bool WiFiServerAPI::checkIsConnected() -{ - return client.connected(); -} - -int32_t WiFiServerAPI::runOnce() -{ - if (client.connected()) { - return StreamAPI::runOncePart(); - } else { - LOG_INFO("Client dropped connection, suspending API service\n"); - enabled = false; // we no longer need to run - return 0; - } -} - -/// If an api server is running, we try to spit out debug 'serial' characters there -void WiFiServerPort::debugOut(char c) -{ - if (apiPort && apiPort->openAPI) - apiPort->openAPI->debugOut(c); -} - - -WiFiServerPort::WiFiServerPort(int port) : WiFiServer(port), concurrency::OSThread("ApiServer") {} - -void WiFiServerPort::init() -{ - begin(); -} - -int32_t WiFiServerPort::runOnce() -{ - auto client = available(); - if (client) { - // Close any previous connection (see FIXME in header file) - if (openAPI) { - LOG_INFO("Force closing previous TCP connection\n"); - delete openAPI; - } - - openAPI = new WiFiServerAPI(client); - } - - return 100; // only check occasionally for incoming connections -} diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index e08b54dae..a0928605f 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -3,7 +3,7 @@ extends = nrf52840_base board = wiscore_rak4631 build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} From 86748bf88ec447653606ec53a86fd5bf2bb8a6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 19:23:41 +0100 Subject: [PATCH 03/16] fix building portduino and make cppcheck happy --- src/RedirectablePrint.cpp | 2 +- src/platform/portduino/SimRadio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 28ae3e635..74b44dd86 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -105,7 +105,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) } void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) { - char alphabet[17] = "0123456789abcdef"; + const char alphabet[17] = "0123456789abcdef"; log(logLevel, " +------------------------------------------------+ +----------------+\n"); log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n"); for (uint16_t i = 0; i < len; i += 16) { diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index d2a36c81e..c4336a22b 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -2,7 +2,7 @@ #include "RadioInterface.h" #include "MeshPacketQueue.h" -#include "wifi/WiFiServerAPI.h" +#include "api/WiFiServerAPI.h" #include From e7d425ef6e1aab694906e3af9c97e3f367cc1ce4 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 9 Jan 2023 16:19:42 -0600 Subject: [PATCH 04/16] Until we figure out what's going on --- src/mesh/SX126xInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 15b808852..0e033eeb6 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -70,7 +70,7 @@ bool SX126xInterface::init() #if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC) // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX if (res == RADIOLIB_ERR_NONE) - res = lora.setDio2AsRfSwitch(false); + res = lora.setDio2AsRfSwitch(true); #endif #if 0 From 1fc5d70221e85728b0acbe6d1c374e6840493329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 9 Jan 2023 23:26:47 +0100 Subject: [PATCH 05/16] let the library handle the reconnect, manually do it after 5 seconds --- src/mesh/http/WiFiAPClient.cpp | 14 ++++++++------ src/mqtt/MQTT.cpp | 14 ++++++++------ src/mqtt/MQTT.h | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index ec34f9927..0a6a1b8df 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -5,7 +5,7 @@ #include "configuration.h" #include "main.h" #include "mesh/http/WebServer.h" -#include "mesh/wifi/WiFiServerAPI.h" +#include "mesh/api/WiFiServerAPI.h" #include "mqtt/MQTT.h" #include "target_specific.h" #include @@ -55,11 +55,13 @@ static int32_t reconnectWiFi() // Make sure we clear old connection credentials WiFi.disconnect(false, true); - LOG_INFO("Reconnecting to WiFi access point %s\n",wifiName); - WiFi.mode(WIFI_MODE_STA); - WiFi.begin(wifiName, wifiPsw); + delay(5000); + + if (!WiFi.isConnected()) { + WiFi.begin(wifiName, wifiPsw); + } } #ifndef DISABLE_NTP @@ -167,7 +169,7 @@ bool initWifi() WiFi.mode(WIFI_MODE_STA); WiFi.setHostname(ourHost); WiFi.onEvent(WiFiEvent); - WiFi.setAutoReconnect(false); + WiFi.setAutoReconnect(true); WiFi.setSleep(false); if (config.network.address_mode == Config_NetworkConfig_AddressMode_STATIC && config.network.ipv4_config.ip != 0) { WiFi.config(config.network.ipv4_config.ip, @@ -182,7 +184,7 @@ bool initWifi() WiFi.onEvent( [](WiFiEvent_t event, WiFiEventInfo_t info) { - LOG_WARN("WiFi lost connection. Reason: %s", info.wifi_sta_disconnected.reason); + LOG_WARN("WiFi lost connection. Reason: %d\n", info.wifi_sta_disconnected.reason); /* If we are disconnected from the AP for some reason, diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index e66b942e9..cc091bcff 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -207,14 +207,17 @@ void MQTT::reconnect() sendSubscriptions(); } else { - LOG_ERROR("Failed to contact MQTT server (%d/10)...\n",reconnectCount); #if HAS_WIFI && !defined(ARCH_PORTDUINO) - if (reconnectCount > 9) { + LOG_ERROR("Failed to contact MQTT server (%d/5)...\n",reconnectCount + 1); + if (reconnectCount >= 4) { needReconnect = true; - wifiReconnect->setIntervalFromNow(1000); + wifiReconnect->setIntervalFromNow(0); + reconnectCount = 0; + } else { + reconnectCount++; } + #endif - reconnectCount++; } } } @@ -284,7 +287,6 @@ int32_t MQTT::runOnce() String topic = cryptTopic + env->channel_id + "/" + owner.id; LOG_INFO("publish %s, %u bytes from queue\n", topic.c_str(), numBytes); - pubSub.publish(topic.c_str(), bytes, numBytes, false); @@ -299,7 +301,7 @@ int32_t MQTT::runOnce() } mqttPool.release(env); } - return 20; + return 200; } else { return 30000; } diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index ddbacbcc4..16ce4c37a 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -13,7 +13,7 @@ #include #endif -#define MAX_MQTT_QUEUE 32 +#define MAX_MQTT_QUEUE 16 /** * Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from From 713f7d5996183895cb1b89a4ed4e4f50676ea288 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 10 Jan 2023 07:36:19 -0600 Subject: [PATCH 06/16] Turn of 3.3v rail on RAK-4631 on shutdown --- src/main.cpp | 2 +- src/platform/nrf52/main-nrf52.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 47236bf7d..2631e68df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,7 +239,7 @@ void setup() #ifdef RAK4630 // We need to enable 3.3V periphery in order to scan it pinMode(PIN_3V3_EN, OUTPUT); - digitalWrite(PIN_3V3_EN, 1); + digitalWrite(PIN_3V3_EN, HIGH); #endif // Currently only the tbeam has a PMU diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 9a942a606..e3096b0ce 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -172,6 +172,9 @@ void cpuDeepSleep(uint64_t msecToWake) Serial1.end(); #endif setBluetoothEnable(false); +#ifdef RAK4630 + digitalWrite(PIN_3V3_EN, LOW); +#endif // FIXME, use system off mode with ram retention for key state? // FIXME, use non-init RAM per // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled From a3b93a4dcfa8e7281cc9d0ef88d8a742c417dddc Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:10:09 +0100 Subject: [PATCH 07/16] Better not to compare float directly --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 69ac1d5c9..b5965f25f 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -199,7 +199,7 @@ ErrorCode Router::send(MeshPacket *p) } // should have already been handled by sendLocal // Abort sending if we are violating the duty cycle - if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) { + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { float hourlyTxPercent = airTime->utilizationTXPercent(); if (hourlyTxPercent > myRegion->dutyCycle) { uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); From e13fb9919e20e640fe309944ca1fd5f4528d24e0 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:12:17 +0100 Subject: [PATCH 08/16] Send NAK only to the API upon duty cycle limit --- src/mesh/Router.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b5965f25f..b3d43cf09 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -200,14 +200,18 @@ ErrorCode Router::send(MeshPacket *p) // Abort sending if we are violating the duty cycle if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { - float hourlyTxPercent = airTime->utilizationTXPercent(); - if (hourlyTxPercent > myRegion->dutyCycle) { - uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); - LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); - Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT; - abortSendAndNak(err, p); - return err; - } + float hourlyTxPercent = airTime->utilizationTXPercent(); + if (hourlyTxPercent > myRegion->dutyCycle) { + uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); + LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); + Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT; + if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh + abortSendAndNak(err, p); + } else { + packetPool.release(p); + } + return err; + } } // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; From ab9d0ba543be246ad7f52280550613a109661fb5 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 10 Jan 2023 21:12:40 +0100 Subject: [PATCH 09/16] Report actual RoutingError --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b3d43cf09..74487588b 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -138,7 +138,7 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelI void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) { LOG_ERROR("Error=%d, returning NAK and dropping packet.\n", err); - sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel); + sendAckNak(err, getFrom(p), p->id, p->channel); packetPool.release(p); } From 4f71ab07c96bb08a6fc2a16500e0cbe96fa8415e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 11 Jan 2023 14:33:54 +0100 Subject: [PATCH 10/16] 2.0.12 is out already. Bump develop too. --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 816f7c2ac..40e7926a9 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 0 -build = 12 +build = 13 From 17a2589b352fe5474c02ccc90cecd17cf0e2b9ac Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 11 Jan 2023 07:50:07 -0600 Subject: [PATCH 11/16] Allow time from phone to be sent to the mesh --- src/mesh/MeshService.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index f881f4d40..9a6fa984c 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -280,8 +280,7 @@ NodeInfo *MeshService::refreshMyNodeInfo() node->last_heard = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid - // For the time in the position field, only set that if we have a real GPS clock - position.time = getValidTime(RTCQualityGPS); + position.time = getValidTime(RTCQualityFromNet); updateBatteryLevel(powerStatus->getBatteryChargePercent()); @@ -327,4 +326,4 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) bool MeshService::isToPhoneQueueEmpty() { return toPhoneQueue.isEmpty(); -} \ No newline at end of file +} From a354cebd8801b616529246df0fba1d4f77414824 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 11 Jan 2023 14:28:10 -0600 Subject: [PATCH 12/16] Update protos ref --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 3b0d871ca..570cee3f3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 3b0d871ca1e0f8a2ed823f0696e2d7cf31ed2ebd +Subproject commit 570cee3f31c8a1acfb31e0f3f434bf25b8451a52 From 721f87af7ef38c6959511d7e773f63f446268b3f Mon Sep 17 00:00:00 2001 From: thebentern Date: Wed, 11 Jan 2023 20:35:13 +0000 Subject: [PATCH 13/16] [create-pull-request] automated change --- src/mesh/generated/localonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 17 +++++++++++------ src/mesh/generated/module_config.pb.h | 6 +++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h index d2b9dfcae..1e4aa633c 100644 --- a/src/mesh/generated/localonly.pb.h +++ b/src/mesh/generated/localonly.pb.h @@ -157,7 +157,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define LocalConfig_size 391 -#define LocalModuleConfig_size 380 +#define LocalModuleConfig_size 412 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index d1f3e5bf5..5ff84a223 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -84,6 +84,8 @@ typedef enum _HardwareModel { HardwareModel_HELTEC_V3 = 43, /* New Heltec Wireless Stick Lite with ESP32-S3 CPU */ HardwareModel_HELTEC_WSL_V3 = 44, + /* New BETAFPV ELRS Micro TX Module 2.4G with ESP32 CPU */ + HardwareModel_BETAFPV_2400_TX = 45, /* Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */ HardwareModel_PRIVATE_HW = 255 } HardwareModel; @@ -439,9 +441,10 @@ typedef struct _Waypoint { bool locked; /* Name of the waypoint - max 30 chars */ char name[30]; - /* * - Description of the waypoint - max 100 chars */ + /* Description of the waypoint - max 100 chars */ char description[100]; + /* Designator icon for the waypoint in the form of a unicode emoji */ + uint32_t emoji; } Waypoint; typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; @@ -778,7 +781,7 @@ extern "C" { #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_default {0, {RouteDiscovery_init_default}} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} -#define Waypoint_init_default {0, 0, 0, 0, 0, "", ""} +#define Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default} #define MyNodeInfo_init_default {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} @@ -792,7 +795,7 @@ extern "C" { #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} -#define Waypoint_init_zero {0, 0, 0, 0, 0, "", ""} +#define Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero} #define MyNodeInfo_init_zero {0, 0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} @@ -850,6 +853,7 @@ extern "C" { #define Waypoint_locked_tag 5 #define Waypoint_name_tag 6 #define Waypoint_description_tag 7 +#define Waypoint_emoji_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_channel_tag 3 @@ -980,7 +984,8 @@ X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 3) \ X(a, STATIC, SINGULAR, UINT32, expire, 4) \ X(a, STATIC, SINGULAR, BOOL, locked, 5) \ X(a, STATIC, SINGULAR, STRING, name, 6) \ -X(a, STATIC, SINGULAR, STRING, description, 7) +X(a, STATIC, SINGULAR, STRING, description, 7) \ +X(a, STATIC, SINGULAR, FIXED32, emoji, 8) #define Waypoint_CALLBACK NULL #define Waypoint_DEFAULT NULL @@ -1133,7 +1138,7 @@ extern const pb_msgdesc_t Compressed_msg; #define Routing_size 42 #define ToRadio_size 324 #define User_size 77 -#define Waypoint_size 156 +#define Waypoint_size 161 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h index da13ac706..bd4e90832 100644 --- a/src/mesh/generated/module_config.pb.h +++ b/src/mesh/generated/module_config.pb.h @@ -80,7 +80,7 @@ typedef struct _ModuleConfig_MQTTConfig { bool enabled; /* The server to use for our MQTT global message gateway feature. If not set, the default server will be used */ - char address[32]; + char address[64]; /* MQTT username to use (most useful for a custom MQTT server). If using a custom server, this will be honoured even if empty. If using the default server, this will only be honoured if set, otherwise the device will use the default username */ @@ -553,13 +553,13 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg; #define ModuleConfig_AudioConfig_size 19 #define ModuleConfig_CannedMessageConfig_size 49 #define ModuleConfig_ExternalNotificationConfig_size 40 -#define ModuleConfig_MQTTConfig_size 169 +#define ModuleConfig_MQTTConfig_size 201 #define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_RemoteHardwareConfig_size 2 #define ModuleConfig_SerialConfig_size 26 #define ModuleConfig_StoreForwardConfig_size 22 #define ModuleConfig_TelemetryConfig_size 18 -#define ModuleConfig_size 172 +#define ModuleConfig_size 204 #ifdef __cplusplus } /* extern "C" */ From fc775012eac7a208fa611d088675625f13b967c7 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Wed, 11 Jan 2023 21:52:19 +0100 Subject: [PATCH 14/16] Don't send NodeInfo and DeviceTelemetry at high Tx air util Also move airtime checking to airtime class --- src/airtime.cpp | 25 +++++++++++++++++++ src/airtime.h | 6 +++++ src/mesh/SinglePortModule.h | 3 --- src/modules/NodeInfoModule.cpp | 8 +++--- src/modules/PositionModule.cpp | 8 ++---- src/modules/Telemetry/DeviceTelemetry.cpp | 2 +- .../Telemetry/EnvironmentTelemetry.cpp | 2 +- src/modules/esp32/RangeTestModule.cpp | 4 +-- src/modules/esp32/StoreForwardModule.cpp | 6 ++--- 9 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index c72a21d54..ae3b30811 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -117,6 +117,31 @@ float AirTime::utilizationTXPercent() return (float(sum) / float(MS_IN_HOUR)) * 100; } +bool AirTime::isTxAllowedChannelUtil(bool polite) +{ + uint8_t percentage = (polite ? polite_channel_util_percent : max_channel_util_percent); + if (channelUtilizationPercent() < percentage) { + return true; + } else { + LOG_WARN("Channel utilization is >%d percent. Skipping this opportunity to send.\n", percentage); + return false; + } +} + + +bool AirTime::isTxAllowedAirUtil() +{ + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { + if (utilizationTXPercent() < polite_tx_util_percent) { + return true; + } else { + LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", polite_tx_util_percent); + return false; + } + } + return true; +} + // Get the amount of minutes we have to be silent before we can send again uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle) { diff --git a/src/airtime.h b/src/airtime.h index 3f38f39f8..2d1f1e2d9 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -4,6 +4,7 @@ #include "configuration.h" #include #include +#include "MeshRadio.h" /* TX_LOG - Time on air this device has transmitted @@ -59,12 +60,17 @@ class AirTime : private concurrency::OSThread uint32_t getSecondsSinceBoot(); uint32_t *airtimeReport(reportTypes reportType); uint8_t getSilentMinutes(float txPercent, float dutyCycle); + bool isTxAllowedChannelUtil(bool polite=false); + bool isTxAllowedAirUtil(); private: bool firstTime = true; uint8_t lastUtilPeriod = 0; uint8_t lastUtilPeriodTX = 0; uint32_t secSinceBoot = 0; + uint8_t max_channel_util_percent = 40; + uint8_t polite_channel_util_percent = 25; + uint8_t polite_tx_util_percent = 5; struct airtimeStruct { uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted diff --git a/src/mesh/SinglePortModule.h b/src/mesh/SinglePortModule.h index 57db73221..2e587cb89 100644 --- a/src/mesh/SinglePortModule.h +++ b/src/mesh/SinglePortModule.h @@ -18,9 +18,6 @@ class SinglePortModule : public MeshModule SinglePortModule(const char *_name, PortNum _ourPortNum) : MeshModule(_name), ourPortNum(_ourPortNum) {} protected: - uint32_t max_channel_util_percent = 40; - uint32_t polite_channel_util_percent = 25; - /** * @return true if you want to receive the specified portnum */ diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index d8047c5f0..5dc05cd95 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -65,8 +65,10 @@ int32_t NodeInfoModule::runOnce() bool requestReplies = currentGeneration != radioGeneration; currentGeneration = radioGeneration; - LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); - sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + if (airTime->isTxAllowedAirUtil()) { + LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); + sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + } return default_broadcast_interval_secs * 1000; -} \ No newline at end of file +} diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 6680eaba5..4d119043c 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -144,7 +144,7 @@ int32_t PositionModule::runOnce() if (lastGpsSend == 0 || (now - lastGpsSend) >= intervalMs) { // Only send packets if the channel is less than 40% utilized. - if (airTime->channelUtilizationPercent() < max_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil()) { if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) { lastGpsSend = now; @@ -158,14 +158,12 @@ int32_t PositionModule::runOnce() LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", node->position.timestamp, requestReplies); sendOurPosition(NODENUM_BROADCAST, requestReplies); } - } else { - LOG_WARN("Channel utilization is >40 percent. Skipping this opportunity to send.\n"); } } else if (config.position.position_broadcast_smart_enabled) { // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < polite_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil(true)) { NodeInfo *node2 = service.refreshMyNodeInfo(); // should guarantee there is now a position @@ -208,8 +206,6 @@ int32_t PositionModule::runOnce() lastGpsSend = now; } } - } else { - LOG_WARN("Channel utilization is >25 percent. Skipping this opportunity to send.\n"); } } diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 109d8b5b1..dda7ab84d 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,7 +17,7 @@ int32_t DeviceTelemetryModule::runOnce() uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) && - airTime->channelUtilizationPercent() < max_channel_util_percent) { + airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; } else if (service.isToPhoneQueueEmpty()) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 3bf303157..2a29405d3 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -107,7 +107,7 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval)) && - airTime->channelUtilizationPercent() < max_channel_util_percent) { + airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; } else if (service.isToPhoneQueueEmpty()) { diff --git a/src/modules/esp32/RangeTestModule.cpp b/src/modules/esp32/RangeTestModule.cpp index 1624a972b..52a18def5 100644 --- a/src/modules/esp32/RangeTestModule.cpp +++ b/src/modules/esp32/RangeTestModule.cpp @@ -73,10 +73,8 @@ int32_t RangeTestModule::runOnce() LOG_INFO("fixed_position() %d\n", config.position.fixed_position); // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < 25) { + if (airTime->isTxAllowedChannelUtil(true)) { rangeTestModuleRadio->sendPayload(); - } else { - LOG_WARN("RangeTest - Channel utilization is >25 percent. Skipping this opportunity to send.\n"); } return (senderHeartbeat); diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index bf0421a9a..b5e0b1e65 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -21,7 +21,7 @@ int32_t StoreForwardModule::runOnce() // Send out the message queue. if (this->busy) { // Only send packets if the channel is less than 25% utilized. - if (airTime->channelUtilizationPercent() < polite_channel_util_percent) { + if (airTime->isTxAllowedChannelUtil(true)) { storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) { // Tell the client we're done sending @@ -34,12 +34,10 @@ int32_t StoreForwardModule::runOnce() } else { this->packetHistoryTXQueue_index++; } - } else { - LOG_WARN("*** Channel utilization is too high. Retrying later.\n"); } LOG_DEBUG("*** SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate); - } else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && (airTime->channelUtilizationPercent() < polite_channel_util_percent)) { + } else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && airTime->isTxAllowedChannelUtil(true)) { lastHeartbeat = millis(); LOG_INFO("*** Sending heartbeat\n"); StoreAndForward sf = StoreAndForward_init_zero; From c0166773e852619adcdb7f56b5dca4cf0238ef98 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Wed, 11 Jan 2023 21:53:23 +0100 Subject: [PATCH 15/16] Portduino can handle this --- src/modules/Telemetry/DeviceTelemetry.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index dda7ab84d..5f96661e5 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -13,7 +13,6 @@ int32_t DeviceTelemetryModule::runOnce() { -#ifndef ARCH_PORTDUINO uint32_t now = millis(); if ((lastSentToMesh == 0 || (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) && @@ -26,7 +25,6 @@ int32_t DeviceTelemetryModule::runOnce() sendTelemetry(NODENUM_BROADCAST, true); } return sendToPhoneIntervalMs; -#endif } bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t) From 440b965e710a6d4475f26c53d6e6ea89f14e2f30 Mon Sep 17 00:00:00 2001 From: thebentern Date: Thu, 12 Jan 2023 01:38:21 +0000 Subject: [PATCH 16/16] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/mesh.pb.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/protobufs b/protobufs index 570cee3f3..e00b5ba7d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 570cee3f31c8a1acfb31e0f3f434bf25b8451a52 +Subproject commit e00b5ba7d06053d820f1123351881fc4fa9270d1 diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 5ff84a223..984ae33ee 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -444,7 +444,7 @@ typedef struct _Waypoint { /* Description of the waypoint - max 100 chars */ char description[100]; /* Designator icon for the waypoint in the form of a unicode emoji */ - uint32_t emoji; + uint32_t icon; } Waypoint; typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; @@ -853,7 +853,7 @@ extern "C" { #define Waypoint_locked_tag 5 #define Waypoint_name_tag 6 #define Waypoint_description_tag 7 -#define Waypoint_emoji_tag 8 +#define Waypoint_icon_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_channel_tag 3 @@ -985,7 +985,7 @@ X(a, STATIC, SINGULAR, UINT32, expire, 4) \ X(a, STATIC, SINGULAR, BOOL, locked, 5) \ X(a, STATIC, SINGULAR, STRING, name, 6) \ X(a, STATIC, SINGULAR, STRING, description, 7) \ -X(a, STATIC, SINGULAR, FIXED32, emoji, 8) +X(a, STATIC, SINGULAR, FIXED32, icon, 8) #define Waypoint_CALLBACK NULL #define Waypoint_DEFAULT NULL