From f5ff77c2b94c5aaea4dc049baefc158fede7dd4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 5 Mar 2024 14:50:52 +0100 Subject: [PATCH 01/94] Turn off certain modules not wanted in custom builds (#3337) --- src/configuration.h | 20 +++++++++++- src/modules/Modules.cpp | 72 ++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index d8b0dba5f..03170c1c7 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -221,4 +221,22 @@ along with this program. If not, see . #ifndef HW_VENDOR #error HW_VENDOR must be defined -#endif \ No newline at end of file +#endif + +// global switch to turn off all optional modules for a minimzed build +#ifdef MESHTASTIC_EXCLUDE_MODULES +#define MESHTASTIC_EXCLUDE_AUDIO 1 +#define MESHTASTIC_EXCLUDE_DETECTIONSENSOR 1 +#define MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR 1 +#define MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION 1 +#define MESHTASTIC_EXCLUDE_PAXCOUNTER 1 +#define MESHTASTIC_EXCLUDE_POWER_TELEMETRY 1 +#define MESHTASTIC_EXCLUDE_RANGETEST 1 +#define MESHTASTIC_EXCLUDE_REMOTEHARDWARE 1 +#define MESHTASTIC_EXCLUDE_STOREFORWARD 1 +#define MESHTASTIC_EXCLUDE_ATAK 1 +#define MESHTASTIC_EXCLUDE_CANNEDMESSAGES 1 +#define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1 +#define MESHTASTIC_EXCLUDE_TRACEROUTE 1 +#define MESHTASTIC_EXCLUDE_WAYPOINT 1 +#endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 2d45868fd..4f0b8f2b0 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -1,74 +1,112 @@ #include "configuration.h" +#if !MESHTASTIC_EXCLUDE_INPUTBROKER #include "input/InputBroker.h" #include "input/RotaryEncoderInterruptImpl1.h" #include "input/TrackballInterruptImpl1.h" #include "input/UpDownInterruptImpl1.h" #include "input/cardKbI2cImpl.h" #include "input/kbMatrixImpl.h" +#endif #include "modules/AdminModule.h" +#if !MESHTASTIC_EXCLUDE_ATAK #include "modules/AtakPluginModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_CANNEDMESSAGES #include "modules/CannedMessageModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR #include "modules/DetectionSensorModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO #include "modules/NeighborInfoModule.h" +#endif #include "modules/NodeInfoModule.h" #include "modules/PositionModule.h" +#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE #include "modules/RemoteHardwareModule.h" +#endif #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" +#if !MESHTASTIC_EXCLUDE_TRACEROUTE #include "modules/TraceRouteModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_WAYPOINT #include "modules/WaypointModule.h" +#endif #if ARCH_PORTDUINO #include "input/LinuxInputImpl.h" #endif #if HAS_TELEMETRY #include "modules/Telemetry/DeviceTelemetry.h" #endif -#if HAS_SENSOR +#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR #include "modules/Telemetry/AirQualityTelemetry.h" #include "modules/Telemetry/EnvironmentTelemetry.h" #endif -#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY #include "modules/Telemetry/PowerTelemetry.h" #endif #ifdef ARCH_ESP32 -#ifdef USE_SX1280 +#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO #include "modules/esp32/AudioModule.h" #endif +#if !MESHTASTIC_EXCLUDE_PAXCOUNTER #include "modules/esp32/PaxcounterModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_STOREFORWARD #include "modules/esp32/StoreForwardModule.h" #endif +#endif #if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) +#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION #include "modules/ExternalNotificationModule.h" +#endif +#if !MESHTASTIC_EXCLUDE_RANGETEST #include "modules/RangeTestModule.h" +#endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) +#if !MESHTASTIC_EXCLUDE_SERIAL #include "modules/SerialModule.h" #endif #endif +#endif /** * Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else) */ void setupModules() { if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { -#if HAS_BUTTON || ARCH_PORTDUINO +#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER inputBroker = new InputBroker(); #endif adminModule = new AdminModule(); nodeInfoModule = new NodeInfoModule(); positionModule = new PositionModule(); +#if !MESHTASTIC_EXCLUDE_WAYPOINT waypointModule = new WaypointModule(); +#endif textMessageModule = new TextMessageModule(); +#if !MESHTASTIC_EXCLUDE_TRACEROUTE traceRouteModule = new TraceRouteModule(); +#endif +#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO neighborInfoModule = new NeighborInfoModule(); +#endif +#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR detectionSensorModule = new DetectionSensorModule(); +#endif +#if !MESHTASTIC_EXCLUDE_ATAK atakPluginModule = new AtakPluginModule(); +#endif // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // to a global variable. +#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE new RemoteHardwareModule(); +#endif // Example: Put your module here // new ReplyModule(); -#if HAS_BUTTON || ARCH_PORTDUINO +#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); if (!rotaryEncoderInterruptImpl1->init()) { delete rotaryEncoderInterruptImpl1; @@ -90,47 +128,59 @@ void setupModules() aLinuxInputImpl = new LinuxInputImpl(); aLinuxInputImpl->init(); #endif -#if HAS_TRACKBALL +#if HAS_TRACKBALL && !MESHTASTIC_EXCLUDE_INPUTBROKER trackballInterruptImpl1 = new TrackballInterruptImpl1(); trackballInterruptImpl1->init(); #endif -#if HAS_SCREEN +#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES cannedMessageModule = new CannedMessageModule(); #endif -#if HAS_TELEMETRY +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) new DeviceTelemetryModule(); #endif -#if HAS_SENSOR +#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR new EnvironmentTelemetryModule(); if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) { new AirQualityTelemetryModule(); } #endif -#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY new PowerTelemetryModule(); #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \ !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !MESHTASTIC_EXCLUDE_SERIAL new SerialModule(); #endif +#endif #ifdef ARCH_ESP32 // Only run on an esp32 based device. -#ifdef USE_SX1280 +#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO audioModule = new AudioModule(); #endif +#if !MESHTASTIC_EXCLUDE_STOREFORWARD storeForwardModule = new StoreForwardModule(); +#endif +#if !MESHTASTIC_EXCLUDE_PAXCOUNTER paxcounterModule = new PaxcounterModule(); #endif +#endif #if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) +#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION externalNotificationModule = new ExternalNotificationModule(); +#endif +#if !MESHTASTIC_EXCLUDE_RANGETEST new RangeTestModule(); +#endif #endif } else { adminModule = new AdminModule(); #if HAS_TELEMETRY new DeviceTelemetryModule(); #endif +#if !MESHTASTIC_EXCLUDE_TRACEROUTE traceRouteModule = new TraceRouteModule(); +#endif } // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks From 9d37a8d17fcebfee819986b69104e820ba521994 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 6 Mar 2024 13:09:46 -0600 Subject: [PATCH 02/94] Stop Fiddling with Newlines! (#3341) --- .vscode/settings.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 03922dc72..e86d31c7d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { "editor.formatOnSave": true, "editor.defaultFormatter": "trunk.io", - "trunk.enableWindows": true + "trunk.enableWindows": true, + "files.insertFinalNewline": false, + "files.trimFinalNewlines": false } From e174328de36bc9a989986cf7a1d8b59802ec5e29 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 6 Mar 2024 16:23:04 -0600 Subject: [PATCH 03/94] Native Webserver (#3343) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added WebServer/WebServices for Native Linux Meshtastic and web gui * Fix bug in login functionality * Added customized config of portdunio.ini with LovyannGFX from marelab repro * Compile Problem resolved with developer version of LovyanGFX.git * Compile against dev version * Fixes to fit into main branch * Update variant.h, main.cpp, .gitignore, WebServer.cpp, esp32s2.ini, WebServer.h, ContentHandler.cpp, rp2040.ini, nrf52.ini, ContentHelper.cpp, Dockerfile, ContentHandler.h, esp32.ini, stm32wl5e.ini * Added linux pi std /usr/include dir * Adding /usr/innclude for Linux compile against native libs that are not hadled by platformio * Review log level changes & translation * Update Dockerfile * Fix Typo & VFS ref. Part1 * Fix Typo & VFS ref. * Dev Version for ulfius web lib * Update platformio.ini * Free VFS path string * Remove unintended changes * More unintentional changes * Make the HTTP server optional on native * Tune-up for Native web defaults * Don't modify build system yet * Remove more unneeded changes --------- Co-authored-by: marc hammermann Co-authored-by: Ben Meadors Co-authored-by: Thomas Göttgens --- .gitignore | 2 + arch/esp32/esp32.ini | 2 +- arch/esp32/esp32s2.ini | 5 +- arch/nrf52/nrf52.ini | 2 +- arch/portduino/portduino.ini | 1 + arch/rp2040/rp2040.ini | 2 +- arch/stm32/stm32wl5e.ini | 2 +- bin/config-dist.yaml | 4 + src/main.cpp | 6 + src/mesh/raspihttp/PiWebServer.cpp | 530 +++++++++++++++++++++++ src/mesh/raspihttp/PiWebServer.h | 61 +++ src/platform/portduino/PortduinoGlue.cpp | 5 + src/platform/portduino/PortduinoGlue.h | 5 +- variants/portduino/platformio.ini | 8 +- 14 files changed, 625 insertions(+), 10 deletions(-) create mode 100644 src/mesh/raspihttp/PiWebServer.cpp create mode 100644 src/mesh/raspihttp/PiWebServer.h diff --git a/.gitignore b/.gitignore index 89f8ee065..0f2202f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ venv/ release/ .vscode/extensions.json /compile_commands.json +src/mesh/raspihttp/certificate.pem +src/mesh/raspihttp/private_key.pem \ No newline at end of file diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index bf84dd939..39935b849 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -4,7 +4,7 @@ extends = arduino_base platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch. build_src_filter = - ${arduino_base.build_src_filter} - - - - + ${arduino_base.build_src_filter} - - - - - upload_speed = 921600 debug_init_break = tbreak setup diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini index 3bde3465a..5de0fa549 100644 --- a/arch/esp32/esp32s2.ini +++ b/arch/esp32/esp32s2.ini @@ -2,7 +2,7 @@ extends = esp32_base build_src_filter = - ${esp32_base.build_src_filter} - + ${esp32_base.build_src_filter} - - monitor_speed = 115200 @@ -12,5 +12,4 @@ build_flags = lib_ignore = ${esp32_base.lib_ignore} - NimBLE-Arduino - + NimBLE-Arduino \ No newline at end of file diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 04ca89a54..5155eaadc 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -11,7 +11,7 @@ build_flags = -Isrc/platform/nrf52 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - lib_deps= ${arduino_base.lib_deps} diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 0dcc9afc2..368fb5d0e 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -12,6 +12,7 @@ build_src_filter = - - - + + - - - diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index 48fe0dae6..edc4373ad 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 diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index 4483ff526..4d74ade8f 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -13,7 +13,7 @@ build_flags = -DVECT_TAB_OFFSET=0x08000000 build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - - - board_upload.offset_address = 0x08000000 upload_protocol = stlink diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index b5b105e4c..a241a929a 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -117,3 +117,7 @@ Input: Logging: LogLevel: info # debug, info, warn, error + +Webserver: +# Port: 443 # Port for Webserver & Webservices +# RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer diff --git a/src/main.cpp b/src/main.cpp index fbfb983d2..3619b0053 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,6 +68,7 @@ NRF52Bluetooth *nrf52Bluetooth; #ifdef ARCH_PORTDUINO #include "linux/LinuxHardwareI2C.h" +#include "mesh/raspihttp/PiWebServer.h" #include "platform/portduino/PortduinoGlue.h" #include #include @@ -857,6 +858,11 @@ void setup() #endif #ifdef ARCH_PORTDUINO +#if __has_include() + if (settingsMap[webserverport] != -1) { + piwebServerThread = new PiWebServerThread(); + } +#endif initApiServer(TCPPort); #endif diff --git a/src/mesh/raspihttp/PiWebServer.cpp b/src/mesh/raspihttp/PiWebServer.cpp new file mode 100644 index 000000000..41f6727a4 --- /dev/null +++ b/src/mesh/raspihttp/PiWebServer.cpp @@ -0,0 +1,530 @@ +/* +Adds a WebServer and WebService callbacks to meshtastic as Linux Version. The WebServer & Webservices +runs in a real linux thread beside the portdunio threading emulation. It replaces the complete ESP32 +Webserver libs including generation of SSL certifcicates, because the use ESP specific details in +the lib that can't be emulated. + +The WebServices adapt to the two major phoneapi functions "handleAPIv1FromRadio,handleAPIv1ToRadio" +The WebServer just adds basaic support to deliver WebContent, so it can be used to +deliver the WebGui definded by the WebClient Project. + +Steps to get it running: +1.) Add these Linux Libs to the compile and target machine: + + sudo apt update && \ + apt -y install openssl libssl-dev libopenssl libsdl2-dev \ + libulfius-dev liborcania-dev + +2.) Configure the root directory of the web Content in the config.yaml file. + The followinng tags should be included and set at your needs + + Example entry in the config.yaml + Webserver: + Port: 9001 # Port for Webserver & Webservices + RootPath: /home/marc/web # Root Dir of WebServer + +3.) Checkout the web project + https://github.com/meshtastic/web.git + + Build it and copy the content of the folder web/dist/* to the folder you did set as "RootPath" + +!!!The WebServer should not be used as production system or exposed to the Internet. Its a raw basic version!!! + +Author: Marc Philipp Hammermann +mail: marchammermann@googlemail.com + +*/ +#ifdef PORTDUINO_LINUX_HARDWARE +#if __has_include() +#include "PiWebServer.h" +#include "NodeDB.h" +#include "PhoneAPI.h" +#include "PowerFSM.h" +#include "RadioLibInterface.h" +#include "airtime.h" +#include "graphics/Screen.h" +#include "main.h" +#include "mesh/wifi/WiFiAPClient.h" +#include "sleep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PortduinoFS.h" +#include "platform/portduino/PortduinoGlue.h" + +#define DEFAULT_REALM "default_realm" +#define PREFIX "" + +struct _file_config configWeb; + +// We need to specify some content-type mapping, so the resources get delivered with the +// right content type and are displayed correctly in the browser +char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}, + {".js", "text/javascript"}, {".png", "image/png"}, + {".jpg", "image/jpg"}, {".gz", "application/gzip"}, + {".gif", "image/gif"}, {".json", "application/json"}, + {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, + {".svg", "image/svg+xml"}, {".ts", "text/javascript"}, + {".tsx", "text/javascript"}, {"", ""}}; + +#undef str + +volatile bool isWebServerReady; +volatile bool isCertReady; + +HttpAPI webAPI; + +PiWebServerThread *piwebServerThread; + +/** + * Return the filename extension + */ +const char *get_filename_ext(const char *path) +{ + const char *dot = strrchr(path, '.'); + if (!dot || dot == path) + return "*"; + if (strchr(dot, '?') != NULL) { + //*strchr(dot, '?') = '\0'; + const char *empty = "\0"; + return empty; + } + return dot; +} + +/** + * Streaming callback function to ease sending large files + */ +static ssize_t callback_static_file_stream(void *cls, uint64_t pos, char *buf, size_t max) +{ + (void)(pos); + if (cls != NULL) { + return fread(buf, 1, max, (FILE *)cls); + } else { + return U_STREAM_END; + } +} + +/** + * Cleanup FILE* structure when streaming is complete + */ +static void callback_static_file_stream_free(void *cls) +{ + if (cls != NULL) { + fclose((FILE *)cls); + } +} + +/** + * static file callback endpoint that delivers the content for WebServer calls + */ +int callback_static_file(const struct _u_request *request, struct _u_response *response, void *user_data) +{ + size_t length; + FILE *f; + char *file_requested, *file_path, *url_dup_save, *real_path = NULL; + const char *content_type; + + /* + * Comment this if statement if you don't access static files url from root dir, like /app + */ + if (request->callback_position > 0) { + return U_CALLBACK_CONTINUE; + } else if (user_data != NULL && (configWeb.files_path != NULL)) { + file_requested = o_strdup(request->http_url); + url_dup_save = file_requested; + + while (file_requested[0] == '/') { + file_requested++; + } + file_requested += o_strlen(configWeb.url_prefix); + while (file_requested[0] == '/') { + file_requested++; + } + + if (strchr(file_requested, '#') != NULL) { + *strchr(file_requested, '#') = '\0'; + } + + if (strchr(file_requested, '?') != NULL) { + *strchr(file_requested, '?') = '\0'; + } + + if (file_requested == NULL || o_strlen(file_requested) == 0 || 0 == o_strcmp("/", file_requested)) { + o_free(url_dup_save); + url_dup_save = file_requested = o_strdup("index.html"); + } + + file_path = msprintf("%s/%s", configWeb.files_path, file_requested); + real_path = realpath(file_path, NULL); + if (0 == o_strncmp(configWeb.files_path, real_path, o_strlen(configWeb.files_path))) { + if (access(file_path, F_OK) != -1) { + f = fopen(file_path, "rb"); + if (f) { + fseek(f, 0, SEEK_END); + length = ftell(f); + fseek(f, 0, SEEK_SET); + + content_type = u_map_get_case(&configWeb.mime_types, get_filename_ext(file_requested)); + if (content_type == NULL) { + content_type = u_map_get(&configWeb.mime_types, "*"); + LOG_DEBUG("Static File Server - Unknown mime type for extension %s \n", get_filename_ext(file_requested)); + } + u_map_put(response->map_header, "Content-Type", content_type); + u_map_copy_into(response->map_header, &configWeb.map_header); + + if (ulfius_set_stream_response(response, 200, callback_static_file_stream, callback_static_file_stream_free, + length, STATIC_FILE_CHUNK, f) != U_OK) { + LOG_DEBUG("callback_static_file - Error ulfius_set_stream_response\n "); + } + } + } else { + if (configWeb.redirect_on_404 == NULL) { + ulfius_set_string_body_response(response, 404, "File not found"); + } else { + ulfius_add_header_to_response(response, "Location", configWeb.redirect_on_404); + response->status = 302; + } + } + } else { + if (configWeb.redirect_on_404 == NULL) { + ulfius_set_string_body_response(response, 404, "File not found"); + } else { + ulfius_add_header_to_response(response, "Location", configWeb.redirect_on_404); + response->status = 302; + } + } + + o_free(file_path); + o_free(url_dup_save); + free(real_path); // realpath uses malloc + return U_CALLBACK_CONTINUE; + } else { + LOG_DEBUG("Static File Server - Error, user_data is NULL or inconsistent\n"); + return U_CALLBACK_ERROR; + } +} + +static void handleWebResponse() {} + +/* + * Adapt the radioapi to the Webservice handleAPIv1ToRadio + * Trigger : WebGui(SAVE)->WebServcice->phoneApi + */ +int handleAPIv1ToRadio(const struct _u_request *req, struct _u_response *res, void *user_data) +{ + LOG_DEBUG("handleAPIv1ToRadio web -> radio \n"); + + ulfius_add_header_to_response(res, "Content-Type", "application/x-protobuf"); + ulfius_add_header_to_response(res, "Access-Control-Allow-Headers", "Content-Type"); + ulfius_add_header_to_response(res, "Access-Control-Allow-Origin", "*"); + ulfius_add_header_to_response(res, "Access-Control-Allow-Methods", "PUT, OPTIONS"); + ulfius_add_header_to_response(res, "X-Protobuf-Schema", + "https://raw.githubusercontent.com/meshtastic/protobufs/master/mesh.proto"); + + if (req->http_verb == "OPTIONS") { + ulfius_set_response_properties(res, U_OPT_STATUS, 204); + return U_CALLBACK_CONTINUE; + } + + byte buffer[MAX_TO_FROM_RADIO_SIZE]; + size_t s = req->binary_body_length; + + memcpy(buffer, req->binary_body, MAX_TO_FROM_RADIO_SIZE); + + // FIXME* Problem with portdunio loosing mountpoint maybe because of running in a real sep. thread + + portduinoVFS->mountpoint("/home/marc/.portduino/default"); + + LOG_DEBUG("Received %d bytes from PUT request\n", s); + webAPI.handleToRadio(buffer, s); + LOG_DEBUG("end web->radio \n"); + return U_CALLBACK_COMPLETE; +} + +/* + * Adapt the radioapi to the Webservice handleAPIv1FromRadio + * Trigger : WebGui(POLL)->handleAPIv1FromRadio->phoneapi->Meshtastic(Radio) events + */ +int handleAPIv1FromRadio(const struct _u_request *req, struct _u_response *res, void *user_data) +{ + + // LOG_DEBUG("handleAPIv1FromRadio radio -> web\n"); + std::string valueAll; + + // Status code is 200 OK by default. + ulfius_add_header_to_response(res, "Content-Type", "application/x-protobuf"); + ulfius_add_header_to_response(res, "Access-Control-Allow-Origin", "*"); + ulfius_add_header_to_response(res, "Access-Control-Allow-Methods", "GET"); + ulfius_add_header_to_response(res, "X-Protobuf-Schema", + "https://raw.githubusercontent.com/meshtastic/protobufs/master/mesh.proto"); + + uint8_t txBuf[MAX_STREAM_BUF_SIZE]; + uint32_t len = 1; + + if (valueAll == "true") { + while (len) { + len = webAPI.getFromRadio(txBuf); + ulfius_set_response_properties(res, U_OPT_STATUS, 200, U_OPT_BINARY_BODY, txBuf, len); + const char *tmpa = (const char *)txBuf; + ulfius_set_string_body_response(res, 200, tmpa); + // LOG_DEBUG("\n----webAPI response all:----\n"); + LOG_DEBUG(tmpa); + LOG_DEBUG("\n"); + } + // Otherwise, just return one protobuf + } else { + len = webAPI.getFromRadio(txBuf); + const char *tmpa = (const char *)txBuf; + ulfius_set_binary_body_response(res, 200, tmpa, len); + // LOG_DEBUG("\n----webAPI response:\n"); + LOG_DEBUG(tmpa); + LOG_DEBUG("\n"); + } + + // LOG_DEBUG("end radio->web\n", len); + return U_CALLBACK_COMPLETE; +} + +/* +OpenSSL RSA Key Gen +*/ +int generate_rsa_key(EVP_PKEY **pkey) +{ + EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!pkey_ctx) + return -1; + if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) + return -1; + if (EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, 2048) <= 0) + return -1; + if (EVP_PKEY_keygen(pkey_ctx, pkey) <= 0) + return -1; + EVP_PKEY_CTX_free(pkey_ctx); + return 0; // SUCCESS +} + +int generate_self_signed_x509(EVP_PKEY *pkey, X509 **x509) +{ + *x509 = X509_new(); + if (!*x509) + return -1; + if (X509_set_version(*x509, 2) != 1) + return -1; + ASN1_INTEGER_set(X509_get_serialNumber(*x509), 1); + X509_gmtime_adj(X509_get_notBefore(*x509), 0); + X509_gmtime_adj(X509_get_notAfter(*x509), 31536000L); // 1 YEAR ACCESS + + X509_set_pubkey(*x509, pkey); + + // SET Subject Name + X509_NAME *name = X509_get_subject_name(*x509); + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"DE", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Meshtastic", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"meshtastic.local", -1, -1, 0); + // Selfsigned, Issuer = Subject + X509_set_issuer_name(*x509, name); + + // Certificate signed with our privte key + if (X509_sign(*x509, pkey, EVP_sha256()) <= 0) + return -1; + + return 0; +} + +char *read_file_into_string(const char *filename) +{ + FILE *file = fopen(filename, "rb"); + if (file == NULL) { + LOG_ERROR("Error reading File : %s \n", filename); + return NULL; + } + + // Size of file + fseek(file, 0, SEEK_END); + long filesize = ftell(file); + rewind(file); + + // reserve mem for file + 1 byte + char *buffer = (char *)malloc(filesize + 1); + if (buffer == NULL) { + LOG_ERROR("Malloc of mem failed for file : %s \n", filename); + fclose(file); + return NULL; + } + + // read content + size_t readSize = fread(buffer, 1, filesize, file); + if (readSize != filesize) { + LOG_ERROR("Error reading file into buffer\n"); + free(buffer); + fclose(file); + return NULL; + } + + // add terminator sign at the end + buffer[filesize] = '\0'; + fclose(file); + return buffer; // return pointer +} + +int PiWebServerThread::CheckSSLandLoad() +{ + // read certificate + cert_pem = read_file_into_string("certificate.pem"); + if (cert_pem == NULL) { + LOG_ERROR("ERROR SSL Certificate File can't be loaded or is missing\n"); + return 1; + } + // read private key + key_pem = read_file_into_string("private_key.pem"); + if (key_pem == NULL) { + LOG_ERROR("ERROR file private_key can't be loaded or is missing\n"); + return 2; + } + + return 0; +} + +int PiWebServerThread::CreateSSLCertificate() +{ + + EVP_PKEY *pkey = NULL; + X509 *x509 = NULL; + + if (generate_rsa_key(&pkey) != 0) { + LOG_ERROR("Error generating RSA-Key.\n"); + return 1; + } + + if (generate_self_signed_x509(pkey, &x509) != 0) { + LOG_ERROR("Error generating of X509-Certificat.\n"); + return 2; + } + + // Ope file to write private key file + FILE *pkey_file = fopen("private_key.pem", "wb"); + if (!pkey_file) { + LOG_ERROR("Error opening private key file.\n"); + return 3; + } + // write private key file + PEM_write_PrivateKey(pkey_file, pkey, NULL, NULL, 0, NULL, NULL); + fclose(pkey_file); + + // open Certificate file + FILE *x509_file = fopen("certificate.pem", "wb"); + if (!x509_file) { + LOG_ERROR("Error opening certificate.\n"); + return 4; + } + // write cirtificate + PEM_write_X509(x509_file, x509); + fclose(x509_file); + + EVP_PKEY_free(pkey); + X509_free(x509); + LOG_INFO("Create SSL Certifictate -certificate.pem- succesfull \n"); + return 0; +} + +void initWebServer() {} + +PiWebServerThread::PiWebServerThread() +{ + int ret, retssl, webservport; + + if (CheckSSLandLoad() != 0) { + CreateSSLCertificate(); + if (CheckSSLandLoad() != 0) { + LOG_ERROR("Major Error Gen & Read SSL Certificate\n"); + } + } + + if (settingsMap[webserverport] != 0) { + webservport = settingsMap[webserverport]; + LOG_INFO("Using webserver port from yaml config. %i \n", webservport); + } else { + LOG_INFO("Webserver port in yaml config set to 0, so defaulting to port 443.\n"); + webservport = 443; + } + + // Web Content Service Instance + if (ulfius_init_instance(&instanceWeb, webservport, NULL, DEFAULT_REALM) != U_OK) { + LOG_ERROR("Webserver couldn't be started, abort execution\n"); + } else { + + LOG_INFO("Webserver started ....\n"); + u_map_init(&configWeb.mime_types); + u_map_put(&configWeb.mime_types, "*", "application/octet-stream"); + u_map_put(&configWeb.mime_types, ".html", "text/html"); + u_map_put(&configWeb.mime_types, ".htm", "text/html"); + u_map_put(&configWeb.mime_types, ".tsx", "application/javascript"); + u_map_put(&configWeb.mime_types, ".ts", "application/javascript"); + u_map_put(&configWeb.mime_types, ".css", "text/css"); + u_map_put(&configWeb.mime_types, ".js", "application/javascript"); + u_map_put(&configWeb.mime_types, ".json", "application/json"); + u_map_put(&configWeb.mime_types, ".png", "image/png"); + u_map_put(&configWeb.mime_types, ".gif", "image/gif"); + u_map_put(&configWeb.mime_types, ".jpeg", "image/jpeg"); + u_map_put(&configWeb.mime_types, ".jpg", "image/jpeg"); + u_map_put(&configWeb.mime_types, ".ttf", "font/ttf"); + u_map_put(&configWeb.mime_types, ".woff", "font/woff"); + u_map_put(&configWeb.mime_types, ".ico", "image/x-icon"); + u_map_put(&configWeb.mime_types, ".svg", "image/svg+xml"); + + webrootpath = settingsStrings[webserverrootpath]; + + configWeb.files_path = (char *)webrootpath.c_str(); + configWeb.url_prefix = ""; + configWeb.rootPath = strdup(portduinoVFS->mountpoint()); + + u_map_put(instanceWeb.default_headers, "Access-Control-Allow-Origin", "*"); + // Maximum body size sent by the client is 1 Kb + instanceWeb.max_post_body_size = 1024; + ulfius_add_endpoint_by_val(&instanceWeb, "GET", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL); + ulfius_add_endpoint_by_val(&instanceWeb, "PUT", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, configWeb.rootPath); + + // Add callback function to all endpoints for the Web Server + ulfius_add_endpoint_by_val(&instanceWeb, "GET", NULL, "/*", 2, &callback_static_file, &configWeb); + + // thats for serving without SSL + // retssl = ulfius_start_framework(&instanceWeb); + + // thats for serving with SSL + retssl = ulfius_start_secure_framework(&instanceWeb, key_pem, cert_pem); + + if (retssl == U_OK) { + LOG_INFO("Web Server framework started on port: %i \n", webservport); + LOG_INFO("Web Server root %s\n", (char *)webrootpath.c_str()); + } else { + LOG_ERROR("Error starting Web Server framework\n"); + } + } +} + +PiWebServerThread::~PiWebServerThread() +{ + u_map_clean(&configWeb.mime_types); + + ulfius_stop_framework(&instanceWeb); + ulfius_stop_framework(&instanceWeb); + free(configWeb.rootPath); + ulfius_clean_instance(&instanceService); + ulfius_clean_instance(&instanceService); + free(cert_pem); + LOG_INFO("End framework"); +} + +#endif +#endif \ No newline at end of file diff --git a/src/mesh/raspihttp/PiWebServer.h b/src/mesh/raspihttp/PiWebServer.h new file mode 100644 index 000000000..c4c49e919 --- /dev/null +++ b/src/mesh/raspihttp/PiWebServer.h @@ -0,0 +1,61 @@ +#pragma once +#ifdef PORTDUINO_LINUX_HARDWARE +#if __has_include() +#include "PhoneAPI.h" +#include "ulfius-cfg.h" +#include "ulfius.h" +#include +#include + +#define STATIC_FILE_CHUNK 256 + +void initWebServer(); +void createSSLCert(); +int callback_static_file(const struct _u_request *request, struct _u_response *response, void *user_data); +const char *get_filename_ext(const char *path); + +struct _file_config { + char *files_path; + char *url_prefix; + struct _u_map mime_types; + struct _u_map map_header; + char *redirect_on_404; + char *rootPath; +}; + +class PiWebServerThread +{ + private: + char *key_pem = NULL; + char *cert_pem = NULL; + // struct _u_map mime_types; + std::string webrootpath; + + public: + PiWebServerThread(); + ~PiWebServerThread(); + int CreateSSLCertificate(); + int CheckSSLandLoad(); + uint32_t requestRestart = 0; + struct _u_instance instanceWeb; + struct _u_instance instanceService; +}; + +class HttpAPI : public PhoneAPI +{ + + public: + // Nothing here yet + + private: + // Nothing here yet + + protected: + /// Check the current underlying physical link to see if the client is currently connected + virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this +}; + +extern PiWebServerThread *piwebServerThread; + +#endif +#endif \ No newline at end of file diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 046509fab..997058406 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -195,6 +195,11 @@ void portduinoSetup() settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as(""); } + if (yamlConfig["Webserver"]) { + settingsMap[webserverport] = (yamlConfig["Webserver"]["Port"]).as(-1); + settingsStrings[webserverrootpath] = (yamlConfig["Webserver"]["RootPath"]).as(""); + } + } catch (YAML::Exception e) { std::cout << "*** Exception " << e.what() << std::endl; exit(EXIT_FAILURE); diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index f8da20e37..3fe5f74bf 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -33,7 +33,10 @@ enum configNames { displayOffsetY, displayInvert, keyboardDevice, - logoutputlevel + logoutputlevel, + webserver, + webserverport, + webserverrootpath }; enum { no_screen, st7789, st7735, st7735s, ili9341 }; enum { no_touchscreen, xpt2046, stmpe610 }; diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini index d37c6be21..46417e388 100644 --- a/variants/portduino/platformio.ini +++ b/variants/portduino/platformio.ini @@ -1,6 +1,10 @@ [env:native] extends = portduino_base -build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino +; The pkg-config commands below optionally add link flags. +; the || : is just a "or run the null command" to avoid returning an error code +build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino -I /usr/include + !pkg-config --libs libulfius --silence-errors || : + !pkg-config --libs openssl --silence-errors || : board = cross_platform lib_deps = ${portduino_base.lib_deps} -build_src_filter = ${portduino_base.build_src_filter} \ No newline at end of file +build_src_filter = ${portduino_base.build_src_filter} From 46ad6237859e60eb1e54b3bb5c69baa895d95c3b Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 6 Mar 2024 17:00:23 -0600 Subject: [PATCH 04/94] Add webroot to .deb --- .github/workflows/package_raspbian.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index 2f9a99e58..ee1643fbf 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -23,6 +23,14 @@ jobs: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} + - name: Pull web ui + uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4 + with: + repo: meshtastic/web + file: build.tar + target: build.tar + token: ${{ secrets.GITHUB_TOKEN }} + - name: Get release version string run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT id: version @@ -37,9 +45,12 @@ jobs: - name: build .debpkg run: | + mkdir -p .debpkg/usr/share/doc/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/usr/lib/systemd/system/ + tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml chmod +x .debpkg/usr/sbin/meshtasticd From bfce3938d24b7190ec78e2faf64041b916550139 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 6 Mar 2024 18:54:09 -0600 Subject: [PATCH 05/94] Add openssl as dependency to meshtasticd .deb --- .github/workflows/package_raspbian.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index ee1643fbf..377074e95 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -63,7 +63,7 @@ jobs: maintainer: Jonathan Bennett version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.* arch: arm64 - depends: libyaml-cpp0.7 + depends: libyaml-cpp0.7, openssl desc: Native Linux Meshtastic binary. - uses: actions/upload-artifact@v3 From 2dd751e3391e9c676f78e7b329a0cdccb03f3c40 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 07:06:47 -0600 Subject: [PATCH 06/94] [create-pull-request] automated change (#3346) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/portnums.pb.h | 10 +++++----- src/mesh/generated/meshtastic/telemetry.pb.h | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index 62b7d8b88..5a97acb17 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 62b7d8b884d70aed5ff18c3b0e228095eeb48de2 +Subproject commit 5a97acb17543a10e114675a205e3274a83e721af diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 88342e5dc..3f3e9aaee 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -38,19 +38,19 @@ typedef enum _meshtastic_PortNum { ENCODING: Protobuf */ meshtastic_PortNum_REMOTE_HARDWARE_APP = 2, /* The built-in position messaging app. - Payload is a [Position](/docs/developers/protobufs/api#position) message + Payload is a Position message. ENCODING: Protobuf */ meshtastic_PortNum_POSITION_APP = 3, /* The built-in user info app. - Payload is a [User](/docs/developers/protobufs/api#user) message + Payload is a User message. ENCODING: Protobuf */ meshtastic_PortNum_NODEINFO_APP = 4, /* Protocol control packets for mesh protocol use. - Payload is a [Routing](/docs/developers/protobufs/api#routing) message + Payload is a Routing message. ENCODING: Protobuf */ meshtastic_PortNum_ROUTING_APP = 5, /* Admin control packets. - Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message + Payload is a AdminMessage message. ENCODING: Protobuf */ meshtastic_PortNum_ADMIN_APP = 6, /* Compressed TEXT_MESSAGE payloads. @@ -60,7 +60,7 @@ typedef enum _meshtastic_PortNum { any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. */ meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7, /* Waypoint payloads. - Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message + Payload is a Waypoint message. ENCODING: Protobuf */ meshtastic_PortNum_WAYPOINT_APP = 8, /* Audio Payloads. diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index fc2780a96..d73c6baa1 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -41,7 +41,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* PM2.5 air quality sensor */ meshtastic_TelemetrySensorType_PMSA003I = 13, /* INA3221 3 Channel Voltage / Current Sensor */ - meshtastic_TelemetrySensorType_INA3221 = 14 + meshtastic_TelemetrySensorType_INA3221 = 14, + /* BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280) */ + meshtastic_TelemetrySensorType_BMP085 = 15 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -141,8 +143,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA3221 -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA3221+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_BMP085 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_BMP085+1)) From c860493e68112d83f5c3707bd4bc4401d8d681de Mon Sep 17 00:00:00 2001 From: Steven Osborn Date: Thu, 7 Mar 2024 05:11:25 -0800 Subject: [PATCH 07/94] Add delay so GPS and Radio have time to power up (#3334) * Add delay so GPS and Radio have time to power up * reduce the delay a bit * make delay more generic / configurable * remove whitespace changes --- boards/canaryone.json | 2 +- src/main.cpp | 5 +++++ variants/canaryone/variant.h | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/boards/canaryone.json b/boards/canaryone.json index d8f966a47..da7c0986f 100644 --- a/boards/canaryone.json +++ b/boards/canaryone.json @@ -7,7 +7,7 @@ "cpu": "cortex-m4", "extra_flags": "-DARDUINO_NRF52840_CANARY -DNRF52840_XXAA", "f_cpu": "64000000L", - "hwids": [["0x239A", "0x4405"]], + "hwids": [["0x239A", "0x4405"], ["0x239A", "0x009F"]], "usb_product": "CanaryOne", "mcu": "nrf52840", "variant": "canaryone", diff --git a/src/main.cpp b/src/main.cpp index 3619b0053..80706d044 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -680,6 +680,11 @@ void setup() digitalWrite(SX126X_ANT_SW, 1); #endif +#ifdef PIN_PWR_DELAY_MS + // This may be required to give the peripherals time to power up. + delay(PIN_PWR_DELAY_MS); +#endif + #ifdef ARCH_PORTDUINO if (settingsMap[use_sx1262]) { if (!rIf) { diff --git a/variants/canaryone/variant.h b/variants/canaryone/variant.h index e31ba3c58..21aa921ce 100644 --- a/variants/canaryone/variant.h +++ b/variants/canaryone/variant.h @@ -103,6 +103,9 @@ static const uint8_t A0 = PIN_A0; #define EXTERNAL_FLASH_DEVICES MX25R1635F #define EXTERNAL_FLASH_USE_QSPI +// Add a delay on startup to allow LoRa and GPS to power up +#define PIN_PWR_DELAY_MS 100 + /* * Lora radio */ From b4940b476daa6817d990f8a019bda741589c76ed Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 7 Mar 2024 15:51:28 -0600 Subject: [PATCH 08/94] Trunk --- boards/canaryone.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/boards/canaryone.json b/boards/canaryone.json index da7c0986f..f64a4a7c7 100644 --- a/boards/canaryone.json +++ b/boards/canaryone.json @@ -7,7 +7,10 @@ "cpu": "cortex-m4", "extra_flags": "-DARDUINO_NRF52840_CANARY -DNRF52840_XXAA", "f_cpu": "64000000L", - "hwids": [["0x239A", "0x4405"], ["0x239A", "0x009F"]], + "hwids": [ + ["0x239A", "0x4405"], + ["0x239A", "0x009F"] + ], "usb_product": "CanaryOne", "mcu": "nrf52840", "variant": "canaryone", From 7f1250571679131424952f01a0e44e489a332793 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 7 Mar 2024 15:52:08 -0600 Subject: [PATCH 09/94] Update trunk --- .trunk/trunk.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index af7d3d21d..0826b71d9 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -4,19 +4,19 @@ cli: plugins: sources: - id: trunk - ref: v1.4.3 + ref: v1.4.4 uri: https://github.com/trunk-io/plugins lint: enabled: - - trufflehog@3.68.2 + - trufflehog@3.68.5 - yamllint@1.35.1 - bandit@1.7.7 - - checkov@3.2.26 - - terrascan@1.18.11 + - checkov@3.2.32 + - terrascan@1.19.1 - trivy@0.49.1 #- trufflehog@3.63.2-rc0 - taplo@0.8.1 - - ruff@0.2.2 + - ruff@0.3.1 - isort@5.13.2 - markdownlint@0.39.0 - oxipng@9.0.0 From 763ae9f2e2e7db779c80021474162a212fa409e8 Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Sat, 2 Mar 2024 22:14:34 +0100 Subject: [PATCH 10/94] add BMP085 (and BMP180) sensor (temperature and air pressure) --- platformio.ini | 1 + src/detect/ScanI2C.h | 1 + src/detect/ScanI2CTwoWire.cpp | 4 +++ src/main.cpp | 1 + .../Telemetry/EnvironmentTelemetry.cpp | 6 ++++ src/modules/Telemetry/Sensor/BMP085Sensor.cpp | 31 +++++++++++++++++++ src/modules/Telemetry/Sensor/BMP085Sensor.h | 17 ++++++++++ 7 files changed, 61 insertions(+) create mode 100644 src/modules/Telemetry/Sensor/BMP085Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/BMP085Sensor.h diff --git a/platformio.ini b/platformio.ini index 0033b6e46..b67ddc50a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -116,6 +116,7 @@ lib_deps = adafruit/Adafruit BusIO@^1.11.4 adafruit/Adafruit Unified Sensor@^1.1.11 adafruit/Adafruit BMP280 Library@^2.6.8 + adafruit/Adafruit BMP085 Library@^1.2.4 adafruit/Adafruit BME280 Library@^2.2.2 https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400 boschsensortec/BME68x Sensor Library@^1.1.40407 diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 2b4b8a735..66e683982 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -23,6 +23,7 @@ class ScanI2C BME_680, BME_280, BMP_280, + BMP_085, INA260, INA219, INA3221, diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 990fb36ea..b6eca5fa4 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -242,6 +242,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address); type = BME_280; break; + case 0x55: + LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = BMP_085; + break; default: LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address); type = BMP_280; diff --git a/src/main.cpp b/src/main.cpp index 80706d044..b62ccf986 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -500,6 +500,7 @@ void setup() SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221) diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index e501f17c2..d4f423e54 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -16,12 +16,14 @@ // Sensors #include "Sensor/BME280Sensor.h" #include "Sensor/BME680Sensor.h" +#include "Sensor/BMP085Sensor.h" #include "Sensor/BMP280Sensor.h" #include "Sensor/LPS22HBSensor.h" #include "Sensor/MCP9808Sensor.h" #include "Sensor/SHT31Sensor.h" #include "Sensor/SHTC3Sensor.h" +BMP085Sensor bmp085Sensor; BMP280Sensor bmp280Sensor; BME280Sensor bme280Sensor; BME680Sensor bme680Sensor; @@ -67,6 +69,8 @@ int32_t EnvironmentTelemetryModule::runOnce() LOG_INFO("Environment Telemetry: Initializing\n"); // it's possible to have this module enabled, only for displaying values on the screen. // therefore, we should only enable the sensor loop if measurement is also enabled + if (bmp085Sensor.hasSensor()) + result = bmp085Sensor.runOnce(); if (bmp280Sensor.hasSensor()) result = bmp280Sensor.runOnce(); if (bme280Sensor.hasSensor()) @@ -219,6 +223,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) valid = lps22hbSensor.getMetrics(&m); if (shtc3Sensor.hasSensor()) valid = shtc3Sensor.getMetrics(&m); + if (bmp085Sensor.hasSensor()) + valid = bmp085Sensor.getMetrics(&m); if (bmp280Sensor.hasSensor()) valid = bmp280Sensor.getMetrics(&m); if (bme280Sensor.hasSensor()) diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.cpp b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp new file mode 100644 index 000000000..b0991749b --- /dev/null +++ b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp @@ -0,0 +1,31 @@ +#include "BMP085Sensor.h" +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "configuration.h" +#include +#include + +BMP085Sensor::BMP085Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP085, "BMP085") {} + +int32_t BMP085Sensor::runOnce() +{ + LOG_INFO("Init sensor: %s\n", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + bmp085 = Adafruit_BMP085(); + status = bmp085.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second); + + return initI2CSensor(); +} + +void BMP085Sensor::setup() {} + +bool BMP085Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + LOG_DEBUG("BMP085Sensor::getMetrics\n"); + measurement->variant.environment_metrics.temperature = bmp085.readTemperature(); + measurement->variant.environment_metrics.barometric_pressure = bmp085.readPressure() / 100.0F; + + return true; +} diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.h b/src/modules/Telemetry/Sensor/BMP085Sensor.h new file mode 100644 index 000000000..c4a9479b9 --- /dev/null +++ b/src/modules/Telemetry/Sensor/BMP085Sensor.h @@ -0,0 +1,17 @@ +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class BMP085Sensor : public TelemetrySensor +{ + private: + Adafruit_BMP085 bmp085; + + protected: + virtual void setup() override; + + public: + BMP085Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; \ No newline at end of file From 585805c3b96d58224ffd2327fd6b4e1712a84abd Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:13:57 +0100 Subject: [PATCH 11/94] Add original hop limit to header to determine hops used (#3321) * Set `hop_start` in header to determine how many hops each packet traveled * Set hopLimit of response according to hops used by request * Identify neighbors based on `hopStart` and `hopLimit` * NeighborInfo: get all packets and assume a default broadcast interval * Add fail-safe in case node in between is running modified firmware * Add `viaMQTT` and `hopsAway` to NodeInfo * Replace `HOP_RELIABLE` with hopStart for repeated packet --------- Co-authored-by: Ben Meadors --- src/mesh/MeshModule.cpp | 9 ++++++--- src/mesh/MeshModule.h | 3 ++- src/mesh/NodeDB.cpp | 6 ++++++ src/mesh/RadioInterface.cpp | 5 ++++- src/mesh/RadioInterface.h | 6 ++++-- src/mesh/RadioLibInterface.cpp | 7 ++++--- src/mesh/ReliableRouter.cpp | 13 +++++++------ src/mesh/Router.cpp | 9 +++++++-- src/mesh/Router.h | 3 ++- src/modules/NeighborInfoModule.cpp | 12 +++++++++--- src/modules/NeighborInfoModule.h | 3 +++ src/modules/RoutingModule.cpp | 19 +++++++++++++++++-- src/modules/RoutingModule.h | 6 +++++- 13 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 9c6ca78ee..ad0c78108 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -32,7 +32,8 @@ MeshModule::~MeshModule() assert(0); // FIXME - remove from list of modules once someone needs this feature } -meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) +meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, + uint8_t hopStart, uint8_t hopLimit) { meshtastic_Routing c = meshtastic_Routing_init_default; @@ -49,7 +50,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod p->priority = meshtastic_MeshPacket_Priority_ACK; - p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender + p->hop_limit = routingModule->getHopLimitForResponse(hopStart, hopLimit); // Flood ACK back to original sender p->to = to; p->decoded.request_id = idFrom; p->channel = chIndex; @@ -176,7 +177,8 @@ void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src) // SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded) // but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs // bad. - routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel); + routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, mp.hop_start, + mp.hop_limit); } } @@ -217,6 +219,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to) assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0 p->channel = to.channel; // Use the same channel that the request came in on + p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit); // No need for an ack if we are just delivering locally (it just generates an ignored ack) p->want_ack = (to.from != 0) ? to.want_ack : false; diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index ebe3af1a0..6c431adb4 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -153,7 +153,8 @@ class MeshModule virtual bool wantUIFrame() { return false; } virtual Observable *getUIFrameObservable() { return NULL; } - meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, + uint8_t hopStart = 0, uint8_t hopLimit = 0); /// Send an error response for the specified packet. meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index dc8d7540c..787c16a79 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -875,6 +875,12 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) if (mp.rx_snr) info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. + + info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT + + // If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway + if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) + info->hops_away = mp.hop_start - mp.hop_limit; } } diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index cea3968ce..c10eb26f6 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -302,6 +302,8 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) out += DEBUG_PORT.mt_sprintf(" rxRSSI=%i", p->rx_rssi); if (p->via_mqtt != 0) out += DEBUG_PORT.mt_sprintf(" via MQTT"); + if (p->hop_start != 0) + out += DEBUG_PORT.mt_sprintf(" hopStart=%d", p->hop_start); if (p->priority != 0) out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority); @@ -561,6 +563,7 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) p->hop_limit = HOP_RELIABLE; } h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0); + h->flags |= (p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK; // if the sender nodenum is zero, that means uninitialized assert(h->from); @@ -569,4 +572,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} +} \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 83c5dae64..f85b3bfa5 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -10,9 +10,11 @@ #define MAX_RHPACKETLEN 256 -#define PACKET_FLAGS_HOP_MASK 0x07 +#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07 #define PACKET_FLAGS_WANT_ACK_MASK 0x08 #define PACKET_FLAGS_VIA_MQTT_MASK 0x10 +#define PACKET_FLAGS_HOP_START_MASK 0xE0 +#define PACKET_FLAGS_HOP_START_SHIFT 5 /** * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility @@ -224,4 +226,4 @@ class RadioInterface }; /// Debug printing for packets -void printPacket(const char *prefix, const meshtastic_MeshPacket *p); +void printPacket(const char *prefix, const meshtastic_MeshPacket *p); \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 8a2bc53e5..9f42afa6d 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -359,8 +359,9 @@ void RadioLibInterface::handleReceiveInterrupt() mp->to = h->to; mp->id = h->id; mp->channel = h->channel; - assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code - mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; + assert(HOP_MAX <= PACKET_FLAGS_HOP_LIMIT_MASK); // If hopmax changes, carefully check this code + mp->hop_limit = h->flags & PACKET_FLAGS_HOP_LIMIT_MASK; + mp->hop_start = (h->flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT; mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK); @@ -407,4 +408,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) // bits enableInterrupt(isrTxLevel0); } -} +} \ No newline at end of file diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index a1e9f281d..167a248ab 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -71,12 +71,12 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) i->second.nextTxMsec += iface->getPacketTime(p); } - /* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE) + /* Resend implicit ACKs for repeated packets (hopStart equals hopLimit); * this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again. * Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and * flooding this ACK back to the original sender already adds redundancy. */ - if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) { - // retransmission on broadcast has hop_limit still equal to HOP_RELIABLE + bool isRepeated = p->hop_start == 0 ? (p->hop_limit == HOP_RELIABLE) : (p->hop_start == p->hop_limit); + if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) { LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n"); meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); tosend->hop_limit--; // bump down the hop count @@ -107,10 +107,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas if (MeshModule::currentReply) { LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n"); } else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel); + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, p->hop_start, p->hop_limit); } else { // Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded - sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex()); + sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), p->hop_start, + p->hop_limit); } } @@ -255,4 +256,4 @@ void ReliableRouter::setNextTx(PendingPacket *pending) LOG_DEBUG("Setting next retransmission in %u msecs: ", d); printPacket("", pending->packet); setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time -} +} \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 1d6a2d96b..7657d2268 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -132,9 +132,10 @@ meshtastic_MeshPacket *Router::allocForSending() /** * Send an ack or a nak packet back towards whoever sent idFrom */ -void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) +void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart, + uint8_t hopLimit) { - routingModule->sendAckNak(err, to, idFrom, chIndex); + routingModule->sendAckNak(err, to, idFrom, chIndex, hopStart, hopLimit); } void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p) @@ -240,6 +241,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // the lora we need to make sure we have replaced it with our local address p->from = getFrom(p); + // If we are the original transmitter, set the hop limit with which we start + if (p->from == getNodeNum()) + p->hop_start = p->hop_limit; + // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || diff --git a/src/mesh/Router.h b/src/mesh/Router.h index db810e42e..98486745b 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -104,7 +104,8 @@ class Router : protected concurrency::OSThread /** * Send an ack or a nak packet back towards whoever sent idFrom */ - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0, + uint8_t hopLimit = 0); private: /** diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 4541958fa..2e0b04afa 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -95,6 +95,7 @@ NeighborInfoModule::NeighborInfoModule() ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP; if (moduleConfig.neighbor_info.enabled) { + isPromiscuous = true; // Update neighbors from all packets this->loadProtoForModule(); setIntervalFromNow(35 * 1000); } else { @@ -202,9 +203,12 @@ Pass it to an upper client; do not persist this data on the mesh */ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np) { - if (enabled) { + if (np) { printNeighborInfo("RECEIVED", np); updateNeighbors(mp, np); + } else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) { + // If the hopLimit is the same as hopStart, then it is a neighbor + getOrCreateNeighbor(mp.from, mp.from, 0, mp.rx_snr); // Set the broadcast interval to 0, as we don't know it } // Allow others to handle this packet return false; @@ -261,7 +265,7 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen nbr->snr = snr; nbr->last_rx_time = getTime(); // Only if this is the original sender, the broadcast interval corresponds to it - if (originalSender == n) + if (originalSender == n && node_broadcast_interval_secs != 0) nbr->node_broadcast_interval_secs = node_broadcast_interval_secs; saveProtoForModule(); // Save the updated neighbor return nbr; @@ -277,8 +281,10 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen new_nbr->snr = snr; new_nbr->last_rx_time = getTime(); // Only if this is the original sender, the broadcast interval corresponds to it - if (originalSender == n) + if (originalSender == n && node_broadcast_interval_secs != 0) new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs; + else // Assume the same broadcast interval as us for the neighbor if we don't know it + new_nbr->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval; saveProtoForModule(); // Save the new neighbor return new_nbr; } diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index 0e3ec09ca..df5c2c948 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -75,6 +75,9 @@ class NeighborInfoModule : public ProtobufModule, priva /* Does our periodic broadcast */ int32_t runOnce() override; + // Override wantPacket to say we want to see all packets when enabled, not just those for our port number + virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return enabled; } + /* These are for debugging only */ void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np); void printNodeDBNodes(const char *header); diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index edeb1fb86..37a7c3755 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -36,13 +36,28 @@ meshtastic_MeshPacket *RoutingModule::allocReply() return NULL; } -void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) +void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart, + uint8_t hopLimit) { - auto p = allocAckNak(err, to, idFrom, chIndex); + auto p = allocAckNak(err, to, idFrom, chIndex, hopStart, hopLimit); router->sendLocal(p); // we sometimes send directly to the local node } +uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit) +{ + if (hopStart != 0) { + // Hops used by the request. If somebody in between running modified firmware modified it, ignore it + uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit; + if (hopsUsed > config.lora.hop_limit) { + return hopsUsed; // If the request used more hops than the limit, use the same amount of hops + } else if (hopsUsed + 2 < config.lora.hop_limit) { + return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different + } + } + return config.lora.hop_limit; // Use the default hop limit +} + RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) { isPromiscuous = true; diff --git a/src/modules/RoutingModule.h b/src/modules/RoutingModule.h index 06e76cfb4..f085b307b 100644 --- a/src/modules/RoutingModule.h +++ b/src/modules/RoutingModule.h @@ -13,7 +13,11 @@ class RoutingModule : public ProtobufModule */ RoutingModule(); - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0, + uint8_t hopLimit = 0); + + // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response + uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit); protected: friend class Router; From 7da1153c2c913903cc0c8603a81ade22f8cf34a8 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 8 Mar 2024 08:31:49 -0600 Subject: [PATCH 12/94] Fix known_only panic by short circuiting for NULL before checking has_user (#3352) --- 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 7657d2268..7c739b8f2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -297,7 +297,7 @@ bool perhapsDecode(meshtastic_MeshPacket *p) return false; if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY && - !nodeDB.getMeshNode(p->from)->has_user) { + (nodeDB.getMeshNode(p->from) == NULL || !nodeDB.getMeshNode(p->from)->has_user)) { LOG_DEBUG("Node 0x%x not in NodeDB. Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from); return false; } From 5d4d91f77512ca7aa2f0dd07cbb09385f397834c Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Tue, 5 Mar 2024 14:53:42 +1300 Subject: [PATCH 13/94] Move Wireless Paper V1.1 custom hibernate behavior to GxEPD2 --- src/graphics/EInkDisplay2.cpp | 6 +++--- variants/heltec_wireless_paper/variant.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index aee30c7f8..026a65e6d 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -84,10 +84,10 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit) adafruitDisplay->nextPage(); #endif -#ifndef EINK_NO_HIBERNATE // Only hibernate if controller IC will preserve image memory - // Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display) + // Power off display hardware + // Most models: deep sleep. + // Wireless Paper V1.1: power off only. Deep sleep clears memory - problems with fast refresh adafruitDisplay->hibernate(); -#endif LOG_DEBUG("done\n"); return true; diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h index 28bc8628a..29b8bbbd1 100644 --- a/variants/heltec_wireless_paper/variant.h +++ b/variants/heltec_wireless_paper/variant.h @@ -5,7 +5,6 @@ #define I2C_SCL SCL #define USE_EINK -#define EINK_NO_HIBERNATE /* * eink display pins From 07da13058684b0d5517d3bfd54a3e2d857e9e5a8 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Thu, 7 Mar 2024 03:26:31 +1300 Subject: [PATCH 14/94] Async full-refresh for EInkDynamicDisplay --- src/graphics/EInkDisplay2.cpp | 25 +++--- src/graphics/EInkDisplay2.h | 7 ++ src/graphics/EInkDynamicDisplay.cpp | 90 +++++++++++++++++-- src/graphics/EInkDynamicDisplay.h | 15 +++- variants/heltec_wireless_paper/platformio.ini | 3 +- .../heltec_wireless_paper_v1/platformio.ini | 3 +- 6 files changed, 117 insertions(+), 26 deletions(-) diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 026a65e6d..a544833c1 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -71,28 +71,24 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit) } } + // Trigger the refresh in GxEPD2 LOG_DEBUG("Updating E-Paper... "); - -#if false - // Currently unused; rescued from commented-out line during a refactor - // Use a meaningful macro here if variant doesn't want fast refresh - - // Full update mode (slow) - adafruitDisplay->display(false) -#else - // Fast update mode adafruitDisplay->nextPage(); -#endif - // Power off display hardware - // Most models: deep sleep. - // Wireless Paper V1.1: power off only. Deep sleep clears memory - problems with fast refresh - adafruitDisplay->hibernate(); + // End the update process + endUpdate(); LOG_DEBUG("done\n"); return true; } +// End the update process - virtual method, overriden in derived class +void EInkDisplay::endUpdate() +{ + // Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep) + adafruitDisplay->hibernate(); +} + // Write the buffer to the display memory void EInkDisplay::display(void) { @@ -193,6 +189,7 @@ bool EInkDisplay::connect() // Init GxEPD2 adafruitDisplay->init(); adafruitDisplay->setRotation(3); + adafruitDisplay->clearScreen(); // Clearing now, so the boot logo will draw nice and smoothe (fast refresh) } #elif defined(PCA10059) { diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 75770a3bc..f74416494 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -45,6 +45,13 @@ class EInkDisplay : public OLEDDisplay */ virtual bool forceDisplay(uint32_t msecLimit = 1000); + /** + * Run any code needed to complete an update, after the physical refresh has completed. + * Split from forceDisplay(), to enable async refresh in derived EInkDynamicDisplay class. + * + */ + virtual void endUpdate(); + /** * shim to make the abstraction happy * diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index ae1e30fe1..75db0e33f 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -94,19 +94,29 @@ void EInkDynamicDisplay::adjustRefreshCounters() // Trigger the display update by calling base class bool EInkDynamicDisplay::update() { + // Detemine the refresh mode to use, and start the update bool refreshApproved = determineMode(); if (refreshApproved) EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system - return refreshApproved; // (Unutilized) Base class promises to return true if update ran + +#if defined(HAS_EINK_ASYNCFULL) + if (refreshApproved) + endOrDetach(); // Either endUpdate() right now (fast refresh), or set the async flag (full refresh) +#endif + + return refreshApproved; // (Unutilized) Base class promises to return true if update ran } // Assess situation, pick a refresh type bool EInkDynamicDisplay::determineMode() { - checkWasFlooded(); + checkForPromotion(); +#if defined(HAS_EINK_ASYNCFULL) + checkAsyncFullRefresh(); +#endif checkRateLimiting(); - // If too soon for a new time, abort here + // If too soon for a new frame, or display busy, abort early if (refresh == SKIPPED) { storeAndReset(); return false; // No refresh @@ -116,7 +126,7 @@ bool EInkDynamicDisplay::determineMode() resetRateLimiting(); // Once determineMode() ends, will have to wait again hashImage(); // Generate here, so we can still copy it to previousImageHash, even if we skip the comparison check - LOG_DEBUG("EInkDynamicDisplay: "); // Begin log entry + LOG_DEBUG("determineMode(): "); // Begin log entry // Once mode determined, any remaining checks will bypass checkCosmetic(); @@ -151,13 +161,25 @@ bool EInkDynamicDisplay::determineMode() } } -// Did RESPONSIVE frames previously exceed the rate-limit for fast refresh? -void EInkDynamicDisplay::checkWasFlooded() +// Was a frame skipped (rate, display busy) that should have been a FAST refresh? +void EInkDynamicDisplay::checkForPromotion() { - if (previousReason == EXCEEDED_RATELIMIT_FAST) { - // If so, allow a BACKGROUND frame to draw as RESPONSIVE - // Because we DID want a RESPONSIVE frame last time, we just didn't get it + // If a frame was skipped (rate, display busy), then promote a BACKGROUND frame + // Because we DID want a RESPONSIVE/COSMETIC/DEMAND_FULL frame last time, we just didn't get it + + switch (previousReason) { + case ASYNC_REFRESH_BLOCKED_DEMANDFAST: + setFrameFlag(DEMAND_FAST); + break; + case ASYNC_REFRESH_BLOCKED_COSMETIC: + setFrameFlag(COSMETIC); + break; + case ASYNC_REFRESH_BLOCKED_RESPONSIVE: + case EXCEEDED_RATELIMIT_FAST: setFrameFlag(RESPONSIVE); + break; + default: + break; } } @@ -381,4 +403,54 @@ void EInkDynamicDisplay::resetGhostPixelTracking() } #endif // EINK_LIMIT_GHOSTING_PX +#ifdef HAS_EINK_ASYNCFULL +// Check the status of an "async full-refresh", and run the finish-up code if the hardware is ready +void EInkDynamicDisplay::checkAsyncFullRefresh() +{ + // No refresh taking place, continue with determineMode() + if (!asyncRefreshRunning) + return; + + // Full refresh still running + if (adafruitDisplay->epd2.isBusy()) { + // No refresh + refresh = SKIPPED; + + // Set the reason, marking what type of frame we're skipping + if (frameFlags & DEMAND_FAST) + reason = ASYNC_REFRESH_BLOCKED_DEMANDFAST; + else if (frameFlags & COSMETIC) + reason = ASYNC_REFRESH_BLOCKED_COSMETIC; + else if (frameFlags & RESPONSIVE) + reason = ASYNC_REFRESH_BLOCKED_RESPONSIVE; + else + reason = ASYNC_REFRESH_BLOCKED_BACKGROUND; + + return; + } + + // If we asyncRefreshRunning flag is still set, but display's BUSY pin reports the refresh is done + adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code + EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override) + asyncRefreshRunning = false; // Unset the flag + LOG_DEBUG("Async full-refresh complete\n"); + + // Note: this code only works because of a modification to meshtastic/GxEPD2. + // It is only equipped to intercept calls to nextPage() +} + +// Figure out who runs the post-update code +void EInkDynamicDisplay::endOrDetach() +{ + if (previousRefresh == FULL) { // Note: previousRefresh is the refresh from this loop. + asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop. + LOG_DEBUG("Async full-refresh begins\n"); + } + + // Fast Refresh + else + EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves. +} +#endif // HAS_EINK_ASYNCFULL + #endif // USE_EINK_DYNAMICDISPLAY \ No newline at end of file diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 2880c716b..3dc00ba7c 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -44,6 +44,11 @@ class EInkDynamicDisplay : public EInkDisplay }; enum reasonTypes : uint8_t { // How was the decision reached NO_OBJECTIONS, + ASYNC_REFRESH_BLOCKED_DEMANDFAST, + ASYNC_REFRESH_BLOCKED_COSMETIC, + ASYNC_REFRESH_BLOCKED_RESPONSIVE, + ASYNC_REFRESH_BLOCKED_BACKGROUND, + DISPLAY_NOT_READY_FOR_FULL, EXCEEDED_RATELIMIT_FAST, EXCEEDED_RATELIMIT_FULL, FLAGGED_COSMETIC, @@ -64,7 +69,7 @@ class EInkDynamicDisplay : public EInkDisplay bool update(); // Trigger the display update - determine mode, then call base class // Checks as part of determineMode() - void checkWasFlooded(); // Was the previous frame skipped for exceeding EINK_LIMIT_RATE_RESPONSIVE_SEC? + void checkForPromotion(); // Was a frame skipped (rate, display busy) that should have been a FAST refresh? void checkRateLimiting(); // Is this frame too soon? void checkCosmetic(); // Was the COSMETIC flag set? void checkDemandingFast(); // Was the DEMAND_FAST flag set? @@ -99,6 +104,14 @@ class EInkDynamicDisplay : public EInkDisplay uint8_t *dirtyPixels; // Any pixels that have been black since last full-refresh (dynamically allocated mem) uint32_t ghostPixelCount = 0; // Number of pixels with problematic ghosting. Retained here for LOG_DEBUG use #endif + + // Conditional - async full refresh - only with modified meshtastic/GxEPD2 +#if defined(HAS_EINK_ASYNCFULL) + void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready + void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh() + void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay() + bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh() +#endif }; #endif \ No newline at end of file diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 0abbe085e..7aebef014 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -16,7 +16,8 @@ build_flags = -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2 + ; https://github.com/meshtastic/GxEPD2/ + https://github.com/todd-herbert/meshtastic-GxEPD2#async ; Revert to meshtastic/firmware before submitting PR before final merge adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index 4e5e291e0..8cd870353 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -16,7 +16,8 @@ build_flags = ;-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/ + ; https://github.com/meshtastic/GxEPD2/ + https://github.com/todd-herbert/meshtastic-GxEPD2#async ; Revert to meshtastic/firmware before submitting PR before final merge adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file From ac89bb33871a37005a50ef2b7410b8102186c1d9 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Fri, 8 Mar 2024 13:16:06 +1300 Subject: [PATCH 15/94] initial config for T-Echo --- variants/t-echo/platformio.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index 49ba3bb34..f894b1203 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -11,6 +11,12 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 -DEINK_HEIGHT=200 + -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -D EINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates + -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} From 7275c21f6b054e57a9c2c1b8a418cb1aa047bab5 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sat, 9 Mar 2024 09:34:53 +1300 Subject: [PATCH 16/94] formatting responds to https://github.com/meshtastic/firmware/pull/3339#discussion_r1518175434 --- variants/t-echo/platformio.ini | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index f894b1203..076f1a747 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -11,12 +11,12 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 -DEINK_HEIGHT=200 - -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk - -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted - -D EINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates - -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates - -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated - -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates + -DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} From 23926210d1bcd841b27e15a5119941621be94c72 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sat, 9 Mar 2024 09:57:30 +1300 Subject: [PATCH 17/94] increase fast-refresh limit for T-Echo https://github.com/meshtastic/firmware/pull/3339#issuecomment-1986245727 --- variants/t-echo/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index 076f1a747..94b6ee087 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -12,7 +12,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo -DEINK_WIDTH=200 -DEINK_HEIGHT=200 -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk - -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates -DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated From 0f1bc98305c3c6fd56b6d394aaf3d0e1ba1b66b9 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 8 Mar 2024 20:15:00 -0600 Subject: [PATCH 18/94] Update MQTT topic to match (#3353) --- src/mqtt/MQTT.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 2b803e3fc..e67958b25 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -80,10 +80,10 @@ class MQTT : private concurrency::OSThread private: std::string statusTopic = "/2/stat/"; - std::string cryptTopic = "/2/c/"; // msh/2/c/CHANNELID/NODEID + std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID - /** return true if we have a channel that wants uplink/downlink - */ + /** return true if we have a channel that wants uplink/downlink + */ bool wantsLink() const; /** Tell the server what subscriptions we want (based on channels.downlink_enabled) From 51df4fc7750b5affda52b82f901173195f201293 Mon Sep 17 00:00:00 2001 From: Andre K Date: Fri, 8 Mar 2024 23:15:37 -0300 Subject: [PATCH 19/94] fix: turn off T-Echo peripherals on deep sleep (#3162) Co-authored-by: Ben Meadors --- src/Power.cpp | 5 ----- src/graphics/EInkDisplay2.cpp | 5 ----- src/graphics/Screen.cpp | 3 +++ src/main.cpp | 9 +++++---- src/sleep.cpp | 7 +++++++ variants/rak10701/variant.h | 4 ---- variants/rak4631/variant.h | 4 ---- variants/rak4631_epaper/variant.h | 4 ---- variants/rak4631_epaper_onrxtx/variant.h | 4 ---- variants/t-echo/variant.h | 6 +++--- 10 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 8e44ddb98..3d1a1b9b2 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -473,11 +473,6 @@ bool Power::setup() void Power::shutdown() { - screen->setOn(false); -#if defined(USE_EINK) && defined(PIN_EINK_EN) - digitalWrite(PIN_EINK_EN, LOW); // power off backlight first -#endif - LOG_INFO("Shutting down\n"); #ifdef HAS_PMU diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index aee30c7f8..6ee4245b3 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -122,11 +122,6 @@ bool EInkDisplay::connect() { LOG_INFO("Doing EInk init\n"); -#ifdef PIN_EINK_PWR_ON - pinMode(PIN_EINK_PWR_ON, OUTPUT); - digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals -#endif - #ifdef PIN_EINK_EN // backlight power, HIGH is backlight on, LOW is off pinMode(PIN_EINK_EN, OUTPUT); diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 33df78462..3ffea4a60 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -938,6 +938,9 @@ void Screen::doDeepSleep() static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]); ui->setFrames(sleepFrames, sleepFrameCount); ui->update(); +#ifdef PIN_EINK_EN + digitalWrite(PIN_EINK_EN, LOW); // power off backlight +#endif #endif setOn(false); } diff --git a/src/main.cpp b/src/main.cpp index b62ccf986..ef1cd53c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -219,10 +219,11 @@ void setup() initDeepSleep(); - // Testing this fix für erratic T-Echo boot behaviour -#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON) - pinMode(PIN_EINK_PWR_ON, OUTPUT); - digitalWrite(PIN_EINK_PWR_ON, HIGH); + // power on peripherals +#if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN) + pinMode(PIN_POWER_EN, OUTPUT); + digitalWrite(PIN_POWER_EN, HIGH); + digitalWrite(PIN_POWER_EN1, INPUT); #endif #if defined(VEXT_ENABLE_V03) diff --git a/src/sleep.cpp b/src/sleep.cpp index 1afba1173..bfacffeb9 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -200,6 +200,13 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) nodeDB.saveToDisk(); +#ifdef TTGO_T_ECHO +#ifdef PIN_POWER_EN + pinMode(PIN_POWER_EN, INPUT); // power off peripherals + pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); +#endif +#endif + // Kill GPS power completely (even if previously we just had it in sleep mode) if (gps) gps->setGPSPower(false, false, 0); diff --git a/variants/rak10701/variant.h b/variants/rak10701/variant.h index 837d081ff..d6eeb71dc 100644 --- a/variants/rak10701/variant.h +++ b/variants/rak10701/variant.h @@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_EINK_SCLK (0 + 3) #define PIN_EINK_MOSI (0 + 30) // also called SDI -// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -// FIXME - I think this is actually just the board power enable - it enables power to the CPU also -// #define PIN_EINK_PWR_ON (-1) - // #define USE_EINK // RAKRGB diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index 4ad99df44..0ccf3b1d7 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_EINK_SCLK (0 + 3) #define PIN_EINK_MOSI (0 + 30) // also called SDI -// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -// FIXME - I think this is actually just the board power enable - it enables power to the CPU also -// #define PIN_EINK_PWR_ON (-1) - // #define USE_EINK // RAKRGB diff --git a/variants/rak4631_epaper/variant.h b/variants/rak4631_epaper/variant.h index d8a5e5597..b1bd84d21 100644 --- a/variants/rak4631_epaper/variant.h +++ b/variants/rak4631_epaper/variant.h @@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_EINK_SCLK (0 + 3) #define PIN_EINK_MOSI (0 + 30) // also called SDI -// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -// FIXME - I think this is actually just the board power enable - it enables power to the CPU also -// #define PIN_EINK_PWR_ON (-1) - #define USE_EINK // RAKRGB diff --git a/variants/rak4631_epaper_onrxtx/variant.h b/variants/rak4631_epaper_onrxtx/variant.h index 411e3eb17..ec53ebd33 100644 --- a/variants/rak4631_epaper_onrxtx/variant.h +++ b/variants/rak4631_epaper_onrxtx/variant.h @@ -119,10 +119,6 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_EINK_SCLK (0 + 14) // SCL #define PIN_EINK_MOSI (0 + 13) // SDA -// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -// FIXME - I think this is actually just the board power enable - it enables power to the CPU also -// #define PIN_EINK_PWR_ON (-1) - // RAKRGB #define HAS_NCP5623 diff --git a/variants/t-echo/variant.h b/variants/t-echo/variant.h index 1af68863e..19a66719f 100644 --- a/variants/t-echo/variant.h +++ b/variants/t-echo/variant.h @@ -156,9 +156,9 @@ External serial flash WP25R1635FZUIL0 #define PIN_EINK_SCLK (0 + 31) #define PIN_EINK_MOSI (0 + 29) // also called SDI -// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -// FIXME - I think this is actually just the board power enable - it enables power to the CPU also -#define PIN_EINK_PWR_ON (0 + 12) +// Controls power for all peripherals (eink + GPS + LoRa + Sensor) +#define PIN_POWER_EN (0 + 12) +#define PIN_POWER_EN1 (0 + 13) #define USE_EINK From 29335a18f58d10ca7f86a234c921f5b3b8e1e469 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 9 Mar 2024 14:55:02 +0200 Subject: [PATCH 20/94] Update variant.h (#3354) --- variants/heltec_esp32c3/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_esp32c3/variant.h b/variants/heltec_esp32c3/variant.h index de6462a38..6641f9d21 100644 --- a/variants/heltec_esp32c3/variant.h +++ b/variants/heltec_esp32c3/variant.h @@ -9,7 +9,7 @@ #define LED_PIN 18 // LED #define LED_INVERTED 1 -#define HAS_SCREEN 0 +#define HAS_SCREEN 1 #define HAS_GPS 0 #undef GPS_RX_PIN #undef GPS_TX_PIN From 3efd606ea7fcc7cda763eff3d5cbab0aa80c2447 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 9 Mar 2024 07:01:46 -0600 Subject: [PATCH 21/94] Bump to 2.3.0 --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 14d1884fb..8927d1781 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 -minor = 2 -build = 25 +minor = 3 +build = 0 From d5c11d18922301864617ff160468bb39751916e0 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 02:11:49 +1300 Subject: [PATCH 22/94] change dependency from private repo to meshtastic/GxEPD2 --- variants/heltec_wireless_paper/platformio.ini | 3 +-- variants/heltec_wireless_paper_v1/platformio.ini | 3 +-- variants/t-echo/platformio.ini | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 7aebef014..14275830a 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -16,8 +16,7 @@ build_flags = -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - ; https://github.com/meshtastic/GxEPD2/ - https://github.com/todd-herbert/meshtastic-GxEPD2#async ; Revert to meshtastic/firmware before submitting PR before final merge + https://github.com/meshtastic/GxEPD2/ adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index 8cd870353..4e5e291e0 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -16,8 +16,7 @@ build_flags = ;-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - ; https://github.com/meshtastic/GxEPD2/ - https://github.com/todd-herbert/meshtastic-GxEPD2#async ; Revert to meshtastic/firmware before submitting PR before final merge + https://github.com/meshtastic/GxEPD2/ adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index 94b6ee087..c97341a3b 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -20,7 +20,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} - https://github.com/meshtastic/GxEPD2#afce87a97dda1ac31d8a28dc8fa7c6f55dc96a61 + https://github.com/meshtastic/GxEPD2 adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs From 576f582cd9a41ac877f11129a834cac9d18e4b81 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 02:30:16 +1300 Subject: [PATCH 23/94] rename setFrameFlag() method --- src/graphics/EInkDynamicDisplay.cpp | 12 ++++++------ src/graphics/EInkDynamicDisplay.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 75db0e33f..c9bd5b22b 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -25,19 +25,19 @@ EInkDynamicDisplay::~EInkDynamicDisplay() // Screen requests a BACKGROUND frame void EInkDynamicDisplay::display() { - setFrameFlag(BACKGROUND); + addFrameFlag(BACKGROUND); update(); } // Screen requests a RESPONSIVE frame bool EInkDynamicDisplay::forceDisplay(uint32_t msecLimit) { - setFrameFlag(RESPONSIVE); + addFrameFlag(RESPONSIVE); return update(); // (Unutilized) Base class promises to return true if update ran } // Add flag for the next frame -void EInkDynamicDisplay::setFrameFlag(frameFlagTypes flag) +void EInkDynamicDisplay::addFrameFlag(frameFlagTypes flag) { // OR the new flag into the existing flags this->frameFlags = (frameFlagTypes)(this->frameFlags | flag); @@ -169,14 +169,14 @@ void EInkDynamicDisplay::checkForPromotion() switch (previousReason) { case ASYNC_REFRESH_BLOCKED_DEMANDFAST: - setFrameFlag(DEMAND_FAST); + addFrameFlag(DEMAND_FAST); break; case ASYNC_REFRESH_BLOCKED_COSMETIC: - setFrameFlag(COSMETIC); + addFrameFlag(COSMETIC); break; case ASYNC_REFRESH_BLOCKED_RESPONSIVE: case EXCEEDED_RATELIMIT_FAST: - setFrameFlag(RESPONSIVE); + addFrameFlag(RESPONSIVE); break; default: break; diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 3dc00ba7c..1eeb28f81 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -29,7 +29,7 @@ class EInkDynamicDisplay : public EInkDisplay COSMETIC = (1 << 2), // For splashes DEMAND_FAST = (1 << 3), // Special case only }; - void setFrameFlag(frameFlagTypes flag); + void addFrameFlag(frameFlagTypes flag); // Set the correct frame flag, then call universal "update()" method void display() override; From efd818fe903dc042aa92ae78ea940466689e67ae Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 03:07:13 +1300 Subject: [PATCH 24/94] move storeAndReset() to end of update() --- src/graphics/EInkDynamicDisplay.cpp | 14 +++++++------- src/graphics/EInkDynamicDisplay.h | 7 ++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index c9bd5b22b..0a4d9691d 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -104,6 +104,7 @@ bool EInkDynamicDisplay::update() endOrDetach(); // Either endUpdate() right now (fast refresh), or set the async flag (full refresh) #endif + storeAndReset(); // Store the result of this loop for next time return refreshApproved; // (Unutilized) Base class promises to return true if update ran } @@ -117,10 +118,8 @@ bool EInkDynamicDisplay::determineMode() checkRateLimiting(); // If too soon for a new frame, or display busy, abort early - if (refresh == SKIPPED) { - storeAndReset(); + if (refresh == SKIPPED) return false; // No refresh - } // -- New frame is due -- @@ -152,12 +151,12 @@ bool EInkDynamicDisplay::determineMode() #endif // Return - call a refresh or not? - if (refresh == SKIPPED) { - storeAndReset(); + if (refresh == SKIPPED) return false; // Don't trigger a refresh - } else { - storeAndReset(); + else return true; // Do trigger a refresh +} + } } @@ -335,6 +334,7 @@ void EInkDynamicDisplay::hashImage() // Store the results of determineMode() for future use, and reset for next call void EInkDynamicDisplay::storeAndReset() { + previousFrameFlags = frameFlags; previousRefresh = refresh; previousReason = reason; diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 1eeb28f81..ad4d9bfd9 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -82,13 +82,14 @@ class EInkDynamicDisplay : public EInkDisplay void storeAndReset(); // Keep results of determineMode() for later, tidy-up for next call // What we are determining for this frame - frameFlagTypes frameFlags = BACKGROUND; // Frame type(s) - determineMode() input + frameFlagTypes frameFlags = BACKGROUND; // Frame characteristics - determineMode() input refreshTypes refresh = UNSPECIFIED; // Refresh type - determineMode() output reasonTypes reason = NO_OBJECTIONS; // Reason - why was refresh type used // What happened last time determineMode() ran - refreshTypes previousRefresh = UNSPECIFIED; // (Previous) Outcome - reasonTypes previousReason = NO_OBJECTIONS; // (Previous) Reason + frameFlagTypes previousFrameFlags = BACKGROUND; // (Previous) Frame flags + refreshTypes previousRefresh = UNSPECIFIED; // (Previous) Outcome + reasonTypes previousReason = NO_OBJECTIONS; // (Previous) Reason uint32_t previousRunMs = -1; // When did determineMode() last run (rather than rejecting for rate-limiting) uint32_t imageHash = 0; // Hash of the current frame. Don't bother updating if nothing has changed! From 95b6f27d2a9dcd436070b81524fbe583e342aa6a Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 03:38:39 +1300 Subject: [PATCH 25/94] change order of determineMode() checks --- src/graphics/EInkDynamicDisplay.cpp | 34 ++++++++++++++--------------- src/graphics/EInkDynamicDisplay.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 0a4d9691d..7666820bd 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -130,11 +130,11 @@ bool EInkDynamicDisplay::determineMode() // Once mode determined, any remaining checks will bypass checkCosmetic(); checkDemandingFast(); - checkConsecutiveFastRefreshes(); #ifdef EINK_LIMIT_GHOSTING_PX checkExcessiveGhosting(); #endif checkFrameMatchesPrevious(); + checkConsecutiveFastRefreshes(); checkFastRequested(); if (refresh == UNSPECIFIED) @@ -244,21 +244,6 @@ void EInkDynamicDisplay::checkDemandingFast() } } -// Have too many fast-refreshes occured consecutively, since last full refresh? -void EInkDynamicDisplay::checkConsecutiveFastRefreshes() -{ - // If a decision was already reached, don't run the check - if (refresh != UNSPECIFIED) - return; - - // If too many FAST refreshes consecutively - force a FULL refresh - if (fastRefreshCount >= EINK_LIMIT_FASTREFRESH) { - refresh = FULL; - reason = EXCEEDED_LIMIT_FASTREFRESH; - LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH\n"); - } -} - // Does the new frame match the currently displayed image? void EInkDynamicDisplay::checkFrameMatchesPrevious() { @@ -283,7 +268,22 @@ void EInkDynamicDisplay::checkFrameMatchesPrevious() // Not redrawn, not COSMETIC, not DEMAND_FAST refresh = SKIPPED; reason = FRAME_MATCHED_PREVIOUS; - LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS\n"); + LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS, frameFlags=0x%x\n", frameFlags); +} + +// Have too many fast-refreshes occured consecutively, since last full refresh? +void EInkDynamicDisplay::checkConsecutiveFastRefreshes() +{ + // If a decision was already reached, don't run the check + if (refresh != UNSPECIFIED) + return; + + // If too many FAST refreshes consecutively - force a FULL refresh + if (fastRefreshCount >= EINK_LIMIT_FASTREFRESH) { + refresh = FULL; + reason = EXCEEDED_LIMIT_FASTREFRESH; + LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH\n"); + } } // No objections, we can perform fast-refresh, if desired diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index ad4d9bfd9..b3e091fb2 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -73,8 +73,8 @@ class EInkDynamicDisplay : public EInkDisplay void checkRateLimiting(); // Is this frame too soon? void checkCosmetic(); // Was the COSMETIC flag set? void checkDemandingFast(); // Was the DEMAND_FAST flag set? - void checkConsecutiveFastRefreshes(); // Too many fast-refreshes consecutively? void checkFrameMatchesPrevious(); // Does the new frame match the existing display image? + void checkConsecutiveFastRefreshes(); // Too many fast-refreshes consecutively? void checkFastRequested(); // Was the flag set for RESPONSIVE, or only BACKGROUND? void resetRateLimiting(); // Set previousRunMs - this now counts as an update, for rate-limiting From 94794edd43392836ddbd88471f6575bc859ac676 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 03:43:07 +1300 Subject: [PATCH 26/94] add init code as a determineMode() check --- src/graphics/EInkDisplay2.cpp | 1 - src/graphics/EInkDynamicDisplay.cpp | 16 ++++++++++++++++ src/graphics/EInkDynamicDisplay.h | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 6f7885b45..0c5fab4fb 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -184,7 +184,6 @@ bool EInkDisplay::connect() // Init GxEPD2 adafruitDisplay->init(); adafruitDisplay->setRotation(3); - adafruitDisplay->clearScreen(); // Clearing now, so the boot logo will draw nice and smoothe (fast refresh) } #elif defined(PCA10059) { diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 7666820bd..8ff8dc4af 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -111,6 +111,7 @@ bool EInkDynamicDisplay::update() // Assess situation, pick a refresh type bool EInkDynamicDisplay::determineMode() { + checkInitialized(); checkForPromotion(); #if defined(HAS_EINK_ASYNCFULL) checkAsyncFullRefresh(); @@ -157,6 +158,21 @@ bool EInkDynamicDisplay::determineMode() return true; // Do trigger a refresh } +// Is this the very first frame? +void EInkDynamicDisplay::checkInitialized() +{ + if (!initialized) { + // Undo GxEPD2_BW::partialWindow(), if set by developer in EInkDisplay::connect() + configForFullRefresh(); + + // Clear any existing image, so we can draw logo with fast-refresh, but also to set GxEPD2_EPD::_initial_write + adafruitDisplay->clearScreen(); + + LOG_DEBUG("initialized, "); + initialized = true; + + // Use a fast-refresh for the next frame; no skipping or else blank screen when waking from deep sleep + addFrameFlag(DEMAND_FAST); } } diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index b3e091fb2..48540a132 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -69,6 +69,7 @@ class EInkDynamicDisplay : public EInkDisplay bool update(); // Trigger the display update - determine mode, then call base class // Checks as part of determineMode() + void checkInitialized(); // Is this the very first frame? void checkForPromotion(); // Was a frame skipped (rate, display busy) that should have been a FAST refresh? void checkRateLimiting(); // Is this frame too soon? void checkCosmetic(); // Was the COSMETIC flag set? @@ -91,6 +92,7 @@ class EInkDynamicDisplay : public EInkDisplay refreshTypes previousRefresh = UNSPECIFIED; // (Previous) Outcome reasonTypes previousReason = NO_OBJECTIONS; // (Previous) Reason + bool initialized = false; // Have we drawn at least one frame yet? uint32_t previousRunMs = -1; // When did determineMode() last run (rather than rejecting for rate-limiting) uint32_t imageHash = 0; // Hash of the current frame. Don't bother updating if nothing has changed! uint32_t previousImageHash = 0; // Hash of the previous update's frame From e232e3462c58bd67711a1706351f3d5a4adb61d6 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 03:48:59 +1300 Subject: [PATCH 27/94] add BLOCKING modifier to frameFlagTypes --- src/graphics/EInkDynamicDisplay.cpp | 21 +++++++++++++++++++-- src/graphics/EInkDynamicDisplay.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 8ff8dc4af..2b3659099 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -458,15 +458,32 @@ void EInkDynamicDisplay::checkAsyncFullRefresh() // Figure out who runs the post-update code void EInkDynamicDisplay::endOrDetach() { - if (previousRefresh == FULL) { // Note: previousRefresh is the refresh from this loop. + if (refresh == FULL) { asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop. - LOG_DEBUG("Async full-refresh begins\n"); + + if (frameFlags & BLOCKING) + awaitRefresh(); + else + LOG_DEBUG("Async full-refresh begins\n"); } // Fast Refresh else EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves. } + +// Hold control while an async refresh runs +void EInkDynamicDisplay::awaitRefresh() +{ + // Continually poll the BUSY pin + while (adafruitDisplay->epd2.isBusy()) + yield(); + + // End the full-refresh process + adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code + EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override) + asyncRefreshRunning = false; // Unset the flag +} #endif // HAS_EINK_ASYNCFULL #endif // USE_EINK_DYNAMICDISPLAY \ No newline at end of file diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 48540a132..ed5be70cd 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -28,6 +28,7 @@ class EInkDynamicDisplay : public EInkDisplay RESPONSIVE = (1 << 1), // For frames via forceDisplay() COSMETIC = (1 << 2), // For splashes DEMAND_FAST = (1 << 3), // Special case only + BLOCKING = (1 << 4), // Modifier - block while refresh runs }; void addFrameFlag(frameFlagTypes flag); @@ -112,6 +113,7 @@ class EInkDynamicDisplay : public EInkDisplay #if defined(HAS_EINK_ASYNCFULL) void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh() + void awaitRefresh(); // Hold control while an async refresh runs void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay() bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh() #endif From a9c07a4c016f330cf6a50c3dd8ed61ab0e535453 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 04:07:51 +1300 Subject: [PATCH 28/94] add frameFlags to LOG_DEBUG() messages --- src/graphics/EInkDynamicDisplay.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 2b3659099..d53969540 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -241,7 +241,7 @@ void EInkDynamicDisplay::checkCosmetic() if (frameFlags & COSMETIC) { refresh = FULL; reason = FLAGGED_COSMETIC; - LOG_DEBUG("refresh=FULL, reason=FLAGGED_COSMETIC\n"); + LOG_DEBUG("refresh=FULL, reason=FLAGGED_COSMETIC, frameFlags=0x%x\n", frameFlags); } } @@ -256,7 +256,7 @@ void EInkDynamicDisplay::checkDemandingFast() if (frameFlags & DEMAND_FAST) { refresh = FAST; reason = FLAGGED_DEMAND_FAST; - LOG_DEBUG("refresh=FAST, reason=FLAGGED_DEMAND_FAST\n"); + LOG_DEBUG("refresh=FAST, reason=FLAGGED_DEMAND_FAST, frameFlags=0x%x\n", frameFlags); } } @@ -276,7 +276,7 @@ void EInkDynamicDisplay::checkFrameMatchesPrevious() if (frameFlags == BACKGROUND && fastRefreshCount > 0) { refresh = FULL; reason = REDRAW_WITH_FULL; - LOG_DEBUG("refresh=FULL, reason=REDRAW_WITH_FULL\n"); + LOG_DEBUG("refresh=FULL, reason=REDRAW_WITH_FULL, frameFlags=0x%x\n", frameFlags); return; } #endif @@ -298,7 +298,7 @@ void EInkDynamicDisplay::checkConsecutiveFastRefreshes() if (fastRefreshCount >= EINK_LIMIT_FASTREFRESH) { refresh = FULL; reason = EXCEEDED_LIMIT_FASTREFRESH; - LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH\n"); + LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH, frameFlags=0x%x\n", frameFlags); } } @@ -313,7 +313,8 @@ void EInkDynamicDisplay::checkFastRequested() // If we want BACKGROUND to use fast. (FULL only when a limit is hit) refresh = FAST; reason = BACKGROUND_USES_FAST; - LOG_DEBUG("refresh=FAST, reason=BACKGROUND_USES_FAST, fastRefreshCount=%lu\n", fastRefreshCount); + LOG_DEBUG("refresh=FAST, reason=BACKGROUND_USES_FAST, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount, + frameFlags); #else // If we do want to use FULL for BACKGROUND updates refresh = FULL; @@ -326,7 +327,7 @@ void EInkDynamicDisplay::checkFastRequested() if (frameFlags & RESPONSIVE) { refresh = FAST; reason = NO_OBJECTIONS; - LOG_DEBUG("refresh=FAST, reason=NO_OBJECTIONS, fastRefreshCount=%lu\n", fastRefreshCount); + LOG_DEBUG("refresh=FAST, reason=NO_OBJECTIONS, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount, frameFlags); } } @@ -407,7 +408,7 @@ void EInkDynamicDisplay::checkExcessiveGhosting() if (ghostPixelCount > EINK_LIMIT_GHOSTING_PX) { refresh = FULL; reason = EXCEEDED_GHOSTINGLIMIT; - LOG_DEBUG("refresh=FULL, reason=EXCEEDED_GHOSTINGLIMIT\n"); + LOG_DEBUG("refresh=FULL, reason=EXCEEDED_GHOSTINGLIMIT, frameFlags=0x%x\n", frameFlags); } } From 94eb837ee8c506ef4838d720f343a51914cd0a94 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 04:14:45 +1300 Subject: [PATCH 29/94] function macro for tidier addFramFlag() calls --- src/graphics/EInkDynamicDisplay.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index ed5be70cd..495d20e7b 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -119,4 +119,10 @@ class EInkDynamicDisplay : public EInkDisplay #endif }; +// Tidier calls to addFrameFlag() from outside class +#define EINK_ADD_FRAMEFLAG(display, flag) static_cast(display)->addFrameFlag(EInkDynamicDisplay::flag) + +#else // !USE_EINK_DYNAMICDISPLAY +// Dummy-macro, removes the need for include guards +#define EINK_ADD_FRAMEFLAG(display, flag) #endif \ No newline at end of file From 7b703244351eb5bbee8542a638a04e12e965db28 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 05:00:51 +1300 Subject: [PATCH 30/94] handle special frames in Screen.cpp --- src/graphics/Screen.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 3ffea4a60..7f20b5666 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -260,6 +260,10 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i /// Used on eink displays while in deep sleep static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { + // Next frame should use full-refresh, and block while running, else device will sleep before async callback + EINK_ADD_FRAMEFLAG(display, COSMETIC); + EINK_ADD_FRAMEFLAG(display, BLOCKING); + drawIconScreen("Sleeping...", display, state, x, y); } #endif @@ -1170,6 +1174,7 @@ int32_t Screen::runOnce() break; case Cmd::STOP_BLUETOOTH_PIN_SCREEN: case Cmd::STOP_BOOT_SCREEN: + EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame setFrames(); break; case Cmd::PRINT: @@ -1350,6 +1355,7 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin) { LOG_DEBUG("showing bluetooth screen\n"); showingNormalScreen = false; + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame static FrameCallback frames[] = {drawFrameBluetooth}; snprintf(btPIN, sizeof(btPIN), "%06u", pin); @@ -1367,6 +1373,7 @@ void Screen::handleShutdownScreen() { LOG_DEBUG("showing shutdown screen\n"); showingNormalScreen = false; + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { drawFrameText(display, state, x, y, "Shutting down..."); @@ -1380,6 +1387,7 @@ void Screen::handleRebootScreen() { LOG_DEBUG("showing reboot screen\n"); showingNormalScreen = false; + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { drawFrameText(display, state, x, y, "Rebooting..."); @@ -1392,6 +1400,7 @@ void Screen::handleStartFirmwareUpdateScreen() { LOG_DEBUG("showing firmware screen\n"); showingNormalScreen = false; + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame static FrameCallback frames[] = {drawFrameFirmware}; setFrameImmediateDraw(frames); From 3da7c0dba709c8b38a80371d59f1f693430cc65c Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:32:49 +0100 Subject: [PATCH 31/94] Add hops_away to JSON output (#3357) --- src/mqtt/MQTT.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 898607eca..b25075177 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -808,6 +808,8 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); if (mp->rx_snr != 0) jsonObj["snr"] = new JSONValue((float)mp->rx_snr); + if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) + jsonObj["hops_away"] = new JSONValue((uint)(mp->hop_start - mp->hop_limit)); // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); From 7167f1e04f3a7f76b4dc476bf36df581d6afeb9c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 9 Mar 2024 15:25:16 -0600 Subject: [PATCH 32/94] Add parens to macro (#3361) --- src/gps/GeoCoord.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h index 9f911ed93..e811035db 100644 --- a/src/gps/GeoCoord.h +++ b/src/gps/GeoCoord.h @@ -11,7 +11,7 @@ #define PI 3.1415926535897932384626433832795 #define OLC_CODE_LEN 11 -#define DEG_CONVERT 180 / PI +#define DEG_CONVERT (180 / PI) // Helper functions // Raises a number to an exponent, handling negative exponents. From dced888492a915e84d74cbd3fc2afa5d07ff54d8 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 9 Mar 2024 13:40:03 -0600 Subject: [PATCH 33/94] Add precision_bit sto json --- src/mqtt/MQTT.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index b25075177..619815e85 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -655,6 +655,9 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) if ((int)decoded->VDOP) { msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP); } + if ((int)decoded->precision_bits) { + msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits); + } jsonObj["payload"] = new JSONValue(msgPayload); } else { LOG_ERROR("Error decoding protobuf for position message!\n"); From 3daae24d29d2962d38fa33f2b4577c09698b04db Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 13:43:57 +1300 Subject: [PATCH 34/94] fix fallback behavior for unmodified GxEPD2 Issues exposed by https://github.com/meshtastic/firmware/pull/3356#issuecomment-1986950317 --- src/graphics/EInkDynamicDisplay.cpp | 58 +++++++++++++++++------------ src/graphics/EInkDynamicDisplay.h | 2 +- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index d53969540..2f3c2fd0e 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -96,18 +96,45 @@ bool EInkDynamicDisplay::update() { // Detemine the refresh mode to use, and start the update bool refreshApproved = determineMode(); - if (refreshApproved) + if (refreshApproved) { EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system + storeAndReset(); // Store the result of this loop for next time. Note: call *before* endOrDetach() + endOrDetach(); // endUpdate() right now, or set the async refresh flag (if FULL and HAS_EINK_ASYNC) + } else + storeAndReset(); // No update, no post-update code, just store the results -#if defined(HAS_EINK_ASYNCFULL) - if (refreshApproved) - endOrDetach(); // Either endUpdate() right now (fast refresh), or set the async flag (full refresh) -#endif - - storeAndReset(); // Store the result of this loop for next time return refreshApproved; // (Unutilized) Base class promises to return true if update ran } +// Figure out who runs the post-update code +void EInkDynamicDisplay::endOrDetach() +{ + // If the GxEPD2 version reports that it has the async modifications +#ifdef HAS_EINK_ASYNCFULL + if (previousRefresh == FULL) { + asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop. + + if (previousFrameFlags & BLOCKING) + awaitRefresh(); + else + LOG_DEBUG("Async full-refresh begins\n"); + } + + // Fast Refresh + else if (previousRefresh == FAST) + EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves. + + // Fallback - If using an unmodified version of GxEPD2 for some reason +#else + if (previousRefresh == FULL || previousRefresh == FAST) { // If refresh wasn't skipped (on unspecified..) + LOG_WARN( + "GxEPD2 version has not been modified to support async refresh; using fallback behavior. Please update lib_deps in " + "variant's platformio.ini file\n"); + EInkDisplay::endUpdate(); + } +#endif +} + // Assess situation, pick a refresh type bool EInkDynamicDisplay::determineMode() { @@ -456,23 +483,6 @@ void EInkDynamicDisplay::checkAsyncFullRefresh() // It is only equipped to intercept calls to nextPage() } -// Figure out who runs the post-update code -void EInkDynamicDisplay::endOrDetach() -{ - if (refresh == FULL) { - asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop. - - if (frameFlags & BLOCKING) - awaitRefresh(); - else - LOG_DEBUG("Async full-refresh begins\n"); - } - - // Fast Refresh - else - EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves. -} - // Hold control while an async refresh runs void EInkDynamicDisplay::awaitRefresh() { diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 495d20e7b..dcae056c6 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -68,6 +68,7 @@ class EInkDynamicDisplay : public EInkDisplay void applyRefreshMode(); // Run any relevant GxEPD2 code, so next update will use correct refresh type void adjustRefreshCounters(); // Update fastRefreshCount bool update(); // Trigger the display update - determine mode, then call base class + void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh() // Checks as part of determineMode() void checkInitialized(); // Is this the very first frame? @@ -112,7 +113,6 @@ class EInkDynamicDisplay : public EInkDisplay // Conditional - async full refresh - only with modified meshtastic/GxEPD2 #if defined(HAS_EINK_ASYNCFULL) void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready - void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh() void awaitRefresh(); // Hold control while an async refresh runs void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay() bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh() From c0a3b20aa3eec657300b9c83b97dc1b3e8d8d00c Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Sun, 10 Mar 2024 13:45:35 +1300 Subject: [PATCH 35/94] while drafting, build from todd-herbert/meshtastic-GxEPD2#async --- variants/heltec_wireless_paper/platformio.ini | 2 +- variants/heltec_wireless_paper_v1/platformio.ini | 2 +- variants/t-echo/platformio.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 14275830a..8ff475d06 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -16,7 +16,7 @@ build_flags = -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/ + https://github.com/todd-herbert/meshtastic-GxEPD2#async adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index 4e5e291e0..9327ed256 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -16,7 +16,7 @@ build_flags = ;-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/ + https://github.com/todd-herbert/meshtastic-GxEPD2#async adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index c97341a3b..1a35f2f28 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -20,7 +20,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} - https://github.com/meshtastic/GxEPD2 + https://github.com/todd-herbert/meshtastic-GxEPD2#async adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs From 3da1b74a103df8cdead31f671eb46ac2ac0acf2a Mon Sep 17 00:00:00 2001 From: Andre K Date: Sun, 10 Mar 2024 05:39:37 -0300 Subject: [PATCH 36/94] refactor: always send range tests with zero hops --- src/modules/RangeTestModule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index ecf4b70c7..b45068b45 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -113,7 +113,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies) meshtastic_MeshPacket *p = allocDataPacket(); p->to = dest; p->decoded.want_response = wantReplies; - + p->hop_limit = 0; p->want_ack = true; packetSequence++; @@ -295,4 +295,4 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp) #endif return 1; -} \ No newline at end of file +} From 1032e16ea44d824fdfe49ffc0c4bf5c146bf712c Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Mon, 11 Mar 2024 01:02:03 +1300 Subject: [PATCH 37/94] reorder determineMode() checks --- src/graphics/EInkDynamicDisplay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index 2f3c2fd0e..732f6d3fb 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -99,7 +99,7 @@ bool EInkDynamicDisplay::update() if (refreshApproved) { EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system storeAndReset(); // Store the result of this loop for next time. Note: call *before* endOrDetach() - endOrDetach(); // endUpdate() right now, or set the async refresh flag (if FULL and HAS_EINK_ASYNC) + endOrDetach(); // endUpdate() right now, or set the async refresh flag (if FULL and HAS_EINK_ASYNCFULL) } else storeAndReset(); // No update, no post-update code, just store the results @@ -158,11 +158,11 @@ bool EInkDynamicDisplay::determineMode() // Once mode determined, any remaining checks will bypass checkCosmetic(); checkDemandingFast(); + checkFrameMatchesPrevious(); + checkConsecutiveFastRefreshes(); #ifdef EINK_LIMIT_GHOSTING_PX checkExcessiveGhosting(); #endif - checkFrameMatchesPrevious(); - checkConsecutiveFastRefreshes(); checkFastRequested(); if (refresh == UNSPECIFIED) From af9d14c370699c8a8cc618763052ecf12eccb461 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 10 Mar 2024 14:52:37 +0100 Subject: [PATCH 38/94] Periodic reporting of device information to a map via MQTT --- src/mesh/Channels.cpp | 20 +++++++ src/mesh/Channels.h | 3 + src/mesh/NodeDB.cpp | 7 ++- src/mesh/NodeDB.h | 8 ++- src/mesh/RadioInterface.cpp | 6 ++ src/mesh/RadioInterface.h | 3 + src/mqtt/MQTT.cpp | 107 +++++++++++++++++++++++++++++++----- src/mqtt/MQTT.h | 17 ++++-- 8 files changed, 149 insertions(+), 22 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 2d27c737d..b50ecf6ca 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -2,6 +2,7 @@ #include "CryptoEngine.h" #include "DisplayFormatters.h" #include "NodeDB.h" +#include "RadioInterface.h" #include "configuration.h" #include @@ -254,6 +255,25 @@ const char *Channels::getName(size_t chIndex) return channelName; } +bool Channels::hasDefaultChannel() +{ + // If we don't use a preset or we override the frequency, we don't have a default channel + if (!config.lora.use_preset || config.lora.override_frequency) + return false; + // Check if any of the channels are using the default name and PSK + for (size_t i = 0; i < getNumChannels(); i++) { + const auto &ch = getByIndex(i); + if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) { + const char *name = getName(i); + const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false); + // Check if the name is the default derived from the modem preset and we use the default frequency slot + if (strcmp(name, presetName) == 0 && RadioInterface::uses_default_frequency_slot) + return true; + } + } + return false; +} + /** * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 87a72e07b..0e11605c4 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -102,6 +102,9 @@ class Channels */ int16_t setActiveByIndex(ChannelIndex channelIndex); + // Returns true if we can be reached via a channel with the default settings given a region and modem preset + bool hasDefaultChannel(); + private: /** Given a channel index, change to use the crypto key specified by that index * diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 787c16a79..9d7647138 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -744,14 +744,17 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p) #define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline -size_t NodeDB::getNumOnlineMeshNodes() +size_t NodeDB::getNumOnlineMeshNodes(bool localOnly) { size_t numseen = 0; // FIXME this implementation is kinda expensive - for (int i = 0; i < *numMeshNodes; i++) + for (int i = 0; i < *numMeshNodes; i++) { + if (localOnly && meshNodes[i].via_mqtt) + continue; if (sinceLastSeen(&meshNodes[i]) < NUM_ONLINE_SECS) numseen++; + } return numseen; } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e24a971c1..8545b08d6 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -108,8 +108,10 @@ class NodeDB // get channel channel index we heard a nodeNum on, defaults to 0 if not found uint8_t getMeshNodeChannel(NodeNum n); - /// Return the number of nodes we've heard from recently (within the last 2 hrs?) - size_t getNumOnlineMeshNodes(); + /* Return the number of nodes we've heard from recently (within the last 2 hrs?) + * @param localOnly if true, ignore nodes heard via MQTT + */ + size_t getNumOnlineMeshNodes(bool localOnly = false); void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum); @@ -246,4 +248,4 @@ extern uint32_t error_address; #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ - ModuleConfig_TelemetryConfig_size + ModuleConfig_size) + ModuleConfig_TelemetryConfig_size + ModuleConfig_size) \ No newline at end of file diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index c10eb26f6..7a2711251 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -1,5 +1,6 @@ #include "RadioInterface.h" #include "Channels.h" +#include "DisplayFormatters.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" @@ -143,6 +144,7 @@ const RegionInfo regions[] = { }; const RegionInfo *myRegion; +bool RadioInterface::uses_default_frequency_slot = true; static uint8_t bytes[MAX_RHPACKETLEN]; @@ -486,6 +488,10 @@ void RadioInterface::applyModemConfig() // channel_num is actually (channel_num - 1), since modulus (%) returns values from 0 to (numChannels - 1) int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels; + // Check if we use the default frequency slot + RadioInterface::uses_default_frequency_slot = + channel_num == hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false)) % numChannels; + // Old frequency selection formula // float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index f85b3bfa5..ee4726d74 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -175,6 +175,9 @@ class RadioInterface /// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers virtual bool isIRQPending() { return false; } + // Whether we use the default frequency slot given our LoRa config (region and modem preset) + static bool uses_default_frequency_slot; + protected: int8_t power = 17; // Set by applyModemConfig() diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 898607eca..426934be8 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -77,8 +77,7 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); p->decoded.payload.size = jsonPayloadStr.length(); - meshtastic_MeshPacket *packet = packetPool.allocCopy(*p); - service.sendToMesh(packet, RX_SRC_LOCAL); + service.sendToMesh(p, RX_SRC_LOCAL); } else { LOG_WARN("Received MQTT json payload too long, dropping\n"); } @@ -192,6 +191,11 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) jsonTopic = "msh" + jsonTopic; } + if (moduleConfig.mqtt.map_reporting_enabled && moduleConfig.mqtt.has_map_report_settings) { + map_position_precision = moduleConfig.mqtt.map_report_settings.position_precision; + map_publish_interval_secs = moduleConfig.mqtt.map_report_settings.publish_interval_secs; + } + #ifdef HAS_NETWORKING if (!moduleConfig.mqtt.proxy_to_client_enabled) pubSub.setCallback(mqttCallback); @@ -365,27 +369,30 @@ void MQTT::sendSubscriptions() bool MQTT::wantsLink() const { - bool hasChannel = false; + bool hasChannelorMapReport = false; if (moduleConfig.mqtt.enabled) { - // No need for link if no channel needed it - size_t numChan = channels.getNumChannels(); - for (size_t i = 0; i < numChan; i++) { - const auto &ch = channels.getByIndex(i); - if (ch.settings.uplink_enabled || ch.settings.downlink_enabled) { - hasChannel = true; - break; + hasChannelorMapReport = moduleConfig.mqtt.map_reporting_enabled; + if (!hasChannelorMapReport) { + // No need for link if no channel needed it + size_t numChan = channels.getNumChannels(); + for (size_t i = 0; i < numChan; i++) { + const auto &ch = channels.getByIndex(i); + if (ch.settings.uplink_enabled || ch.settings.downlink_enabled) { + hasChannelorMapReport = true; + break; + } } } } - if (hasChannel && moduleConfig.mqtt.proxy_to_client_enabled) + if (hasChannelorMapReport && moduleConfig.mqtt.proxy_to_client_enabled) return true; #if HAS_WIFI - return hasChannel && WiFi.isConnected(); + return hasChannelorMapReport && WiFi.isConnected(); #endif #if HAS_ETHERNET - return hasChannel && Ethernet.linkStatus() == LinkON; + return hasChannelorMapReport && Ethernet.linkStatus() == LinkON; #endif return false; } @@ -397,6 +404,8 @@ int32_t MQTT::runOnce() bool wantConnection = wantsLink(); + perhapsReportToMap(); + // If connected poll rapidly, otherwise only occasionally check for a wifi connection change and ability to contact server if (moduleConfig.mqtt.proxy_to_client_enabled) { publishQueuedMessages(); @@ -536,6 +545,78 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & } } +void MQTT::perhapsReportToMap() +{ + if (!moduleConfig.mqtt.map_reporting_enabled || !(moduleConfig.mqtt.proxy_to_client_enabled || isConnectedDirectly())) + return; + + if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) { + LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n"); + return; + } + + if (millis() - last_report_to_map < map_publish_interval_secs * 1000) { + return; + } else { + // Allocate ServiceEnvelope and fill it + meshtastic_ServiceEnvelope *se = mqttPool.allocZeroed(); + se->channel_id = (char *)channels.getGlobalId(channels.getPrimaryIndex()); // Use primary channel as the channel_id + se->gateway_id = owner.id; + + // Allocate MeshPacket and fill it + meshtastic_MeshPacket *mp = packetPool.allocZeroed(); + mp->which_payload_variant = meshtastic_MeshPacket_decoded_tag; + mp->from = nodeDB.getNodeNum(); + mp->to = NODENUM_BROADCAST; + mp->decoded.portnum = meshtastic_PortNum_MAP_REPORT_APP; + + // Fill MapReport message + meshtastic_MapReport mapReport = meshtastic_MapReport_init_default; + memcpy(mapReport.long_name, owner.long_name, sizeof(owner.long_name)); + memcpy(mapReport.short_name, owner.short_name, sizeof(owner.short_name)); + mapReport.role = config.device.role; + mapReport.hw_model = owner.hw_model; + strncpy(mapReport.firmware_version, optstr(APP_VERSION), sizeof(mapReport.firmware_version)); + mapReport.region = config.lora.region; + mapReport.modem_preset = config.lora.modem_preset; + mapReport.has_default_channel = channels.hasDefaultChannel(); + + // Set position with precision (same as in PositionModule) + if (map_position_precision < 32 && map_position_precision > 0) { + mapReport.latitude_i = localPosition.latitude_i & (UINT32_MAX << (32 - map_position_precision)); + mapReport.longitude_i = localPosition.longitude_i & (UINT32_MAX << (32 - map_position_precision)); + mapReport.latitude_i += (1 << (31 - map_position_precision)); + mapReport.longitude_i += (1 << (31 - map_position_precision)); + } else { + mapReport.latitude_i = localPosition.latitude_i; + mapReport.longitude_i = localPosition.longitude_i; + } + mapReport.altitude = localPosition.altitude; + mapReport.position_precision = map_position_precision; + + mapReport.num_online_local_nodes = nodeDB.getNumOnlineMeshNodes(true); + + // Encode MapReport message and set it to MeshPacket in ServiceEnvelope + mp->decoded.payload.size = pb_encode_to_bytes(mp->decoded.payload.bytes, sizeof(mp->decoded.payload.bytes), + &meshtastic_MapReport_msg, &mapReport); + se->packet = mp; + + // FIXME - this size calculation is super sloppy, but it will go away once we dynamically alloc meshpackets + static uint8_t bytes[meshtastic_MeshPacket_size + 64]; + size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, se); + + LOG_INFO("MQTT Publish map report to %s\n", statusTopic.c_str()); + publish(statusTopic.c_str(), bytes, numBytes, false); + + // Release the allocated memory for ServiceEnvelope and MeshPacket + mqttPool.release(se); + packetPool.release(mp); + + // Update the last report time + last_report_to_map = millis(); + } +} + // converts a downstream packet into a json message std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) { diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 2b803e3fc..1599c7ae8 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -79,10 +79,16 @@ class MQTT : private concurrency::OSThread virtual int32_t runOnce() override; private: - std::string statusTopic = "/2/stat/"; - std::string cryptTopic = "/2/c/"; // msh/2/c/CHANNELID/NODEID - std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID - /** return true if we have a channel that wants uplink/downlink + std::string statusTopic = "/2/stat/"; // For "online"/"offline" message and MapReport + std::string cryptTopic = "/2/c/"; // msh/2/c/CHANNELID/NODEID + std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID + + // For map reporting (only applies when enabled) + uint32_t last_report_to_map = 0; + uint32_t map_position_precision = 32; // default to full precision + uint32_t map_publish_interval_secs = 60 * 15; // default to 15 minutes + + /** return true if we have a channel that wants uplink/downlink or map reporting is enabled */ bool wantsLink() const; @@ -102,6 +108,9 @@ class MQTT : private concurrency::OSThread void publishStatus(); void publishQueuedMessages(); + // Check if we should report unencrypted information about our node for consumption by a map + void perhapsReportToMap(); + // returns true if this is a valid JSON envelope which we accept on downlink bool isValidJsonEnvelope(JSONObject &json); From 69dcc948b9631e798f232c3669e114a8da0ab9a7 Mon Sep 17 00:00:00 2001 From: caveman99 Date: Sun, 10 Mar 2024 14:39:40 +0000 Subject: [PATCH 39/94] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- .../generated/meshtastic/module_config.pb.c | 5 +- .../generated/meshtastic/module_config.pb.h | 42 ++++++++++-- src/mesh/generated/meshtastic/mqtt.pb.c | 3 + src/mesh/generated/meshtastic/mqtt.pb.h | 68 +++++++++++++++++++ src/mesh/generated/meshtastic/portnums.pb.h | 2 + 8 files changed, 117 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index 5a97acb17..00332412b 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 5a97acb17543a10e114675a205e3274a83e721af +Subproject commit 00332412b238fe559175a6e83fdf8d31fa5e209a diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index ca4b2176b..556821e1c 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -324,7 +324,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; #define meshtastic_DeviceState_size 17571 #define meshtastic_NodeInfoLite_size 158 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3246 +#define meshtastic_OEMStore_size 3262 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 7d39da01f..2e22cb1e4 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_LocalConfig_size 469 -#define meshtastic_LocalModuleConfig_size 631 +#define meshtastic_LocalModuleConfig_size 647 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.c b/src/mesh/generated/meshtastic/module_config.pb.c index 38965f3e2..a75c3fb59 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.c +++ b/src/mesh/generated/meshtastic/module_config.pb.c @@ -6,12 +6,15 @@ #error Regenerate this file with the current version of nanopb generator. #endif -PB_BIND(meshtastic_ModuleConfig, meshtastic_ModuleConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig, meshtastic_ModuleConfig, 2) PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig_MapReportSettings, meshtastic_ModuleConfig_MapReportSettings, AUTO) + + PB_BIND(meshtastic_ModuleConfig_RemoteHardwareConfig, meshtastic_ModuleConfig_RemoteHardwareConfig, AUTO) diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index edfd56e4c..2e1c25c7f 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -84,6 +84,14 @@ typedef enum _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar { } meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar; /* Struct definitions */ +/* Settings for reporting unencrypted information about our node to a map via MQTT */ +typedef struct _meshtastic_ModuleConfig_MapReportSettings { + /* How often we should report our info to the map (in seconds) */ + uint32_t publish_interval_secs; + /* Bits of precision for the location sent (default of 32 is full precision). */ + uint32_t position_precision; +} meshtastic_ModuleConfig_MapReportSettings; + /* MQTT Client Config */ typedef struct _meshtastic_ModuleConfig_MQTTConfig { /* If a meshtastic node is able to reach the internet it will normally attempt to gateway any channels that are marked as @@ -114,6 +122,11 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig { char root[16]; /* If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection */ bool proxy_to_client_enabled; + /* If true, we will periodically report unencrypted information about our node to a map via MQTT */ + bool map_reporting_enabled; + /* Settings for reporting information about our node to a map via MQTT */ + bool has_map_report_settings; + meshtastic_ModuleConfig_MapReportSettings map_report_settings; } meshtastic_ModuleConfig_MQTTConfig; /* NeighborInfoModule Config */ @@ -427,6 +440,7 @@ extern "C" { + #define meshtastic_ModuleConfig_AudioConfig_bitrate_ENUMTYPE meshtastic_ModuleConfig_AudioConfig_Audio_Baud @@ -447,7 +461,8 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}} -#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0} +#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_default} +#define meshtastic_ModuleConfig_MapReportSettings_init_default {0, 0} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0} #define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0} @@ -462,7 +477,8 @@ extern "C" { #define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} #define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}} -#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0} +#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_zero} +#define meshtastic_ModuleConfig_MapReportSettings_init_zero {0, 0} #define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}} #define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0} #define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0} @@ -478,6 +494,8 @@ extern "C" { #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} /* Field tags (for use in manual encoding/decoding) */ +#define meshtastic_ModuleConfig_MapReportSettings_publish_interval_secs_tag 1 +#define meshtastic_ModuleConfig_MapReportSettings_position_precision_tag 2 #define meshtastic_ModuleConfig_MQTTConfig_enabled_tag 1 #define meshtastic_ModuleConfig_MQTTConfig_address_tag 2 #define meshtastic_ModuleConfig_MQTTConfig_username_tag 3 @@ -487,6 +505,8 @@ extern "C" { #define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7 #define meshtastic_ModuleConfig_MQTTConfig_root_tag 8 #define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9 +#define meshtastic_ModuleConfig_MQTTConfig_map_reporting_enabled_tag 10 +#define meshtastic_ModuleConfig_MQTTConfig_map_report_settings_tag 11 #define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1 #define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2 #define meshtastic_ModuleConfig_DetectionSensorConfig_enabled_tag 1 @@ -623,9 +643,18 @@ X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) \ X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7) \ X(a, STATIC, SINGULAR, STRING, root, 8) \ -X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9) +X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9) \ +X(a, STATIC, SINGULAR, BOOL, map_reporting_enabled, 10) \ +X(a, STATIC, OPTIONAL, MESSAGE, map_report_settings, 11) #define meshtastic_ModuleConfig_MQTTConfig_CALLBACK NULL #define meshtastic_ModuleConfig_MQTTConfig_DEFAULT NULL +#define meshtastic_ModuleConfig_MQTTConfig_map_report_settings_MSGTYPE meshtastic_ModuleConfig_MapReportSettings + +#define meshtastic_ModuleConfig_MapReportSettings_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, publish_interval_secs, 1) \ +X(a, STATIC, SINGULAR, UINT32, position_precision, 2) +#define meshtastic_ModuleConfig_MapReportSettings_CALLBACK NULL +#define meshtastic_ModuleConfig_MapReportSettings_DEFAULT NULL #define meshtastic_ModuleConfig_RemoteHardwareConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ @@ -764,6 +793,7 @@ X(a, STATIC, SINGULAR, UENUM, type, 3) extern const pb_msgdesc_t meshtastic_ModuleConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_MQTTConfig_msg; +extern const pb_msgdesc_t meshtastic_ModuleConfig_MapReportSettings_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_RemoteHardwareConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_NeighborInfoConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_DetectionSensorConfig_msg; @@ -781,6 +811,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_ModuleConfig_fields &meshtastic_ModuleConfig_msg #define meshtastic_ModuleConfig_MQTTConfig_fields &meshtastic_ModuleConfig_MQTTConfig_msg +#define meshtastic_ModuleConfig_MapReportSettings_fields &meshtastic_ModuleConfig_MapReportSettings_msg #define meshtastic_ModuleConfig_RemoteHardwareConfig_fields &meshtastic_ModuleConfig_RemoteHardwareConfig_msg #define meshtastic_ModuleConfig_NeighborInfoConfig_fields &meshtastic_ModuleConfig_NeighborInfoConfig_msg #define meshtastic_ModuleConfig_DetectionSensorConfig_fields &meshtastic_ModuleConfig_DetectionSensorConfig_msg @@ -801,7 +832,8 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_CannedMessageConfig_size 49 #define meshtastic_ModuleConfig_DetectionSensorConfig_size 44 #define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42 -#define meshtastic_ModuleConfig_MQTTConfig_size 222 +#define meshtastic_ModuleConfig_MQTTConfig_size 238 +#define meshtastic_ModuleConfig_MapReportSettings_size 12 #define meshtastic_ModuleConfig_NeighborInfoConfig_size 8 #define meshtastic_ModuleConfig_PaxcounterConfig_size 8 #define meshtastic_ModuleConfig_RangeTestConfig_size 10 @@ -809,7 +841,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 22 #define meshtastic_ModuleConfig_TelemetryConfig_size 36 -#define meshtastic_ModuleConfig_size 225 +#define meshtastic_ModuleConfig_size 241 #define meshtastic_RemoteHardwarePin_size 21 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/mqtt.pb.c b/src/mesh/generated/meshtastic/mqtt.pb.c index 3046e6109..a43f364e1 100644 --- a/src/mesh/generated/meshtastic/mqtt.pb.c +++ b/src/mesh/generated/meshtastic/mqtt.pb.c @@ -9,4 +9,7 @@ PB_BIND(meshtastic_ServiceEnvelope, meshtastic_ServiceEnvelope, AUTO) +PB_BIND(meshtastic_MapReport, meshtastic_MapReport, AUTO) + + diff --git a/src/mesh/generated/meshtastic/mqtt.pb.h b/src/mesh/generated/meshtastic/mqtt.pb.h index 12e83c724..8ca570d78 100644 --- a/src/mesh/generated/meshtastic/mqtt.pb.h +++ b/src/mesh/generated/meshtastic/mqtt.pb.h @@ -5,6 +5,7 @@ #define PB_MESHTASTIC_MESHTASTIC_MQTT_PB_H_INCLUDED #include #include "meshtastic/mesh.pb.h" +#include "meshtastic/config.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. @@ -23,6 +24,38 @@ typedef struct _meshtastic_ServiceEnvelope { char *gateway_id; } meshtastic_ServiceEnvelope; +/* Information about a node intended to be reported unencrypted to a map using MQTT. */ +typedef struct _meshtastic_MapReport { + /* A full name for this user, i.e. "Kevin Hester" */ + char long_name[40]; + /* A VERY short name, ideally two characters. + Suitable for a tiny OLED screen */ + char short_name[5]; + /* Role of the node that applies specific settings for a particular use-case */ + meshtastic_Config_DeviceConfig_Role role; + /* Hardware model of the node, i.e. T-Beam, Heltec V3, etc... */ + meshtastic_HardwareModel hw_model; + /* Device firmware version string */ + char firmware_version[18]; + /* The region code for the radio (US, CN, EU433, etc...) */ + meshtastic_Config_LoRaConfig_RegionCode region; + /* Modem preset used by the radio (LongFast, MediumSlow, etc...) */ + meshtastic_Config_LoRaConfig_ModemPreset modem_preset; + /* Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...) + and it uses the default frequency slot given the region and modem preset. */ + bool has_default_channel; + /* Latitude: multiply by 1e-7 to get degrees in floating point */ + int32_t latitude_i; + /* Longitude: multiply by 1e-7 to get degrees in floating point */ + int32_t longitude_i; + /* Altitude in meters above MSL */ + int32_t altitude; + /* Indicates the bits of precision for latitude and longitude set by the sending node */ + uint32_t position_precision; + /* Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT) */ + uint16_t num_online_local_nodes; +} meshtastic_MapReport; + #ifdef __cplusplus extern "C" { @@ -30,12 +63,27 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_ServiceEnvelope_init_default {NULL, NULL, NULL} +#define meshtastic_MapReport_init_default {"", "", _meshtastic_Config_DeviceConfig_Role_MIN, _meshtastic_HardwareModel_MIN, "", _meshtastic_Config_LoRaConfig_RegionCode_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, 0, 0} #define meshtastic_ServiceEnvelope_init_zero {NULL, NULL, NULL} +#define meshtastic_MapReport_init_zero {"", "", _meshtastic_Config_DeviceConfig_Role_MIN, _meshtastic_HardwareModel_MIN, "", _meshtastic_Config_LoRaConfig_RegionCode_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, 0, 0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_ServiceEnvelope_packet_tag 1 #define meshtastic_ServiceEnvelope_channel_id_tag 2 #define meshtastic_ServiceEnvelope_gateway_id_tag 3 +#define meshtastic_MapReport_long_name_tag 1 +#define meshtastic_MapReport_short_name_tag 2 +#define meshtastic_MapReport_role_tag 3 +#define meshtastic_MapReport_hw_model_tag 4 +#define meshtastic_MapReport_firmware_version_tag 5 +#define meshtastic_MapReport_region_tag 6 +#define meshtastic_MapReport_modem_preset_tag 7 +#define meshtastic_MapReport_has_default_channel_tag 8 +#define meshtastic_MapReport_latitude_i_tag 9 +#define meshtastic_MapReport_longitude_i_tag 10 +#define meshtastic_MapReport_altitude_tag 11 +#define meshtastic_MapReport_position_precision_tag 12 +#define meshtastic_MapReport_num_online_local_nodes_tag 13 /* Struct field encoding specification for nanopb */ #define meshtastic_ServiceEnvelope_FIELDLIST(X, a) \ @@ -46,13 +94,33 @@ X(a, POINTER, SINGULAR, STRING, gateway_id, 3) #define meshtastic_ServiceEnvelope_DEFAULT NULL #define meshtastic_ServiceEnvelope_packet_MSGTYPE meshtastic_MeshPacket +#define meshtastic_MapReport_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, long_name, 1) \ +X(a, STATIC, SINGULAR, STRING, short_name, 2) \ +X(a, STATIC, SINGULAR, UENUM, role, 3) \ +X(a, STATIC, SINGULAR, UENUM, hw_model, 4) \ +X(a, STATIC, SINGULAR, STRING, firmware_version, 5) \ +X(a, STATIC, SINGULAR, UENUM, region, 6) \ +X(a, STATIC, SINGULAR, UENUM, modem_preset, 7) \ +X(a, STATIC, SINGULAR, BOOL, has_default_channel, 8) \ +X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 9) \ +X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 10) \ +X(a, STATIC, SINGULAR, INT32, altitude, 11) \ +X(a, STATIC, SINGULAR, UINT32, position_precision, 12) \ +X(a, STATIC, SINGULAR, UINT32, num_online_local_nodes, 13) +#define meshtastic_MapReport_CALLBACK NULL +#define meshtastic_MapReport_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_ServiceEnvelope_msg; +extern const pb_msgdesc_t meshtastic_MapReport_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_ServiceEnvelope_fields &meshtastic_ServiceEnvelope_msg +#define meshtastic_MapReport_fields &meshtastic_MapReport_msg /* Maximum encoded size of messages (where known) */ /* meshtastic_ServiceEnvelope_size depends on runtime parameters */ +#define meshtastic_MapReport_size 108 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 3f3e9aaee..f576c7893 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -122,6 +122,8 @@ typedef enum _meshtastic_PortNum { /* ATAK Plugin Portnum for payloads from the official Meshtastic ATAK plugin */ meshtastic_PortNum_ATAK_PLUGIN = 72, + /* Provides unencrypted information about a node for consumption by a map via MQTT */ + meshtastic_PortNum_MAP_REPORT_APP = 73, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ From b45a912409c067b9ea6c0c41799a1128800cab4b Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 10 Mar 2024 15:56:00 +0100 Subject: [PATCH 40/94] Use dedicated `map` topic --- src/mqtt/MQTT.cpp | 6 ++++-- src/mqtt/MQTT.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index b33132aa4..2de35971a 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -185,10 +185,12 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) statusTopic = moduleConfig.mqtt.root + statusTopic; cryptTopic = moduleConfig.mqtt.root + cryptTopic; jsonTopic = moduleConfig.mqtt.root + jsonTopic; + mapTopic = moduleConfig.mqtt.root + jsonTopic; } else { statusTopic = "msh" + statusTopic; cryptTopic = "msh" + cryptTopic; jsonTopic = "msh" + jsonTopic; + mapTopic = "msh" + mapTopic; } if (moduleConfig.mqtt.map_reporting_enabled && moduleConfig.mqtt.has_map_report_settings) { @@ -605,8 +607,8 @@ void MQTT::perhapsReportToMap() static uint8_t bytes[meshtastic_MeshPacket_size + 64]; size_t numBytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_ServiceEnvelope_msg, se); - LOG_INFO("MQTT Publish map report to %s\n", statusTopic.c_str()); - publish(statusTopic.c_str(), bytes, numBytes, false); + LOG_INFO("MQTT Publish map report to %s\n", mapTopic.c_str()); + publish(mapTopic.c_str(), bytes, numBytes, false); // Release the allocated memory for ServiceEnvelope and MeshPacket mqttPool.release(se); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index b665a6efc..eeeb00d92 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -79,9 +79,10 @@ class MQTT : private concurrency::OSThread virtual int32_t runOnce() override; private: - std::string statusTopic = "/2/stat/"; // For "online"/"offline" message and MapReport + std::string statusTopic = "/2/stat/"; // For "online"/"offline" message std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID + std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages // For map reporting (only applies when enabled) uint32_t last_report_to_map = 0; From cb7407e06ba88f8c9d1aec45e0ccae2101cc5d99 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 10 Mar 2024 16:04:59 +0100 Subject: [PATCH 41/94] Don't need to check all channels if not using default frequency slot --- src/mesh/Channels.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index b50ecf6ca..3e9c78241 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -257,8 +257,8 @@ const char *Channels::getName(size_t chIndex) bool Channels::hasDefaultChannel() { - // If we don't use a preset or we override the frequency, we don't have a default channel - if (!config.lora.use_preset || config.lora.override_frequency) + // If we don't use a preset or the default frequency slot, or we override the frequency, we don't have a default channel + if (!config.lora.use_preset || !RadioInterface::uses_default_frequency_slot || config.lora.override_frequency) return false; // Check if any of the channels are using the default name and PSK for (size_t i = 0; i < getNumChannels(); i++) { @@ -266,8 +266,8 @@ bool Channels::hasDefaultChannel() if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) { const char *name = getName(i); const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false); - // Check if the name is the default derived from the modem preset and we use the default frequency slot - if (strcmp(name, presetName) == 0 && RadioInterface::uses_default_frequency_slot) + // Check if the name is the default derived from the modem preset + if (strcmp(name, presetName) == 0) return true; } } From fb4faf790ba28fd09344c61a713728e647f6c711 Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Tue, 5 Mar 2024 23:39:43 +0100 Subject: [PATCH 42/94] split query of paxcounter data from sending funcionality; don't cummulate (count mode != 1); use flag to signal changed count data --- src/modules/esp32/PaxcounterModule.cpp | 24 ++++++++++++++++++------ src/modules/esp32/PaxcounterModule.h | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 2182ed124..29edb069d 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -7,8 +7,6 @@ PaxcounterModule *paxcounterModule; -void NullFunc(){}; - // paxcounterModule->sendInfo(NODENUM_BROADCAST); PaxcounterModule::PaxcounterModule() @@ -19,10 +17,14 @@ PaxcounterModule::PaxcounterModule() bool PaxcounterModule::sendInfo(NodeNum dest) { - libpax_counter_count(&count_from_libpax); - LOG_INFO("(Sending): pax: wifi=%d; ble=%d; uptime=%d\n", count_from_libpax.wifi_count, count_from_libpax.ble_count, + if (paxcounterModule->reportedDataSent) + return false; + + LOG_INFO("(Sending): pax: wifi=%d; ble=%d; uptime=%lu\n", count_from_libpax.wifi_count, count_from_libpax.ble_count, millis() / 1000); + paxcounterModule->reportedDataSent = true; + meshtastic_Paxcount pl = meshtastic_Paxcount_init_default; pl.wifi = count_from_libpax.wifi_count; pl.ble = count_from_libpax.ble_count; @@ -55,6 +57,14 @@ meshtastic_MeshPacket *PaxcounterModule::allocReply() return allocDataProtobuf(pl); } +void PaxcounterModule::handlePaxCounterReportRequest() +{ + // libpax_counter_count(&paxcounterModule->count_from_libpax); + LOG_INFO("(Reading): libPax reported new data: wifi=%d; ble=%d; uptime=%lu\n", paxcounterModule->count_from_libpax.wifi_count, + paxcounterModule->count_from_libpax.ble_count, millis() / 1000); + paxcounterModule->reportedDataSent = false; +} + int32_t PaxcounterModule::runOnce() { if (isActive()) { @@ -76,12 +86,14 @@ int32_t PaxcounterModule::runOnce() libpax_update_config(&configuration); // internal processing initialization - libpax_counter_init(NullFunc, &count_from_libpax, UINT16_MAX, 1); + libpax_counter_init(handlePaxCounterReportRequest, &count_from_libpax, + moduleConfig.paxcounter.paxcounter_update_interval, 0); libpax_counter_start(); } else { sendInfo(NODENUM_BROADCAST); } - return getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, default_broadcast_interval_secs); + // we check every second if the counter had new data to send + return 1000; } else { return disable(); } diff --git a/src/modules/esp32/PaxcounterModule.h b/src/modules/esp32/PaxcounterModule.h index e72f87450..67d47be56 100644 --- a/src/modules/esp32/PaxcounterModule.h +++ b/src/modules/esp32/PaxcounterModule.h @@ -13,10 +13,13 @@ class PaxcounterModule : private concurrency::OSThread, public ProtobufModule { bool firstTime = true; + bool reportedDataSent = true; public: PaxcounterModule(); + static void handlePaxCounterReportRequest(); + protected: struct count_payload_t count_from_libpax = {0, 0, 0}; virtual int32_t runOnce() override; From 73c77b663c0bff89aa28817d27faf667201088f6 Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Tue, 5 Mar 2024 23:48:52 +0100 Subject: [PATCH 43/94] fix typo --- src/modules/esp32/PaxcounterModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 29edb069d..94fcca36f 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -77,7 +77,7 @@ int32_t PaxcounterModule::runOnce() libpax_default_config(&configuration); configuration.blecounter = 1; - configuration.blescantime = 0; // infinit + configuration.blescantime = 0; // infinite configuration.wificounter = 1; configuration.wifi_channel_map = WIFI_CHANNEL_ALL; configuration.wifi_channel_switch_interval = 50; From 09e08e0091dc2c4ef2dfc2debdf7bda7b4f6f5b2 Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Wed, 6 Mar 2024 19:15:04 +0100 Subject: [PATCH 44/94] add some documentation, cleanup --- src/modules/esp32/PaxcounterModule.cpp | 39 +++++++++++++++++--------- src/modules/esp32/PaxcounterModule.h | 7 +++-- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 94fcca36f..e718d6261 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -7,7 +7,18 @@ PaxcounterModule *paxcounterModule; -// paxcounterModule->sendInfo(NODENUM_BROADCAST); +/** + * Callback function for libpax. + * We only clear our sent flag here, since this function is called from another thread, so we + * cannot send to the mesh directly. + */ +void PaxcounterModule::handlePaxCounterReportRequest() +{ + // The libpax library already updated our data structure, just before invoking this callback. + LOG_INFO("PaxcounterModule: libpax reported new data: wifi=%d; ble=%d; uptime=%lu\n", + paxcounterModule->count_from_libpax.wifi_count, paxcounterModule->count_from_libpax.ble_count, millis() / 1000); + paxcounterModule->reportedDataSent = false; +} PaxcounterModule::PaxcounterModule() : concurrency::OSThread("PaxcounterModule"), @@ -15,15 +26,20 @@ PaxcounterModule::PaxcounterModule() { } +/** + * Send the Pax information to the mesh if we got new data from libpax. + * This is called periodically from our runOnce() method and will actually send the data to the mesh + * if libpax updated it since the last transmission through the callback. + * @param dest - destination node (usually NODENUM_BROADCAST) + * @return false if sending is unnecessary, true if information was sent + */ bool PaxcounterModule::sendInfo(NodeNum dest) { if (paxcounterModule->reportedDataSent) return false; - LOG_INFO("(Sending): pax: wifi=%d; ble=%d; uptime=%lu\n", count_from_libpax.wifi_count, count_from_libpax.ble_count, - millis() / 1000); - - paxcounterModule->reportedDataSent = true; + LOG_INFO("PaxcounterModule: sending pax info wifi=%d; ble=%d; uptime=%lu\n", count_from_libpax.wifi_count, + count_from_libpax.ble_count, millis() / 1000); meshtastic_Paxcount pl = meshtastic_Paxcount_init_default; pl.wifi = count_from_libpax.wifi_count; @@ -33,9 +49,12 @@ bool PaxcounterModule::sendInfo(NodeNum dest) meshtastic_MeshPacket *p = allocDataProtobuf(pl); p->to = dest; p->decoded.want_response = false; - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_DEFAULT; service.sendToMesh(p, RX_SRC_LOCAL, true); + + paxcounterModule->reportedDataSent = true; + return true; } @@ -57,14 +76,6 @@ meshtastic_MeshPacket *PaxcounterModule::allocReply() return allocDataProtobuf(pl); } -void PaxcounterModule::handlePaxCounterReportRequest() -{ - // libpax_counter_count(&paxcounterModule->count_from_libpax); - LOG_INFO("(Reading): libPax reported new data: wifi=%d; ble=%d; uptime=%lu\n", paxcounterModule->count_from_libpax.wifi_count, - paxcounterModule->count_from_libpax.ble_count, millis() / 1000); - paxcounterModule->reportedDataSent = false; -} - int32_t PaxcounterModule::runOnce() { if (isActive()) { diff --git a/src/modules/esp32/PaxcounterModule.h b/src/modules/esp32/PaxcounterModule.h index 67d47be56..ebd6e7191 100644 --- a/src/modules/esp32/PaxcounterModule.h +++ b/src/modules/esp32/PaxcounterModule.h @@ -8,18 +8,19 @@ #include /** - * A simple example module that just replies with "Message received" to any message it receives. + * Wrapper module for the estimate passenger (PAX) count library (https://github.com/dbinfrago/libpax) which + * implements the core functionality of the ESP32 Paxcounter project (https://github.com/cyberman54/ESP32-Paxcounter) */ class PaxcounterModule : private concurrency::OSThread, public ProtobufModule { bool firstTime = true; bool reportedDataSent = true; + static void handlePaxCounterReportRequest(); + public: PaxcounterModule(); - static void handlePaxCounterReportRequest(); - protected: struct count_payload_t count_from_libpax = {0, 0, 0}; virtual int32_t runOnce() override; From 26691c0be7145b726eafad236def154cad3122d5 Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Fri, 8 Mar 2024 23:48:56 +0100 Subject: [PATCH 45/94] include requested change and suggestions on PR from @caveman99 --- src/modules/esp32/PaxcounterModule.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index e718d6261..580fc46e1 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -18,6 +18,7 @@ void PaxcounterModule::handlePaxCounterReportRequest() LOG_INFO("PaxcounterModule: libpax reported new data: wifi=%d; ble=%d; uptime=%lu\n", paxcounterModule->count_from_libpax.wifi_count, paxcounterModule->count_from_libpax.ble_count, millis() / 1000); paxcounterModule->reportedDataSent = false; + paxcounterModule->setIntervalFromNow(0); } PaxcounterModule::PaxcounterModule() @@ -49,7 +50,7 @@ bool PaxcounterModule::sendInfo(NodeNum dest) meshtastic_MeshPacket *p = allocDataProtobuf(pl); p->to = dest; p->decoded.want_response = false; - p->priority = meshtastic_MeshPacket_Priority_DEFAULT; + p->priority = meshtastic_MeshPacket_Priority_MIN; service.sendToMesh(p, RX_SRC_LOCAL, true); @@ -103,8 +104,7 @@ int32_t PaxcounterModule::runOnce() } else { sendInfo(NODENUM_BROADCAST); } - // we check every second if the counter had new data to send - return 1000; + return getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, default_broadcast_interval_secs); } else { return disable(); } From 766beefbc5796f700e5d6d94f7f9d7682cc0a4c8 Mon Sep 17 00:00:00 2001 From: Kevin Cai Date: Sun, 10 Mar 2024 18:24:32 -0400 Subject: [PATCH 46/94] Update AccelerometerThread.h to work with T-Watch S3 --- src/AccelerometerThread.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index 744f0ad64..9898f4d49 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -103,12 +103,21 @@ class AccelerometerThread : public concurrency::OSThread #endif struct bma423_axes_remap remap_data; +#ifdef T_WATCH_S3 + remap_data.x_axis = 1; + remap_data.x_axis_sign = 0; + remap_data.y_axis = 0; + remap_data.y_axis_sign = 0; + remap_data.z_axis = 2; + remap_data.z_axis_sign = 1; +#else remap_data.x_axis = 0; remap_data.x_axis_sign = 1; remap_data.y_axis = 1; remap_data.y_axis_sign = 0; remap_data.z_axis = 2; remap_data.z_axis_sign = 1; +#endif // Need to raise the wrist function, need to set the correct axis bmaSensor.setRemapAxes(&remap_data); // sensor.enableFeature(BMA423_STEP_CNTR, true); @@ -171,4 +180,4 @@ class AccelerometerThread : public concurrency::OSThread Adafruit_LIS3DH lis; }; -} // namespace concurrency \ No newline at end of file +} // namespace concurrency From b65b9e5d659b6bd8f4eb3314d8cf24f4892e47f4 Mon Sep 17 00:00:00 2001 From: David Ellefsen Date: Thu, 7 Mar 2024 16:03:01 +0200 Subject: [PATCH 47/94] Include esp32c3 build step --- .github/workflows/build_esp32.yml | 1 + .github/workflows/build_esp32_c3.yml | 60 ++++++++++++++++++++++++++++ .github/workflows/build_esp32_s3.yml | 1 + .github/workflows/main_matrix.yml | 14 ++++++- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build_esp32_c3.yml diff --git a/.github/workflows/build_esp32.yml b/.github/workflows/build_esp32.yml index c9664152e..31f0dd5a0 100644 --- a/.github/workflows/build_esp32.yml +++ b/.github/workflows/build_esp32.yml @@ -35,6 +35,7 @@ jobs: sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini - name: Build ESP32 run: bin/build-esp32.sh ${{ inputs.board }} diff --git a/.github/workflows/build_esp32_c3.yml b/.github/workflows/build_esp32_c3.yml new file mode 100644 index 000000000..f9164b96a --- /dev/null +++ b/.github/workflows/build_esp32_c3.yml @@ -0,0 +1,60 @@ +name: Build ESP32-C3 + +on: + workflow_call: + inputs: + board: + required: true + type: string + +jobs: + build-esp32-c3: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build base + id: base + uses: ./.github/actions/setup-base + + - name: Pull web ui + uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4 + with: + repo: meshtastic/web + file: build.tar + target: build.tar + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Unpack web ui + run: | + tar -xf build.tar -C data/static + rm build.tar + - name: Remove debug flags for release + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini + - name: Build ESP32 + run: bin/build-esp32.sh ${{ inputs.board }} + + - name: Pull OTA Firmware + uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4 + with: + repo: meshtastic/firmware-ota + file: firmware-c3.bin + target: release/bleota-c3.bin + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Get release version string + shell: bash + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v3 + with: + name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip + path: | + release/*.bin + release/*.elf diff --git a/.github/workflows/build_esp32_s3.yml b/.github/workflows/build_esp32_s3.yml index 9611dd5b8..f603a6a31 100644 --- a/.github/workflows/build_esp32_s3.yml +++ b/.github/workflows/build_esp32_s3.yml @@ -34,6 +34,7 @@ jobs: sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini - name: Build ESP32 run: bin/build-esp32.sh ${{ inputs.board }} diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index e77b4a261..03d47f18e 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -67,7 +67,6 @@ jobs: - board: tlora-v2-1-1_6-tcxo - board: tlora-v2-1-1_8 - board: tbeam - - board: heltec-ht62-esp32c3-sx1262 - board: heltec-v2_0 - board: heltec-v2_1 - board: tbeam0_7 @@ -105,6 +104,16 @@ jobs: with: board: ${{ matrix.board }} + build-esp32-c3: + strategy: + fail-fast: false + matrix: + include: + - board: heltec-ht62-esp32c3-sx1262 + uses: ./.github/workflows/build_esp32_c3.yml + with: + board: ${{ matrix.board }} + build-nrf52: strategy: fail-fast: false @@ -226,6 +235,7 @@ jobs: [ build-esp32, build-esp32-s3, + build-esp32-c3, build-nrf52, build-raspbian, build-native, @@ -251,7 +261,7 @@ jobs: id: version - name: Move files up - run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml + run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./*esp32c3*/bleota-c3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml - name: Repackage in single firmware zip uses: actions/upload-artifact@v3 From b3ec3c20fbd80081328e44e7d4ce084afd42fa58 Mon Sep 17 00:00:00 2001 From: David Ellefsen Date: Thu, 7 Mar 2024 16:31:20 +0200 Subject: [PATCH 48/94] Update device-install.sh files to account for bleota-c3.bin file --- bin/device-install.bat | 8 ++++++-- bin/device-install.sh | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bin/device-install.bat b/bin/device-install.bat index c7d8a10cf..cb652346f 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -31,9 +31,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% ( %PYTHON% -m esptool --baud 115200 erase_flash %PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME% - @REM Account for S3 board's different OTA partition + @REM Account for S3 and C3 board's different OTA partition IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% ( - %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin + IF x%FILENAME:esp32c3=%==x%FILENAME% ( + %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin + ) else ( + %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-c3.bin + ) ) else ( %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin ) diff --git a/bin/device-install.sh b/bin/device-install.sh index 35d99286d..52a27309a 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -51,7 +51,11 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then "$PYTHON" -m esptool write_flash 0x00 ${FILENAME} # Account for S3 board's different OTA partition if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then - "$PYTHON" -m esptool write_flash 0x260000 bleota.bin + if [ ! -z "${FILENAME##*"esp32c3"*}" ]; then + "$PYTHON" -m esptool write_flash 0x260000 bleota.bin + else + "$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin + fi else "$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin fi From a493ab526f82979890d97e9354a2753eec8c06a7 Mon Sep 17 00:00:00 2001 From: David Ellefsen Date: Fri, 8 Mar 2024 10:50:03 +0200 Subject: [PATCH 49/94] Trunk fmt to correct failing PR check for device-install.sh --- bin/device-install.sh | 56 ++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/bin/device-install.sh b/bin/device-install.sh index 52a27309a..a4ee20c9c 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -1,12 +1,12 @@ #!/bin/sh -PYTHON=${PYTHON:-$(which python3 python|head -n 1)} +PYTHON=${PYTHON:-$(which python3 python | head -n 1)} set -e # Usage info show_help() { -cat << EOF + cat <&2 - exit 1 - ;; - esac + case "${opt}" in + h) + show_help + exit 0 + ;; + p) + export ESPTOOL_PORT=${OPTARG} + ;; + P) + PYTHON=${OPTARG} + ;; + f) + FILENAME=${OPTARG} + ;; + *) + echo "Invalid flag." + show_help >&2 + exit 1 + ;; + esac done -shift "$((OPTIND-1))" +shift "$((OPTIND - 1))" [ -z "$FILENAME" -a -n "$1" ] && { - FILENAME=$1 - shift + FILENAME=$1 + shift } if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then echo "Trying to flash ${FILENAME}, but first erasing and writing system information" - "$PYTHON" -m esptool erase_flash - "$PYTHON" -m esptool write_flash 0x00 ${FILENAME} + "$PYTHON" -m esptool erase_flash + "$PYTHON" -m esptool write_flash 0x00 ${FILENAME} # Account for S3 board's different OTA partition if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then if [ ! -z "${FILENAME##*"esp32c3"*}" ]; then @@ -57,9 +59,9 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then "$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin fi else - "$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin + "$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin fi - "$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin + "$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin else show_help From f09e5c96fcad715a7e3b3fe4bb285f1348d6c29d Mon Sep 17 00:00:00 2001 From: David Ellefsen Date: Fri, 8 Mar 2024 11:03:03 +0200 Subject: [PATCH 50/94] Add permission: read-all to silence CKV_GHA_1 check --- .github/workflows/build_esp32_c3.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_esp32_c3.yml b/.github/workflows/build_esp32_c3.yml index f9164b96a..a30cf33f1 100644 --- a/.github/workflows/build_esp32_c3.yml +++ b/.github/workflows/build_esp32_c3.yml @@ -7,6 +7,8 @@ on: required: true type: string +permissions: read-all + jobs: build-esp32-c3: runs-on: ubuntu-latest From 3a8f623f8adfc73e0c3b36453d8392394377713a Mon Sep 17 00:00:00 2001 From: David Ellefsen Date: Fri, 8 Mar 2024 11:27:31 +0200 Subject: [PATCH 51/94] Change '! -z' to '-n' to addresss shellcheck/SC2236 --- bin/device-install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/device-install.sh b/bin/device-install.sh index a4ee20c9c..0e7bd8ada 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -47,13 +47,13 @@ shift "$((OPTIND - 1))" shift } -if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then +if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then echo "Trying to flash ${FILENAME}, but first erasing and writing system information" "$PYTHON" -m esptool erase_flash "$PYTHON" -m esptool write_flash 0x00 ${FILENAME} # Account for S3 board's different OTA partition - if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then - if [ ! -z "${FILENAME##*"esp32c3"*}" ]; then + if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ]; then + if [ -n "${FILENAME##*"esp32c3"*}" ]; then "$PYTHON" -m esptool write_flash 0x260000 bleota.bin else "$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin From 658ed6fd2874f8e7e73007a492ff81e40af1093b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 11 Mar 2024 13:51:26 +0100 Subject: [PATCH 52/94] tryfix SHT31 sensor on secondary bus --- src/mesh/NodeDB.h | 2 +- src/modules/Telemetry/Sensor/SHT31Sensor.cpp | 2 +- src/modules/Telemetry/Sensor/SHT31Sensor.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 8545b08d6..e472f7151 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -248,4 +248,4 @@ extern uint32_t error_address; #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ - ModuleConfig_TelemetryConfig_size + ModuleConfig_size) \ No newline at end of file + ModuleConfig_TelemetryConfig_size + ModuleConfig_size) diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp index 7ffb68254..7f2b7691e 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp @@ -12,7 +12,7 @@ int32_t SHT31Sensor::runOnce() if (!hasSensor()) { return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } - status = sht31.begin(); + status = sht31.begin(nodeTelemetrySensorsMap[sensorType].first); return initI2CSensor(); } diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.h b/src/modules/Telemetry/Sensor/SHT31Sensor.h index 940361325..9700bdf2c 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.h +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.h @@ -5,7 +5,7 @@ class SHT31Sensor : public TelemetrySensor { private: - Adafruit_SHT31 sht31 = Adafruit_SHT31(); + Adafruit_SHT31 sht31 = Adafruit_SHT31(nodeTelemetrySensorsMap[sensorType].second); protected: virtual void setup() override; From 892223a297c23b788ae879b3a6dab92a10e391ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 11 Mar 2024 13:52:46 +0100 Subject: [PATCH 53/94] fix typos and add 2 missing modules to the equasion (#3370) --- src/configuration.h | 2 ++ src/modules/Modules.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 03170c1c7..ac8f9435a 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -239,4 +239,6 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1 #define MESHTASTIC_EXCLUDE_TRACEROUTE 1 #define MESHTASTIC_EXCLUDE_WAYPOINT 1 +#define MESHTASTIC_EXCLUDE_INPUTBROKER 1 +#define MESHTASTIC_EXCLUDE_SERIAL 1 #endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 4f0b8f2b0..97ed90cf1 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -39,11 +39,11 @@ #if HAS_TELEMETRY #include "modules/Telemetry/DeviceTelemetry.h" #endif -#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR +#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "modules/Telemetry/AirQualityTelemetry.h" #include "modules/Telemetry/EnvironmentTelemetry.h" #endif -#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY #include "modules/Telemetry/PowerTelemetry.h" #endif #ifdef ARCH_ESP32 @@ -138,13 +138,13 @@ void setupModules() #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) new DeviceTelemetryModule(); #endif -#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR +#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR new EnvironmentTelemetryModule(); if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) { new AirQualityTelemetryModule(); } #endif -#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY new PowerTelemetryModule(); #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \ From cf4753f7fd32ce43e6f11b5760f1e0366f7c07a5 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Tue, 12 Mar 2024 01:56:55 +1300 Subject: [PATCH 54/94] Async full-refresh for EInkDynamicDisplay (#3339) * Move Wireless Paper V1.1 custom hibernate behavior to GxEPD2 * Async full-refresh for EInkDynamicDisplay * initial config for T-Echo * formatting responds to https://github.com/meshtastic/firmware/pull/3339#discussion_r1518175434 * increase fast-refresh limit for T-Echo https://github.com/meshtastic/firmware/pull/3339#issuecomment-1986245727 * change dependency from private repo to meshtastic/GxEPD2 --------- Co-authored-by: Ben Meadors --- src/graphics/EInkDisplay2.cpp | 25 +++--- src/graphics/EInkDisplay2.h | 7 ++ src/graphics/EInkDynamicDisplay.cpp | 90 +++++++++++++++++-- src/graphics/EInkDynamicDisplay.h | 15 +++- variants/heltec_wireless_paper/platformio.ini | 2 +- variants/heltec_wireless_paper/variant.h | 1 - variants/t-echo/platformio.ini | 8 +- 7 files changed, 121 insertions(+), 27 deletions(-) diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 6ee4245b3..6f7885b45 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -71,28 +71,24 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit) } } + // Trigger the refresh in GxEPD2 LOG_DEBUG("Updating E-Paper... "); - -#if false - // Currently unused; rescued from commented-out line during a refactor - // Use a meaningful macro here if variant doesn't want fast refresh - - // Full update mode (slow) - adafruitDisplay->display(false) -#else - // Fast update mode adafruitDisplay->nextPage(); -#endif -#ifndef EINK_NO_HIBERNATE // Only hibernate if controller IC will preserve image memory - // Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display) - adafruitDisplay->hibernate(); -#endif + // End the update process + endUpdate(); LOG_DEBUG("done\n"); return true; } +// End the update process - virtual method, overriden in derived class +void EInkDisplay::endUpdate() +{ + // Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep) + adafruitDisplay->hibernate(); +} + // Write the buffer to the display memory void EInkDisplay::display(void) { @@ -188,6 +184,7 @@ bool EInkDisplay::connect() // Init GxEPD2 adafruitDisplay->init(); adafruitDisplay->setRotation(3); + adafruitDisplay->clearScreen(); // Clearing now, so the boot logo will draw nice and smoothe (fast refresh) } #elif defined(PCA10059) { diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 75770a3bc..f74416494 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -45,6 +45,13 @@ class EInkDisplay : public OLEDDisplay */ virtual bool forceDisplay(uint32_t msecLimit = 1000); + /** + * Run any code needed to complete an update, after the physical refresh has completed. + * Split from forceDisplay(), to enable async refresh in derived EInkDynamicDisplay class. + * + */ + virtual void endUpdate(); + /** * shim to make the abstraction happy * diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp index ae1e30fe1..75db0e33f 100644 --- a/src/graphics/EInkDynamicDisplay.cpp +++ b/src/graphics/EInkDynamicDisplay.cpp @@ -94,19 +94,29 @@ void EInkDynamicDisplay::adjustRefreshCounters() // Trigger the display update by calling base class bool EInkDynamicDisplay::update() { + // Detemine the refresh mode to use, and start the update bool refreshApproved = determineMode(); if (refreshApproved) EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system - return refreshApproved; // (Unutilized) Base class promises to return true if update ran + +#if defined(HAS_EINK_ASYNCFULL) + if (refreshApproved) + endOrDetach(); // Either endUpdate() right now (fast refresh), or set the async flag (full refresh) +#endif + + return refreshApproved; // (Unutilized) Base class promises to return true if update ran } // Assess situation, pick a refresh type bool EInkDynamicDisplay::determineMode() { - checkWasFlooded(); + checkForPromotion(); +#if defined(HAS_EINK_ASYNCFULL) + checkAsyncFullRefresh(); +#endif checkRateLimiting(); - // If too soon for a new time, abort here + // If too soon for a new frame, or display busy, abort early if (refresh == SKIPPED) { storeAndReset(); return false; // No refresh @@ -116,7 +126,7 @@ bool EInkDynamicDisplay::determineMode() resetRateLimiting(); // Once determineMode() ends, will have to wait again hashImage(); // Generate here, so we can still copy it to previousImageHash, even if we skip the comparison check - LOG_DEBUG("EInkDynamicDisplay: "); // Begin log entry + LOG_DEBUG("determineMode(): "); // Begin log entry // Once mode determined, any remaining checks will bypass checkCosmetic(); @@ -151,13 +161,25 @@ bool EInkDynamicDisplay::determineMode() } } -// Did RESPONSIVE frames previously exceed the rate-limit for fast refresh? -void EInkDynamicDisplay::checkWasFlooded() +// Was a frame skipped (rate, display busy) that should have been a FAST refresh? +void EInkDynamicDisplay::checkForPromotion() { - if (previousReason == EXCEEDED_RATELIMIT_FAST) { - // If so, allow a BACKGROUND frame to draw as RESPONSIVE - // Because we DID want a RESPONSIVE frame last time, we just didn't get it + // If a frame was skipped (rate, display busy), then promote a BACKGROUND frame + // Because we DID want a RESPONSIVE/COSMETIC/DEMAND_FULL frame last time, we just didn't get it + + switch (previousReason) { + case ASYNC_REFRESH_BLOCKED_DEMANDFAST: + setFrameFlag(DEMAND_FAST); + break; + case ASYNC_REFRESH_BLOCKED_COSMETIC: + setFrameFlag(COSMETIC); + break; + case ASYNC_REFRESH_BLOCKED_RESPONSIVE: + case EXCEEDED_RATELIMIT_FAST: setFrameFlag(RESPONSIVE); + break; + default: + break; } } @@ -381,4 +403,54 @@ void EInkDynamicDisplay::resetGhostPixelTracking() } #endif // EINK_LIMIT_GHOSTING_PX +#ifdef HAS_EINK_ASYNCFULL +// Check the status of an "async full-refresh", and run the finish-up code if the hardware is ready +void EInkDynamicDisplay::checkAsyncFullRefresh() +{ + // No refresh taking place, continue with determineMode() + if (!asyncRefreshRunning) + return; + + // Full refresh still running + if (adafruitDisplay->epd2.isBusy()) { + // No refresh + refresh = SKIPPED; + + // Set the reason, marking what type of frame we're skipping + if (frameFlags & DEMAND_FAST) + reason = ASYNC_REFRESH_BLOCKED_DEMANDFAST; + else if (frameFlags & COSMETIC) + reason = ASYNC_REFRESH_BLOCKED_COSMETIC; + else if (frameFlags & RESPONSIVE) + reason = ASYNC_REFRESH_BLOCKED_RESPONSIVE; + else + reason = ASYNC_REFRESH_BLOCKED_BACKGROUND; + + return; + } + + // If we asyncRefreshRunning flag is still set, but display's BUSY pin reports the refresh is done + adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code + EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override) + asyncRefreshRunning = false; // Unset the flag + LOG_DEBUG("Async full-refresh complete\n"); + + // Note: this code only works because of a modification to meshtastic/GxEPD2. + // It is only equipped to intercept calls to nextPage() +} + +// Figure out who runs the post-update code +void EInkDynamicDisplay::endOrDetach() +{ + if (previousRefresh == FULL) { // Note: previousRefresh is the refresh from this loop. + asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop. + LOG_DEBUG("Async full-refresh begins\n"); + } + + // Fast Refresh + else + EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves. +} +#endif // HAS_EINK_ASYNCFULL + #endif // USE_EINK_DYNAMICDISPLAY \ No newline at end of file diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index 2880c716b..3dc00ba7c 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -44,6 +44,11 @@ class EInkDynamicDisplay : public EInkDisplay }; enum reasonTypes : uint8_t { // How was the decision reached NO_OBJECTIONS, + ASYNC_REFRESH_BLOCKED_DEMANDFAST, + ASYNC_REFRESH_BLOCKED_COSMETIC, + ASYNC_REFRESH_BLOCKED_RESPONSIVE, + ASYNC_REFRESH_BLOCKED_BACKGROUND, + DISPLAY_NOT_READY_FOR_FULL, EXCEEDED_RATELIMIT_FAST, EXCEEDED_RATELIMIT_FULL, FLAGGED_COSMETIC, @@ -64,7 +69,7 @@ class EInkDynamicDisplay : public EInkDisplay bool update(); // Trigger the display update - determine mode, then call base class // Checks as part of determineMode() - void checkWasFlooded(); // Was the previous frame skipped for exceeding EINK_LIMIT_RATE_RESPONSIVE_SEC? + void checkForPromotion(); // Was a frame skipped (rate, display busy) that should have been a FAST refresh? void checkRateLimiting(); // Is this frame too soon? void checkCosmetic(); // Was the COSMETIC flag set? void checkDemandingFast(); // Was the DEMAND_FAST flag set? @@ -99,6 +104,14 @@ class EInkDynamicDisplay : public EInkDisplay uint8_t *dirtyPixels; // Any pixels that have been black since last full-refresh (dynamically allocated mem) uint32_t ghostPixelCount = 0; // Number of pixels with problematic ghosting. Retained here for LOG_DEBUG use #endif + + // Conditional - async full refresh - only with modified meshtastic/GxEPD2 +#if defined(HAS_EINK_ASYNCFULL) + void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready + void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh() + void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay() + bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh() +#endif }; #endif \ No newline at end of file diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 0abbe085e..14275830a 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -16,7 +16,7 @@ build_flags = -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2 + https://github.com/meshtastic/GxEPD2/ adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h index 28bc8628a..29b8bbbd1 100644 --- a/variants/heltec_wireless_paper/variant.h +++ b/variants/heltec_wireless_paper/variant.h @@ -5,7 +5,6 @@ #define I2C_SCL SCL #define USE_EINK -#define EINK_NO_HIBERNATE /* * eink display pins diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index 49ba3bb34..c97341a3b 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -11,10 +11,16 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 -DEINK_HEIGHT=200 + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates + -DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} - https://github.com/meshtastic/GxEPD2#afce87a97dda1ac31d8a28dc8fa7c6f55dc96a61 + https://github.com/meshtastic/GxEPD2 adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs From 1d31be939ff36dd2ad675a72893d502aa91808e2 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Tue, 12 Mar 2024 03:06:01 +1300 Subject: [PATCH 55/94] Swap Wireless Paper V1.0 dependency to meshtastic/GxEPD2 --- variants/heltec_wireless_paper_v1/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index 9327ed256..de832d6d7 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -16,7 +16,7 @@ build_flags = ;-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. lib_deps = ${esp32s3_base.lib_deps} - https://github.com/todd-herbert/meshtastic-GxEPD2#async + https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file From 1f766a04aa036c83094eb34c6048f8ab6774f0f4 Mon Sep 17 00:00:00 2001 From: Todd Herbert Date: Tue, 12 Mar 2024 04:04:28 +1300 Subject: [PATCH 56/94] purge unused enum val --- src/graphics/EInkDynamicDisplay.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h index dcae056c6..81963df58 100644 --- a/src/graphics/EInkDynamicDisplay.h +++ b/src/graphics/EInkDynamicDisplay.h @@ -49,7 +49,6 @@ class EInkDynamicDisplay : public EInkDisplay ASYNC_REFRESH_BLOCKED_COSMETIC, ASYNC_REFRESH_BLOCKED_RESPONSIVE, ASYNC_REFRESH_BLOCKED_BACKGROUND, - DISPLAY_NOT_READY_FOR_FULL, EXCEEDED_RATELIMIT_FAST, EXCEEDED_RATELIMIT_FULL, FLAGGED_COSMETIC, From c80098f517b9f69071227f96f96834e57282e9d8 Mon Sep 17 00:00:00 2001 From: Andre K Date: Mon, 11 Mar 2024 13:49:46 -0300 Subject: [PATCH 57/94] refactor: remove ACKs in range tests so zero hops is honored (#3374) --- src/modules/RangeTestModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index b45068b45..904fb25db 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -114,7 +114,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies) p->to = dest; p->decoded.want_response = wantReplies; p->hop_limit = 0; - p->want_ack = true; + p->want_ack = false; packetSequence++; From e16689a0d6b3192c12fe5b7090992b61d540aeb8 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:45:59 +0100 Subject: [PATCH 58/94] fix heap use after delete (#3373) --- src/mesh/ReliableRouter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 167a248ab..2327cbfb7 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -167,8 +167,6 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key) auto old = findPendingPacket(key); if (old) { auto p = old->packet; - auto numErased = pending.erase(key); - assert(numErased == 1); /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue to avoid canceling a transmission if it was ACKed super fast via MQTT */ if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) { @@ -177,6 +175,8 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key) // now free the pooled copy for retransmission too packetPool.release(p); } + auto numErased = pending.erase(key); + assert(numErased == 1); return true; } else return false; From c7839b469b5a3dee6711c4d892bb9a002d7d96d2 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:51:14 +0100 Subject: [PATCH 59/94] fix of tryfix SHT31 sensor (#3377) --- src/modules/Telemetry/Sensor/SHT31Sensor.cpp | 1 + src/modules/Telemetry/Sensor/SHT31Sensor.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp index 7f2b7691e..35978d970 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp @@ -12,6 +12,7 @@ int32_t SHT31Sensor::runOnce() if (!hasSensor()) { return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } + sht31 = Adafruit_SHT31(nodeTelemetrySensorsMap[sensorType].second); status = sht31.begin(nodeTelemetrySensorsMap[sensorType].first); return initI2CSensor(); } diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.h b/src/modules/Telemetry/Sensor/SHT31Sensor.h index 9700bdf2c..c6f8f1596 100644 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.h +++ b/src/modules/Telemetry/Sensor/SHT31Sensor.h @@ -5,7 +5,7 @@ class SHT31Sensor : public TelemetrySensor { private: - Adafruit_SHT31 sht31 = Adafruit_SHT31(nodeTelemetrySensorsMap[sensorType].second); + Adafruit_SHT31 sht31; protected: virtual void setup() override; From 5f47ca1f32dd283739c4d78a4e08f20a9bd60fa1 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:58:45 +0100 Subject: [PATCH 60/94] Don't spam logs if no position with map reporting (#3378) --- src/mqtt/MQTT.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 2de35971a..760aa7210 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -552,14 +552,14 @@ void MQTT::perhapsReportToMap() if (!moduleConfig.mqtt.map_reporting_enabled || !(moduleConfig.mqtt.proxy_to_client_enabled || isConnectedDirectly())) return; - if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) { - LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n"); - return; - } - if (millis() - last_report_to_map < map_publish_interval_secs * 1000) { return; } else { + if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) { + LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n"); + return; + } + // Allocate ServiceEnvelope and fill it meshtastic_ServiceEnvelope *se = mqttPool.allocZeroed(); se->channel_id = (char *)channels.getGlobalId(channels.getPrimaryIndex()); // Use primary channel as the channel_id From f9bf9e2dcc3e9ea11c4ae3fbe8916f54aa2df171 Mon Sep 17 00:00:00 2001 From: thebentern Date: Mon, 11 Mar 2024 21:43:46 +0000 Subject: [PATCH 61/94] [create-pull-request] automated change --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 8927d1781..07fadd0d8 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 0 +build = 1 From affbd7f2b91ffb397066df70e22e34d3e6ac3aeb Mon Sep 17 00:00:00 2001 From: AeroXuk Date: Tue, 12 Mar 2024 02:13:52 +0000 Subject: [PATCH 62/94] Update MQTT.cpp Bug fix for #3382 --- src/mqtt/MQTT.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 760aa7210..4250ad5cd 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -185,7 +185,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) statusTopic = moduleConfig.mqtt.root + statusTopic; cryptTopic = moduleConfig.mqtt.root + cryptTopic; jsonTopic = moduleConfig.mqtt.root + jsonTopic; - mapTopic = moduleConfig.mqtt.root + jsonTopic; + mapTopic = moduleConfig.mqtt.root + mapTopic; } else { statusTopic = "msh" + statusTopic; cryptTopic = "msh" + cryptTopic; @@ -915,4 +915,4 @@ bool MQTT::isValidJsonEnvelope(JSONObject &json) (json["from"]->AsNumber() == nodeDB.getNodeNum()) && // only accept message if the "from" is us (json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type (json.find("payload") != json.end()); // should have a payload -} \ No newline at end of file +} From 7f063fbf811faf0c722cd377f5b7bde572872fbd Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Tue, 12 Mar 2024 17:55:31 +0100 Subject: [PATCH 63/94] Support external charge detection (#3386) * Support external charge detection * trunk fmt --- src/Power.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Power.cpp b/src/Power.cpp index 3d1a1b9b2..71554daa3 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -54,6 +54,19 @@ static const adc_atten_t atten = ADC_ATTENUATION; #endif #endif // BATTERY_PIN && ARCH_ESP32 +#ifdef EXT_CHRG_DETECT +#ifndef EXT_CHRG_DETECT_MODE +static const uint8_t ext_chrg_detect_mode = INPUT; +#else +static const uint8_t ext_chrg_detect_mode = EXT_CHRG_DETECT_MODE; +#endif +#ifndef EXT_CHRG_DETECT_VALUE +static const uint8_t ext_chrg_detect_value = HIGH; +#else +static const uint8_t ext_chrg_detect_value = EXT_CHRG_DETECT_VALUE; +#endif +#endif + #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) INA260Sensor ina260Sensor; INA219Sensor ina219Sensor; @@ -322,7 +335,14 @@ class AnalogBatteryLevel : public HasBatteryLevel /// Assume charging if we have a battery and external power is connected. /// we can't be smart enough to say 'full'? - virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); } + virtual bool isCharging() override + { +#ifdef EXT_CHRG_DETECT + return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value; +#else + return isBatteryConnect() && isVbusIn(); +#endif + } private: /// If we see a battery voltage higher than physics allows - assume charger is pumping @@ -389,6 +409,9 @@ bool Power::analogInit() #ifdef EXT_PWR_DETECT pinMode(EXT_PWR_DETECT, INPUT); #endif +#ifdef EXT_CHRG_DETECT + pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode); +#endif #ifdef BATTERY_PIN LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN); From cf11807f9711eb4575ada4dce1fbb32c18f9e89a Mon Sep 17 00:00:00 2001 From: Thomas Herrmann Date: Tue, 12 Mar 2024 18:21:09 +0100 Subject: [PATCH 64/94] use priority background for low priority messages (#3381) --- src/modules/Telemetry/AirQualityTelemetry.cpp | 2 +- src/modules/Telemetry/DeviceTelemetry.cpp | 2 +- src/modules/Telemetry/EnvironmentTelemetry.cpp | 2 +- src/modules/Telemetry/PowerTelemetry.cpp | 2 +- src/modules/esp32/PaxcounterModule.cpp | 2 +- src/modules/esp32/StoreForwardModule.cpp | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index f87ea504b..ada1fdef8 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -112,7 +112,7 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) p->priority = meshtastic_MeshPacket_Priority_RELIABLE; else - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; // release previous packet before occupying a new spot if (lastMeasurementPacket != nullptr) diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index a6eecda80..55000e4c6 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -91,7 +91,7 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) meshtastic_MeshPacket *p = allocDataProtobuf(telemetry); p->to = dest; p->decoded.want_response = false; - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; nodeDB.updateTelemetry(nodeDB.getNodeNum(), telemetry, RX_SRC_LOCAL); if (phoneOnly) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index d4f423e54..7b59c28a6 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -253,7 +253,7 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) p->priority = meshtastic_MeshPacket_Priority_RELIABLE; else - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; // release previous packet before occupying a new spot if (lastMeasurementPacket != nullptr) packetPool.release(lastMeasurementPacket); diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 30628bfd7..300ab1f62 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -195,7 +195,7 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) p->priority = meshtastic_MeshPacket_Priority_RELIABLE; else - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; // release previous packet before occupying a new spot if (lastMeasurementPacket != nullptr) packetPool.release(lastMeasurementPacket); diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 580fc46e1..54c67fad7 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -50,7 +50,7 @@ bool PaxcounterModule::sendInfo(NodeNum dest) meshtastic_MeshPacket *p = allocDataProtobuf(pl); p->to = dest; p->decoded.want_response = false; - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; service.sendToMesh(p, RX_SRC_LOCAL, true); diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index 70d13afca..71d75750a 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -255,7 +255,7 @@ void StoreForwardModule::sendMessage(NodeNum dest, const meshtastic_StoreAndForw p->to = dest; - p->priority = meshtastic_MeshPacket_Priority_MIN; + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; // FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume // everything is broadcast. @@ -334,7 +334,7 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m LOG_INFO("*** S&F - Busy. Try again shortly.\n"); meshtastic_MeshPacket *pr = allocReply(); pr->to = getFrom(&mp); - pr->priority = meshtastic_MeshPacket_Priority_MIN; + pr->priority = meshtastic_MeshPacket_Priority_BACKGROUND; pr->want_ack = false; pr->decoded.want_response = false; pr->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP; From ee685b4ed78edad0f06b5816b913f39af8e25fb4 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Tue, 12 Mar 2024 19:03:04 +0100 Subject: [PATCH 65/94] Check AQ_SET_PIN instead of EINK dependency (#3387) --- src/main.cpp | 2 +- src/platform/nrf52/main-nrf52.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ef1cd53c3..535051811 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -342,7 +342,7 @@ void setup() pinMode(PIN_3V3_EN, OUTPUT); digitalWrite(PIN_3V3_EN, HIGH); #endif -#ifndef USE_EINK +#ifdef AQ_SET_PIN // RAK-12039 set pin for Air quality sensor pinMode(AQ_SET_PIN, OUTPUT); digitalWrite(AQ_SET_PIN, HIGH); diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 9e8798e37..2f670dee3 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -177,7 +177,7 @@ void cpuDeepSleep(uint32_t msecToWake) #ifdef PIN_3V3_EN digitalWrite(PIN_3V3_EN, LOW); #endif -#ifndef USE_EINK +#ifdef AQ_SET_PIN // RAK-12039 set pin for Air quality sensor digitalWrite(AQ_SET_PIN, LOW); #endif From 38ea6814331c26cdb72af024e401151a6f466de5 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Tue, 12 Mar 2024 22:42:21 +0100 Subject: [PATCH 66/94] Fix LTO discharge curve (#3385) * Fix LTO discharge curve * Remove duplicate info --- src/power.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/power.h b/src/power.h index 4dd35e710..b94ce8f98 100644 --- a/src/power.h +++ b/src/power.h @@ -10,13 +10,6 @@ #define NUM_OCV_POINTS 11 #endif -// 3400,3350,3320,3290,3270,3260,3250,3230,3200,3120,3000 //3.4 to 3.0 LiFePO4 -// 2120,2090,2070,2050,2030,2010,1990,1980,1970,1960,1950 //2.12 to 1.95 Lead Acid -// 4200,4050,3990,3890,3790,3700,3650,3550,3450,3300,3200 //4.2 to 3.2 LiIon/LiPo -// 4200,4050,3990,3890,3790,3700,3650,3550,3400,3300,3000 //4.2 to 3.0 LiIon/LiPo -// 4150,4050,3990,3890,3790,3690,3620,3520,3420,3300,3100 //4.15 to 3.1 LiIon/LiPo -// 2770,2650,2540,2420,2300,2180,2060,1940,1800,1680,1550 //2.8 to 1.5 Lithium Titanate - #ifndef OCV_ARRAY #ifdef CELL_TYPE_LIFEPO4 #define OCV_ARRAY 3400, 3350, 3320, 3290, 3270, 3260, 3250, 3230, 3200, 3120, 3000 @@ -27,7 +20,7 @@ #elif defined(CELL_TYPE_NIMH) #define OCV_ARRAY 1400, 1300, 1280, 1270, 1260, 1250, 1240, 1230, 1210, 1150, 1000 #elif defined(CELL_TYPE_LTO) -#define OCV_ARRAY 2770, 2650, 2540, 2420, 2300, 2180, 2060, 1940, 1800, 1680, 1550 +#define OCV_ARRAY 2700, 2560, 2540, 2520, 2500, 2460, 2420, 2400, 2380, 2320, 1500 #else // LiIon #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif From 724fa38a552ddd952ceeca336e65ae187962bb59 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:42:34 +0100 Subject: [PATCH 67/94] Fix T-LoRa V2.1-6 with TCXO init (#3392) --- src/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 535051811..bb9b68631 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -226,6 +226,11 @@ void setup() digitalWrite(PIN_POWER_EN1, INPUT); #endif +#if defined(LORA_TCXO_GPIO) + pinMode(LORA_TCXO_GPIO, OUTPUT); + digitalWrite(LORA_TCXO_GPIO, HIGH); +#endif + #if defined(VEXT_ENABLE_V03) pinMode(VEXT_ENABLE_V03, OUTPUT); pinMode(ST7735_BL_V03, OUTPUT); From 333c3c1c9ebf71910c78e90d171db5a921b4d733 Mon Sep 17 00:00:00 2001 From: Tavis Date: Tue, 12 Mar 2024 21:42:08 -1000 Subject: [PATCH 68/94] fix off by one error buzzer is index 2, but loop was 0-1 so buzzer never got turned off. --- src/modules/ExternalNotificationModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 9af1f9e00..652965f6d 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -81,7 +81,7 @@ int32_t ExternalNotificationModule::runOnce() // let the song finish if we reach timeout nagCycleCutoff = UINT32_MAX; LOG_INFO("Turning off external notification: "); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { setExternalOff(i); externalTurnedOn[i] = 0; LOG_INFO("%d ", i); From 2efe436102d097d535bf2d20b90f399e58f4a0ef Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 13 Mar 2024 07:20:51 -0500 Subject: [PATCH 69/94] Update nrf52 platform and consolidate Adafruit Bus IO (#3393) --- arch/nrf52/nrf52.ini | 2 +- platformio.ini | 2 +- variants/canaryone/platformio.ini | 1 - variants/heltec_wireless_paper/platformio.ini | 1 - variants/heltec_wireless_paper_v1/platformio.ini | 1 - variants/nano-g2-ultra/platformio.ini | 1 - variants/t-echo/platformio.ini | 1 - 7 files changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 5155eaadc..2505fe315 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,6 +1,6 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^10.1.0 +platform = platformio/nordicnrf52@^10.4.0 extends = arduino_base build_type = debug ; I'm debugging with ICE a lot now diff --git a/platformio.ini b/platformio.ini index b67ddc50a..392b38fd7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -113,7 +113,7 @@ lib_deps = ; (not included in native / portduino) [environmental_base] lib_deps = - adafruit/Adafruit BusIO@^1.11.4 + adafruit/Adafruit BusIO@^1.15.0 adafruit/Adafruit Unified Sensor@^1.1.11 adafruit/Adafruit BMP280 Library@^2.6.8 adafruit/Adafruit BMP085 Library@^1.2.4 diff --git a/variants/canaryone/platformio.ini b/variants/canaryone/platformio.ini index d52bbb24a..4917f52c7 100644 --- a/variants/canaryone/platformio.ini +++ b/variants/canaryone/platformio.ini @@ -10,6 +10,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/canaryone build_src_filter = ${nrf52_base.build_src_filter} +<../variants/canaryone> lib_deps = ${nrf52840_base.lib_deps} - adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 94ed15ed1..1e1bb9376 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -17,6 +17,5 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a - adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index de832d6d7..cae1940b3 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -17,6 +17,5 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a - adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 upload_speed = 115200 \ No newline at end of file diff --git a/variants/nano-g2-ultra/platformio.ini b/variants/nano-g2-ultra/platformio.ini index d5e5a6137..2b011e032 100644 --- a/variants/nano-g2-ultra/platformio.ini +++ b/variants/nano-g2-ultra/platformio.ini @@ -9,6 +9,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/nano-g2-ultra -D NANO_G2_U build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nano-g2-ultra> lib_deps = ${nrf52840_base.lib_deps} - adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini index be8900e0f..9ff60be3f 100644 --- a/variants/t-echo/platformio.ini +++ b/variants/t-echo/platformio.ini @@ -21,6 +21,5 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo> lib_deps = ${nrf52840_base.lib_deps} https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a - adafruit/Adafruit BusIO@^1.13.2 lewisxhe/PCF8563_Library@^1.0.1 ;upload_protocol = fs From 216f85ff221990a86b4ffd4548c90220b59fd255 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 09:02:48 -0500 Subject: [PATCH 70/94] [create-pull-request] automated change (#3397) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/clientonly.pb.c | 3 +++ src/mesh/generated/meshtastic/clientonly.pb.h | 16 ++++++++++++++++ src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/module_config.pb.c | 2 +- src/mesh/generated/meshtastic/module_config.pb.h | 6 +++--- 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index 00332412b..7e3ee8cd9 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 00332412b238fe559175a6e83fdf8d31fa5e209a +Subproject commit 7e3ee8cd96740910d0611433cb9a05a7a692568c diff --git a/src/mesh/generated/meshtastic/clientonly.pb.c b/src/mesh/generated/meshtastic/clientonly.pb.c index ebc2ffabc..90e8e2d8a 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.c +++ b/src/mesh/generated/meshtastic/clientonly.pb.c @@ -9,4 +9,7 @@ PB_BIND(meshtastic_DeviceProfile, meshtastic_DeviceProfile, 2) +PB_BIND(meshtastic_Heartbeat, meshtastic_Heartbeat, AUTO) + + diff --git a/src/mesh/generated/meshtastic/clientonly.pb.h b/src/mesh/generated/meshtastic/clientonly.pb.h index 0f70e09c6..19b0a0e5f 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.h +++ b/src/mesh/generated/meshtastic/clientonly.pb.h @@ -30,6 +30,12 @@ typedef struct _meshtastic_DeviceProfile { meshtastic_LocalModuleConfig module_config; } meshtastic_DeviceProfile; +/* A heartbeat message is sent by a node to indicate that it is still alive. + This is currently only needed to keep serial connections alive. */ +typedef struct _meshtastic_Heartbeat { + char dummy_field; +} meshtastic_Heartbeat; + #ifdef __cplusplus extern "C" { @@ -37,7 +43,9 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceProfile_init_default {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default} +#define meshtastic_Heartbeat_init_default {0} #define meshtastic_DeviceProfile_init_zero {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero} +#define meshtastic_Heartbeat_init_zero {0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_DeviceProfile_long_name_tag 1 @@ -58,13 +66,21 @@ X(a, STATIC, OPTIONAL, MESSAGE, module_config, 5) #define meshtastic_DeviceProfile_config_MSGTYPE meshtastic_LocalConfig #define meshtastic_DeviceProfile_module_config_MSGTYPE meshtastic_LocalModuleConfig +#define meshtastic_Heartbeat_FIELDLIST(X, a) \ + +#define meshtastic_Heartbeat_CALLBACK NULL +#define meshtastic_Heartbeat_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_DeviceProfile_msg; +extern const pb_msgdesc_t meshtastic_Heartbeat_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_DeviceProfile_fields &meshtastic_DeviceProfile_msg +#define meshtastic_Heartbeat_fields &meshtastic_Heartbeat_msg /* Maximum encoded size of messages (where known) */ /* meshtastic_DeviceProfile_size depends on runtime parameters */ +#define meshtastic_Heartbeat_size 0 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 556821e1c..79800d4b4 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -324,7 +324,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; #define meshtastic_DeviceState_size 17571 #define meshtastic_NodeInfoLite_size 158 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3262 +#define meshtastic_OEMStore_size 3278 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 2e22cb1e4..f27c119bd 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_LocalConfig_size 469 -#define meshtastic_LocalModuleConfig_size 647 +#define meshtastic_LocalModuleConfig_size 663 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.c b/src/mesh/generated/meshtastic/module_config.pb.c index a75c3fb59..594cf9628 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.c +++ b/src/mesh/generated/meshtastic/module_config.pb.c @@ -9,7 +9,7 @@ PB_BIND(meshtastic_ModuleConfig, meshtastic_ModuleConfig, 2) -PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig_MQTTConfig, meshtastic_ModuleConfig_MQTTConfig, 2) PB_BIND(meshtastic_ModuleConfig_MapReportSettings, meshtastic_ModuleConfig_MapReportSettings, AUTO) diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 2e1c25c7f..a2adbc1b9 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -119,7 +119,7 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig { bool tls_enabled; /* The root topic to use for MQTT messages. Default is "msh". This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs */ - char root[16]; + char root[32]; /* If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection */ bool proxy_to_client_enabled; /* If true, we will periodically report unencrypted information about our node to a map via MQTT */ @@ -832,7 +832,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_CannedMessageConfig_size 49 #define meshtastic_ModuleConfig_DetectionSensorConfig_size 44 #define meshtastic_ModuleConfig_ExternalNotificationConfig_size 42 -#define meshtastic_ModuleConfig_MQTTConfig_size 238 +#define meshtastic_ModuleConfig_MQTTConfig_size 254 #define meshtastic_ModuleConfig_MapReportSettings_size 12 #define meshtastic_ModuleConfig_NeighborInfoConfig_size 8 #define meshtastic_ModuleConfig_PaxcounterConfig_size 8 @@ -841,7 +841,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_SerialConfig_size 28 #define meshtastic_ModuleConfig_StoreForwardConfig_size 22 #define meshtastic_ModuleConfig_TelemetryConfig_size 36 -#define meshtastic_ModuleConfig_size 241 +#define meshtastic_ModuleConfig_size 257 #define meshtastic_RemoteHardwarePin_size 21 #ifdef __cplusplus From 3995e2f7084b5776b655a7027af4620ee7c21e02 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 13 Mar 2024 15:06:52 -0500 Subject: [PATCH 71/94] Remove bunk code --- src/platform/nrf52/NRF52Bluetooth.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 9a93f5cc6..e1914a184 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -202,8 +202,6 @@ void setupMeshService(void) toRadio.begin(); } -// FIXME, turn off soft device access for debugging -static bool isSoftDeviceAllowed = true; static uint32_t configuredPasskey; void NRF52Bluetooth::shutdown() @@ -281,14 +279,11 @@ void NRF52Bluetooth::setup() LOG_INFO("Configuring the Mesh bluetooth service\n"); setupMeshService(); - // Supposedly debugging works with soft device if you disable advertising - if (isSoftDeviceAllowed) { - // Setup the advertising packet(s) - LOG_INFO("Setting up the advertising payload(s)\n"); - startAdv(); + // Setup the advertising packet(s) + LOG_INFO("Setting up the advertising payload(s)\n"); + startAdv(); - LOG_INFO("Advertising\n"); - } + LOG_INFO("Advertising\n"); } void NRF52Bluetooth::resumeAdverising() From 9d2fcbe1e108d221824fc5a1ead1c4cfa08e909b Mon Sep 17 00:00:00 2001 From: Andre K Date: Wed, 13 Mar 2024 20:24:49 -0300 Subject: [PATCH 72/94] use decoded packets in public MQTT range test/detection sensor filter (#3404) Co-authored-by: Ben Meadors --- src/mqtt/MQTT.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 4250ad5cd..c518bc4b5 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -486,9 +486,9 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & auto &ch = channels.getByIndex(chIndex); - if (&mp.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && - (mp.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP || - mp.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) { + if (&mp_decoded.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && + (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP || + mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) { LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt\n"); return; } From 9c37e57e750a72324ea58f6acda53168c4efae50 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 13 Mar 2024 20:27:26 -0500 Subject: [PATCH 73/94] Only allow phone to set time for fixed positions (#3403) --- src/mesh/NodeDB.h | 9 +++++++-- src/modules/PositionModule.cpp | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e472f7151..20cc5c25b 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -133,8 +133,13 @@ class NodeDB meshtastic_NodeInfoLite *getMeshNode(NodeNum n); size_t getNumMeshNodes() { return *numMeshNodes; } - void setLocalPosition(meshtastic_Position position) + void setLocalPosition(meshtastic_Position position, bool timeOnly = false) { + if (timeOnly) { + LOG_DEBUG("Setting local position time only: time=%i\n", position.time); + localPosition.time = position.time; + return; + } LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i, position.time); localPosition = position; @@ -248,4 +253,4 @@ extern uint32_t error_address; #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ - ModuleConfig_TelemetryConfig_size + ModuleConfig_size) + ModuleConfig_TelemetryConfig_size + ModuleConfig_size) \ No newline at end of file diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 4634f8fef..59f62bd5c 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -59,9 +59,15 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes // to set fixed location, EUD-GPS location or just the time (see also issue #900) bool isLocal = false; if (nodeDB.getNodeNum() == getFrom(&mp)) { - LOG_DEBUG("Incoming update from MYSELF\n"); isLocal = true; - nodeDB.setLocalPosition(p); + if (config.position.fixed_position) { + LOG_DEBUG("Ignore incoming position update from myself except for time, because position.fixed_position is true\n"); + nodeDB.setLocalPosition(p, true); + return false; + } else { + LOG_DEBUG("Incoming update from MYSELF\n"); + nodeDB.setLocalPosition(p); + } } // Log packet size and data fields From 58cdf360f862d7027f77148fc4f78d16d237365e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 14 Mar 2024 16:18:33 +0100 Subject: [PATCH 74/94] (1/3) Support L76B GNSS chip found on pico waveshare shield. Original work by @Mictronics --- platformio.ini | 4 ++-- src/gps/GPS.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++-- src/gps/GPS.h | 12 +++++------- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/platformio.ini b/platformio.ini index 392b38fd7..7680f2f20 100644 --- a/platformio.ini +++ b/platformio.ini @@ -77,7 +77,7 @@ lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 - https://github.com/meshtastic/TinyGPSPlus.git#2044b2c51e91ab4cd8cc93b15e40658cd808dd06 + https://github.com/meshtastic/TinyGPSPlus.git#f9f4fef2183514aa52be91d714c1455dd6f26e45 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 nanopb/Nanopb@^0.4.7 erriez/ErriezCRC32@^1.0.1 @@ -130,4 +130,4 @@ lib_deps = adafruit/Adafruit PM25 AQI Sensor@^1.0.6 adafruit/Adafruit MPU6050@^2.2.4 adafruit/Adafruit LIS3DH@^1.2.4 - https://github.com/lewisxhe/BMA423_Library@^0.0.1 + https://github.com/lewisxhe/BMA423_Library@^0.0.1 \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 849c38794..5b7d18bab 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -290,6 +290,26 @@ bool GPS::setup() // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g _serial_gps->write("$PCAS11,3*1E\r\n"); delay(250); + } else if (gnssModel == GNSS_MODEL_MTK_L76B) { + // Waveshare Pico-GPS hat uses the L76B with 9600 baud + // Initialize the L76B Chip, use GPS + GLONASS + // See note in L76_Series_GNSS_Protocol_Specification, chapter 3.29 + _serial_gps->write("$PMTK353,1,1,0,0,0*2B\r\n"); + // Above command will reset the GPS and takes longer before it will accept new commands + delay(1000); + // only ask for RMC and GGA (GNRMC and GNGGA) + // See note in L76_Series_GNSS_Protocol_Specification, chapter 2.1 + _serial_gps->write("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"); + delay(250); + // Enable SBAS + _serial_gps->write("$PMTK301,2*2E\r\n"); + delay(250); + // Enable PPS for 2D/3D fix only + _serial_gps->write("$PMTK285,3,100*3F\r\n"); + delay(250); + // Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s) + _serial_gps->write("$PMTK886,1*29\r\n"); + delay(250); } else if (gnssModel == GNSS_MODEL_UC6580) { // The Unicore UC6580 can use a lot of sat systems, enable it to // use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS @@ -625,17 +645,27 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) return; } #endif -#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76K and clones +#ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76B, L76K and clones if (on) { LOG_INFO("Waking GPS\n"); pinMode(PIN_GPS_STANDBY, OUTPUT); + // Some PCB's use an inverse logic due to a transistor driver + // Example for this is the Pico-Waveshare Lora+GPS HAT +#ifdef PIN_GPS_STANDBY_INVERTED + digitalWrite(PIN_GPS_STANDBY, 0); +#else digitalWrite(PIN_GPS_STANDBY, 1); +#endif return; } else { LOG_INFO("GPS entering sleep\n"); // notifyGPSSleep.notifyObservers(NULL); pinMode(PIN_GPS_STANDBY, OUTPUT); +#ifdef PIN_GPS_STANDBY_INVERTED + digitalWrite(PIN_GPS_STANDBY, 1); +#else digitalWrite(PIN_GPS_STANDBY, 0); +#endif return; } #endif @@ -916,7 +946,7 @@ GnssModel_t GPS::probe(int serialSpeed) uint8_t buffer[768] = {0}; delay(100); - // Close all NMEA sentences , Only valid for MTK platform + // Close all NMEA sentences , Only valid for L76K MTK platform _serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); delay(20); @@ -928,6 +958,18 @@ GnssModel_t GPS::probe(int serialSpeed) return GNSS_MODEL_MTK; } + // Close all NMEA sentences, valid for L76B MTK platform (Waveshare Pico GPS) + _serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n"); + delay(20); + + // Get version information + clearBuffer(); + _serial_gps->write("$PMTK605*31\r\n"); + if (getACK("Quectel-L76B", 500) == GNSS_RESPONSE_OK) { + LOG_INFO("L76B GNSS init succeeded, using L76B GNSS Module\n"); + return GNSS_MODEL_MTK_L76B; + } + uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00}; UBXChecksum(cfg_rate, sizeof(cfg_rate)); clearBuffer(); @@ -1111,6 +1153,7 @@ GPS *GPS::createGps() _serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio); #else + _serial_gps->setFIFOSize(256); _serial_gps->begin(GPS_BAUDRATE); #endif @@ -1168,6 +1211,9 @@ bool GPS::factoryReset() // byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B}; // _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART)); // delay(1000); + } else if (HW_VENDOR == meshtastic_HardwareModel_RPI_PICO) { + _serial_gps->write("$PMTK104*37\r\n"); + // No PMTK_ACK for this command. } else { // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. // Factory Reset diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 77e1d8042..502763bb6 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -20,12 +20,7 @@ struct uBloxGnssModelInfo { char extension[10][30]; }; -typedef enum { - GNSS_MODEL_MTK, - GNSS_MODEL_UBLOX, - GNSS_MODEL_UC6580, - GNSS_MODEL_UNKNOWN, -} GnssModel_t; +typedef enum { GNSS_MODEL_MTK, GNSS_MODEL_UBLOX, GNSS_MODEL_UC6580, GNSS_MODEL_UNKNOWN, GNSS_MODEL_MTK_L76B } GnssModel_t; typedef enum { GNSS_RESPONSE_NONE, @@ -92,8 +87,11 @@ class GPS : private concurrency::OSThread public: /** If !NULL we will use this serial port to construct our GPS */ +#if defined(RPI_PICO_WAVESHARE) + static SerialUART *_serial_gps; +#else static HardwareSerial *_serial_gps; - +#endif static uint8_t _message_PMREQ[]; static uint8_t _message_PMREQ_10[]; static const uint8_t _message_CFG_RXM_PSM[]; From a085c3ddb334fb4977f68980ebd2ef79e625c861 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 14 Mar 2024 17:00:57 -0500 Subject: [PATCH 75/94] Try-fix router missed messages (#3405) --- src/PowerFSM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index c359e4c12..f98b03077 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -358,10 +358,10 @@ void PowerFSM_setup() // Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the // modules if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) { - powerFSM.add_timed_transition(&stateNB, isInfrastructureRole ? &stateSDS : &stateLS, + powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); - powerFSM.add_timed_transition(&stateDARK, isInfrastructureRole ? &stateSDS : &stateLS, + powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout"); } From ec6bdeed8115be3904d413c1cd0ad79928d4f55e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 15 Mar 2024 07:12:03 -0500 Subject: [PATCH 76/94] NodeInfo broadcast ensure default on 0 and enforce 1 hour minimum (#3415) * NodeInfo broadcasts ensure defaults on 0 and enforce 1 hour minumum * Doh! * Hey that's not on config! --- src/mesh/NodeDB.cpp | 13 ++----------- src/mesh/NodeDB.h | 2 ++ src/modules/AdminModule.cpp | 4 ++++ src/modules/NodeInfoModule.cpp | 3 +-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 9d7647138..6898f7702 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -101,16 +101,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset) // devicestate.no_save = true; if (devicestate.no_save) { LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n"); - - // Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins - config.display.screen_on_secs = 10; - config.power.wait_bluetooth_secs = 10; - config.position.position_broadcast_secs = 6 * 60; - config.power.ls_secs = 60; - config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_TW; - - // Enter super deep sleep soon and stay there not very long - // radioConfig.preferences.sds_secs = 60; + // Put your development config changes here } // Update the global myRegion @@ -199,7 +190,7 @@ void NodeDB::installDefaultConfig() config.position.broadcast_smart_minimum_distance = 100; config.position.broadcast_smart_minimum_interval_secs = 30; if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER) - config.device.node_info_broadcast_secs = 3 * 60 * 60; + config.device.node_info_broadcast_secs = default_node_info_broadcast_secs; config.device.serial_enabled = true; resetRadioConfig(); strncpy(config.network.ntp_server, "0.pool.ntp.org", 32); diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 20cc5c25b..b34059fb9 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -203,6 +203,8 @@ extern NodeDB nodeDB; #define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60) #define default_min_wake_secs 10 #define default_screen_on_secs IF_ROUTER(1, 60 * 10) +#define default_node_info_broadcast_secs 3 * 60 * 60 +#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour #define default_mqtt_address "mqtt.meshtastic.org" #define default_mqtt_username "meshdev" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index abd7c2e54..06818dc88 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -302,6 +302,10 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) // If we're setting router role for the first time, install its intervals if (existingRole != c.payload_variant.device.role) nodeDB.installRoleDefaults(c.payload_variant.device.role); + if (config.device.node_info_broadcast_secs < min_node_info_broadcast_secs) { + LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d\n", min_node_info_broadcast_secs); + config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; + } break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index b0b4bbdcd..5177af33a 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -91,6 +91,5 @@ int32_t NodeInfoModule::runOnce() LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) } - - return getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_broadcast_interval_secs); + return getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_node_info_broadcast_secs); } From 50cc4cfcf15a65997f72960c7f1ab762d796dba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 15 Mar 2024 14:07:54 +0100 Subject: [PATCH 77/94] We don't use Lorawan (#3417) #warning "Persistent storage not supported!" [-Wcpp] --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 392b38fd7..68cfa1753 100644 --- a/platformio.ini +++ b/platformio.ini @@ -69,6 +69,7 @@ build_flags = -Wno-missing-field-initializers -DRADIOLIB_EXCLUDE_PAGER -DRADIOLIB_EXCLUDE_FSK4 -DRADIOLIB_EXCLUDE_APRS + -DRADIOLIB_EXCLUDE_LORAWAN monitor_speed = 115200 From 876a0520a99787f371d36e42db6475b4e80dcc34 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 08:09:48 -0500 Subject: [PATCH 78/94] [create-pull-request] automated change (#3418) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/clientonly.pb.c | 3 - src/mesh/generated/meshtastic/clientonly.pb.h | 16 ---- src/mesh/generated/meshtastic/mesh.pb.c | 3 + src/mesh/generated/meshtastic/mesh.pb.h | 86 ++++++++++++------- 5 files changed, 58 insertions(+), 52 deletions(-) diff --git a/protobufs b/protobufs index 7e3ee8cd9..cf25b390d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 7e3ee8cd96740910d0611433cb9a05a7a692568c +Subproject commit cf25b390d65113980b1a239e16faa79c7730a736 diff --git a/src/mesh/generated/meshtastic/clientonly.pb.c b/src/mesh/generated/meshtastic/clientonly.pb.c index 90e8e2d8a..ebc2ffabc 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.c +++ b/src/mesh/generated/meshtastic/clientonly.pb.c @@ -9,7 +9,4 @@ PB_BIND(meshtastic_DeviceProfile, meshtastic_DeviceProfile, 2) -PB_BIND(meshtastic_Heartbeat, meshtastic_Heartbeat, AUTO) - - diff --git a/src/mesh/generated/meshtastic/clientonly.pb.h b/src/mesh/generated/meshtastic/clientonly.pb.h index 19b0a0e5f..0f70e09c6 100644 --- a/src/mesh/generated/meshtastic/clientonly.pb.h +++ b/src/mesh/generated/meshtastic/clientonly.pb.h @@ -30,12 +30,6 @@ typedef struct _meshtastic_DeviceProfile { meshtastic_LocalModuleConfig module_config; } meshtastic_DeviceProfile; -/* A heartbeat message is sent by a node to indicate that it is still alive. - This is currently only needed to keep serial connections alive. */ -typedef struct _meshtastic_Heartbeat { - char dummy_field; -} meshtastic_Heartbeat; - #ifdef __cplusplus extern "C" { @@ -43,9 +37,7 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceProfile_init_default {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default} -#define meshtastic_Heartbeat_init_default {0} #define meshtastic_DeviceProfile_init_zero {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero} -#define meshtastic_Heartbeat_init_zero {0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_DeviceProfile_long_name_tag 1 @@ -66,21 +58,13 @@ X(a, STATIC, OPTIONAL, MESSAGE, module_config, 5) #define meshtastic_DeviceProfile_config_MSGTYPE meshtastic_LocalConfig #define meshtastic_DeviceProfile_module_config_MSGTYPE meshtastic_LocalModuleConfig -#define meshtastic_Heartbeat_FIELDLIST(X, a) \ - -#define meshtastic_Heartbeat_CALLBACK NULL -#define meshtastic_Heartbeat_DEFAULT NULL - extern const pb_msgdesc_t meshtastic_DeviceProfile_msg; -extern const pb_msgdesc_t meshtastic_Heartbeat_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_DeviceProfile_fields &meshtastic_DeviceProfile_msg -#define meshtastic_Heartbeat_fields &meshtastic_Heartbeat_msg /* Maximum encoded size of messages (where known) */ /* meshtastic_DeviceProfile_size depends on runtime parameters */ -#define meshtastic_Heartbeat_size 0 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.c b/src/mesh/generated/meshtastic/mesh.pb.c index 790f8be2d..97bb7e53b 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.c +++ b/src/mesh/generated/meshtastic/mesh.pb.c @@ -60,6 +60,9 @@ PB_BIND(meshtastic_Neighbor, meshtastic_Neighbor, AUTO) PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO) +PB_BIND(meshtastic_Heartbeat, meshtastic_Heartbeat, AUTO) + + diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 04590210e..8f260589c 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -682,32 +682,6 @@ typedef struct _meshtastic_QueueStatus { uint32_t mesh_packet_id; } meshtastic_QueueStatus; -/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic. - Once the write completes the phone can assume it is handled. */ -typedef struct _meshtastic_ToRadio { - pb_size_t which_payload_variant; - union { - /* Send this packet on the mesh */ - meshtastic_MeshPacket packet; - /* Phone wants radio to send full node db to the phone, This is - typically the first packet sent to the radio when the phone gets a - bluetooth connection. The radio will respond by sending back a - MyNodeInfo, a owner, a radio config and a series of - FromRadio.node_infos, and config_complete - the integer you write into this field will be reported back in the - config_complete_id response this allows clients to never be confused by - a stale old partially sent config. */ - uint32_t want_config_id; - /* Tell API server we are disconnecting now. - This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link. - (Sending this message is optional for clients) */ - bool disconnect; - meshtastic_XModem xmodemPacket; - /* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */ - meshtastic_MqttClientProxyMessage mqttClientProxyMessage; - }; -} meshtastic_ToRadio; - typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { @@ -815,6 +789,40 @@ typedef struct _meshtastic_FromRadio { }; } meshtastic_FromRadio; +/* A heartbeat message is sent to the node from the client to keep the connection alive. + This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. */ +typedef struct _meshtastic_Heartbeat { + char dummy_field; +} meshtastic_Heartbeat; + +/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic. + Once the write completes the phone can assume it is handled. */ +typedef struct _meshtastic_ToRadio { + pb_size_t which_payload_variant; + union { + /* Send this packet on the mesh */ + meshtastic_MeshPacket packet; + /* Phone wants radio to send full node db to the phone, This is + typically the first packet sent to the radio when the phone gets a + bluetooth connection. The radio will respond by sending back a + MyNodeInfo, a owner, a radio config and a series of + FromRadio.node_infos, and config_complete + the integer you write into this field will be reported back in the + config_complete_id response this allows clients to never be confused by + a stale old partially sent config. */ + uint32_t want_config_id; + /* Tell API server we are disconnecting now. + This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link. + (Sending this message is optional for clients) */ + bool disconnect; + meshtastic_XModem xmodemPacket; + /* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */ + meshtastic_MqttClientProxyMessage mqttClientProxyMessage; + /* Heartbeat message (used to keep the device connection awake on serial) */ + meshtastic_Heartbeat hearbeat; + }; +} meshtastic_ToRadio; + #ifdef __cplusplus extern "C" { @@ -888,6 +896,7 @@ extern "C" { #define meshtastic_DeviceMetadata_hw_model_ENUMTYPE meshtastic_HardwareModel + /* Initializer values for message structs */ #define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN} @@ -907,6 +916,7 @@ extern "C" { #define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}} #define meshtastic_Neighbor_init_default {0, 0, 0, 0} #define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0} +#define meshtastic_Heartbeat_init_default {0} #define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN} #define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} @@ -925,6 +935,7 @@ extern "C" { #define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}} #define meshtastic_Neighbor_init_zero {0, 0, 0, 0} #define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0} +#define meshtastic_Heartbeat_init_zero {0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_Position_latitude_i_tag 1 @@ -1016,11 +1027,6 @@ extern "C" { #define meshtastic_QueueStatus_free_tag 2 #define meshtastic_QueueStatus_maxlen_tag 3 #define meshtastic_QueueStatus_mesh_packet_id_tag 4 -#define meshtastic_ToRadio_packet_tag 1 -#define meshtastic_ToRadio_want_config_id_tag 3 -#define meshtastic_ToRadio_disconnect_tag 4 -#define meshtastic_ToRadio_xmodemPacket_tag 5 -#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6 #define meshtastic_Compressed_portnum_tag 1 #define meshtastic_Compressed_data_tag 2 #define meshtastic_Neighbor_node_id_tag 1 @@ -1055,6 +1061,12 @@ extern "C" { #define meshtastic_FromRadio_xmodemPacket_tag 12 #define meshtastic_FromRadio_metadata_tag 13 #define meshtastic_FromRadio_mqttClientProxyMessage_tag 14 +#define meshtastic_ToRadio_packet_tag 1 +#define meshtastic_ToRadio_want_config_id_tag 3 +#define meshtastic_ToRadio_disconnect_tag 4 +#define meshtastic_ToRadio_xmodemPacket_tag 5 +#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6 +#define meshtastic_ToRadio_hearbeat_tag 7 /* Struct field encoding specification for nanopb */ #define meshtastic_Position_FIELDLIST(X, a) \ @@ -1234,12 +1246,14 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_id), 3) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,hearbeat,hearbeat), 7) #define meshtastic_ToRadio_CALLBACK NULL #define meshtastic_ToRadio_DEFAULT NULL #define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket #define meshtastic_ToRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_ToRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage +#define meshtastic_ToRadio_payload_variant_hearbeat_MSGTYPE meshtastic_Heartbeat #define meshtastic_Compressed_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ @@ -1278,6 +1292,11 @@ X(a, STATIC, SINGULAR, BOOL, hasRemoteHardware, 10) #define meshtastic_DeviceMetadata_CALLBACK NULL #define meshtastic_DeviceMetadata_DEFAULT NULL +#define meshtastic_Heartbeat_FIELDLIST(X, a) \ + +#define meshtastic_Heartbeat_CALLBACK NULL +#define meshtastic_Heartbeat_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_Position_msg; extern const pb_msgdesc_t meshtastic_User_msg; extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg; @@ -1296,6 +1315,7 @@ extern const pb_msgdesc_t meshtastic_Compressed_msg; extern const pb_msgdesc_t meshtastic_NeighborInfo_msg; extern const pb_msgdesc_t meshtastic_Neighbor_msg; extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; +extern const pb_msgdesc_t meshtastic_Heartbeat_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_Position_fields &meshtastic_Position_msg @@ -1316,12 +1336,14 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; #define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg #define meshtastic_Neighbor_fields &meshtastic_Neighbor_msg #define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg +#define meshtastic_Heartbeat_fields &meshtastic_Heartbeat_msg /* Maximum encoded size of messages (where known) */ #define meshtastic_Compressed_size 243 #define meshtastic_Data_size 270 #define meshtastic_DeviceMetadata_size 46 #define meshtastic_FromRadio_size 510 +#define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 81 #define meshtastic_MeshPacket_size 326 #define meshtastic_MqttClientProxyMessage_size 501 From cbc0aa16c5851f4a822a37d24f2d1798a153ad80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 15 Mar 2024 16:37:47 +0100 Subject: [PATCH 79/94] fix compilation --- src/gps/GPS.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 5b7d18bab..7073e4eb0 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1151,10 +1151,11 @@ GPS *GPS::createGps() LOG_DEBUG("Using GPIO%d for GPS RX\n", new_gps->rx_gpio); LOG_DEBUG("Using GPIO%d for GPS TX\n", new_gps->tx_gpio); _serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio); - -#else +#elif defined(ARCH_RP2040) _serial_gps->setFIFOSize(256); _serial_gps->begin(GPS_BAUDRATE); +#else + _serial_gps->begin(GPS_BAUDRATE); #endif /* From b06c77d46fa2867a629dbc0c3d14e9400076005f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 15 Mar 2024 16:43:39 +0100 Subject: [PATCH 80/94] don't fix this to a hardware model. --- src/gps/GPS.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 7073e4eb0..4812786cb 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1212,10 +1212,11 @@ bool GPS::factoryReset() // byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B}; // _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART)); // delay(1000); - } else if (HW_VENDOR == meshtastic_HardwareModel_RPI_PICO) { + } else { + // fire this for good measure, if we have an L76B - won't harm other devices. _serial_gps->write("$PMTK104*37\r\n"); // No PMTK_ACK for this command. - } else { + delay(100); // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. // Factory Reset byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00, From da7cd5fc7fbe460969246e83bad981f68460a0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 15 Mar 2024 16:45:14 +0100 Subject: [PATCH 81/94] new Accelerometer lib (#3413) * new Accelerometer lib * Use our fork till upstreasm merges changes. * that PR escalated quickly * resurrect display flip --- platformio.ini | 2 +- src/AccelerometerThread.h | 70 ++++++++++++++------------------------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/platformio.ini b/platformio.ini index 68cfa1753..dbd15645f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -131,4 +131,4 @@ lib_deps = adafruit/Adafruit PM25 AQI Sensor@^1.0.6 adafruit/Adafruit MPU6050@^2.2.4 adafruit/Adafruit LIS3DH@^1.2.4 - https://github.com/lewisxhe/BMA423_Library@^0.0.1 + https://github.com/lewisxhe/SensorLib#27fd0f721e20cd09e1f81383f0ba58a54fe84a17 diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index 9898f4d49..6827908b7 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -7,16 +7,16 @@ #include #include #include +#include #include -#include -BMA423 bmaSensor; +SensorBMA423 bmaSensor; bool BMA_IRQ = false; #define ACCELEROMETER_CHECK_INTERVAL_MS 100 #define ACCELEROMETER_CLICK_THRESHOLD 40 -uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len) +int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len) { Wire.beginTransmission(address); Wire.write(reg); @@ -29,7 +29,7 @@ uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len) return 0; // Pass } -uint16_t writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len) +int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len) { Wire.beginTransmission(address); Wire.write(reg); @@ -72,24 +72,14 @@ class AccelerometerThread : public concurrency::OSThread lis.setRange(LIS3DH_RANGE_2_G); // Adjust threshold, higher numbers are less sensitive lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD); - } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.begin(readRegister, writeRegister, delay)) { + } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && + bmaSensor.begin(accelerometer_found.address, &readRegister, &writeRegister)) { LOG_DEBUG("BMA423 initializing\n"); - Acfg cfg; - cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ; - cfg.range = BMA4_ACCEL_RANGE_2G; - cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4; - cfg.perf_mode = BMA4_CONTINUOUS_MODE; - bmaSensor.setAccelConfig(cfg); - bmaSensor.enableAccel(); - - struct bma4_int_pin_config pin_config; - pin_config.edge_ctrl = BMA4_LEVEL_TRIGGER; - pin_config.lvl = BMA4_ACTIVE_HIGH; - pin_config.od = BMA4_PUSH_PULL; - pin_config.output_en = BMA4_OUTPUT_ENABLE; - pin_config.input_en = BMA4_INPUT_DISABLE; - // The correct trigger interrupt needs to be configured as needed - bmaSensor.setINTPinConfig(pin_config, BMA4_INTR1_MAP); + bmaSensor.configAccelerometer(bmaSensor.RANGE_2G, bmaSensor.ODR_100HZ, bmaSensor.BW_NORMAL_AVG4, + bmaSensor.PERF_CONTINUOUS_MODE); + bmaSensor.enableAccelerometer(); + bmaSensor.configInterrupt(BMA4_LEVEL_TRIGGER, BMA4_ACTIVE_HIGH, BMA4_PUSH_PULL, BMA4_OUTPUT_ENABLE, + BMA4_INPUT_DISABLE); #ifdef BMA423_INT pinMode(BMA4XX_INT, INPUT); @@ -102,34 +92,22 @@ class AccelerometerThread : public concurrency::OSThread RISING); // Select the interrupt mode according to the actual circuit #endif - struct bma423_axes_remap remap_data; #ifdef T_WATCH_S3 - remap_data.x_axis = 1; - remap_data.x_axis_sign = 0; - remap_data.y_axis = 0; - remap_data.y_axis_sign = 0; - remap_data.z_axis = 2; - remap_data.z_axis_sign = 1; -#else - remap_data.x_axis = 0; - remap_data.x_axis_sign = 1; - remap_data.y_axis = 1; - remap_data.y_axis_sign = 0; - remap_data.z_axis = 2; - remap_data.z_axis_sign = 1; -#endif // Need to raise the wrist function, need to set the correct axis - bmaSensor.setRemapAxes(&remap_data); - // sensor.enableFeature(BMA423_STEP_CNTR, true); - bmaSensor.enableFeature(BMA423_TILT, true); - bmaSensor.enableFeature(BMA423_WAKEUP, true); - // sensor.resetStepCounter(); + bmaSensor.setReampAxes(bmaSensor.REMAP_TOP_LAYER_RIGHT_CORNER); +#else + bmaSensor.setReampAxes(bmaSensor.REMAP_BOTTOM_LAYER_BOTTOM_LEFT_CORNER); +#endif + // bmaSensor.enableFeature(bmaSensor.FEATURE_STEP_CNTR, true); + bmaSensor.enableFeature(bmaSensor.FEATURE_TILT, true); + bmaSensor.enableFeature(bmaSensor.FEATURE_WAKEUP, true); + // bmaSensor.resetPedometer(); // Turn on feature interrupt - bmaSensor.enableStepCountInterrupt(); - bmaSensor.enableTiltInterrupt(); + bmaSensor.enablePedometerIRQ(); + bmaSensor.enableTiltIRQ(); // It corresponds to isDoubleClick interrupt - bmaSensor.enableWakeupInterrupt(); + bmaSensor.enableWakeupIRQ(); } } @@ -150,8 +128,8 @@ class AccelerometerThread : public concurrency::OSThread buttonPress(); return 500; } - } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.getINT()) { - if (bmaSensor.isTilt() || bmaSensor.isDoubleClick()) { + } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.readIrqStatus() != DEV_WIRE_NONE) { + if (bmaSensor.isTilt() || bmaSensor.isDoubleTap()) { wakeScreen(); return 500; } From b9004152189933d9e0de7184ec7687166d9415c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 15 Mar 2024 19:47:47 +0100 Subject: [PATCH 82/94] that should work now --- src/gps/GPS.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 4812786cb..2321ee246 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1151,9 +1151,6 @@ GPS *GPS::createGps() LOG_DEBUG("Using GPIO%d for GPS RX\n", new_gps->rx_gpio); LOG_DEBUG("Using GPIO%d for GPS TX\n", new_gps->tx_gpio); _serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio); -#elif defined(ARCH_RP2040) - _serial_gps->setFIFOSize(256); - _serial_gps->begin(GPS_BAUDRATE); #else _serial_gps->begin(GPS_BAUDRATE); #endif From 34bc22f94db27fb59d609b969c285644f30937a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 14 Mar 2024 16:29:28 +0100 Subject: [PATCH 83/94] (2/3) Add Slow Clock Support for RP2040 platform. This will disable USB Softserial. --- arch/rp2040/rp2040.ini | 4 +-- src/SerialConsole.cpp | 8 +++++ src/modules/SerialModule.cpp | 10 ++++++ src/platform/rp2040/main-rp2040.cpp | 52 ++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini index edc4373ad..dd3a4d7ff 100644 --- a/arch/rp2040/rp2040.ini +++ b/arch/rp2040/rp2040.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#612de5399d68b359053f1307ed223d400aea975c +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#60d6ae81fcc73c34b1493ca9e261695e471bc0c2 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.2 +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.7.2 board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index ed217c3ed..485329ddc 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -3,7 +3,11 @@ #include "PowerFSM.h" #include "configuration.h" +#ifdef RP2040_SLOW_CLOCK +#define Port Serial2 +#else #define Port Serial +#endif // Defaulting to the formerly removed phone_timeout_secs value of 15 minutes #define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL @@ -31,6 +35,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con canWrite = false; // We don't send packets to our port until it has talked to us first // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks +#ifdef RP2040_SLOW_CLOCK + Port.setTX(SERIAL2_TX); + Port.setRX(SERIAL2_RX); +#endif Port.begin(SERIAL_BAUD); #if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040) time_t timeout = millis(); diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 820e1fb62..1dee42a8d 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -126,8 +126,13 @@ int32_t SerialModule::runOnce() uint32_t baud = getBaudRate(); if (moduleConfig.serial.override_console_serial_port) { +#ifdef RP2040_SLOW_CLOCK + Serial2.flush(); + serialPrint = &Serial2; +#else Serial.flush(); serialPrint = &Serial; +#endif // Give it a chance to flush out 💩 delay(10); } @@ -151,8 +156,13 @@ int32_t SerialModule::runOnce() Serial2.begin(baud, SERIAL_8N1); Serial2.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT); } else { +#ifdef RP2040_SLOW_CLOCK + Serial2.begin(baud, SERIAL_8N1); + Serial2.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT); +#else Serial.begin(baud, SERIAL_8N1); Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT); +#endif } #else Serial.begin(baud, SERIAL_8N1); diff --git a/src/platform/rp2040/main-rp2040.cpp b/src/platform/rp2040/main-rp2040.cpp index 283b801f1..af3aeadc3 100644 --- a/src/platform/rp2040/main-rp2040.cpp +++ b/src/platform/rp2040/main-rp2040.cpp @@ -1,4 +1,7 @@ #include "configuration.h" +#include +#include +#include #include #include @@ -35,9 +38,56 @@ void rp2040Setup() Taken from CPU cycle counter and ROSC oscillator, so should be pretty random. */ randomSeed(rp2040.hwrand32()); + +#ifdef RP2040_SLOW_CLOCK + uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY); + uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY); + uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC); + uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS); + uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI); + uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB); + uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC); + uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC); + + LOG_INFO("Clock speed:\n"); + LOG_INFO("pll_sys = %dkHz\n", f_pll_sys); + LOG_INFO("pll_usb = %dkHz\n", f_pll_usb); + LOG_INFO("rosc = %dkHz\n", f_rosc); + LOG_INFO("clk_sys = %dkHz\n", f_clk_sys); + LOG_INFO("clk_peri = %dkHz\n", f_clk_peri); + LOG_INFO("clk_usb = %dkHz\n", f_clk_usb); + LOG_INFO("clk_adc = %dkHz\n", f_clk_adc); + LOG_INFO("clk_rtc = %dkHz\n", f_clk_rtc); +#endif } void enterDfuMode() { reset_usb_boot(0, 0); -} \ No newline at end of file +} + +/* Init in early boot state. */ +#ifdef RP2040_SLOW_CLOCK +void initVariant() +{ + /* Set the system frequency to 18 MHz. */ + set_sys_clock_khz(18 * KHZ, false); + /* The previous line automatically detached clk_peri from clk_sys, and + attached it to pll_usb. We need to attach clk_peri back to system PLL to keep SPI + working at this low speed. + For details see https://github.com/jgromes/RadioLib/discussions/938 + */ + clock_configure(clk_peri, + 0, // No glitchless mux + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux + 18 * MHZ, // Input frequency + 18 * MHZ // Output (must be same as no divider) + ); + /* Run also ADC on lower clk_sys. */ + clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 18 * MHZ, 18 * MHZ); + /* Run RTC from XOSC since USB clock is off */ + clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, 12 * MHZ, 47 * KHZ); + /* Turn off USB PLL */ + pll_deinit(pll_usb); +} +#endif \ No newline at end of file From 52cfec29fcf595aa3f069993a6b0dec293110647 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 15 Mar 2024 16:17:47 -0500 Subject: [PATCH 84/94] More comprehensive client proxy queue guards (#3414) * More comprehensive MQTT thread and queue guards * Consolidate logic * Remove channel check * Check for map_reporting_enabled as well * Update message * Remove channel check from here as well * One liner * Start the mqtt thread back up when channels change and we want mqtt --- src/mesh/Channels.cpp | 16 ++++++++++++++++ src/mesh/Channels.h | 3 +++ src/mesh/PhoneAPI.cpp | 6 +++++- src/mqtt/MQTT.cpp | 21 ++++----------------- src/mqtt/MQTT.h | 4 ++++ 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 3e9c78241..93dec7e7d 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -7,6 +7,8 @@ #include +#include "mqtt/MQTT.h" + /// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128) static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01}; @@ -193,6 +195,10 @@ void Channels::onConfigChanged() if (ch.role == meshtastic_Channel_Role_PRIMARY) primaryIndex = i; } + if (channels.anyMqttEnabled() && mqtt && !mqtt->isEnabled()) { + LOG_DEBUG("MQTT is enabled on at least one channel, so set MQTT thread to run immediately\n"); + mqtt->start(); + } } meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex) @@ -237,6 +243,16 @@ void Channels::setChannel(const meshtastic_Channel &c) old = c; // slam in the new settings/role } +bool Channels::anyMqttEnabled() +{ + for (int i = 0; i < getNumChannels(); i++) + if (channelFile.channels[i].role != meshtastic_Channel_Role_DISABLED && channelFile.channels[i].has_settings && + (channelFile.channels[i].settings.downlink_enabled || channelFile.channels[i].settings.uplink_enabled)) + return true; + + return false; +} + const char *Channels::getName(size_t chIndex) { // Convert the short "" representation for Default into a usable string diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 0e11605c4..a1c4ba171 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -105,6 +105,9 @@ class Channels // Returns true if we can be reached via a channel with the default settings given a region and modem preset bool hasDefaultChannel(); + // Returns true if any of our channels have enabled MQTT uplink or downlink + bool anyMqttEnabled(); + private: /** Given a channel index, change to use the crypto key specified by that index * diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 270bf613f..8e8d69156 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -105,8 +105,12 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) break; case meshtastic_ToRadio_mqttClientProxyMessage_tag: LOG_INFO("Got MqttClientProxy message\n"); - if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled) { + if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled && moduleConfig.mqtt.enabled && + (channels.anyMqttEnabled() || moduleConfig.mqtt.map_reporting_enabled)) { mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage); + } else { + LOG_WARN("MqttClientProxy received but proxy is not enabled, no channels have up/downlink, or map reporting " + "not enabled\n"); } break; default: diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index c518bc4b5..0d99a3cfd 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -371,22 +371,9 @@ void MQTT::sendSubscriptions() bool MQTT::wantsLink() const { - bool hasChannelorMapReport = false; + bool hasChannelorMapReport = + moduleConfig.mqtt.enabled && (moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled()); - if (moduleConfig.mqtt.enabled) { - hasChannelorMapReport = moduleConfig.mqtt.map_reporting_enabled; - if (!hasChannelorMapReport) { - // No need for link if no channel needed it - size_t numChan = channels.getNumChannels(); - for (size_t i = 0; i < numChan; i++) { - const auto &ch = channels.getByIndex(i); - if (ch.settings.uplink_enabled || ch.settings.downlink_enabled) { - hasChannelorMapReport = true; - break; - } - } - } - } if (hasChannelorMapReport && moduleConfig.mqtt.proxy_to_client_enabled) return true; @@ -401,7 +388,7 @@ bool MQTT::wantsLink() const int32_t MQTT::runOnce() { - if (!moduleConfig.mqtt.enabled) + if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled())) return disable(); bool wantConnection = wantsLink(); @@ -915,4 +902,4 @@ bool MQTT::isValidJsonEnvelope(JSONObject &json) (json["from"]->AsNumber() == nodeDB.getNodeNum()) && // only accept message if the "from" is us (json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type (json.find("payload") != json.end()); // should have a payload -} +} \ No newline at end of file diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index eeeb00d92..dbc0c77b3 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -71,6 +71,10 @@ class MQTT : private concurrency::OSThread void onClientProxyReceive(meshtastic_MqttClientProxyMessage msg); + bool isEnabled() { return this->enabled; }; + + void start() { setIntervalFromNow(0); }; + protected: PointerQueue mqttQueue; From 0dda20bc353343d8e8a8edcfab7fed80d33b047a Mon Sep 17 00:00:00 2001 From: Andre K Date: Fri, 15 Mar 2024 19:12:30 -0300 Subject: [PATCH 85/94] fix for I2C scan getting stuck (#3375) * refactor: add delay for T-Echo peripherals setup * comment out `PIN_POWER_EN1` --- src/main.cpp | 4 ++-- src/sleep.cpp | 2 +- variants/t-echo/variant.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bb9b68631..fe5d455f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -223,7 +223,7 @@ void setup() #if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN) pinMode(PIN_POWER_EN, OUTPUT); digitalWrite(PIN_POWER_EN, HIGH); - digitalWrite(PIN_POWER_EN1, INPUT); + // digitalWrite(PIN_POWER_EN1, INPUT); #endif #if defined(LORA_TCXO_GPIO) @@ -965,4 +965,4 @@ void loop() mainDelay.delay(delayMsec); } // if (didWake) LOG_DEBUG("wake!\n"); -} \ No newline at end of file +} diff --git a/src/sleep.cpp b/src/sleep.cpp index bfacffeb9..6d8e4f3cc 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -203,7 +203,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #ifdef TTGO_T_ECHO #ifdef PIN_POWER_EN pinMode(PIN_POWER_EN, INPUT); // power off peripherals - pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); + // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); #endif #endif diff --git a/variants/t-echo/variant.h b/variants/t-echo/variant.h index 19a66719f..13f74d303 100644 --- a/variants/t-echo/variant.h +++ b/variants/t-echo/variant.h @@ -158,7 +158,7 @@ External serial flash WP25R1635FZUIL0 // Controls power for all peripherals (eink + GPS + LoRa + Sensor) #define PIN_POWER_EN (0 + 12) -#define PIN_POWER_EN1 (0 + 13) +// #define PIN_POWER_EN1 (0 + 13) #define USE_EINK From 0de36fbfb0bd5a6cd773726de03b084ab96d7960 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:12:45 -0500 Subject: [PATCH 86/94] [create-pull-request] automated change (#3419) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/protobufs b/protobufs index cf25b390d..b2b145e33 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit cf25b390d65113980b1a239e16faa79c7730a736 +Subproject commit b2b145e3321beab1441fa59290137ab42eb38dc8 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 8f260589c..2f57f1ae2 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -819,7 +819,7 @@ typedef struct _meshtastic_ToRadio { /* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */ meshtastic_MqttClientProxyMessage mqttClientProxyMessage; /* Heartbeat message (used to keep the device connection awake on serial) */ - meshtastic_Heartbeat hearbeat; + meshtastic_Heartbeat heartbeat; }; } meshtastic_ToRadio; @@ -1066,7 +1066,7 @@ extern "C" { #define meshtastic_ToRadio_disconnect_tag 4 #define meshtastic_ToRadio_xmodemPacket_tag 5 #define meshtastic_ToRadio_mqttClientProxyMessage_tag 6 -#define meshtastic_ToRadio_hearbeat_tag 7 +#define meshtastic_ToRadio_heartbeat_tag 7 /* Struct field encoding specification for nanopb */ #define meshtastic_Position_FIELDLIST(X, a) \ @@ -1247,13 +1247,13 @@ X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_i X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,hearbeat,hearbeat), 7) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,heartbeat,heartbeat), 7) #define meshtastic_ToRadio_CALLBACK NULL #define meshtastic_ToRadio_DEFAULT NULL #define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket #define meshtastic_ToRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_ToRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage -#define meshtastic_ToRadio_payload_variant_hearbeat_MSGTYPE meshtastic_Heartbeat +#define meshtastic_ToRadio_payload_variant_heartbeat_MSGTYPE meshtastic_Heartbeat #define meshtastic_Compressed_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ From 9586606229f59883938b263c9abc451ce6967b3a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 15 Mar 2024 18:40:48 -0500 Subject: [PATCH 87/94] Handle for heartbeat toradio packets (#3420) --- src/SerialConsole.cpp | 2 +- src/mesh/PhoneAPI.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 485329ddc..e17c8f99e 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -72,7 +72,7 @@ bool SerialConsole::checkIsConnected() /** * we override this to notice when we've received a protobuf over the serial - * stream. Then we shunt off debug serial output. + * stream. Then we shut off debug serial output. */ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len) { diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 8e8d69156..e6b336d41 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -113,6 +113,9 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) "not enabled\n"); } break; + case meshtastic_ToRadio_heartbeat_tag: + LOG_DEBUG("Got client heartbeat\n"); + break; default: // Ignore nop messages // LOG_DEBUG("Error: unexpected ToRadio variant\n"); From 611f291d4d5e26e6d19c9f54ff0188b836209a4b Mon Sep 17 00:00:00 2001 From: David Ellefsen <93522+titan098@users.noreply.github.com> Date: Sat, 16 Mar 2024 02:19:50 +0200 Subject: [PATCH 88/94] Factory reset GNSS_MODEL_MTK GPS modules with PCAS10,3 (#3388) Co-authored-by: Ben Meadors --- src/gps/GPS.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 2321ee246..18932e066 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1209,6 +1209,11 @@ bool GPS::factoryReset() // byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B}; // _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART)); // delay(1000); + } else if (gnssModel == GNSS_MODEL_MTK) { + // send the CAS10 to perform a factory restart of the device (and other device that support PCAS statements) + LOG_INFO("GNSS Factory Reset via PCAS10,3\n"); + _serial_gps->write("$PCAS10,3*1F\r\n"); + delay(100); } else { // fire this for good measure, if we have an L76B - won't harm other devices. _serial_gps->write("$PMTK104*37\r\n"); From 54a2a4bcc67793fc8e72621d487153d4eb801c3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Mar 2024 07:39:28 -0500 Subject: [PATCH 89/94] [create-pull-request] automated change (#3422) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/protobufs b/protobufs index b2b145e33..556e49ba6 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit b2b145e3321beab1441fa59290137ab42eb38dc8 +Subproject commit 556e49ba619e2f4d8fa3c2dee2a94129a43d5f08 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 79800d4b4..d6a2a0272 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -141,7 +141,8 @@ typedef struct _meshtastic_DeviceState { NodeDB.cpp in the device code. */ uint32_t version; /* Used only during development. - Indicates developer is testing and changes should never be saved to flash. */ + Indicates developer is testing and changes should never be saved to flash. + Deprecated in 2.3.1 */ bool no_save; /* Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. */ bool did_gps_reset; From 13cc1b0252b5fdae9a195412039ea46b0288d634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 16 Mar 2024 16:01:43 +0100 Subject: [PATCH 90/94] (3/3) Add variant for pico with waveshare and GPS hat (#3412) * (3/3) Add variant for pico with waveshare and GPS hat, utilizing slow clock. * Not everybody has Serial2 * Trunk * Push it real gud * No init --------- Co-authored-by: Ben Meadors --- src/configuration.h | 1 + src/detect/ScanI2CTwoWire.cpp | 10 ++- src/modules/Telemetry/Sensor/INA219Sensor.cpp | 6 +- variants/rpipico-slowclock/platformio.ini | 28 ++++++ variants/rpipico-slowclock/variant.h | 87 +++++++++++++++++++ 5 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 variants/rpipico-slowclock/platformio.ini create mode 100644 variants/rpipico-slowclock/variant.h diff --git a/src/configuration.h b/src/configuration.h index ac8f9435a..ec32c72d1 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -111,6 +111,7 @@ along with this program. If not, see . #define MCP9808_ADDR 0x18 #define INA_ADDR 0x40 #define INA_ADDR_ALTERNATE 0x41 +#define INA_ADDR_WAVESHARE_UPS 0x43 #define INA3221_ADDR 0x42 #define QMC6310_ADDR 0x1C #define QMI8658_ADDR 0x6B diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index b6eca5fa4..146daa3dc 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -183,8 +183,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) case ATECC608B_ADDR: - type = ATECC608B; - if (atecc.begin(addr.address) == true) { +#ifdef RP2040_SLOW_CLOCK + if (atecc.begin(addr.address, Wire, Serial2) == true) +#else + if (atecc.begin(addr.address) == true) +#endif + + { LOG_INFO("ATECC608B initialized\n"); } else { LOG_WARN("ATECC608B initialization failed\n"); @@ -254,6 +259,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) case INA_ADDR: case INA_ADDR_ALTERNATE: + case INA_ADDR_WAVESHARE_UPS: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue); if (registerValue == 0x5449) { diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.cpp b/src/modules/Telemetry/Sensor/INA219Sensor.cpp index 5a1faa99f..ecb564368 100644 --- a/src/modules/Telemetry/Sensor/INA219Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA219Sensor.cpp @@ -4,6 +4,10 @@ #include "configuration.h" #include +#ifndef INA219_MULTIPLIER +#define INA219_MULTIPLIER 1.0f +#endif + INA219Sensor::INA219Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_INA219, "INA219") {} int32_t INA219Sensor::runOnce() @@ -26,7 +30,7 @@ void INA219Sensor::setup() {} bool INA219Sensor::getMetrics(meshtastic_Telemetry *measurement) { measurement->variant.environment_metrics.voltage = ina219.getBusVoltage_V(); - measurement->variant.environment_metrics.current = ina219.getCurrent_mA(); + measurement->variant.environment_metrics.current = ina219.getCurrent_mA() * INA219_MULTIPLIER; return true; } diff --git a/variants/rpipico-slowclock/platformio.ini b/variants/rpipico-slowclock/platformio.ini new file mode 100644 index 000000000..e583c4b0d --- /dev/null +++ b/variants/rpipico-slowclock/platformio.ini @@ -0,0 +1,28 @@ +[env:pico_slowclock] +extends = rp2040_base +board = rpipico +upload_protocol = jlink +# debug settings for external openocd with RP2040 support (custom build) +debug_tool = custom +debug_init_cmds = + target extended-remote localhost:3333 + $INIT_BREAK + monitor reset halt + $LOAD_CMDS + monitor init + monitor reset halt + +# add our variants files to the include and src paths +build_flags = ${rp2040_base.build_flags} + -DRPI_PICO + -Ivariants/rpipico_slowclock + -DDEBUG_RP2040_PORT=Serial2 + -DHW_SPI1_DEVICE + -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus" + -g + -DNO_USB +lib_deps = + ${rp2040_base.lib_deps} +debug_build_flags = ${rp2040_base.build_flags} + -g + -DNO_USB \ No newline at end of file diff --git a/variants/rpipico-slowclock/variant.h b/variants/rpipico-slowclock/variant.h new file mode 100644 index 000000000..fb97ec0fb --- /dev/null +++ b/variants/rpipico-slowclock/variant.h @@ -0,0 +1,87 @@ +#define ARDUINO_ARCH_AVR + +// Build with slow system clock enabled to reduce power consumption. +#define RP2040_SLOW_CLOCK + +#ifdef RP2040_SLOW_CLOCK +// Redefine UART1 serial log output to avoid collision with UART0 for GPS. +#define SERIAL2_TX 4 +#define SERIAL2_RX 5 +// Reroute log output in SensorLib when USB is not available +#define log_e(...) Serial2.printf(__VA_ARGS__) +#define log_i(...) Serial2.printf(__VA_ARGS__) +#define log_d(...) Serial2.printf(__VA_ARGS__) +#endif + +// Expecting the Waveshare Pico GPS hat +#define HAS_GPS 1 + +// Enable OLED Screen +#define HAS_SCREEN 1 +#define USE_SH1106 1 +#define RESET_OLED 13 + +// Redefine I2C0 pins to avoid collision with UART1/Serial2. +#define I2C_SDA 8 +#define I2C_SCL 9 + +// Redefine Waveshare UPS-A/B I2C_1 pins: +#define I2C_SDA1 6 +#define I2C_SCL1 7 +// Waveshare UPS-A/B uses a 0.01 Ohm shunt for the INA219 sensor +#define INA219_MULTIPLIER 10.0f + +// Waveshare Pico GPS L76B pins: +#define GPS_RX_PIN 1 +#define GPS_TX_PIN 0 + +// Wakeup from backup mode +// #define PIN_GPS_FORCE_ON 14 +// No GPS reset available +#undef PIN_GPS_RESET +/* + * For PPS output the resistor R20 needs to be populated with 0 Ohm + * on the Waveshare Pico GPS board. + */ +#define PIN_GPS_PPS 16 +/* + * For standby mode switching the resistor R18 needs to be populated + * with 0 Ohm on the Waveshare Pico GPS board. + */ +#define PIN_GPS_STANDBY 17 + +#define BUTTON_PIN 18 +#define EXT_NOTIFY_OUT 22 +#define LED_PIN PIN_LED + +#define BATTERY_PIN 26 +// ratio of voltage divider = 3.0 (R17=200k, R18=100k) +#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic +#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION + +#define USE_SX1262 + +#undef LORA_SCK +#undef LORA_MISO +#undef LORA_MOSI +#undef LORA_CS + +#define LORA_SCK 10 +#define LORA_MISO 12 +#define LORA_MOSI 11 +#define LORA_CS 3 + +#define LORA_DIO0 RADIOLIB_NC +#define LORA_RESET 15 +#define LORA_DIO1 20 +#define LORA_DIO2 2 +#define LORA_DIO3 RADIOLIB_NC + +#ifdef USE_SX1262 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#endif \ No newline at end of file From e27f029d09424698f6e8b00ac64efe73ee85749a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Mar 2024 19:56:42 -0500 Subject: [PATCH 91/94] Bump minimum NodeInfo send to 5 minutes (#3423) * Bump minimum NodeInfo send to 3 minutes * 5 --- src/modules/NodeInfoModule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 5177af33a..6b4289970 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -58,8 +58,8 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha meshtastic_MeshPacket *NodeInfoModule::allocReply() { uint32_t now = millis(); - // If we sent our NodeInfo less than 1 min. ago, don't send it again as it may be still underway. - if (lastSentToMesh && (now - lastSentToMesh) < 60 * 1000) { + // If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway. + if (lastSentToMesh && (now - lastSentToMesh) < (5 * 60 * 1000)) { LOG_DEBUG("Sending NodeInfo will be ignored since we just sent it.\n"); ignoreRequest = true; // Mark it as ignored for MeshModule return NULL; From bb57ccfc9eccc9520950c125debcf7bfe73b87ab Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 17 Mar 2024 08:16:22 -0500 Subject: [PATCH 92/94] Remove devicestate no_save (#3424) --- src/mesh/NodeDB.cpp | 74 ++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 6898f7702..a9fffc335 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -97,13 +97,6 @@ bool NodeDB::resetRadioConfig(bool factory_reset) channels.onConfigChanged(); - // temp hack for quicker testing - // devicestate.no_save = true; - if (devicestate.no_save) { - LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n"); - // Put your development config changes here - } - // Update the global myRegion initRegion(); @@ -644,61 +637,52 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_ void NodeDB::saveChannelsToDisk() { - if (!devicestate.no_save) { #ifdef FSCom - FSCom.mkdir("/prefs"); + FSCom.mkdir("/prefs"); #endif - saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile); - } + saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile); } void NodeDB::saveDeviceStateToDisk() { - if (!devicestate.no_save) { #ifdef FSCom - FSCom.mkdir("/prefs"); + FSCom.mkdir("/prefs"); #endif - saveProto(prefFileName, meshtastic_DeviceState_size, &meshtastic_DeviceState_msg, &devicestate); - } } void NodeDB::saveToDisk(int saveWhat) { - if (!devicestate.no_save) { #ifdef FSCom - FSCom.mkdir("/prefs"); + FSCom.mkdir("/prefs"); #endif - if (saveWhat & SEGMENT_DEVICESTATE) { - saveDeviceStateToDisk(); - } + if (saveWhat & SEGMENT_DEVICESTATE) { + saveDeviceStateToDisk(); + } - if (saveWhat & SEGMENT_CONFIG) { - config.has_device = true; - config.has_display = true; - config.has_lora = true; - config.has_position = true; - config.has_power = true; - config.has_network = true; - config.has_bluetooth = true; - saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config); - } + if (saveWhat & SEGMENT_CONFIG) { + config.has_device = true; + config.has_display = true; + config.has_lora = true; + config.has_position = true; + config.has_power = true; + config.has_network = true; + config.has_bluetooth = true; + saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config); + } - if (saveWhat & SEGMENT_MODULECONFIG) { - moduleConfig.has_canned_message = true; - moduleConfig.has_external_notification = true; - moduleConfig.has_mqtt = true; - moduleConfig.has_range_test = true; - moduleConfig.has_serial = true; - moduleConfig.has_store_forward = true; - moduleConfig.has_telemetry = true; - saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig); - } + if (saveWhat & SEGMENT_MODULECONFIG) { + moduleConfig.has_canned_message = true; + moduleConfig.has_external_notification = true; + moduleConfig.has_mqtt = true; + moduleConfig.has_range_test = true; + moduleConfig.has_serial = true; + moduleConfig.has_store_forward = true; + moduleConfig.has_telemetry = true; + saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig); + } - if (saveWhat & SEGMENT_CHANNELS) { - saveChannelsToDisk(); - } - } else { - LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n"); + if (saveWhat & SEGMENT_CHANNELS) { + saveChannelsToDisk(); } } From 0d1d79b6d15f5e7c4bcde12a1f59af3c204117c3 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 17 Mar 2024 08:18:30 -0500 Subject: [PATCH 93/94] Extract default intervals and coalesce methods into their own file / static class methods (#3425) * Extract default intervals and coalesce methods into their own file / static class methods * Missed pax * Still managed to miss one --- src/PowerFSM.cpp | 18 ++++---- src/PowerFSMThread.h | 3 +- src/gps/GPS.cpp | 4 +- src/mesh/Default.cpp | 23 ++++++++++ src/mesh/Default.h | 30 +++++++++++++ src/mesh/NodeDB.cpp | 1 + src/mesh/NodeDB.h | 42 ------------------- src/mesh/PhoneAPI.cpp | 1 + src/modules/AdminModule.cpp | 1 + src/modules/AtakPluginModule.cpp | 1 + src/modules/DetectionSensorModule.cpp | 7 ++-- src/modules/NeighborInfoModule.cpp | 3 +- src/modules/NodeInfoModule.cpp | 3 +- src/modules/PositionModule.cpp | 11 +++-- src/modules/Telemetry/AirQualityTelemetry.cpp | 3 +- src/modules/Telemetry/DeviceTelemetry.cpp | 3 +- .../Telemetry/EnvironmentTelemetry.cpp | 5 ++- src/modules/Telemetry/PowerTelemetry.cpp | 5 ++- src/modules/esp32/PaxcounterModule.cpp | 11 ++--- src/mqtt/MQTT.cpp | 1 + 20 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 src/mesh/Default.cpp create mode 100644 src/mesh/Default.h diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index f98b03077..5d86987df 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -8,6 +8,7 @@ * actions to be taken upon entering or exiting each state. */ #include "PowerFSM.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "configuration.h" @@ -45,7 +46,7 @@ static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw - doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs), false); + doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } extern Power *power; @@ -343,13 +344,13 @@ void PowerFSM_setup() powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone"); powerFSM.add_timed_transition(&stateON, &stateDARK, - getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, + Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&statePOWER, &stateDARK, - getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, + Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateDARK, &stateDARK, - getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, + Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) @@ -359,11 +360,12 @@ void PowerFSM_setup() // modules if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) { powerFSM.add_timed_transition(&stateNB, &stateLS, - getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, + Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); - powerFSM.add_timed_transition(&stateDARK, &stateLS, - getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), - NULL, "Bluetooth timeout"); + powerFSM.add_timed_transition( + &stateDARK, &stateLS, + Default::getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, + "Bluetooth timeout"); } #endif diff --git a/src/PowerFSMThread.h b/src/PowerFSMThread.h index 584c955aa..fb640dd8b 100644 --- a/src/PowerFSMThread.h +++ b/src/PowerFSMThread.h @@ -1,3 +1,4 @@ +#include "Default.h" #include "NodeDB.h" #include "PowerFSM.h" #include "concurrency/OSThread.h" @@ -28,7 +29,7 @@ class PowerFSMThread : public OSThread timeLastPowered = millis(); } else if (config.power.on_battery_shutdown_after_secs > 0 && config.power.on_battery_shutdown_after_secs != UINT32_MAX && millis() > (timeLastPowered + - getConfiguredOrDefaultMs( + Default::getConfiguredOrDefaultMs( config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered powerFSM.trigger(EVENT_SHUTDOWN); } diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 18932e066..5595172dd 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1,4 +1,5 @@ #include "GPS.h" +#include "Default.h" #include "NodeDB.h" #include "RTC.h" #include "configuration.h" @@ -495,7 +496,6 @@ bool GPS::setup() } } } - } else { // LOG_INFO("u-blox M10 hardware found.\n"); delay(1000); @@ -759,7 +759,7 @@ uint32_t GPS::getWakeTime() const if (t == UINT32_MAX) return t; // already maxint - return getConfiguredOrDefaultMs(t, default_broadcast_interval_secs); + return Default::Default::getConfiguredOrDefaultMs(t, default_broadcast_interval_secs); } /** Get how long we should sleep between aqusition attempts in msecs diff --git a/src/mesh/Default.cpp b/src/mesh/Default.cpp new file mode 100644 index 000000000..db058c5b0 --- /dev/null +++ b/src/mesh/Default.cpp @@ -0,0 +1,23 @@ +#include "Default.h" + +uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval) +{ + if (configuredInterval > 0) + return configuredInterval * 1000; + return default_broadcast_interval_secs * 1000; +} + +uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) +{ + if (configuredInterval > 0) + return configuredInterval * 1000; + return defaultInterval * 1000; +} + +uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue) +{ + if (configured > 0) + return configured; + + return defaultValue; +} \ No newline at end of file diff --git a/src/mesh/Default.h b/src/mesh/Default.h new file mode 100644 index 000000000..734cdf519 --- /dev/null +++ b/src/mesh/Default.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#define ONE_DAY 24 * 60 * 60 + +#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) +#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) +#define default_wait_bluetooth_secs IF_ROUTER(1, 60) +#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep +#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60) +#define default_min_wake_secs 10 +#define default_screen_on_secs IF_ROUTER(1, 60 * 10) +#define default_node_info_broadcast_secs 3 * 60 * 60 +#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour + +#define default_mqtt_address "mqtt.meshtastic.org" +#define default_mqtt_username "meshdev" +#define default_mqtt_password "large4cats" +#define default_mqtt_root "msh" + +#define IF_ROUTER(routerVal, normalVal) \ + ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) ? (routerVal) : (normalVal)) + +class Default +{ + public: + static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval); + static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval); + static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue); +}; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a9fffc335..04b6fe89d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -3,6 +3,7 @@ #include "../detect/ScanI2C.h" #include "Channels.h" #include "CryptoEngine.h" +#include "Default.h" #include "FSCommon.h" #include "GPS.h" #include "MeshRadio.h" diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index b34059fb9..930b3483e 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -191,48 +191,6 @@ extern NodeDB nodeDB; // Our delay functions check for this for times that should never expire #define NODE_DELAY_FOREVER 0xffffffff -#define IF_ROUTER(routerVal, normalVal) \ - ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) ? (routerVal) : (normalVal)) - -#define ONE_DAY 24 * 60 * 60 - -#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) -#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) -#define default_wait_bluetooth_secs IF_ROUTER(1, 60) -#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep -#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60) -#define default_min_wake_secs 10 -#define default_screen_on_secs IF_ROUTER(1, 60 * 10) -#define default_node_info_broadcast_secs 3 * 60 * 60 -#define min_node_info_broadcast_secs 60 * 60 // No regular broadcasts of more than once an hour - -#define default_mqtt_address "mqtt.meshtastic.org" -#define default_mqtt_username "meshdev" -#define default_mqtt_password "large4cats" -#define default_mqtt_root "msh" - -inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval) -{ - if (configuredInterval > 0) - return configuredInterval * 1000; - return default_broadcast_interval_secs * 1000; -} - -inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) -{ - if (configuredInterval > 0) - return configuredInterval * 1000; - return defaultInterval * 1000; -} - -inline uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue) -{ - if (configured > 0) - return configured; - - return defaultValue; -} - /// Sometimes we will have Position objects that only have a time, so check for /// valid lat/lon static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index e6b336d41..d8e842149 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -1,5 +1,6 @@ #include "PhoneAPI.h" #include "Channels.h" +#include "Default.h" #include "GPS.h" #include "MeshService.h" #include "NodeDB.h" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 06818dc88..6c4c80dbb 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -16,6 +16,7 @@ #ifdef ARCH_PORTDUINO #include "unistd.h" #endif +#include "Default.h" #include "mqtt/MQTT.h" diff --git a/src/modules/AtakPluginModule.cpp b/src/modules/AtakPluginModule.cpp index ffc4fe68a..64a85e2bf 100644 --- a/src/modules/AtakPluginModule.cpp +++ b/src/modules/AtakPluginModule.cpp @@ -1,4 +1,5 @@ #include "AtakPluginModule.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" diff --git a/src/modules/DetectionSensorModule.cpp b/src/modules/DetectionSensorModule.cpp index 6c35e94ae..fd26749c1 100644 --- a/src/modules/DetectionSensorModule.cpp +++ b/src/modules/DetectionSensorModule.cpp @@ -1,10 +1,10 @@ #include "DetectionSensorModule.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" #include "configuration.h" #include "main.h" - DetectionSensorModule *detectionSensorModule; #define GPIO_POLLING_INTERVAL 100 @@ -49,7 +49,7 @@ int32_t DetectionSensorModule::runOnce() // LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin)); - if ((millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) && + if ((millis() - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) && hasDetectionEvent()) { sendDetectionMessage(); return DELAYED_INTERVAL; @@ -58,7 +58,8 @@ int32_t DetectionSensorModule::runOnce() // of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state // change detections. else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 && - (millis() - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) { + (millis() - lastSentToMesh) >= + Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) { sendCurrentStateMessage(); return DELAYED_INTERVAL; } diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 2e0b04afa..024f321e6 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -1,4 +1,5 @@ #include "NeighborInfoModule.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" @@ -194,7 +195,7 @@ int32_t NeighborInfoModule::runOnce() { bool requestReplies = false; sendNeighborInfo(NODENUM_BROADCAST, requestReplies); - return getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs); + return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs); } /* diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 6b4289970..370847b94 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -1,4 +1,5 @@ #include "NodeInfoModule.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" @@ -91,5 +92,5 @@ int32_t NodeInfoModule::runOnce() LOG_INFO("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) } - return getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_node_info_broadcast_secs); + return Default::getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_node_info_broadcast_secs); } diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 59f62bd5c..853808f44 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -1,4 +1,5 @@ #include "PositionModule.h" +#include "Default.h" #include "GPS.h" #include "MeshService.h" #include "NodeDB.h" @@ -280,7 +281,7 @@ int32_t PositionModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs); LOG_DEBUG("Sleeping for %ims, then awaking to send position again.\n", nightyNightMs); doDeepSleep(nightyNightMs, false); } @@ -291,7 +292,8 @@ int32_t PositionModule::runOnce() // We limit our GPS broadcasts to a max rate uint32_t now = millis(); - uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); + uint32_t intervalMs = + Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); uint32_t msSinceLastSend = now - lastGpsSend; // Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized. if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && @@ -322,7 +324,7 @@ int32_t PositionModule::runOnce() if (hasValidPosition(node2)) { // The minimum time (in seconds) that would pass before we are able to send a new position packet. const uint32_t minimumTimeThreshold = - getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); + Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); auto smartPosition = getDistanceTraveledSinceLastSend(node->position); @@ -369,7 +371,8 @@ void PositionModule::sendLostAndFoundText() struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition) { // The minimum distance to travel before we are able to send a new position packet. - const uint32_t distanceTravelThreshold = getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100); + const uint32_t distanceTravelThreshold = + Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100); // Determine the distance in meters between two points on the globe float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter( diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index ada1fdef8..3e9b069c4 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -1,5 +1,6 @@ #include "AirQualityTelemetry.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" @@ -43,7 +44,7 @@ int32_t AirQualityTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 55000e4c6..3ed106d1c 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -1,5 +1,6 @@ #include "DeviceTelemetry.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" @@ -16,7 +17,7 @@ int32_t DeviceTelemetryModule::runOnce() { uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) && airTime->isTxAllowedChannelUtil() && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 7b59c28a6..203b632a7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -1,5 +1,6 @@ #include "EnvironmentTelemetry.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" @@ -41,7 +42,7 @@ int32_t EnvironmentTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -102,7 +103,7 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 300ab1f62..713f6aacb 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -1,5 +1,6 @@ #include "PowerTelemetry.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" @@ -20,7 +21,7 @@ int32_t PowerTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -66,7 +67,7 @@ int32_t PowerTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 54c67fad7..aad7b5d63 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -1,8 +1,8 @@ #include "configuration.h" #if defined(ARCH_ESP32) +#include "Default.h" #include "MeshService.h" #include "PaxcounterModule.h" - #include PaxcounterModule *paxcounterModule; @@ -82,9 +82,9 @@ int32_t PaxcounterModule::runOnce() if (isActive()) { if (firstTime) { firstTime = false; - LOG_DEBUG( - "Paxcounter starting up with interval of %d seconds\n", - getConfiguredOrDefault(moduleConfig.paxcounter.paxcounter_update_interval, default_broadcast_interval_secs)); + LOG_DEBUG("Paxcounter starting up with interval of %d seconds\n", + Default::getConfiguredOrDefault(moduleConfig.paxcounter.paxcounter_update_interval, + default_broadcast_interval_secs)); struct libpax_config_t configuration; libpax_default_config(&configuration); @@ -104,7 +104,8 @@ int32_t PaxcounterModule::runOnce() } else { sendInfo(NODENUM_BROADCAST); } - return getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, default_broadcast_interval_secs); + return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, + default_broadcast_interval_secs); } else { return disable(); } diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 0d99a3cfd..7e341a18c 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -17,6 +17,7 @@ #include "mesh/wifi/WiFiAPClient.h" #include #endif +#include "Default.h" #include const int reconnectMax = 5; From aae49f5ecf06fb216a59b8ac4bad2e5cc008d641 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 17 Mar 2024 08:38:49 -0500 Subject: [PATCH 94/94] Remove confusing channel suffix (#3432) * Remove confusing channel suffix * Missed it --- src/graphics/Screen.cpp | 3 +-- src/mesh/Channels.cpp | 34 ---------------------------------- src/mesh/Channels.h | 19 ------------------- 3 files changed, 1 insertion(+), 55 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 7f20b5666..cfd8494d2 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1513,8 +1513,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 char channelStr[20]; { concurrency::LockGuard guard(&lock); - auto chName = channels.getPrimaryName(); - snprintf(channelStr, sizeof(channelStr), "%s", chName); + snprintf(channelStr, sizeof(channelStr), "#%s", channels.getName(channels.getPrimaryIndex())); } // Display power status diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 93dec7e7d..840e65bca 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -290,40 +290,6 @@ bool Channels::hasDefaultChannel() return false; } -/** -* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. -* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they -their nodes -* aren't talking to each other. -* -* This string is of the form "#name-X". -* -* Where X is either: -* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, -* -* This function will also need to be implemented in GUI apps that talk to the radio. -* -* https://github.com/meshtastic/firmware/issues/269 -*/ -const char *Channels::getPrimaryName() -{ - static char buf[32]; - - char suffix; - // auto channelSettings = getPrimary(); - // if (channelSettings.psk.size != 1) { - // We have a standard PSK, so generate a letter based hash. - uint8_t code = getHash(primaryIndex); - - suffix = 'A' + (code % 26); - /* } else { - suffix = '0' + channelSettings.psk.bytes[0]; - } */ - - snprintf(buf, sizeof(buf), "#%s-%c", getName(primaryIndex), suffix); - return buf; -} - /** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured) * * This method is called before decoding inbound packets diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index a1c4ba171..952445a1d 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -61,25 +61,6 @@ class Channels ChannelIndex getNumChannels() { return channelFile.channels_count; } - /** - * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different - PSKs. - * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why - they their nodes - * aren't talking to each other. - * - * This string is of the form "#name-X". - * - * Where X is either: - * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, - * OR (for the standard minimially secure PSKs) a number from 0 to 9. - * - * This function will also need to be implemented in GUI apps that talk to the radio. - * - * https://github.com/meshtastic/firmware/issues/269 - */ - const char *getPrimaryName(); - /// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config. void initDefaults();