From 61028293b866cf13b098a3d18c8f00e3e59205b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 27 Jan 2023 14:46:53 +0100 Subject: [PATCH 01/27] move temporary reboot code to blink thread --- src/concurrency/OSThread.cpp | 15 +-------------- src/main.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/concurrency/OSThread.cpp b/src/concurrency/OSThread.cpp index c52efd626..af50d28f5 100644 --- a/src/concurrency/OSThread.cpp +++ b/src/concurrency/OSThread.cpp @@ -1,9 +1,5 @@ #include "OSThread.h" #include "configuration.h" -#ifdef HAS_SCREEN -#include "graphics/Screen.h" -#endif -#include "main.h" #include namespace concurrency @@ -83,21 +79,12 @@ void OSThread::run() #endif currentThread = this; auto newDelay = runOnce(); -#ifdef ARCH_ESP32 - auto newHeap = ESP.getFreeHeap(); - if (newHeap < 10000) { - LOG_DEBUG("\n\n====== heap too low [10000] -> reboot in 5s ======\n\n"); -#ifdef HAS_SCREEN - screen->startRebootScreen(); -#endif - rebootAtMsec = millis() + 5000; - } #ifdef DEBUG_HEAP + auto newHeap = ESP.getFreeHeap(); if (newHeap < heap) LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap); if (heap < newHeap) LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++\n", ThreadName.c_str(), heap, newHeap, newHeap - heap); -#endif #endif runned(); diff --git a/src/main.cpp b/src/main.cpp index 4f72be7da..c91a71719 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,6 +128,17 @@ static int32_t ledBlinker() setLed(ledOn); +#ifdef ARCH_ESP32 + auto newHeap = ESP.getFreeHeap(); + if (newHeap < 11000) { + LOG_DEBUG("\n\n====== heap too low [11000] -> reboot in 1s ======\n\n"); +#ifdef HAS_SCREEN + screen->startRebootScreen(); +#endif + rebootAtMsec = millis() + 900; + } +#endif + // have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000); } From 2e8832babbcd4f7866b62dbefdfb3be1edf50b5d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 27 Jan 2023 10:22:17 -0600 Subject: [PATCH 02/27] Trunk, you got a big storm coming, honey --- .github/ISSUE_TEMPLATE/New Board.yml | 2 +- .github/actions/setup-base/action.yml | 8 +-- .github/workflows/build_esp32.yml | 6 +-- .github/workflows/build_nrf52.yml | 4 +- .github/workflows/build_rpi2040.yml | 4 +- .github/workflows/sec_sast_flawfinder.yml | 48 +++++++++--------- .github/workflows/sec_sast_semgrep_cron.yml | 56 ++++++++++----------- .github/workflows/sec_sast_semgrep_pull.yml | 5 +- 8 files changed, 64 insertions(+), 69 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/New Board.yml b/.github/ISSUE_TEMPLATE/New Board.yml index ad706f3c0..c71ed4ba2 100644 --- a/.github/ISSUE_TEMPLATE/New Board.yml +++ b/.github/ISSUE_TEMPLATE/New Board.yml @@ -28,7 +28,7 @@ body: description: What LoRa IC does the board have? validations: required: true - + - type: input id: link attributes: diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index 1791f80ae..45930a94f 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -1,5 +1,5 @@ -name: 'Setup Build Base Composite Action' -description: 'Base build actions for Meshtastic Platform IO steps' +name: "Setup Build Base Composite Action" +description: "Base build actions for Meshtastic Platform IO steps" runs: using: "composite" @@ -10,7 +10,7 @@ runs: submodules: "recursive" ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} - + - name: Install cppcheck shell: bash run: | @@ -38,4 +38,4 @@ runs: - name: Upgrade platformio shell: bash run: | - pio upgrade \ No newline at end of file + pio upgrade diff --git a/.github/workflows/build_esp32.yml b/.github/workflows/build_esp32.yml index 74b71db50..7996a9b1b 100644 --- a/.github/workflows/build_esp32.yml +++ b/.github/workflows/build_esp32.yml @@ -7,7 +7,7 @@ on: required: true type: string -jobs: +jobs: build-esp32: runs-on: ubuntu-latest steps: @@ -31,7 +31,7 @@ jobs: - name: Remove debug flags for release if: ${{ github.event_name == 'workflow_dispatch' }} - run: | + 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 @@ -46,7 +46,7 @@ jobs: file: "firmware.bin" target: "release/bleota.bin" token: ${{ secrets.GITHUB_TOKEN }} - + - name: Get release version string shell: bash run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml index cdf43c22e..33ee4d00c 100644 --- a/.github/workflows/build_nrf52.yml +++ b/.github/workflows/build_nrf52.yml @@ -7,7 +7,7 @@ on: required: true type: string -jobs: +jobs: build-nrf52: runs-on: ubuntu-latest steps: @@ -30,4 +30,4 @@ jobs: path: | release/*.uf2 release/*.elf - release/*.zip \ No newline at end of file + release/*.zip diff --git a/.github/workflows/build_rpi2040.yml b/.github/workflows/build_rpi2040.yml index fb7e3db5b..76ca2c20e 100644 --- a/.github/workflows/build_rpi2040.yml +++ b/.github/workflows/build_rpi2040.yml @@ -7,7 +7,7 @@ on: required: true type: string -jobs: +jobs: build-rpi2040: runs-on: ubuntu-latest steps: @@ -29,4 +29,4 @@ jobs: name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip path: | release/*.uf2 - release/*.elf \ No newline at end of file + release/*.elf diff --git a/.github/workflows/sec_sast_flawfinder.yml b/.github/workflows/sec_sast_flawfinder.yml index e2ba44090..2c7e751af 100644 --- a/.github/workflows/sec_sast_flawfinder.yml +++ b/.github/workflows/sec_sast_flawfinder.yml @@ -10,31 +10,31 @@ on: jobs: flawfinder: - runs-on: ubuntu-latest - name: Flawfinder + runs-on: ubuntu-latest + name: Flawfinder - steps: - # step 1 - - name: clone application source code - uses: actions/checkout@v3 + steps: + # step 1 + - name: clone application source code + uses: actions/checkout@v3 - # step 2 - - name: flawfinder_scan - uses: david-a-wheeler/flawfinder@2.0.19 - with: - arguments: '--sarif ./' - output: 'flawfinder_report.sarif' + # step 2 + - name: flawfinder_scan + uses: david-a-wheeler/flawfinder@2.0.19 + with: + arguments: "--sarif ./" + output: "flawfinder_report.sarif" - # step 3 - - name: save report as pipeline artifact - uses: actions/upload-artifact@v3 - with: - name: flawfinder_report.sarif - path: flawfinder_report.sarif + # step 3 + - name: save report as pipeline artifact + uses: actions/upload-artifact@v3 + with: + name: flawfinder_report.sarif + path: flawfinder_report.sarif - # step 4 - - name: publish code scanning alerts - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: flawfinder_report.sarif - category: flawfinder + # step 4 + - name: publish code scanning alerts + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: flawfinder_report.sarif + category: flawfinder diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml index 426250280..cdd2c3c37 100644 --- a/.github/workflows/sec_sast_semgrep_cron.yml +++ b/.github/workflows/sec_sast_semgrep_cron.yml @@ -6,39 +6,37 @@ on: branches: - master schedule: - - cron: '0 1 * * 6' + - cron: "0 1 * * 6" jobs: - semgrep-full: - runs-on: ubuntu-latest - container: - image: returntocorp/semgrep + runs-on: ubuntu-latest + container: + image: returntocorp/semgrep - steps: + steps: + # step 1 + - name: clone application source code + uses: actions/checkout@v3 - # step 1 - - name: clone application source code - uses: actions/checkout@v3 + # step 2 + - name: full scan + run: | + semgrep \ + --sarif --output report.sarif \ + --metrics=off \ + --config="p/default" - # step 2 - - name: full scan - run: | - semgrep \ - --sarif --output report.sarif \ - --metrics=off \ - --config="p/default" + # step 3 + - name: save report as pipeline artifact + uses: actions/upload-artifact@v3 + with: + name: report.sarif + path: report.sarif - # step 3 - - name: save report as pipeline artifact - uses: actions/upload-artifact@v3 - with: - name: report.sarif - path: report.sarif - - # step 4 - - name: publish code scanning alerts - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: report.sarif - category: semgrep + # step 4 + - name: publish code scanning alerts + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: report.sarif + category: semgrep diff --git a/.github/workflows/sec_sast_semgrep_pull.yml b/.github/workflows/sec_sast_semgrep_pull.yml index 8fe3632b4..1697ffb1b 100644 --- a/.github/workflows/sec_sast_semgrep_pull.yml +++ b/.github/workflows/sec_sast_semgrep_pull.yml @@ -1,17 +1,14 @@ --- name: Semgrep Differential Scan -on: - pull_request +on: pull_request jobs: - semgrep-diff: runs-on: ubuntu-latest container: image: returntocorp/semgrep steps: - # step 1 - name: clone application source code uses: actions/checkout@v3 From 2baaad8298f67c1608924efddd78569ce8d02d5d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 27 Jan 2023 11:19:45 -0600 Subject: [PATCH 03/27] I swear --- .vscode/tasks.json | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b2340005e..cdb8f5114 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,17 +1,15 @@ { - "version": "2.0.0", - "tasks": [ - { - "type": "PlatformIO", - "task": "Build", - "problemMatcher": [ - "$platformio" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "label": "PlatformIO: Build" - } - ] -} \ No newline at end of file + "version": "2.0.0", + "tasks": [ + { + "type": "PlatformIO", + "task": "Build", + "problemMatcher": ["$platformio"], + "group": { + "kind": "build", + "isDefault": true + }, + "label": "PlatformIO: Build" + } + ] +} From 7950739d850acb5d61581d5f69a6047b7e866f3d Mon Sep 17 00:00:00 2001 From: thebentern Date: Fri, 27 Jan 2023 17:56:16 +0000 Subject: [PATCH 04/27] [create-pull-request] automated change --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 7cf773466..4b12a2fc8 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 0 -build = 14 +build = 15 From 96f763dfa301486a95bd8b6282a9cf553c7a7eb1 Mon Sep 17 00:00:00 2001 From: thebentern Date: Fri, 27 Jan 2023 20:16:23 +0000 Subject: [PATCH 05/27] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 11 ----------- src/mesh/generated/meshtastic/config.pb.h | 16 ++++++++++++---- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/protobufs b/protobufs index 8cb6ed3c9..0754d5820 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8cb6ed3c91e23062cf0a4b8e50e4f98ef36170d3 +Subproject commit 0754d58205de4105292f25ca90cdf3501d94587b diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 5caa22bb7..c47fb886f 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -112,13 +112,6 @@ typedef struct _meshtastic_AdminMessage { bool begin_edit_settings; /* Commits an open transaction for any edits made to config, module config, owner, and channel settings */ bool commit_edit_settings; - /* Setting channels/radio config remotely carries the risk that you might send an invalid config and the radio never talks to your mesh again. - Therefore if setting either of these properties remotely, you must send a confirm_xxx message within 10 minutes. - If you fail to do so, the radio will assume loss of comms and revert your changes. - These messages are optional when changing the local node. */ - bool confirm_set_channel; - /* TODO: REPLACE */ - bool confirm_set_radio; /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */ int32_t reboot_ota_seconds; @@ -181,8 +174,6 @@ extern "C" { #define meshtastic_AdminMessage_set_ringtone_message_tag 37 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 -#define meshtastic_AdminMessage_confirm_set_channel_tag 66 -#define meshtastic_AdminMessage_confirm_set_radio_tag 67 #define meshtastic_AdminMessage_reboot_ota_seconds_tag 95 #define meshtastic_AdminMessage_exit_simulator_tag 96 #define meshtastic_AdminMessage_reboot_seconds_tag 97 @@ -214,8 +205,6 @@ X(a, STATIC, ONEOF, STRING, (payload_variant,set_canned_message_module_me X(a, STATIC, ONEOF, STRING, (payload_variant,set_ringtone_message,set_ringtone_message), 37) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ -X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_channel,confirm_set_channel), 66) \ -X(a, STATIC, ONEOF, BOOL, (payload_variant,confirm_set_radio,confirm_set_radio), 67) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_seconds), 97) \ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 907824fb2..d90467582 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -19,11 +19,19 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE = 1, /* Router device role. Mesh packets will prefer to be routed over this node. This node will not be used by client apps. - The wifi/ble radios and the oled screen will be put to sleep. */ + The wifi/ble radios and the oled screen will be put to sleep. + This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. */ meshtastic_Config_DeviceConfig_Role_ROUTER = 2, /* Router Client device role Mesh packets will prefer to be routed over this node. The Router Client can be used as both a Router and an app connected Client. */ - meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3 + meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3, + /* Repeater device role + Mesh packets will simply be rebroadcasted over this node. Nodes under this role node will not originate NodeInfo, Position, Telemetry + or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factory, and coding rate. */ + meshtastic_Config_DeviceConfig_Role_REPEATER = 4, + /* Tracker device role + Position Mesh packets for will be higher priority and sent more frequently by default. */ + meshtastic_Config_DeviceConfig_Role_TRACKER = 5 } meshtastic_Config_DeviceConfig_Role; /* Bit field of boolean configuration options, indicating which optional @@ -419,8 +427,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT -#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT -#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT+1)) +#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TRACKER +#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TRACKER+1)) #define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET #define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED From de82119415df121070179c4a5ba517ab25d39f60 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 06:38:13 -0600 Subject: [PATCH 06/27] Start of repeater role with in firmware --- src/gps/GPS.cpp | 238 ++++++++++++++++++++++----------- src/mesh/RadioLibInterface.h | 236 ++++++++++++++++---------------- src/mesh/ReliableRouter.cpp | 63 ++++++--- src/mesh/Router.cpp | 118 +++++++++++----- src/mesh/Router.h | 194 +++++++++++++-------------- src/modules/RepeaterModule.cpp | 27 ++++ src/modules/RepeaterModule.h | 31 +++++ 7 files changed, 564 insertions(+), 343 deletions(-) create mode 100644 src/modules/RepeaterModule.cpp create mode 100644 src/modules/RepeaterModule.h diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 4368bc3a7..468f8e9f4 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -29,29 +29,38 @@ bool GPS::getACK(uint8_t c, uint8_t i) uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned long startTime = millis(); - for (int j = 2; j < 6; j++) { + for (int j = 2; j < 6; j++) + { buf[8] += buf[j]; buf[9] += buf[8]; } - for (int j = 0; j < 2; j++) { + for (int j = 0; j < 2; j++) + { buf[6 + j] = ackP[j]; buf[8] += buf[6 + j]; buf[9] += buf[8]; } - while (1) { - if (ack > 9) { + while (1) + { + if (ack > 9) + { return true; } - if (millis() - startTime > 1000) { + if (millis() - startTime > 1000) + { return false; } - if (_serial_gps->available()) { + if (_serial_gps->available()) + { b = _serial_gps->read(); - if (b == buf[ack]) { + if (b == buf[ack]) + { ack++; - } else { + } + else + { ack = 0; } } @@ -73,37 +82,50 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t uint32_t startTime = millis(); uint16_t needRead; - while (millis() - startTime < 800) { - while (_serial_gps->available()) { + while (millis() - startTime < 800) + { + while (_serial_gps->available()) + { int c = _serial_gps->read(); - switch (ubxFrameCounter) { + switch (ubxFrameCounter) + { case 0: // ubxFrame 'μ' - if (c == 0xB5) { + if (c == 0xB5) + { ubxFrameCounter++; } break; case 1: // ubxFrame 'b' - if (c == 0x62) { + if (c == 0x62) + { ubxFrameCounter++; - } else { + } + else + { ubxFrameCounter = 0; } break; case 2: // Class - if (c == requestedClass) { + if (c == requestedClass) + { ubxFrameCounter++; - } else { + } + else + { ubxFrameCounter = 0; } break; case 3: // Message ID - if (c == requestedID) { + if (c == requestedID) + { ubxFrameCounter++; - } else { + } + else + { ubxFrameCounter = 0; } break; @@ -119,13 +141,17 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t break; case 6: // Check for buffer overflow - if (needRead >= size) { + if (needRead >= size) + { ubxFrameCounter = 0; break; } - if (_serial_gps->readBytes(buffer, needRead) != needRead) { + if (_serial_gps->readBytes(buffer, needRead) != needRead) + { ubxFrameCounter = 0; - } else { + } + else + { // return payload lenght return needRead; } @@ -141,7 +167,8 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t bool GPS::setupGPS() { - if (_serial_gps && !didSerialInit) { + if (_serial_gps && !didSerialInit) + { didSerialInit = true; #ifdef ARCH_ESP32 @@ -173,7 +200,8 @@ bool GPS::setupGPS() */ gnssModel = probe(); - if (gnssModel == GNSS_MODEL_MTK) { + if (gnssModel == GNSS_MODEL_MTK) + { /* * t-beam-s3-core uses the same L76K GNSS module as t-echo. * Unlike t-echo, L76K uses 9600 baud rate for communication by default. @@ -190,8 +218,9 @@ bool GPS::setupGPS() // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g _serial_gps->write("$PCAS11,3*1E\r\n"); delay(250); - - } else if (gnssModel == GNSS_MODEL_UBLOX) { + } + else if (gnssModel == GNSS_MODEL_UBLOX) + { /* tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after @@ -213,7 +242,8 @@ bool GPS::setupGPS() byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A}; _serial_gps->write(_message_GGL, sizeof(_message_GGL)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to disable NMEA GGL.\n"); return true; } @@ -222,7 +252,8 @@ bool GPS::setupGPS() byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41}; _serial_gps->write(_message_GSA, sizeof(_message_GSA)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to disable NMEA GSA.\n"); return true; } @@ -231,7 +262,8 @@ bool GPS::setupGPS() byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48}; _serial_gps->write(_message_GSV, sizeof(_message_GSV)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to disable NMEA GSV.\n"); return true; } @@ -240,7 +272,8 @@ bool GPS::setupGPS() byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56}; _serial_gps->write(_message_VTG, sizeof(_message_VTG)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to disable NMEA VTG.\n"); return true; } @@ -249,7 +282,8 @@ bool GPS::setupGPS() byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54}; _serial_gps->write(_message_RMC, sizeof(_message_RMC)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to enable NMEA RMC.\n"); return true; } @@ -258,7 +292,8 @@ bool GPS::setupGPS() byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38}; _serial_gps->write(_message_GGA, sizeof(_message_GGA)); - if (!getACK(0x06, 0x01)) { + if (!getACK(0x06, 0x01)) + { LOG_WARN("Unable to enable NMEA GGA.\n"); } } @@ -276,7 +311,8 @@ bool GPS::setup() #endif #ifdef HAS_PMU - if (config.position.gps_enabled) { + if (config.position.gps_enabled) + { setGPSPower(true); } #endif @@ -290,13 +326,15 @@ bool GPS::setup() setAwake(true); // Wake GPS power before doing any init bool ok = setupGPS(); - if (ok) { + if (ok) + { notifySleepObserver.observe(¬ifySleep); notifyDeepSleepObserver.observe(¬ifyDeepSleep); notifyGPSSleepObserver.observe(¬ifyGPSSleep); } - if (config.position.gps_enabled == false && config.position.fixed_position == false) { + if (config.position.gps_enabled == false && config.position.fixed_position == false) + { setAwake(false); doGPSpowersave(false); } @@ -345,7 +383,8 @@ void GPS::sleep() /// Record that we have a GPS void GPS::setConnected() { - if (!hasGPS) { + if (!hasGPS) + { hasGPS = true; shouldPublish = true; } @@ -353,7 +392,8 @@ void GPS::setConnected() void GPS::setNumSatellites(uint8_t n) { - if (n != numSatellites) { + if (n != numSatellites) + { numSatellites = n; shouldPublish = true; } @@ -366,17 +406,22 @@ void GPS::setNumSatellites(uint8_t n) */ void GPS::setAwake(bool on) { - if (!wakeAllowed && on) { + if (!wakeAllowed && on) + { LOG_WARN("Inhibiting because !wakeAllowed\n"); on = false; } - if (isAwake != on) { + if (isAwake != on) + { LOG_DEBUG("WANT GPS=%d\n", on); - if (on) { + if (on) + { lastWakeStartMsec = millis(); wake(); - } else { + } + else + { lastSleepStartMsec = millis(); sleep(); } @@ -415,7 +460,8 @@ uint32_t GPS::getSleepTime() const void GPS::publishUpdate() { - if (shouldPublish) { + if (shouldPublish) + { shouldPublish = false; // In debug logs, identify position by @timestamp:stage (stage 2 = publish) @@ -429,13 +475,22 @@ void GPS::publishUpdate() int32_t GPS::runOnce() { - if (whileIdle()) { + // Repeaters have no need for GPS + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) + disable(); + + if (whileIdle()) + { // if we have received valid NMEA claim we are connected setConnected(); - } else { - if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) { + } + else + { + if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) + { // reset the GPS on next bootup - if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) { + if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) + { LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); devicestate.did_gps_reset = false; nodeDB.saveDeviceStateToDisk(); @@ -448,28 +503,33 @@ int32_t GPS::runOnce() uint32_t now = millis(); auto sleepTime = getSleepTime(); - if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) { + if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) + { // We now want to be awake - so wake up the GPS setAwake(true); } // While we are awake - if (isAwake) { + if (isAwake) + { // LOG_DEBUG("looking for location\n"); - if ((now - lastWhileActiveMsec) > 5000) { + if ((now - lastWhileActiveMsec) > 5000) + { lastWhileActiveMsec = now; whileActive(); } // If we've already set time from the GPS, no need to ask the GPS bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time + if (!gotTime && lookForTime()) + { // Note: we count on this && short-circuiting and not resetting the RTC time gotTime = true; shouldPublish = true; } bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) { // declare that we have location ASAP + if (gotLoc && !hasValidLocation) + { // declare that we have location ASAP LOG_DEBUG("hasValidLocation RISING EDGE\n"); hasValidLocation = true; shouldPublish = true; @@ -482,11 +542,14 @@ int32_t GPS::runOnce() // Once we get a location we no longer desperately want an update // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && gotTime) || tooLong) { + if ((gotLoc && gotTime) || tooLong) + { - if (tooLong) { + if (tooLong) + { // we didn't get a location during this ack window, therefore declare loss of lock - if (hasValidLocation) { + if (hasValidLocation) + { LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); } p = meshtastic_Position_init_default; @@ -501,10 +564,12 @@ int32_t GPS::runOnce() // If state has changed do a publish publishUpdate(); - if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) { + if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) + { fixeddelayCtr++; // LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr); - if (fixeddelayCtr >= 20) { + if (fixeddelayCtr >= 20) + { doGPSpowersave(false); forceWake(false); } @@ -516,11 +581,14 @@ int32_t GPS::runOnce() void GPS::forceWake(bool on) { - if (on) { + if (on) + { LOG_DEBUG("Allowing GPS lock\n"); // lastSleepStartMsec = 0; // Force an update ASAP wakeAllowed = true; - } else { + } + else + { wakeAllowed = false; // Note: if the gps was already awake, we DO NOT shut it down, because we want to allow it to complete its lock @@ -575,15 +643,19 @@ GnssModel_t GPS::probe() // Get version information _serial_gps->write("$PCAS06,0*1B\r\n"); uint32_t startTimeout = millis() + 500; - while (millis() < startTimeout) { - if (_serial_gps->available()) { + while (millis() < startTimeout) + { + if (_serial_gps->available()) + { String ver = _serial_gps->readStringUntil('\r'); // Get module info , If the correct header is returned, // it can be determined that it is the MTK chip int index = ver.indexOf("$"); - if (index != -1) { + if (index != -1) + { ver = ver.substring(index); - if (ver.startsWith("$GPTXT,01,01,02")) { + if (ver.startsWith("$GPTXT,01,01,02")) + { LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n"); return GNSS_MODEL_MTK; } @@ -594,7 +666,8 @@ GnssModel_t GPS::probe() uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30}; _serial_gps->write(cfg_rate, sizeof(cfg_rate)); // Check that the returned response class and message ID are correct - if (!getAck(buffer, 256, 0x06, 0x08)) { + if (!getAck(buffer, 256, 0x06, 0x08)) + { LOG_WARN("Failed to find UBlox & MTK GNSS Module\n"); return GNSS_MODEL_UNKONW; } @@ -604,20 +677,25 @@ GnssModel_t GPS::probe() _serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw)); uint16_t len = getAck(buffer, 256, 0x0A, 0x04); - if (len) { + if (len) + { uint16_t position = 0; - for (int i = 0; i < 30; i++) { + for (int i = 0; i < 30; i++) + { info.swVersion[i] = buffer[position]; position++; } - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) + { info.hwVersion[i] = buffer[position]; position++; } - while (len >= position + 30) { - for (int i = 0; i < 30; i++) { + while (len >= position + 30) + { + for (int i = 0; i < 30; i++) + { info.extension[info.extensionNo][i] = buffer[position]; position++; } @@ -630,24 +708,30 @@ GnssModel_t GPS::probe() LOG_DEBUG("Soft version: %s\n", info.swVersion); LOG_DEBUG("Hard version: %s\n", info.hwVersion); LOG_DEBUG("Extensions:%d\n", info.extensionNo); - for (int i = 0; i < info.extensionNo; i++) { + for (int i = 0; i < info.extensionNo; i++) + { LOG_DEBUG(" %s\n", info.extension[i]); } memset(buffer, 0, sizeof(buffer)); // tips: extensionNo field is 0 on some 6M GNSS modules - for (int i = 0; i < info.extensionNo; ++i) { - if (!strncmp(info.extension[i], "OD=", 3)) { + for (int i = 0; i < info.extensionNo; ++i) + { + if (!strncmp(info.extension[i], "OD=", 3)) + { strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer)); LOG_DEBUG("GetModel:%s\n", (char *)buffer); } } } - if (strlen((char *)buffer)) { + if (strlen((char *)buffer)) + { LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer); - } else { + } + else + { LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n"); } @@ -665,20 +749,24 @@ GPS *createGps() #if !HAS_GPS return nullptr; #else - if (config.position.gps_enabled) { + if (config.position.gps_enabled) + { #ifdef GPS_ALTITUDE_HAE LOG_DEBUG("Using HAE altitude model\n"); #else LOG_DEBUG("Using MSL altitude model\n"); #endif - if (GPS::_serial_gps) { + if (GPS::_serial_gps) + { // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // assume NMEA at 9600 baud. GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; } - } else { + } + else + { GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index c5cc85df7..6694393c7 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -18,162 +18,168 @@ */ class LockingModule : public Module { - public: - /*! - \brief Extended SPI-based module constructor. +public: + /*! + \brief Extended SPI-based module constructor. - \param cs Arduino pin to be used as chip select. + \param cs Arduino pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. + \param irq Arduino pin to be used as interrupt/GPIO. - \param rst Arduino pin to be used as hardware reset for the module. + \param rst Arduino pin to be used as hardware reset for the module. - \param gpio Arduino pin to be used as additional interrupt/GPIO. + \param gpio Arduino pin to be used as additional interrupt/GPIO. - \param spi SPI interface to be used, can also use software SPI implementations. + \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. - */ - LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi, - SPISettings spiSettings) - : Module(cs, irq, rst, gpio, spi, spiSettings) - { - } + \param spiSettings SPI interface settings. + */ + LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi, + SPISettings spiSettings) + : Module(cs, irq, rst, gpio, spi, spiSettings) + { + } - void SPIbeginTransaction() override; - void SPIendTransaction() override; + void SPIbeginTransaction() override; + void SPIendTransaction() override; }; class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread { - /// Used as our notification from the ISR - enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED }; + /// Used as our notification from the ISR + enum PendingISR + { + ISR_NONE = 0, + ISR_RX, + ISR_TX, + TRANSMIT_DELAY_COMPLETED + }; - /** - * Raw ISR handler that just calls our polymorphic method - */ - static void isrTxLevel0(), isrLevel0Common(PendingISR code); + /** + * Raw ISR handler that just calls our polymorphic method + */ + static void isrTxLevel0(), isrLevel0Common(PendingISR code); - /** - * Debugging counts - */ - uint32_t rxBad = 0, rxGood = 0, txGood = 0; + /** + * Debugging counts + */ + uint32_t rxBad = 0, rxGood = 0, txGood = 0; - MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); + MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); - protected: - /** - * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old - * loads 0x14) Note: do not use 0x34 - that is reserved for lorawan - * - * We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with - * this code for a long time. - */ - const uint8_t syncWord = 0x2b; +protected: + /** + * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old + * loads 0x14) Note: do not use 0x34 - that is reserved for lorawan + * + * We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with + * this code for a long time. + */ + const uint8_t syncWord = 0x2b; - float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset. + float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset. - LockingModule module; // The HW interface to the radio + LockingModule module; // The HW interface to the radio - /** - * provides lowest common denominator RadioLib API - */ - PhysicalLayer *iface; + /** + * provides lowest common denominator RadioLib API + */ + PhysicalLayer *iface; - /// are _trying_ to receive a packet currently (note - we might just be waiting for one) - bool isReceiving = false; + /// are _trying_ to receive a packet currently (note - we might just be waiting for one) + bool isReceiving = false; - public: - /** Our ISR code currently needs this to find our active instance - */ - static RadioLibInterface *instance; +public: + /** Our ISR code currently needs this to find our active instance + */ + static RadioLibInterface *instance; - /** - * Glue functions called from ISR land - */ - virtual void disableInterrupt() = 0; + /** + * Glue functions called from ISR land + */ + virtual void disableInterrupt() = 0; - /** - * Enable a particular ISR callback glue function - */ - virtual void enableInterrupt(void (*)()) = 0; + /** + * Enable a particular ISR callback glue function + */ + virtual void enableInterrupt(void (*)()) = 0; - public: - RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi, - PhysicalLayer *iface = NULL); +public: + RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi, + PhysicalLayer *iface = NULL); - virtual ErrorCode send(meshtastic_MeshPacket *p) override; + virtual ErrorCode send(meshtastic_MeshPacket *p) override; - /** - * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) - * - * This method must be used before putting the CPU into deep or light sleep. - */ - virtual bool canSleep() override; + /** + * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) + * + * This method must be used before putting the CPU into deep or light sleep. + */ + virtual bool canSleep() override; - /** - * Start waiting to receive a message - * - * External functions can call this method to wake the device from sleep. - */ - virtual void startReceive() = 0; + /** + * Start waiting to receive a message + * + * External functions can call this method to wake the device from sleep. + */ + virtual void startReceive() = 0; - /** can we detect a LoRa preamble on the current channel? */ - virtual bool isChannelActive() = 0; + /** can we detect a LoRa preamble on the current channel? */ + virtual bool isChannelActive() = 0; - /** are we actively receiving a packet (only called during receiving state) - * This method is only public to facilitate debugging. Do not call. - */ - virtual bool isActivelyReceiving() = 0; + /** are we actively receiving a packet (only called during receiving state) + * This method is only public to facilitate debugging. Do not call. + */ + virtual bool isActivelyReceiving() = 0; - /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ - virtual bool cancelSending(NodeNum from, PacketId id) override; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id) override; - private: - /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually - * doing the transmit */ - void setTransmitDelay(); +private: + /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually + * doing the transmit */ + void setTransmitDelay(); - /** random timer with certain min. and max. settings */ - void startTransmitTimer(bool withDelay = true); + /** random timer with certain min. and max. settings */ + void startTransmitTimer(bool withDelay = true); - /** timer scaled to SNR of to be flooded packet */ - void startTransmitTimerSNR(float snr); + /** timer scaled to SNR of to be flooded packet */ + void startTransmitTimerSNR(float snr); - void handleTransmitInterrupt(); - void handleReceiveInterrupt(); + void handleTransmitInterrupt(); + void handleReceiveInterrupt(); - static void timerCallback(void *p1, uint32_t p2); + static void timerCallback(void *p1, uint32_t p2); - virtual void onNotify(uint32_t notification) override; + virtual void onNotify(uint32_t notification) override; - /** start an immediate transmit - * This method is virtual so subclasses can hook as needed, subclasses should not call directly - */ - virtual void startSend(meshtastic_MeshPacket *txp); + /** start an immediate transmit + * This method is virtual so subclasses can hook as needed, subclasses should not call directly + */ + virtual void startSend(meshtastic_MeshPacket *txp); - meshtastic_QueueStatus getQueueStatus(); + meshtastic_QueueStatus getQueueStatus(); - protected: - /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ - virtual void configHardwareForSend() {} +protected: + /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ + virtual void configHardwareForSend() {} - /** Could we send right now (i.e. either not actively receiving or transmitting)? */ - virtual bool canSendImmediately(); + /** Could we send right now (i.e. either not actively receiving or transmitting)? */ + virtual bool canSendImmediately(); - /** - * Raw ISR handler that just calls our polymorphic method - */ - static void isrRxLevel0(); + /** + * Raw ISR handler that just calls our polymorphic method + */ + static void isrRxLevel0(); - /** - * If a send was in progress finish it and return the buffer to the pool */ - void completeSending(); + /** + * If a send was in progress finish it and return the buffer to the pool */ + void completeSending(); - /** - * Add SNR data to received messages - */ - virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; + /** + * Add SNR data to received messages + */ + virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - virtual void setStandby() = 0; + virtual void setStandby() = 0; }; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 8000926f3..0e8481a8b 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -12,11 +12,13 @@ */ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) { - if (p->want_ack) { + if (p->want_ack) + { // If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our // message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop // counts and we want this message to get through the whole mesh, so use the default. - if (p->hop_limit == 0) { + if (p->hop_limit == 0) + { p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit; } @@ -30,7 +32,8 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { // Note: do not use getFrom() here, because we want to ignore messages sent from phone - if (p->from == getNodeNum()) { + if (p->from == getNodeNum()) + { printPacket("Rx someone rebroadcasting for us", p); // We are seeing someone rebroadcast one of our broadcast attempts. @@ -41,14 +44,17 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // from the intended recipient. auto key = GlobalPacketId(getFrom(p), p->id); auto old = findPendingPacket(key); - if (old) { + if (old) + { LOG_DEBUG("generating implicit ack\n"); // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be // marked as wantAck sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, old->packet->channel); stopRetransmission(key); - } else { + } + else + { LOG_DEBUG("didn't find pending packet\n"); } } @@ -57,7 +63,8 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) * 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()) { + 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 LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n"); meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); @@ -84,8 +91,10 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas { NodeNum ourNode = getNodeNum(); - if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability) - if (p->want_ack) { + if (p->to == ourNode) + { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability) + if (p->want_ack) + { 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) @@ -102,11 +111,15 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records - if (ackId || nakId) { - if (ackId) { + if (ackId || nakId) + { + if (ackId) + { LOG_DEBUG("Received an ack for 0x%x, stopping retransmissions\n", ackId); stopRetransmission(p->to, ackId); - } else { + } + else + { LOG_DEBUG("Received a nak for 0x%x, stopping retransmissions\n", nakId); stopRetransmission(p->to, nakId); } @@ -128,9 +141,11 @@ PendingPacket::PendingPacket(meshtastic_MeshPacket *p) PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key) { auto old = pending.find(key); // If we have an old record, someone messed up because id got reused - if (old != pending.end()) { + if (old != pending.end()) + { return &old->second; - } else + } + else return NULL; } /** @@ -145,12 +160,14 @@ bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id) bool ReliableRouter::stopRetransmission(GlobalPacketId key) { auto old = findPendingPacket(key); - if (old) { + if (old) + { auto numErased = pending.erase(key); assert(numErased == 1); cancelSending(getFrom(old->packet), old->packet->id); return true; - } else + } + else return false; } @@ -180,22 +197,27 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, we should use a better datastructure rather than walking through this map. // for(auto el: pending) { - for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) { + for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) + { ++nextIt; // we use this odd pattern because we might be deleting it... auto &p = it->second; bool stillValid = true; // assume we'll keep this record around // FIXME, handle 51 day rolloever here!!! - if (p.nextTxMsec <= now) { - if (p.numRetransmissions == 0) { + if (p.nextTxMsec <= now) + { + if (p.numRetransmissions == 0) + { LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived stopRetransmission(it->first); stillValid = false; // just deleted it - } else { + } + else + { LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); @@ -209,7 +231,8 @@ int32_t ReliableRouter::doRetransmissions() } } - if (stillValid) { + if (stillValid) + { // Update our desired sleep delay int32_t t = p.nextTxMsec - now; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 0cb7ee8be..6540d2652 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -8,7 +8,8 @@ #include "main.h" #include "mesh-pb-constants.h" #include "modules/RoutingModule.h" -extern "C" { +extern "C" +{ #include "mesh/compression/unishox2.h" } @@ -25,13 +26,13 @@ extern "C" { * **/ -#define MAX_RX_FROMRADIO \ +#define MAX_RX_FROMRADIO \ 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big // I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX // And every TX packet might have a retransmission packet or an ack alive at any moment -#define MAX_PACKETS \ - (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \ +#define MAX_PACKETS \ + (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \ 2) // max number of packets which can be in flight (either queued from reception or queued for sending) // static MemoryPool staticPool(MAX_PACKETS); @@ -64,7 +65,8 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA int32_t Router::runOnce() { meshtastic_MeshPacket *mp; - while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) { + while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) + { // printPacket("handle fromRadioQ", mp); perhapsHandleReceived(mp); } @@ -79,11 +81,14 @@ int32_t Router::runOnce() */ void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p) { - if (fromRadioQueue.enqueue(p, 0)) { // NOWAIT - fixme, if queue is full, delete older messages + if (fromRadioQueue.enqueue(p, 0)) + { // NOWAIT - fixme, if queue is full, delete older messages // Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME setReceivedMessage(); - } else { + } + else + { printPacket("BUG! fromRadioQueue is full! Discarding!", p); packetPool.release(p); } @@ -98,7 +103,8 @@ PacketId generatePacketId() uint32_t numPacketId = UINT32_MAX; - if (!didInit) { + if (!didInit) + { didInit = true; // pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0) @@ -157,19 +163,25 @@ meshtastic_QueueStatus Router::getQueueStatus() ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src) { // No need to deliver externally if the destination is the local node - if (p->to == nodeDB.getNodeNum()) { + if (p->to == nodeDB.getNodeNum()) + { printPacket("Enqueued local", p); enqueueReceivedMessage(p); return ERRNO_OK; - } else if (!iface) { + } + else if (!iface) + { // We must be sending to remote nodes also, fail if no interface found abortSendAndNak(meshtastic_Routing_Error_NO_INTERFACE, p); return ERRNO_NO_INTERFACES; - } else { + } + else + { // If we are sending a broadcast, we also treat it as if we just received it ourself // this allows local apps (and PCs) to see broadcasts sourced locally - if (p->to == NODENUM_BROADCAST) { + if (p->to == NODENUM_BROADCAST) + { handleReceived(p, src); } @@ -192,22 +204,35 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes) */ ErrorCode Router::send(meshtastic_MeshPacket *p) { - if (p->to == nodeDB.getNodeNum()) { + // Skip the normal ceremony for repeaters + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) + { + assert(iface); + return iface->send(p); + } + + if (p->to == nodeDB.getNodeNum()) + { LOG_ERROR("BUG! send() called with packet destined for local node!\n"); packetPool.release(p); return meshtastic_Routing_Error_BAD_REQUEST; } // should have already been handled by sendLocal // Abort sending if we are violating the duty cycle - if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) + { float hourlyTxPercent = airTime->utilizationTXPercent(); - if (hourlyTxPercent > myRegion->dutyCycle) { + if (hourlyTxPercent > myRegion->dutyCycle) + { uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT; - if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh + if (getFrom(p) == nodeDB.getNodeNum()) + { // only send NAK to API, not to the mesh abortSendAndNak(err, p); - } else { + } + else + { packetPool.release(p); } return err; @@ -232,13 +257,15 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now // If the packet is not yet encrypted, do so now - if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) + { ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it bool shouldActuallyEncrypt = true; #if HAS_WIFI || HAS_ETHERNET - if (moduleConfig.mqtt.enabled) { + if (moduleConfig.mqtt.enabled) + { // check if we should send decrypted packets to mqtt // truth table: @@ -251,7 +278,8 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) * => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE */ - if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) { + if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) + { shouldActuallyEncrypt = false; } @@ -264,13 +292,15 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) #endif auto encodeResult = perhapsEncode(p); - if (encodeResult != meshtastic_Routing_Error_NONE) { + if (encodeResult != meshtastic_Routing_Error_NONE) + { abortSendAndNak(encodeResult, p); return encodeResult; // FIXME - this isn't a valid ErrorCode } #if HAS_WIFI || HAS_ETHERNET - if (moduleConfig.mqtt.enabled) { + if (moduleConfig.mqtt.enabled) + { // the packet is now encrypted. // check if we should send encrypted packets to mqtt if (mqtt && shouldActuallyEncrypt) @@ -309,9 +339,11 @@ bool perhapsDecode(meshtastic_MeshPacket *p) // assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // Try to find a channel that works with this hash - for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { + for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) + { // Try to use this hash/channel pair - if (channels.decryptForHash(chIndex, p->channel)) { + if (channels.decryptForHash(chIndex, p->channel)) + { // Try to decrypt the packet if we can size_t rawSize = p->encrypted.size; assert(rawSize <= sizeof(bytes)); @@ -323,17 +355,23 @@ bool perhapsDecode(meshtastic_MeshPacket *p) // Take those raw bytes and convert them back into a well structured protobuf we can understand memset(&p->decoded, 0, sizeof(p->decoded)); - if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) { + if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) + { LOG_ERROR("Invalid protobufs in received mesh packet (bad psk?)!\n"); - } else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) { + } + else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) + { LOG_ERROR("Invalid portnum (bad psk?)!\n"); - } else { + } + else + { // parsing was successful p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded p->channel = chIndex; // change to store the index instead of the hash // Decompress if needed. jm - if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) { + if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) + { // Decompress the payload char compressed_in[meshtastic_Constants_DATA_PAYLOAD_LEN] = {}; char decompressed_out[meshtastic_Constants_DATA_PAYLOAD_LEN] = {}; @@ -366,13 +404,14 @@ bool perhapsDecode(meshtastic_MeshPacket *p) meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) { // If the packet is not yet encrypted, do so now - if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) + { size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded); // Only allow encryption on the text message app. // TODO: Allow modules to opt into compression. - if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) { + if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) + { char original_payload[meshtastic_Constants_DATA_PAYLOAD_LEN]; memcpy(original_payload, p->decoded.payload.bytes, p->decoded.payload.size); @@ -387,14 +426,17 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes); // If the compressed length is greater than or equal to the original size, don't use the compressed form - if (compressed_len >= p->decoded.payload.size) { + if (compressed_len >= p->decoded.payload.size) + { LOG_DEBUG("Not using compressing message.\n"); // Set the uncompressed payload varient anyway. Shouldn't hurt? // p->decoded.which_payloadVariant = Data_payload_tag; // Otherwise we use the compressor - } else { + } + else + { LOG_DEBUG("Using compressed message.\n"); // Copy the compressed data into the meshpacket @@ -445,7 +487,8 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) // Take those raw bytes and convert them back into a well structured protobuf we can understand bool decoded = perhapsDecode(p); - if (decoded) { + if (decoded) + { // parsing was successful, queue for our recipient if (src == RX_SRC_LOCAL) printPacket("handleReceived(LOCAL)", p); @@ -453,7 +496,9 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) printPacket("handleReceived(USER)", p); else printPacket("handleReceived(REMOTE)", p); - } else { + } + else + { printPacket("packet decoding failed (no PSK?)", p); } @@ -468,7 +513,8 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) if (ignore) LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from); - else if (ignore |= shouldFilterReceived(p)) { + else if (ignore |= shouldFilterReceived(p)) + { LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from); } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 8e116dca0..8ad67bc0e 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -13,122 +13,122 @@ */ class Router : protected concurrency::OSThread { - private: - /// Packets which have just arrived from the radio, ready to be processed by this service and possibly - /// forwarded to the phone. - PointerQueue fromRadioQueue; +private: + /// Packets which have just arrived from the radio, ready to be processed by this service and possibly + /// forwarded to the phone. + PointerQueue fromRadioQueue; - protected: - RadioInterface *iface = NULL; +protected: + RadioInterface *iface = NULL; - public: - /** - * Constructor - * - */ - Router(); +public: + /** + * Constructor + * + */ + Router(); - /** - * Currently we only allow one interface, that may change in the future - */ - void addInterface(RadioInterface *_iface) { iface = _iface; } + /** + * Currently we only allow one interface, that may change in the future + */ + void addInterface(RadioInterface *_iface) { iface = _iface; } - /** - * do idle processing - * Mostly looking in our incoming rxPacket queue and calling handleReceived. - */ - virtual int32_t runOnce() override; + /** + * do idle processing + * Mostly looking in our incoming rxPacket queue and calling handleReceived. + */ + virtual int32_t runOnce() override; - /** - * Works like send, but if we are sending to the local node, we directly put the message in the receive queue. - * This is the primary method used for sending packets, because it handles both the remote and local cases. - * - * NOTE: This method will free the provided packet (even if we return an error code) - */ - ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); + /** + * Works like send, but if we are sending to the local node, we directly put the message in the receive queue. + * This is the primary method used for sending packets, because it handles both the remote and local cases. + * + * NOTE: This method will free the provided packet (even if we return an error code) + */ + ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); - /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ - bool cancelSending(NodeNum from, PacketId id); + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + bool cancelSending(NodeNum from, PacketId id); - /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. - * The returned packet is guaranteed to have a unique packet ID already assigned - */ - meshtastic_MeshPacket *allocForSending(); + /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. + * The returned packet is guaranteed to have a unique packet ID already assigned + */ + meshtastic_MeshPacket *allocForSending(); - /** Return Underlying interface's TX queue status */ - meshtastic_QueueStatus getQueueStatus(); + /** Return Underlying interface's TX queue status */ + meshtastic_QueueStatus getQueueStatus(); - /** - * @return our local nodenum */ - NodeNum getNodeNum(); + /** + * @return our local nodenum */ + NodeNum getNodeNum(); - /** Wake up the router thread ASAP, because we just queued a message for it. - * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' - */ - void setReceivedMessage(); + /** Wake up the router thread ASAP, because we just queued a message for it. + * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' + */ + void setReceivedMessage(); - /** - * RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for - * freeing the packet - */ - void enqueueReceivedMessage(meshtastic_MeshPacket *p); + /** + * RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for + * freeing the packet + */ + void enqueueReceivedMessage(meshtastic_MeshPacket *p); - protected: - friend class RoutingModule; + /** + * Send a packet on a suitable interface. This routine will + * later free() the packet to pool. This routine is not allowed to stall. + * If the txmit queue is full it might return an error + * + * NOTE: This method will free the provided packet (even if we return an error code) + */ + virtual ErrorCode send(meshtastic_MeshPacket *p); - /** - * Send a packet on a suitable interface. This routine will - * later free() the packet to pool. This routine is not allowed to stall. - * If the txmit queue is full it might return an error - * - * NOTE: This method will free the provided packet (even if we return an error code) - */ - virtual ErrorCode send(meshtastic_MeshPacket *p); +protected: + friend class RoutingModule; - /** - * Should this incoming filter be dropped? - * - * FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic - * - * Called immedately on receiption, before any further processing. - * @return true to abandon the packet - */ - virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; } + /** + * Should this incoming filter be dropped? + * + * FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic + * + * Called immedately on receiption, before any further processing. + * @return true to abandon the packet + */ + virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; } - /** - * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to - * update routing tables etc... based on what we overhear (even for messages not destined to our node) - */ - virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c); + /** + * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to + * update routing tables etc... based on what we overhear (even for messages not destined to our node) + */ + virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c); - /** - * Send an ack or a nak packet back towards whoever sent idFrom - */ - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + /** + * Send an ack or a nak packet back towards whoever sent idFrom + */ + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); - private: - /** - * Called from loop() - * Handle any packet that is received by an interface on this node. - * Note: some packets may merely being passed through this node and will be forwarded elsewhere. - * - * Note: this packet will never be called for messages sent/generated by this node. - * Note: this method will free the provided packet. - */ - void perhapsHandleReceived(meshtastic_MeshPacket *p); +private: + /** + * Called from loop() + * Handle any packet that is received by an interface on this node. + * Note: some packets may merely being passed through this node and will be forwarded elsewhere. + * + * Note: this packet will never be called for messages sent/generated by this node. + * Note: this method will free the provided packet. + */ + void perhapsHandleReceived(meshtastic_MeshPacket *p); - /** - * Called from perhapsHandleReceived() - allows subclass message delivery behavior. - * Handle any packet that is received by an interface on this node. - * Note: some packets may merely being passed through this node and will be forwarded elsewhere. - * - * Note: this packet will never be called for messages sent/generated by this node. - * Note: this method will free the provided packet. - */ - void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); + /** + * Called from perhapsHandleReceived() - allows subclass message delivery behavior. + * Handle any packet that is received by an interface on this node. + * Note: some packets may merely being passed through this node and will be forwarded elsewhere. + * + * Note: this packet will never be called for messages sent/generated by this node. + * Note: this method will free the provided packet. + */ + void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); - /** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */ - void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p); + /** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */ + void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p); }; /** FIXME - move this into a mesh packet class diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp new file mode 100644 index 000000000..06147f9f2 --- /dev/null +++ b/src/modules/RepeaterModule.cpp @@ -0,0 +1,27 @@ +#include "RepeaterModule.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" + +RepeaterModule *repeaterModule; + +bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *r) +{ + printPacket("Repeater rebroadcasting", &mp); + meshtastic_MeshPacket *p = const_cast(&mp); + router->send(p); + return true; +} + +meshtastic_MeshPacket *RepeaterModule::allocReply() +{ + return NULL; +} + +RepeaterModule::RepeaterModule() : ProtobufModule("repeater", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) +{ + isPromiscuous = true; + encryptedOk = true; +} diff --git a/src/modules/RepeaterModule.h b/src/modules/RepeaterModule.h new file mode 100644 index 000000000..d24bbb296 --- /dev/null +++ b/src/modules/RepeaterModule.h @@ -0,0 +1,31 @@ +#pragma once +#include "Channels.h" +#include "ProtobufModule.h" + +/** + * Routing module for router control messages + */ +class RepeaterModule : public ProtobufModule +{ +public: + /** Constructor + * name is for debugging output + */ + RepeaterModule(); + +protected: + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override; + + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked + * so that subclasses can (optionally) send a response back to the original sender. */ + virtual meshtastic_MeshPacket *allocReply() override; + + /// Override wantPacket to say we want to see all packets, not just those for our port number + virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } +}; + +extern RepeaterModule *repeaterModule; From e8908784f9a1425b10a264e8437545670c25ab2c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 06:39:14 -0600 Subject: [PATCH 07/27] Format --- src/gps/GPS.cpp | 233 +++++++++++----------------------- src/mesh/RadioLibInterface.h | 236 +++++++++++++++++------------------ src/mesh/ReliableRouter.cpp | 63 +++------- src/mesh/Router.cpp | 113 ++++++----------- src/mesh/Router.h | 194 ++++++++++++++-------------- src/modules/RepeaterModule.h | 30 ++--- 6 files changed, 357 insertions(+), 512 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 468f8e9f4..1b7c8511f 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -29,38 +29,29 @@ bool GPS::getACK(uint8_t c, uint8_t i) uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned long startTime = millis(); - for (int j = 2; j < 6; j++) - { + for (int j = 2; j < 6; j++) { buf[8] += buf[j]; buf[9] += buf[8]; } - for (int j = 0; j < 2; j++) - { + for (int j = 0; j < 2; j++) { buf[6 + j] = ackP[j]; buf[8] += buf[6 + j]; buf[9] += buf[8]; } - while (1) - { - if (ack > 9) - { + while (1) { + if (ack > 9) { return true; } - if (millis() - startTime > 1000) - { + if (millis() - startTime > 1000) { return false; } - if (_serial_gps->available()) - { + if (_serial_gps->available()) { b = _serial_gps->read(); - if (b == buf[ack]) - { + if (b == buf[ack]) { ack++; - } - else - { + } else { ack = 0; } } @@ -82,50 +73,37 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t uint32_t startTime = millis(); uint16_t needRead; - while (millis() - startTime < 800) - { - while (_serial_gps->available()) - { + while (millis() - startTime < 800) { + while (_serial_gps->available()) { int c = _serial_gps->read(); - switch (ubxFrameCounter) - { + switch (ubxFrameCounter) { case 0: // ubxFrame 'μ' - if (c == 0xB5) - { + if (c == 0xB5) { ubxFrameCounter++; } break; case 1: // ubxFrame 'b' - if (c == 0x62) - { + if (c == 0x62) { ubxFrameCounter++; - } - else - { + } else { ubxFrameCounter = 0; } break; case 2: // Class - if (c == requestedClass) - { + if (c == requestedClass) { ubxFrameCounter++; - } - else - { + } else { ubxFrameCounter = 0; } break; case 3: // Message ID - if (c == requestedID) - { + if (c == requestedID) { ubxFrameCounter++; - } - else - { + } else { ubxFrameCounter = 0; } break; @@ -141,17 +119,13 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t break; case 6: // Check for buffer overflow - if (needRead >= size) - { + if (needRead >= size) { ubxFrameCounter = 0; break; } - if (_serial_gps->readBytes(buffer, needRead) != needRead) - { + if (_serial_gps->readBytes(buffer, needRead) != needRead) { ubxFrameCounter = 0; - } - else - { + } else { // return payload lenght return needRead; } @@ -167,8 +141,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t bool GPS::setupGPS() { - if (_serial_gps && !didSerialInit) - { + if (_serial_gps && !didSerialInit) { didSerialInit = true; #ifdef ARCH_ESP32 @@ -200,8 +173,7 @@ bool GPS::setupGPS() */ gnssModel = probe(); - if (gnssModel == GNSS_MODEL_MTK) - { + if (gnssModel == GNSS_MODEL_MTK) { /* * t-beam-s3-core uses the same L76K GNSS module as t-echo. * Unlike t-echo, L76K uses 9600 baud rate for communication by default. @@ -218,9 +190,7 @@ bool GPS::setupGPS() // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g _serial_gps->write("$PCAS11,3*1E\r\n"); delay(250); - } - else if (gnssModel == GNSS_MODEL_UBLOX) - { + } else if (gnssModel == GNSS_MODEL_UBLOX) { /* tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after @@ -242,8 +212,7 @@ bool GPS::setupGPS() byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A}; _serial_gps->write(_message_GGL, sizeof(_message_GGL)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GGL.\n"); return true; } @@ -252,8 +221,7 @@ bool GPS::setupGPS() byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41}; _serial_gps->write(_message_GSA, sizeof(_message_GSA)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GSA.\n"); return true; } @@ -262,8 +230,7 @@ bool GPS::setupGPS() byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48}; _serial_gps->write(_message_GSV, sizeof(_message_GSV)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GSV.\n"); return true; } @@ -272,8 +239,7 @@ bool GPS::setupGPS() byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56}; _serial_gps->write(_message_VTG, sizeof(_message_VTG)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA VTG.\n"); return true; } @@ -282,8 +248,7 @@ bool GPS::setupGPS() byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54}; _serial_gps->write(_message_RMC, sizeof(_message_RMC)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA RMC.\n"); return true; } @@ -292,8 +257,7 @@ bool GPS::setupGPS() byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38}; _serial_gps->write(_message_GGA, sizeof(_message_GGA)); - if (!getACK(0x06, 0x01)) - { + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA GGA.\n"); } } @@ -311,8 +275,7 @@ bool GPS::setup() #endif #ifdef HAS_PMU - if (config.position.gps_enabled) - { + if (config.position.gps_enabled) { setGPSPower(true); } #endif @@ -326,15 +289,13 @@ bool GPS::setup() setAwake(true); // Wake GPS power before doing any init bool ok = setupGPS(); - if (ok) - { + if (ok) { notifySleepObserver.observe(¬ifySleep); notifyDeepSleepObserver.observe(¬ifyDeepSleep); notifyGPSSleepObserver.observe(¬ifyGPSSleep); } - if (config.position.gps_enabled == false && config.position.fixed_position == false) - { + if (config.position.gps_enabled == false && config.position.fixed_position == false) { setAwake(false); doGPSpowersave(false); } @@ -383,8 +344,7 @@ void GPS::sleep() /// Record that we have a GPS void GPS::setConnected() { - if (!hasGPS) - { + if (!hasGPS) { hasGPS = true; shouldPublish = true; } @@ -392,8 +352,7 @@ void GPS::setConnected() void GPS::setNumSatellites(uint8_t n) { - if (n != numSatellites) - { + if (n != numSatellites) { numSatellites = n; shouldPublish = true; } @@ -406,22 +365,17 @@ void GPS::setNumSatellites(uint8_t n) */ void GPS::setAwake(bool on) { - if (!wakeAllowed && on) - { + if (!wakeAllowed && on) { LOG_WARN("Inhibiting because !wakeAllowed\n"); on = false; } - if (isAwake != on) - { + if (isAwake != on) { LOG_DEBUG("WANT GPS=%d\n", on); - if (on) - { + if (on) { lastWakeStartMsec = millis(); wake(); - } - else - { + } else { lastSleepStartMsec = millis(); sleep(); } @@ -460,8 +414,7 @@ uint32_t GPS::getSleepTime() const void GPS::publishUpdate() { - if (shouldPublish) - { + if (shouldPublish) { shouldPublish = false; // In debug logs, identify position by @timestamp:stage (stage 2 = publish) @@ -479,18 +432,13 @@ int32_t GPS::runOnce() if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) disable(); - if (whileIdle()) - { + if (whileIdle()) { // if we have received valid NMEA claim we are connected setConnected(); - } - else - { - if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) - { + } else { + if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) { // reset the GPS on next bootup - if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) - { + if (devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) { LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); devicestate.did_gps_reset = false; nodeDB.saveDeviceStateToDisk(); @@ -503,33 +451,28 @@ int32_t GPS::runOnce() uint32_t now = millis(); auto sleepTime = getSleepTime(); - if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) - { + if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) { // We now want to be awake - so wake up the GPS setAwake(true); } // While we are awake - if (isAwake) - { + if (isAwake) { // LOG_DEBUG("looking for location\n"); - if ((now - lastWhileActiveMsec) > 5000) - { + if ((now - lastWhileActiveMsec) > 5000) { lastWhileActiveMsec = now; whileActive(); } // If we've already set time from the GPS, no need to ask the GPS bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) - { // Note: we count on this && short-circuiting and not resetting the RTC time + if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time gotTime = true; shouldPublish = true; } bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) - { // declare that we have location ASAP + if (gotLoc && !hasValidLocation) { // declare that we have location ASAP LOG_DEBUG("hasValidLocation RISING EDGE\n"); hasValidLocation = true; shouldPublish = true; @@ -542,14 +485,11 @@ int32_t GPS::runOnce() // Once we get a location we no longer desperately want an update // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && gotTime) || tooLong) - { + if ((gotLoc && gotTime) || tooLong) { - if (tooLong) - { + if (tooLong) { // we didn't get a location during this ack window, therefore declare loss of lock - if (hasValidLocation) - { + if (hasValidLocation) { LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); } p = meshtastic_Position_init_default; @@ -564,12 +504,10 @@ int32_t GPS::runOnce() // If state has changed do a publish publishUpdate(); - if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) - { + if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) { fixeddelayCtr++; // LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr); - if (fixeddelayCtr >= 20) - { + if (fixeddelayCtr >= 20) { doGPSpowersave(false); forceWake(false); } @@ -581,14 +519,11 @@ int32_t GPS::runOnce() void GPS::forceWake(bool on) { - if (on) - { + if (on) { LOG_DEBUG("Allowing GPS lock\n"); // lastSleepStartMsec = 0; // Force an update ASAP wakeAllowed = true; - } - else - { + } else { wakeAllowed = false; // Note: if the gps was already awake, we DO NOT shut it down, because we want to allow it to complete its lock @@ -643,19 +578,15 @@ GnssModel_t GPS::probe() // Get version information _serial_gps->write("$PCAS06,0*1B\r\n"); uint32_t startTimeout = millis() + 500; - while (millis() < startTimeout) - { - if (_serial_gps->available()) - { + while (millis() < startTimeout) { + if (_serial_gps->available()) { String ver = _serial_gps->readStringUntil('\r'); // Get module info , If the correct header is returned, // it can be determined that it is the MTK chip int index = ver.indexOf("$"); - if (index != -1) - { + if (index != -1) { ver = ver.substring(index); - if (ver.startsWith("$GPTXT,01,01,02")) - { + if (ver.startsWith("$GPTXT,01,01,02")) { LOG_INFO("L76K GNSS init succeeded, using L76K GNSS Module\n"); return GNSS_MODEL_MTK; } @@ -666,8 +597,7 @@ GnssModel_t GPS::probe() uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30}; _serial_gps->write(cfg_rate, sizeof(cfg_rate)); // Check that the returned response class and message ID are correct - if (!getAck(buffer, 256, 0x06, 0x08)) - { + if (!getAck(buffer, 256, 0x06, 0x08)) { LOG_WARN("Failed to find UBlox & MTK GNSS Module\n"); return GNSS_MODEL_UNKONW; } @@ -677,25 +607,20 @@ GnssModel_t GPS::probe() _serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw)); uint16_t len = getAck(buffer, 256, 0x0A, 0x04); - if (len) - { + if (len) { uint16_t position = 0; - for (int i = 0; i < 30; i++) - { + for (int i = 0; i < 30; i++) { info.swVersion[i] = buffer[position]; position++; } - for (int i = 0; i < 10; i++) - { + for (int i = 0; i < 10; i++) { info.hwVersion[i] = buffer[position]; position++; } - while (len >= position + 30) - { - for (int i = 0; i < 30; i++) - { + while (len >= position + 30) { + for (int i = 0; i < 30; i++) { info.extension[info.extensionNo][i] = buffer[position]; position++; } @@ -708,30 +633,24 @@ GnssModel_t GPS::probe() LOG_DEBUG("Soft version: %s\n", info.swVersion); LOG_DEBUG("Hard version: %s\n", info.hwVersion); LOG_DEBUG("Extensions:%d\n", info.extensionNo); - for (int i = 0; i < info.extensionNo; i++) - { + for (int i = 0; i < info.extensionNo; i++) { LOG_DEBUG(" %s\n", info.extension[i]); } memset(buffer, 0, sizeof(buffer)); // tips: extensionNo field is 0 on some 6M GNSS modules - for (int i = 0; i < info.extensionNo; ++i) - { - if (!strncmp(info.extension[i], "OD=", 3)) - { + for (int i = 0; i < info.extensionNo; ++i) { + if (!strncmp(info.extension[i], "OD=", 3)) { strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer)); LOG_DEBUG("GetModel:%s\n", (char *)buffer); } } } - if (strlen((char *)buffer)) - { + if (strlen((char *)buffer)) { LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer); - } - else - { + } else { LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n"); } @@ -749,24 +668,20 @@ GPS *createGps() #if !HAS_GPS return nullptr; #else - if (config.position.gps_enabled) - { + if (config.position.gps_enabled) { #ifdef GPS_ALTITUDE_HAE LOG_DEBUG("Using HAE altitude model\n"); #else LOG_DEBUG("Using MSL altitude model\n"); #endif - if (GPS::_serial_gps) - { + if (GPS::_serial_gps) { // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // assume NMEA at 9600 baud. GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; } - } - else - { + } else { GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 6694393c7..c5cc85df7 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -18,168 +18,162 @@ */ class LockingModule : public Module { -public: - /*! - \brief Extended SPI-based module constructor. + public: + /*! + \brief Extended SPI-based module constructor. - \param cs Arduino pin to be used as chip select. + \param cs Arduino pin to be used as chip select. - \param irq Arduino pin to be used as interrupt/GPIO. + \param irq Arduino pin to be used as interrupt/GPIO. - \param rst Arduino pin to be used as hardware reset for the module. + \param rst Arduino pin to be used as hardware reset for the module. - \param gpio Arduino pin to be used as additional interrupt/GPIO. + \param gpio Arduino pin to be used as additional interrupt/GPIO. - \param spi SPI interface to be used, can also use software SPI implementations. + \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. - */ - LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi, - SPISettings spiSettings) - : Module(cs, irq, rst, gpio, spi, spiSettings) - { - } + \param spiSettings SPI interface settings. + */ + LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi, + SPISettings spiSettings) + : Module(cs, irq, rst, gpio, spi, spiSettings) + { + } - void SPIbeginTransaction() override; - void SPIendTransaction() override; + void SPIbeginTransaction() override; + void SPIendTransaction() override; }; class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread { - /// Used as our notification from the ISR - enum PendingISR - { - ISR_NONE = 0, - ISR_RX, - ISR_TX, - TRANSMIT_DELAY_COMPLETED - }; + /// Used as our notification from the ISR + enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED }; - /** - * Raw ISR handler that just calls our polymorphic method - */ - static void isrTxLevel0(), isrLevel0Common(PendingISR code); + /** + * Raw ISR handler that just calls our polymorphic method + */ + static void isrTxLevel0(), isrLevel0Common(PendingISR code); - /** - * Debugging counts - */ - uint32_t rxBad = 0, rxGood = 0, txGood = 0; + /** + * Debugging counts + */ + uint32_t rxBad = 0, rxGood = 0, txGood = 0; - MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); + MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); -protected: - /** - * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old - * loads 0x14) Note: do not use 0x34 - that is reserved for lorawan - * - * We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with - * this code for a long time. - */ - const uint8_t syncWord = 0x2b; + protected: + /** + * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old + * loads 0x14) Note: do not use 0x34 - that is reserved for lorawan + * + * We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with + * this code for a long time. + */ + const uint8_t syncWord = 0x2b; - float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset. + float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset. - LockingModule module; // The HW interface to the radio + LockingModule module; // The HW interface to the radio - /** - * provides lowest common denominator RadioLib API - */ - PhysicalLayer *iface; + /** + * provides lowest common denominator RadioLib API + */ + PhysicalLayer *iface; - /// are _trying_ to receive a packet currently (note - we might just be waiting for one) - bool isReceiving = false; + /// are _trying_ to receive a packet currently (note - we might just be waiting for one) + bool isReceiving = false; -public: - /** Our ISR code currently needs this to find our active instance - */ - static RadioLibInterface *instance; + public: + /** Our ISR code currently needs this to find our active instance + */ + static RadioLibInterface *instance; - /** - * Glue functions called from ISR land - */ - virtual void disableInterrupt() = 0; + /** + * Glue functions called from ISR land + */ + virtual void disableInterrupt() = 0; - /** - * Enable a particular ISR callback glue function - */ - virtual void enableInterrupt(void (*)()) = 0; + /** + * Enable a particular ISR callback glue function + */ + virtual void enableInterrupt(void (*)()) = 0; -public: - RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi, - PhysicalLayer *iface = NULL); + public: + RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi, + PhysicalLayer *iface = NULL); - virtual ErrorCode send(meshtastic_MeshPacket *p) override; + virtual ErrorCode send(meshtastic_MeshPacket *p) override; - /** - * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) - * - * This method must be used before putting the CPU into deep or light sleep. - */ - virtual bool canSleep() override; + /** + * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) + * + * This method must be used before putting the CPU into deep or light sleep. + */ + virtual bool canSleep() override; - /** - * Start waiting to receive a message - * - * External functions can call this method to wake the device from sleep. - */ - virtual void startReceive() = 0; + /** + * Start waiting to receive a message + * + * External functions can call this method to wake the device from sleep. + */ + virtual void startReceive() = 0; - /** can we detect a LoRa preamble on the current channel? */ - virtual bool isChannelActive() = 0; + /** can we detect a LoRa preamble on the current channel? */ + virtual bool isChannelActive() = 0; - /** are we actively receiving a packet (only called during receiving state) - * This method is only public to facilitate debugging. Do not call. - */ - virtual bool isActivelyReceiving() = 0; + /** are we actively receiving a packet (only called during receiving state) + * This method is only public to facilitate debugging. Do not call. + */ + virtual bool isActivelyReceiving() = 0; - /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ - virtual bool cancelSending(NodeNum from, PacketId id) override; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id) override; -private: - /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually - * doing the transmit */ - void setTransmitDelay(); + private: + /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually + * doing the transmit */ + void setTransmitDelay(); - /** random timer with certain min. and max. settings */ - void startTransmitTimer(bool withDelay = true); + /** random timer with certain min. and max. settings */ + void startTransmitTimer(bool withDelay = true); - /** timer scaled to SNR of to be flooded packet */ - void startTransmitTimerSNR(float snr); + /** timer scaled to SNR of to be flooded packet */ + void startTransmitTimerSNR(float snr); - void handleTransmitInterrupt(); - void handleReceiveInterrupt(); + void handleTransmitInterrupt(); + void handleReceiveInterrupt(); - static void timerCallback(void *p1, uint32_t p2); + static void timerCallback(void *p1, uint32_t p2); - virtual void onNotify(uint32_t notification) override; + virtual void onNotify(uint32_t notification) override; - /** start an immediate transmit - * This method is virtual so subclasses can hook as needed, subclasses should not call directly - */ - virtual void startSend(meshtastic_MeshPacket *txp); + /** start an immediate transmit + * This method is virtual so subclasses can hook as needed, subclasses should not call directly + */ + virtual void startSend(meshtastic_MeshPacket *txp); - meshtastic_QueueStatus getQueueStatus(); + meshtastic_QueueStatus getQueueStatus(); -protected: - /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ - virtual void configHardwareForSend() {} + protected: + /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ + virtual void configHardwareForSend() {} - /** Could we send right now (i.e. either not actively receiving or transmitting)? */ - virtual bool canSendImmediately(); + /** Could we send right now (i.e. either not actively receiving or transmitting)? */ + virtual bool canSendImmediately(); - /** - * Raw ISR handler that just calls our polymorphic method - */ - static void isrRxLevel0(); + /** + * Raw ISR handler that just calls our polymorphic method + */ + static void isrRxLevel0(); - /** - * If a send was in progress finish it and return the buffer to the pool */ - void completeSending(); + /** + * If a send was in progress finish it and return the buffer to the pool */ + void completeSending(); - /** - * Add SNR data to received messages - */ - virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; + /** + * Add SNR data to received messages + */ + virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - virtual void setStandby() = 0; + virtual void setStandby() = 0; }; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 0e8481a8b..8000926f3 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -12,13 +12,11 @@ */ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) { - if (p->want_ack) - { + if (p->want_ack) { // If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our // message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop // counts and we want this message to get through the whole mesh, so use the default. - if (p->hop_limit == 0) - { + if (p->hop_limit == 0) { p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit; } @@ -32,8 +30,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { // Note: do not use getFrom() here, because we want to ignore messages sent from phone - if (p->from == getNodeNum()) - { + if (p->from == getNodeNum()) { printPacket("Rx someone rebroadcasting for us", p); // We are seeing someone rebroadcast one of our broadcast attempts. @@ -44,17 +41,14 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // from the intended recipient. auto key = GlobalPacketId(getFrom(p), p->id); auto old = findPendingPacket(key); - if (old) - { + if (old) { LOG_DEBUG("generating implicit ack\n"); // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be // marked as wantAck sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, old->packet->channel); stopRetransmission(key); - } - else - { + } else { LOG_DEBUG("didn't find pending packet\n"); } } @@ -63,8 +57,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) * 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()) - { + 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 LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n"); meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); @@ -91,10 +84,8 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas { NodeNum ourNode = getNodeNum(); - if (p->to == ourNode) - { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability) - if (p->want_ack) - { + if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability) + if (p->want_ack) { 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) @@ -111,15 +102,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records - if (ackId || nakId) - { - if (ackId) - { + if (ackId || nakId) { + if (ackId) { LOG_DEBUG("Received an ack for 0x%x, stopping retransmissions\n", ackId); stopRetransmission(p->to, ackId); - } - else - { + } else { LOG_DEBUG("Received a nak for 0x%x, stopping retransmissions\n", nakId); stopRetransmission(p->to, nakId); } @@ -141,11 +128,9 @@ PendingPacket::PendingPacket(meshtastic_MeshPacket *p) PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key) { auto old = pending.find(key); // If we have an old record, someone messed up because id got reused - if (old != pending.end()) - { + if (old != pending.end()) { return &old->second; - } - else + } else return NULL; } /** @@ -160,14 +145,12 @@ bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id) bool ReliableRouter::stopRetransmission(GlobalPacketId key) { auto old = findPendingPacket(key); - if (old) - { + if (old) { auto numErased = pending.erase(key); assert(numErased == 1); cancelSending(getFrom(old->packet), old->packet->id); return true; - } - else + } else return false; } @@ -197,27 +180,22 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, we should use a better datastructure rather than walking through this map. // for(auto el: pending) { - for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) - { + for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) { ++nextIt; // we use this odd pattern because we might be deleting it... auto &p = it->second; bool stillValid = true; // assume we'll keep this record around // FIXME, handle 51 day rolloever here!!! - if (p.nextTxMsec <= now) - { - if (p.numRetransmissions == 0) - { + if (p.nextTxMsec <= now) { + if (p.numRetransmissions == 0) { LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived stopRetransmission(it->first); stillValid = false; // just deleted it - } - else - { + } else { LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); @@ -231,8 +209,7 @@ int32_t ReliableRouter::doRetransmissions() } } - if (stillValid) - { + if (stillValid) { // Update our desired sleep delay int32_t t = p.nextTxMsec - now; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 6540d2652..70659c6ca 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -8,8 +8,7 @@ #include "main.h" #include "mesh-pb-constants.h" #include "modules/RoutingModule.h" -extern "C" -{ +extern "C" { #include "mesh/compression/unishox2.h" } @@ -26,13 +25,13 @@ extern "C" * **/ -#define MAX_RX_FROMRADIO \ +#define MAX_RX_FROMRADIO \ 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big // I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX // And every TX packet might have a retransmission packet or an ack alive at any moment -#define MAX_PACKETS \ - (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \ +#define MAX_PACKETS \ + (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \ 2) // max number of packets which can be in flight (either queued from reception or queued for sending) // static MemoryPool staticPool(MAX_PACKETS); @@ -65,8 +64,7 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA int32_t Router::runOnce() { meshtastic_MeshPacket *mp; - while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) - { + while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) { // printPacket("handle fromRadioQ", mp); perhapsHandleReceived(mp); } @@ -81,14 +79,11 @@ int32_t Router::runOnce() */ void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p) { - if (fromRadioQueue.enqueue(p, 0)) - { // NOWAIT - fixme, if queue is full, delete older messages + if (fromRadioQueue.enqueue(p, 0)) { // NOWAIT - fixme, if queue is full, delete older messages // Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME setReceivedMessage(); - } - else - { + } else { printPacket("BUG! fromRadioQueue is full! Discarding!", p); packetPool.release(p); } @@ -103,8 +98,7 @@ PacketId generatePacketId() uint32_t numPacketId = UINT32_MAX; - if (!didInit) - { + if (!didInit) { didInit = true; // pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0) @@ -163,25 +157,19 @@ meshtastic_QueueStatus Router::getQueueStatus() ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src) { // No need to deliver externally if the destination is the local node - if (p->to == nodeDB.getNodeNum()) - { + if (p->to == nodeDB.getNodeNum()) { printPacket("Enqueued local", p); enqueueReceivedMessage(p); return ERRNO_OK; - } - else if (!iface) - { + } else if (!iface) { // We must be sending to remote nodes also, fail if no interface found abortSendAndNak(meshtastic_Routing_Error_NO_INTERFACE, p); return ERRNO_NO_INTERFACES; - } - else - { + } else { // If we are sending a broadcast, we also treat it as if we just received it ourself // this allows local apps (and PCs) to see broadcasts sourced locally - if (p->to == NODENUM_BROADCAST) - { + if (p->to == NODENUM_BROADCAST) { handleReceived(p, src); } @@ -205,34 +193,27 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes) ErrorCode Router::send(meshtastic_MeshPacket *p) { // Skip the normal ceremony for repeaters - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) - { + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { assert(iface); return iface->send(p); } - if (p->to == nodeDB.getNodeNum()) - { + if (p->to == nodeDB.getNodeNum()) { LOG_ERROR("BUG! send() called with packet destined for local node!\n"); packetPool.release(p); return meshtastic_Routing_Error_BAD_REQUEST; } // should have already been handled by sendLocal // Abort sending if we are violating the duty cycle - if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) - { + if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { float hourlyTxPercent = airTime->utilizationTXPercent(); - if (hourlyTxPercent > myRegion->dutyCycle) - { + if (hourlyTxPercent > myRegion->dutyCycle) { uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT; - if (getFrom(p) == nodeDB.getNodeNum()) - { // only send NAK to API, not to the mesh + if (getFrom(p) == nodeDB.getNodeNum()) { // only send NAK to API, not to the mesh abortSendAndNak(err, p); - } - else - { + } else { packetPool.release(p); } return err; @@ -257,15 +238,13 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now // If the packet is not yet encrypted, do so now - if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) - { + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it bool shouldActuallyEncrypt = true; #if HAS_WIFI || HAS_ETHERNET - if (moduleConfig.mqtt.enabled) - { + if (moduleConfig.mqtt.enabled) { // check if we should send decrypted packets to mqtt // truth table: @@ -278,8 +257,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) * => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE */ - if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) - { + if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) { shouldActuallyEncrypt = false; } @@ -292,15 +270,13 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) #endif auto encodeResult = perhapsEncode(p); - if (encodeResult != meshtastic_Routing_Error_NONE) - { + if (encodeResult != meshtastic_Routing_Error_NONE) { abortSendAndNak(encodeResult, p); return encodeResult; // FIXME - this isn't a valid ErrorCode } #if HAS_WIFI || HAS_ETHERNET - if (moduleConfig.mqtt.enabled) - { + if (moduleConfig.mqtt.enabled) { // the packet is now encrypted. // check if we should send encrypted packets to mqtt if (mqtt && shouldActuallyEncrypt) @@ -339,11 +315,9 @@ bool perhapsDecode(meshtastic_MeshPacket *p) // assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // Try to find a channel that works with this hash - for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) - { + for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { // Try to use this hash/channel pair - if (channels.decryptForHash(chIndex, p->channel)) - { + if (channels.decryptForHash(chIndex, p->channel)) { // Try to decrypt the packet if we can size_t rawSize = p->encrypted.size; assert(rawSize <= sizeof(bytes)); @@ -355,23 +329,17 @@ bool perhapsDecode(meshtastic_MeshPacket *p) // Take those raw bytes and convert them back into a well structured protobuf we can understand memset(&p->decoded, 0, sizeof(p->decoded)); - if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) - { + if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) { LOG_ERROR("Invalid protobufs in received mesh packet (bad psk?)!\n"); - } - else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) - { + } else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) { LOG_ERROR("Invalid portnum (bad psk?)!\n"); - } - else - { + } else { // parsing was successful p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded p->channel = chIndex; // change to store the index instead of the hash // Decompress if needed. jm - if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) - { + if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) { // Decompress the payload char compressed_in[meshtastic_Constants_DATA_PAYLOAD_LEN] = {}; char decompressed_out[meshtastic_Constants_DATA_PAYLOAD_LEN] = {}; @@ -404,14 +372,12 @@ bool perhapsDecode(meshtastic_MeshPacket *p) meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) { // If the packet is not yet encrypted, do so now - if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) - { + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded); // Only allow encryption on the text message app. // TODO: Allow modules to opt into compression. - if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) - { + if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) { char original_payload[meshtastic_Constants_DATA_PAYLOAD_LEN]; memcpy(original_payload, p->decoded.payload.bytes, p->decoded.payload.size); @@ -426,17 +392,14 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) LOG_DEBUG("Original message - %s \n", p->decoded.payload.bytes); // If the compressed length is greater than or equal to the original size, don't use the compressed form - if (compressed_len >= p->decoded.payload.size) - { + if (compressed_len >= p->decoded.payload.size) { LOG_DEBUG("Not using compressing message.\n"); // Set the uncompressed payload varient anyway. Shouldn't hurt? // p->decoded.which_payloadVariant = Data_payload_tag; // Otherwise we use the compressor - } - else - { + } else { LOG_DEBUG("Using compressed message.\n"); // Copy the compressed data into the meshpacket @@ -487,8 +450,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) // Take those raw bytes and convert them back into a well structured protobuf we can understand bool decoded = perhapsDecode(p); - if (decoded) - { + if (decoded) { // parsing was successful, queue for our recipient if (src == RX_SRC_LOCAL) printPacket("handleReceived(LOCAL)", p); @@ -496,9 +458,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) printPacket("handleReceived(USER)", p); else printPacket("handleReceived(REMOTE)", p); - } - else - { + } else { printPacket("packet decoding failed (no PSK?)", p); } @@ -513,8 +473,7 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) if (ignore) LOG_DEBUG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from); - else if (ignore |= shouldFilterReceived(p)) - { + else if (ignore |= shouldFilterReceived(p)) { LOG_DEBUG("Incoming message was filtered 0x%x\n", p->from); } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 8ad67bc0e..f43f92158 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -13,122 +13,122 @@ */ class Router : protected concurrency::OSThread { -private: - /// Packets which have just arrived from the radio, ready to be processed by this service and possibly - /// forwarded to the phone. - PointerQueue fromRadioQueue; + private: + /// Packets which have just arrived from the radio, ready to be processed by this service and possibly + /// forwarded to the phone. + PointerQueue fromRadioQueue; -protected: - RadioInterface *iface = NULL; + protected: + RadioInterface *iface = NULL; -public: - /** - * Constructor - * - */ - Router(); + public: + /** + * Constructor + * + */ + Router(); - /** - * Currently we only allow one interface, that may change in the future - */ - void addInterface(RadioInterface *_iface) { iface = _iface; } + /** + * Currently we only allow one interface, that may change in the future + */ + void addInterface(RadioInterface *_iface) { iface = _iface; } - /** - * do idle processing - * Mostly looking in our incoming rxPacket queue and calling handleReceived. - */ - virtual int32_t runOnce() override; + /** + * do idle processing + * Mostly looking in our incoming rxPacket queue and calling handleReceived. + */ + virtual int32_t runOnce() override; - /** - * Works like send, but if we are sending to the local node, we directly put the message in the receive queue. - * This is the primary method used for sending packets, because it handles both the remote and local cases. - * - * NOTE: This method will free the provided packet (even if we return an error code) - */ - ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); + /** + * Works like send, but if we are sending to the local node, we directly put the message in the receive queue. + * This is the primary method used for sending packets, because it handles both the remote and local cases. + * + * NOTE: This method will free the provided packet (even if we return an error code) + */ + ErrorCode sendLocal(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); - /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ - bool cancelSending(NodeNum from, PacketId id); + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + bool cancelSending(NodeNum from, PacketId id); - /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. - * The returned packet is guaranteed to have a unique packet ID already assigned - */ - meshtastic_MeshPacket *allocForSending(); + /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. + * The returned packet is guaranteed to have a unique packet ID already assigned + */ + meshtastic_MeshPacket *allocForSending(); - /** Return Underlying interface's TX queue status */ - meshtastic_QueueStatus getQueueStatus(); + /** Return Underlying interface's TX queue status */ + meshtastic_QueueStatus getQueueStatus(); - /** - * @return our local nodenum */ - NodeNum getNodeNum(); + /** + * @return our local nodenum */ + NodeNum getNodeNum(); - /** Wake up the router thread ASAP, because we just queued a message for it. - * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' - */ - void setReceivedMessage(); + /** Wake up the router thread ASAP, because we just queued a message for it. + * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' + */ + void setReceivedMessage(); - /** - * RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for - * freeing the packet - */ - void enqueueReceivedMessage(meshtastic_MeshPacket *p); + /** + * RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for + * freeing the packet + */ + void enqueueReceivedMessage(meshtastic_MeshPacket *p); - /** - * Send a packet on a suitable interface. This routine will - * later free() the packet to pool. This routine is not allowed to stall. - * If the txmit queue is full it might return an error - * - * NOTE: This method will free the provided packet (even if we return an error code) - */ - virtual ErrorCode send(meshtastic_MeshPacket *p); + /** + * Send a packet on a suitable interface. This routine will + * later free() the packet to pool. This routine is not allowed to stall. + * If the txmit queue is full it might return an error + * + * NOTE: This method will free the provided packet (even if we return an error code) + */ + virtual ErrorCode send(meshtastic_MeshPacket *p); -protected: - friend class RoutingModule; + protected: + friend class RoutingModule; - /** - * Should this incoming filter be dropped? - * - * FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic - * - * Called immedately on receiption, before any further processing. - * @return true to abandon the packet - */ - virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; } + /** + * Should this incoming filter be dropped? + * + * FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic + * + * Called immedately on receiption, before any further processing. + * @return true to abandon the packet + */ + virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; } - /** - * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to - * update routing tables etc... based on what we overhear (even for messages not destined to our node) - */ - virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c); + /** + * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to + * update routing tables etc... based on what we overhear (even for messages not destined to our node) + */ + virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c); - /** - * Send an ack or a nak packet back towards whoever sent idFrom - */ - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + /** + * Send an ack or a nak packet back towards whoever sent idFrom + */ + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); -private: - /** - * Called from loop() - * Handle any packet that is received by an interface on this node. - * Note: some packets may merely being passed through this node and will be forwarded elsewhere. - * - * Note: this packet will never be called for messages sent/generated by this node. - * Note: this method will free the provided packet. - */ - void perhapsHandleReceived(meshtastic_MeshPacket *p); + private: + /** + * Called from loop() + * Handle any packet that is received by an interface on this node. + * Note: some packets may merely being passed through this node and will be forwarded elsewhere. + * + * Note: this packet will never be called for messages sent/generated by this node. + * Note: this method will free the provided packet. + */ + void perhapsHandleReceived(meshtastic_MeshPacket *p); - /** - * Called from perhapsHandleReceived() - allows subclass message delivery behavior. - * Handle any packet that is received by an interface on this node. - * Note: some packets may merely being passed through this node and will be forwarded elsewhere. - * - * Note: this packet will never be called for messages sent/generated by this node. - * Note: this method will free the provided packet. - */ - void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); + /** + * Called from perhapsHandleReceived() - allows subclass message delivery behavior. + * Handle any packet that is received by an interface on this node. + * Note: some packets may merely being passed through this node and will be forwarded elsewhere. + * + * Note: this packet will never be called for messages sent/generated by this node. + * Note: this method will free the provided packet. + */ + void handleReceived(meshtastic_MeshPacket *p, RxSource src = RX_SRC_RADIO); - /** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */ - void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p); + /** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */ + void abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p); }; /** FIXME - move this into a mesh packet class diff --git a/src/modules/RepeaterModule.h b/src/modules/RepeaterModule.h index d24bbb296..b609ce3b5 100644 --- a/src/modules/RepeaterModule.h +++ b/src/modules/RepeaterModule.h @@ -7,25 +7,25 @@ */ class RepeaterModule : public ProtobufModule { -public: - /** Constructor - * name is for debugging output - */ - RepeaterModule(); + public: + /** Constructor + * name is for debugging output + */ + RepeaterModule(); -protected: - /** Called to handle a particular incoming message + protected: + /** Called to handle a particular incoming message - @return true if you've guaranteed you've handled this message and no other handlers should be considered for it - */ - virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override; + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override; - /** Messages can be received that have the want_response bit set. If set, this callback will be invoked - * so that subclasses can (optionally) send a response back to the original sender. */ - virtual meshtastic_MeshPacket *allocReply() override; + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked + * so that subclasses can (optionally) send a response back to the original sender. */ + virtual meshtastic_MeshPacket *allocReply() override; - /// Override wantPacket to say we want to see all packets, not just those for our port number - virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } + /// Override wantPacket to say we want to see all packets, not just those for our port number + virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } }; extern RepeaterModule *repeaterModule; From db192481bd43fba1271ecd23b27a978e757fbbd6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:03:32 -0600 Subject: [PATCH 08/27] Swap out reliable router with flood router and dump modules --- src/main.cpp | 4 +++ src/modules/Modules.cpp | 65 +++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c91a71719..4f65ff51b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -310,6 +310,10 @@ void setup() // but we need to do this after main cpu iniot (esp32setup), because we need the random seed set nodeDB.init(); + // If we're taking on the repeater role, use flood router + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) + router = new FloodingRouter(); + playStartMelody(); // fixed screen override? diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index aacb77151..76f42b519 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -8,6 +8,7 @@ #include "modules/NodeInfoModule.h" #include "modules/PositionModule.h" #include "modules/RemoteHardwareModule.h" +#include "modules/RepeaterModule.h" #include "modules/ReplyModule.h" #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" @@ -33,51 +34,57 @@ */ void setupModules() { + if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { #if HAS_BUTTON - inputBroker = new InputBroker(); + inputBroker = new InputBroker(); #endif - adminModule = new AdminModule(); - nodeInfoModule = new NodeInfoModule(); - positionModule = new PositionModule(); - waypointModule = new WaypointModule(); - textMessageModule = new TextMessageModule(); - traceRouteModule = new TraceRouteModule(); + adminModule = new AdminModule(); + nodeInfoModule = new NodeInfoModule(); + positionModule = new PositionModule(); + waypointModule = new WaypointModule(); + textMessageModule = new TextMessageModule(); + traceRouteModule = new TraceRouteModule(); - // 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. + // 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. - new RemoteHardwareModule(); - new ReplyModule(); + new RemoteHardwareModule(); + new ReplyModule(); #if HAS_BUTTON - rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); - rotaryEncoderInterruptImpl1->init(); - upDownInterruptImpl1 = new UpDownInterruptImpl1(); - upDownInterruptImpl1->init(); - cardKbI2cImpl = new CardKbI2cImpl(); - cardKbI2cImpl->init(); + rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); + rotaryEncoderInterruptImpl1->init(); + upDownInterruptImpl1 = new UpDownInterruptImpl1(); + upDownInterruptImpl1->init(); + cardKbI2cImpl = new CardKbI2cImpl(); + cardKbI2cImpl->init(); #endif #if HAS_SCREEN - cannedMessageModule = new CannedMessageModule(); + cannedMessageModule = new CannedMessageModule(); #endif #if HAS_TELEMETRY - new DeviceTelemetryModule(); - new EnvironmentTelemetryModule(); + new DeviceTelemetryModule(); + new EnvironmentTelemetryModule(); #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) - new SerialModule(); + new SerialModule(); #endif #ifdef ARCH_ESP32 - // Only run on an esp32 based device. - audioModule = new AudioModule(); - externalNotificationModule = new ExternalNotificationModule(); + // Only run on an esp32 based device. + audioModule = new AudioModule(); + externalNotificationModule = new ExternalNotificationModule(); - storeForwardModule = new StoreForwardModule(); + storeForwardModule = new StoreForwardModule(); - new RangeTestModule(); + new RangeTestModule(); #elif defined(ARCH_NRF52) - externalNotificationModule = new ExternalNotificationModule(); + externalNotificationModule = new ExternalNotificationModule(); #endif - // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks - routingModule = new RoutingModule(); + // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra + // acks + routingModule = new RoutingModule(); + } else { + adminModule = new AdminModule(); + repeaterModule = new RepeaterModule(); + } } From e01e830c0e913d6a3f09248399c634c63a7e1cb1 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:09:10 -0600 Subject: [PATCH 09/27] Print --- src/modules/RepeaterModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp index 06147f9f2..d9e1fa686 100644 --- a/src/modules/RepeaterModule.cpp +++ b/src/modules/RepeaterModule.cpp @@ -9,7 +9,7 @@ RepeaterModule *repeaterModule; bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *r) { - printPacket("Repeater rebroadcasting", &mp); + printPacket("Repeater rebroadcasting message", &mp); meshtastic_MeshPacket *p = const_cast(&mp); router->send(p); return true; From 654d38ed3fb02f808b368971b565a79c7c87b576 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:17:29 -0600 Subject: [PATCH 10/27] Router --- src/mesh/Router.cpp | 6 ------ src/modules/RepeaterModule.cpp | 15 +++++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 70659c6ca..e729a225d 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -192,12 +192,6 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes) */ ErrorCode Router::send(meshtastic_MeshPacket *p) { - // Skip the normal ceremony for repeaters - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - assert(iface); - return iface->send(p); - } - if (p->to == nodeDB.getNodeNum()) { LOG_ERROR("BUG! send() called with packet destined for local node!\n"); packetPool.release(p); diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp index d9e1fa686..f4539f3bf 100644 --- a/src/modules/RepeaterModule.cpp +++ b/src/modules/RepeaterModule.cpp @@ -9,10 +9,17 @@ RepeaterModule *repeaterModule; bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *r) { - printPacket("Repeater rebroadcasting message", &mp); - meshtastic_MeshPacket *p = const_cast(&mp); - router->send(p); - return true; + printPacket("Repeater observed message", &mp); + router->sniffReceived(&mp, r); + + // FIXME - move this to a non promsicious PhoneAPI module? + // Note: we are careful not to send back packets that started with the phone back to the phone + if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) { + printPacket("Delivering rx packet", &mp); + service.handleFromRadio(&mp); + } + + return false; } meshtastic_MeshPacket *RepeaterModule::allocReply() From a5f80167e09d74cd8a58555a3f756fbeecfdcdbc Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:18:47 -0600 Subject: [PATCH 11/27] Remove comments --- src/modules/RepeaterModule.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp index f4539f3bf..6ae7fe33a 100644 --- a/src/modules/RepeaterModule.cpp +++ b/src/modules/RepeaterModule.cpp @@ -12,9 +12,8 @@ bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes printPacket("Repeater observed message", &mp); router->sniffReceived(&mp, r); - // FIXME - move this to a non promsicious PhoneAPI module? - // Note: we are careful not to send back packets that started with the phone back to the phone - if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) { + if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) + { printPacket("Delivering rx packet", &mp); service.handleFromRadio(&mp); } From 14372c7e35e426a2f27d309c15ab56e9e4cc7f09 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:18:56 -0600 Subject: [PATCH 12/27] Fmt --- src/modules/RepeaterModule.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp index 6ae7fe33a..3ffe81bc2 100644 --- a/src/modules/RepeaterModule.cpp +++ b/src/modules/RepeaterModule.cpp @@ -12,8 +12,7 @@ bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes printPacket("Repeater observed message", &mp); router->sniffReceived(&mp, r); - if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) - { + if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) { printPacket("Delivering rx packet", &mp); service.handleFromRadio(&mp); } From a7153a7aa96e611e6d9399ce10c2d3342e927d75 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:40:50 -0600 Subject: [PATCH 13/27] Be a friend --- src/modules/RepeaterModule.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/RepeaterModule.h b/src/modules/RepeaterModule.h index b609ce3b5..bcb81fe49 100644 --- a/src/modules/RepeaterModule.h +++ b/src/modules/RepeaterModule.h @@ -14,6 +14,8 @@ class RepeaterModule : public ProtobufModule RepeaterModule(); protected: + friend class Router; + /** Called to handle a particular incoming message @return true if you've guaranteed you've handled this message and no other handlers should be considered for it From e229a67d254c3eb297209124bd0c735f45868d33 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 08:44:29 -0600 Subject: [PATCH 14/27] More friends --- src/mesh/Router.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index f43f92158..c0244019e 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -84,6 +84,7 @@ class Router : protected concurrency::OSThread protected: friend class RoutingModule; + friend class RepeaterModule; /** * Should this incoming filter be dropped? From 103f1992dd861b2782278c6537eacc815f542c84 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 09:11:12 -0600 Subject: [PATCH 15/27] Yank repeater module and just guard clause the alloc --- src/mesh/Router.h | 1 - src/modules/Modules.cpp | 3 +-- src/modules/RepeaterModule.cpp | 32 -------------------------------- src/modules/RepeaterModule.h | 33 --------------------------------- src/modules/RoutingModule.cpp | 2 ++ 5 files changed, 3 insertions(+), 68 deletions(-) delete mode 100644 src/modules/RepeaterModule.cpp delete mode 100644 src/modules/RepeaterModule.h diff --git a/src/mesh/Router.h b/src/mesh/Router.h index c0244019e..f43f92158 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -84,7 +84,6 @@ class Router : protected concurrency::OSThread protected: friend class RoutingModule; - friend class RepeaterModule; /** * Should this incoming filter be dropped? diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 76f42b519..ee7587112 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -82,9 +82,8 @@ void setupModules() // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks - routingModule = new RoutingModule(); } else { adminModule = new AdminModule(); - repeaterModule = new RepeaterModule(); } + routingModule = new RoutingModule(); } diff --git a/src/modules/RepeaterModule.cpp b/src/modules/RepeaterModule.cpp deleted file mode 100644 index 3ffe81bc2..000000000 --- a/src/modules/RepeaterModule.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "RepeaterModule.h" -#include "MeshService.h" -#include "NodeDB.h" -#include "Router.h" -#include "configuration.h" -#include "main.h" - -RepeaterModule *repeaterModule; - -bool RepeaterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *r) -{ - printPacket("Repeater observed message", &mp); - router->sniffReceived(&mp, r); - - if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) { - printPacket("Delivering rx packet", &mp); - service.handleFromRadio(&mp); - } - - return false; -} - -meshtastic_MeshPacket *RepeaterModule::allocReply() -{ - return NULL; -} - -RepeaterModule::RepeaterModule() : ProtobufModule("repeater", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) -{ - isPromiscuous = true; - encryptedOk = true; -} diff --git a/src/modules/RepeaterModule.h b/src/modules/RepeaterModule.h deleted file mode 100644 index bcb81fe49..000000000 --- a/src/modules/RepeaterModule.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "Channels.h" -#include "ProtobufModule.h" - -/** - * Routing module for router control messages - */ -class RepeaterModule : public ProtobufModule -{ - public: - /** Constructor - * name is for debugging output - */ - RepeaterModule(); - - protected: - friend class Router; - - /** Called to handle a particular incoming message - - @return true if you've guaranteed you've handled this message and no other handlers should be considered for it - */ - virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Routing *p) override; - - /** Messages can be received that have the want_response bit set. If set, this callback will be invoked - * so that subclasses can (optionally) send a response back to the original sender. */ - virtual meshtastic_MeshPacket *allocReply() override; - - /// Override wantPacket to say we want to see all packets, not just those for our port number - virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } -}; - -extern RepeaterModule *repeaterModule; diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index bf3739f2c..f91d32a20 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -24,6 +24,8 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh meshtastic_MeshPacket *RoutingModule::allocReply() { + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) + return NULL; assert(currentRequest); // We only consider making replies if the request was a legit routing packet (not just something we were sniffing) From 92a43685a87318a31022594c9cb7d43cf06175c6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 09:13:01 -0600 Subject: [PATCH 16/27] Modules --- src/modules/Modules.cpp | 72 +++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index ee7587112..f02d01b86 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -8,7 +8,6 @@ #include "modules/NodeInfoModule.h" #include "modules/PositionModule.h" #include "modules/RemoteHardwareModule.h" -#include "modules/RepeaterModule.h" #include "modules/ReplyModule.h" #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" @@ -34,56 +33,59 @@ */ void setupModules() { - if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) + { #if HAS_BUTTON - inputBroker = new InputBroker(); + inputBroker = new InputBroker(); #endif - adminModule = new AdminModule(); - nodeInfoModule = new NodeInfoModule(); - positionModule = new PositionModule(); - waypointModule = new WaypointModule(); - textMessageModule = new TextMessageModule(); - traceRouteModule = new TraceRouteModule(); + adminModule = new AdminModule(); + nodeInfoModule = new NodeInfoModule(); + positionModule = new PositionModule(); + waypointModule = new WaypointModule(); + textMessageModule = new TextMessageModule(); + traceRouteModule = new TraceRouteModule(); - // 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. + // 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. - new RemoteHardwareModule(); - new ReplyModule(); + new RemoteHardwareModule(); + new ReplyModule(); #if HAS_BUTTON - rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); - rotaryEncoderInterruptImpl1->init(); - upDownInterruptImpl1 = new UpDownInterruptImpl1(); - upDownInterruptImpl1->init(); - cardKbI2cImpl = new CardKbI2cImpl(); - cardKbI2cImpl->init(); + rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); + rotaryEncoderInterruptImpl1->init(); + upDownInterruptImpl1 = new UpDownInterruptImpl1(); + upDownInterruptImpl1->init(); + cardKbI2cImpl = new CardKbI2cImpl(); + cardKbI2cImpl->init(); #endif #if HAS_SCREEN - cannedMessageModule = new CannedMessageModule(); + cannedMessageModule = new CannedMessageModule(); #endif #if HAS_TELEMETRY - new DeviceTelemetryModule(); - new EnvironmentTelemetryModule(); + new DeviceTelemetryModule(); + new EnvironmentTelemetryModule(); #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) - new SerialModule(); + new SerialModule(); #endif #ifdef ARCH_ESP32 - // Only run on an esp32 based device. - audioModule = new AudioModule(); - externalNotificationModule = new ExternalNotificationModule(); + // Only run on an esp32 based device. + audioModule = new AudioModule(); + externalNotificationModule = new ExternalNotificationModule(); - storeForwardModule = new StoreForwardModule(); + storeForwardModule = new StoreForwardModule(); - new RangeTestModule(); + new RangeTestModule(); #elif defined(ARCH_NRF52) - externalNotificationModule = new ExternalNotificationModule(); + externalNotificationModule = new ExternalNotificationModule(); #endif - // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra - // acks - } else { - adminModule = new AdminModule(); - } - routingModule = new RoutingModule(); + // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra + // acks + } + else + { + adminModule = new AdminModule(); + } + routingModule = new RoutingModule(); } From f45a25b3584ab9947cf3cd84413045b84ae4fdfe Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 09:18:06 -0600 Subject: [PATCH 17/27] Fmt --- src/modules/Modules.cpp | 71 ++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index f02d01b86..b0e4bd2b1 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -33,59 +33,56 @@ */ void setupModules() { - if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) - { + if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { #if HAS_BUTTON - inputBroker = new InputBroker(); + inputBroker = new InputBroker(); #endif - adminModule = new AdminModule(); - nodeInfoModule = new NodeInfoModule(); - positionModule = new PositionModule(); - waypointModule = new WaypointModule(); - textMessageModule = new TextMessageModule(); - traceRouteModule = new TraceRouteModule(); + adminModule = new AdminModule(); + nodeInfoModule = new NodeInfoModule(); + positionModule = new PositionModule(); + waypointModule = new WaypointModule(); + textMessageModule = new TextMessageModule(); + traceRouteModule = new TraceRouteModule(); - // 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. + // 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. - new RemoteHardwareModule(); - new ReplyModule(); + new RemoteHardwareModule(); + new ReplyModule(); #if HAS_BUTTON - rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); - rotaryEncoderInterruptImpl1->init(); - upDownInterruptImpl1 = new UpDownInterruptImpl1(); - upDownInterruptImpl1->init(); - cardKbI2cImpl = new CardKbI2cImpl(); - cardKbI2cImpl->init(); + rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1(); + rotaryEncoderInterruptImpl1->init(); + upDownInterruptImpl1 = new UpDownInterruptImpl1(); + upDownInterruptImpl1->init(); + cardKbI2cImpl = new CardKbI2cImpl(); + cardKbI2cImpl->init(); #endif #if HAS_SCREEN - cannedMessageModule = new CannedMessageModule(); + cannedMessageModule = new CannedMessageModule(); #endif #if HAS_TELEMETRY - new DeviceTelemetryModule(); - new EnvironmentTelemetryModule(); + new DeviceTelemetryModule(); + new EnvironmentTelemetryModule(); #endif #if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2) - new SerialModule(); + new SerialModule(); #endif #ifdef ARCH_ESP32 - // Only run on an esp32 based device. - audioModule = new AudioModule(); - externalNotificationModule = new ExternalNotificationModule(); + // Only run on an esp32 based device. + audioModule = new AudioModule(); + externalNotificationModule = new ExternalNotificationModule(); - storeForwardModule = new StoreForwardModule(); + storeForwardModule = new StoreForwardModule(); - new RangeTestModule(); + new RangeTestModule(); #elif defined(ARCH_NRF52) - externalNotificationModule = new ExternalNotificationModule(); + externalNotificationModule = new ExternalNotificationModule(); #endif - // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra - // acks - } - else - { - adminModule = new AdminModule(); - } - routingModule = new RoutingModule(); + // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra + // acks + } else { + adminModule = new AdminModule(); + } + routingModule = new RoutingModule(); } From d9af4f46fa6d221f6caafe12c0b8a9ed0709834e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 13:28:57 -0600 Subject: [PATCH 18/27] Skip decoding for Repeaters --- src/mesh/Router.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index e729a225d..a150e358c 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -300,8 +300,8 @@ void Router::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Rout bool perhapsDecode(meshtastic_MeshPacket *p) { - - // LOG_DEBUG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant); + if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) + return false; if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) return true; // If packet was already decoded just return From bdf3fe3f5cfe0867df6ed5d9789efd94c8de3f2e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 13:40:14 -0600 Subject: [PATCH 19/27] Logging tweaks --- src/mesh/FloodingRouter.cpp | 4 +--- src/mesh/Router.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 6fd4d0401..16c20d7a2 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -48,15 +48,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas traceRouteModule->updateRoute(tosend); } - LOG_INFO("Rebroadcasting received floodmsg to neighbors", p); + LOG_INFO("Rebroadcasting received floodmsg to neighbors\n"); // Note: we are careful to resend using the original senders node id // We are careful not to call our hooked version of send() - because we don't want to check this again Router::send(tosend); - } else { LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n"); } - } else { LOG_DEBUG("Ignoring a simple (0 id) broadcast\n"); } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index a150e358c..4ac6f8f46 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -453,7 +453,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) else printPacket("handleReceived(REMOTE)", p); } else { - printPacket("packet decoding failed (no PSK?)", p); + printPacket("packet decoding failed or skipped (no PSK?)", p); } // call modules here From 171c1df3fa0297418d8be983938a888a223fd102 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 14:32:57 -0600 Subject: [PATCH 20/27] Role based defaults --- src/mesh/NodeDB.cpp | 20 ++++++++++++++++++-- src/mesh/NodeDB.h | 2 ++ src/modules/AdminModule.cpp | 8 +++----- src/modules/PositionModule.cpp | 6 ++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cfb815d1e..5e49301ea 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -225,6 +225,24 @@ void NodeDB::installDefaultModuleConfig() initModuleConfigIntervals(); } +void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) +{ + if (role == meshtastic_Config_DeviceConfig_Role_ROUTER) { + initConfigIntervals(); + initModuleConfigIntervals(); + } else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) { + config.display.screen_on_secs = 1; + meshtastic_Channel &ch = channels.getByIndex(channels.getPrimaryIndex()); + meshtastic_ChannelSettings &channelSettings = ch.settings; + uint8_t defaultpskIndex = 1; + channelSettings.psk.bytes[0] = defaultpskIndex; + channelSettings.psk.size = 1; + } else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) { + config.position.position_broadcast_smart_enabled = false; + config.position.position_broadcast_secs = 120; + } +} + void NodeDB::initModuleConfigIntervals() { moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs; @@ -609,13 +627,11 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i, p.altitude); info->position = p; - } else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO // (stop-gap fix for issue #900) LOG_DEBUG("updatePosition SPECIAL time setting time=%u\n", p.time); info->position.time = p.time; - } else { // Be careful to only update fields that have been set by the REMOTE sender // A lot of position reports don't have time populated. In that case, be careful to not blow away the time we diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index c169a85cd..106d35402 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -129,6 +129,8 @@ class NodeDB bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct); bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct); + void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role); + private: /// Find a node in our DB, create an empty NodeInfo if missing meshtastic_NodeInfo *getOrCreateNode(NodeNum n); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index b67751bf2..18557f0b3 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -225,7 +225,7 @@ void AdminModule::handleSetOwner(const meshtastic_User &o) void AdminModule::handleSetConfig(const meshtastic_Config &c) { - bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER); + auto existingRole = config.device.role; bool isRegionUnset = (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET); switch (c.which_payload_variant) { @@ -234,10 +234,8 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) config.has_device = true; config.device = c.payload_variant.device; // If we're setting router role for the first time, install its intervals - if (!isRouter && c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) { - nodeDB.initConfigIntervals(); - nodeDB.initModuleConfigIntervals(); - } + if (existingRole != c.payload_variant.device.role) + nodeDB.installRoleDefaults(c.payload_variant.device.role); break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index ee3ba493f..d923dad8a 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -129,7 +129,10 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies) meshtastic_MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; - p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER) + p->priority = meshtastic_MeshPacket_Priority_RELIABLE; + else + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; prevPacketId = p->id; service.sendToMesh(p, RX_SRC_LOCAL, true); @@ -161,7 +164,6 @@ int32_t PositionModule::runOnce() sendOurPosition(NODENUM_BROADCAST, requestReplies); } } - } else if (config.position.position_broadcast_smart_enabled) { // Only send packets if the channel is less than 25% utilized. From 75ea6fd7043aeeeefca6452820aa8c3c0ff908a1 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 14:44:47 -0600 Subject: [PATCH 21/27] Update interval --- src/mesh/NodeDB.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 5e49301ea..3961c4ae2 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -240,6 +240,7 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) } else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) { config.position.position_broadcast_smart_enabled = false; config.position.position_broadcast_secs = 120; + config.position.gps_update_interval = 60; } } From aafbde0f10b9806d97fbbc7a6b32c70349465c67 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 28 Jan 2023 14:50:07 -0600 Subject: [PATCH 22/27] Remove the dirty d --- bin/readprops.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/readprops.py b/bin/readprops.py index c23092e41..ffa361541 100644 --- a/bin/readprops.py +++ b/bin/readprops.py @@ -22,9 +22,9 @@ def readProps(prefsLoc): isDirty = subprocess.check_output( ['git', 'diff', 'HEAD']).decode("utf-8").strip() suffix = sha - if isDirty: - # short for 'dirty', we want to keep our verstrings source for protobuf reasons - suffix = sha + "-d" + # if isDirty: + # # short for 'dirty', we want to keep our verstrings source for protobuf reasons + # suffix = sha + "-d" verObj['long'] = "{}.{}.{}.{}".format( version["major"], version["minor"], version["build"], suffix) except: From 0e6cfcd48a6b662be457356f89a1b3f165fe0ac7 Mon Sep 17 00:00:00 2001 From: thebentern Date: Sat, 28 Jan 2023 21:19:03 +0000 Subject: [PATCH 23/27] [create-pull-request] automated change --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 4b12a2fc8..8ad7a80c8 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 0 -build = 15 +build = 16 From 7ed39d27e48cd8db5bfb6f033b2b318dc06729f7 Mon Sep 17 00:00:00 2001 From: thebentern Date: Sun, 29 Jan 2023 13:57:30 +0000 Subject: [PATCH 24/27] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/protobufs b/protobufs index 0754d5820..22ffb71c3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 0754d58205de4105292f25ca90cdf3501d94587b +Subproject commit 22ffb71c35ee7f097b9fb54d282f9c1d3f3d953f diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index d90467582..ff602b668 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -180,7 +180,9 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset { /* Short Range - Slow */ meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW = 5, /* Short Range - Fast */ - meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST = 6 + meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST = 6, + /* Long Range - Moderately Fast */ + meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE = 7 } meshtastic_Config_LoRaConfig_ModemPreset; typedef enum _meshtastic_Config_BluetoothConfig_PairingMode { @@ -459,8 +461,8 @@ extern "C" { #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_UA_868+1)) #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST -#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST -#define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST+1)) +#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE +#define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE+1)) #define _meshtastic_Config_BluetoothConfig_PairingMode_MIN meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN #define _meshtastic_Config_BluetoothConfig_PairingMode_MAX meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN From c499302092a96b8b54c027169816b017e8106192 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 29 Jan 2023 16:32:18 +0100 Subject: [PATCH 25/27] Remove decode guard clause for repeater --- src/mesh/Router.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 4ac6f8f46..15bcc1d2a 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -300,8 +300,6 @@ void Router::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Rout bool perhapsDecode(meshtastic_MeshPacket *p) { - if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) - return false; if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) return true; // If packet was already decoded just return From 14831e597caae5217f93f05b3775bb07d643e452 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sun, 29 Jan 2023 16:37:02 +0100 Subject: [PATCH 26/27] Add TraceRouteModule to Repeater --- src/modules/Modules.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index b0e4bd2b1..e8481356b 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -78,11 +78,11 @@ void setupModules() #elif defined(ARCH_NRF52) externalNotificationModule = new ExternalNotificationModule(); #endif - - // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra - // acks } else { adminModule = new AdminModule(); + traceRouteModule = new TraceRouteModule(); } + // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra + // acks routingModule = new RoutingModule(); } From 00196ab7e79891265383c854f86a7016b8891577 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 29 Jan 2023 09:53:38 -0600 Subject: [PATCH 27/27] Long moderate --- src/graphics/Screen.cpp | 4 +++- src/mesh/RadioInterface.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 45af8e415..375e08215 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -610,7 +610,6 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const } else { display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine); } - } else { char latLine[22]; char lonLine[22]; @@ -1695,6 +1694,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST: mode = "LongF"; break; + case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE: + mode = "LongM"; + break; case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW: mode = "VeryL"; break; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 3c59867f6..d7c1e1aec 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -401,13 +401,18 @@ void RadioInterface::applyModemConfig() cr = 8; sf = 11; break; + case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE: + bw = (myRegion->wideLora) ? 406.25 : 125; + cr = 8; + sf = 11; + break; case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW: bw = (myRegion->wideLora) ? 406.25 : 125; cr = 8; sf = 12; break; case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW: - bw = (myRegion->wideLora) ? 203.125 : 31.25; + bw = (myRegion->wideLora) ? 203.125 : 62.5; cr = 8; sf = 12; break;