diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..616c16ce2
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,26 @@
+version: 2
+updates:
+ - package-ecosystem: docker
+ directory: devcontainer
+ schedule:
+ interval: daily
+ time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
+ timezone: US/Pacific
+ - package-ecosystem: docker
+ directory: /
+ schedule:
+ interval: daily
+ time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
+ timezone: US/Pacific
+ - package-ecosystem: gitsubmodule
+ directory: /
+ schedule:
+ interval: daily
+ time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
+ timezone: US/Pacific
+ - package-ecosystem: github-actions
+ directory: /.github/workflows
+ schedule:
+ interval: daily
+ time: "05:00" # trunk-ignore(yamllint/quoted-strings): required by dependabot syntax check
+ timezone: US/Pacific
diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml
index 51bef0c13..1fb44a717 100644
--- a/.github/workflows/build_native.yml
+++ b/.github/workflows/build_native.yml
@@ -67,7 +67,7 @@ jobs:
- name: Docker build and push tagged versions
if: ${{ github.event_name == 'workflow_dispatch' }}
continue-on-error: true # FIXME: Failing docker login auth
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
@@ -77,7 +77,7 @@ jobs:
- name: Docker build and push
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
continue-on-error: true # FIXME: Failing docker login auth
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index 9b97dcb2e..19a92d8b8 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -251,12 +251,6 @@ jobs:
merge-multiple: true
path: ./output
- - uses: actions/download-artifact@v4
- with:
- pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
- merge-multiple: true
- path: ./output
-
- name: Display structure of downloaded files
run: ls -R
@@ -314,6 +308,12 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
+ - uses: actions/download-artifact@v4
+ with:
+ pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
+ merge-multiple: true
+ path: ./output
+
- name: Add raspbian aarch64 .deb
uses: actions/upload-release-asset@v1
env:
@@ -349,7 +349,35 @@ jobs:
bin/bump_version.py
- name: Create version.properties pull request
- uses: peter-evans/create-pull-request@v6
+ uses: peter-evans/create-pull-request@v7
with:
+ title: Bump version.properties
add-paths: |
version.properties
+
+ - name: Checkout meshtastic/meshtastic.github.io
+ uses: actions/checkout@v4
+ with:
+ repository: meshtastic/meshtastic.github.io
+ token: ${{ secrets.ARTIFACTS_TOKEN }}
+ path: meshtastic.github.io
+
+ - name: Display structure of downloaded files
+ run: ls -R
+
+ - name: Extract firmware.zip
+ run: |
+ unzip ./firmware-${{ steps.version.outputs.version }}.zip -d meshtastic.github.io/firmware-${{ steps.version.outputs.version }}
+
+ - name: Display structure of downloaded files
+ run: ls -R
+
+ - name: Commit and push changes
+ run: |
+ cd meshtastic.github.io
+ find . -type f -name 'meshtasticd_*' -exec rm -f {} +
+ git config --global user.name "github-actions[bot]"
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git add .
+ git commit -m "Add firmware version ${{ steps.version.outputs.version }}"
+ git push
diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml
index ae7bf3242..0b5093f24 100644
--- a/.github/workflows/package_amd64.yml
+++ b/.github/workflows/package_amd64.yml
@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_native.yml
package-native:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
needs: build-native
steps:
- name: Checkout code
diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml
index 5471332c5..bcbda53e2 100644
--- a/.github/workflows/package_raspbian.yml
+++ b/.github/workflows/package_raspbian.yml
@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_raspbian.yml
package-raspbian:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
needs: build-raspbian
steps:
- name: Checkout code
diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml
index 5b9c9aa71..1308fe925 100644
--- a/.github/workflows/package_raspbian_armv7l.yml
+++ b/.github/workflows/package_raspbian_armv7l.yml
@@ -13,7 +13,7 @@ jobs:
uses: ./.github/workflows/build_raspbian_armv7l.yml
package-raspbian_armv7l:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
needs: build-raspbian_armv7l
steps:
- name: Checkout code
diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml
index 2a0361f5e..54bbbe6d2 100644
--- a/.github/workflows/sec_sast_semgrep_cron.yml
+++ b/.github/workflows/sec_sast_semgrep_cron.yml
@@ -12,7 +12,7 @@ jobs:
semgrep-full:
runs-on: ubuntu-latest
container:
- image: returntocorp/semgrep
+ image: semgrep/semgrep
steps:
# step 1
diff --git a/.github/workflows/sec_sast_semgrep_pull.yml b/.github/workflows/sec_sast_semgrep_pull.yml
index 2575cbf01..9013f1c74 100644
--- a/.github/workflows/sec_sast_semgrep_pull.yml
+++ b/.github/workflows/sec_sast_semgrep_pull.yml
@@ -6,7 +6,7 @@ jobs:
semgrep-diff:
runs-on: ubuntu-22.04
container:
- image: returntocorp/semgrep
+ image: semgrep/semgrep
steps:
# step 1
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f58b38ac9..bf3d15dba 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -77,7 +77,7 @@ jobs:
pio upgrade
- name: Setup pnpm
- uses: pnpm/action-setup@v2
+ uses: pnpm/action-setup@v4
with:
version: latest
diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml
index 4402a280e..7ce767370 100644
--- a/.github/workflows/update_protobufs.yml
+++ b/.github/workflows/update_protobufs.yml
@@ -1,4 +1,4 @@
-name: "Update protobufs and regenerate classes"
+name: Update protobufs and regenerate classes
on: workflow_dispatch
jobs:
@@ -26,8 +26,9 @@ jobs:
./bin/regen-protos.sh
- name: Create pull request
- uses: peter-evans/create-pull-request@v6
+ uses: peter-evans/create-pull-request@v7
with:
+ title: Update protobufs and classes
add-paths: |
protobufs
src/mesh
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index 0dd6cbc1d..13360be78 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
platform = platformio/espressif32@6.7.0
build_src_filter =
- ${arduino_base.build_src_filter} - - - - -
+ ${arduino_base.build_src_filter} - - - - -
upload_speed = 921600
debug_init_break = tbreak setup
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 503da2aab..04880d540 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -16,7 +16,7 @@ build_flags =
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
build_src_filter =
- ${arduino_base.build_src_filter} - - - - - - - - - -
+ ${arduino_base.build_src_filter} - - - - - - - - - -
lib_deps=
${arduino_base.lib_deps}
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index 482b1f9c5..30cc190d2 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
-platform = https://github.com/meshtastic/platform-native.git#ad8112adf82ce1f5b917092cf32be07a077801a0
+platform = https://github.com/meshtastic/platform-native.git#6b3796d697481c8f6e3f4aa5c111bd9979f29e64
framework = arduino
build_src_filter =
@@ -9,7 +9,7 @@ build_src_filter =
-
-
-
- -
+ -
-
-
+
diff --git a/arch/rp2040/rp2040.ini b/arch/rp2xx0/rp2040.ini
similarity index 97%
rename from arch/rp2040/rp2040.ini
rename to arch/rp2xx0/rp2040.ini
index dd3a4d7ff..d3f27a676 100644
--- a/arch/rp2040/rp2040.ini
+++ b/arch/rp2xx0/rp2040.ini
@@ -8,7 +8,7 @@ board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
- -Isrc/platform/rp2040
+ -Isrc/platform/rp2xx0
-D__PLAT_RP2040__
# -D _POSIX_THREADS
build_src_filter =
diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini
new file mode 100644
index 000000000..96ed0cb21
--- /dev/null
+++ b/arch/rp2xx0/rp2350.ini
@@ -0,0 +1,23 @@
+; Common settings for rp2040 Processor based targets
+[rp2350_base]
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672
+extends = arduino_base
+platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+
+
+board_build.core = earlephilhower
+board_build.filesystem_size = 0.5m
+build_flags =
+ ${arduino_base.build_flags} -Wno-unused-variable
+ -Isrc/platform/rp2xx0
+ -D__PLAT_RP2040__
+# -D _POSIX_THREADS
+build_src_filter =
+ ${arduino_base.build_src_filter} - - - - - - - - -
+
+lib_ignore =
+ BluetoothOTA
+
+lib_deps =
+ ${arduino_base.lib_deps}
+ ${environmental_base.lib_deps}
+ rweather/Crypto
\ No newline at end of file
diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini
index 050dbf7f0..4be290015 100644
--- a/arch/stm32/stm32.ini
+++ b/arch/stm32/stm32.ini
@@ -22,7 +22,7 @@ build_flags =
-fdata-sections
build_src_filter =
- ${arduino_base.build_src_filter} - - - - - - - - - - - - - -
+ ${arduino_base.build_src_filter} - - - - - - - - - - - - - -
board_upload.offset_address = 0x08000000
upload_protocol = stlink
diff --git a/meshtestic b/meshtestic
index 31ee3d90c..37245b3d6 160000
--- a/meshtestic
+++ b/meshtestic
@@ -1 +1 @@
-Subproject commit 31ee3d90c8bef61e835c3271be2c7cda8c4a5cc2
+Subproject commit 37245b3d612a9272f546bbb092837bafdad46bc2
diff --git a/protobufs b/protobufs
index 5709c0a05..9b8490784 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 5709c0a05eaefccbc9cb8ed3917adbf5fd134197
+Subproject commit 9b84907847b67047b72f9792f4b47532b308bbe4
diff --git a/src/Power.cpp b/src/Power.cpp
index 61a6c987d..b3a67abd5 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -13,6 +13,7 @@
#include "power.h"
#include "NodeDB.h"
#include "PowerFSM.h"
+#include "Throttle.h"
#include "buzz/buzz.h"
#include "configuration.h"
#include "main.h"
@@ -30,6 +31,7 @@
#if HAS_WIFI
#include
#endif
+
#endif
#ifndef DELAY_FOREVER
@@ -244,7 +246,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER;
// Do not call analogRead() often.
const uint32_t min_read_interval = 5000;
- if (millis() - last_read_time_ms > min_read_interval) {
+ if (!Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
last_read_time_ms = millis();
uint32_t raw = 0;
diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp
index b911e15da..2c1133771 100644
--- a/src/SerialConsole.cpp
+++ b/src/SerialConsole.cpp
@@ -1,6 +1,8 @@
#include "SerialConsole.h"
+#include "Default.h"
#include "NodeDB.h"
#include "PowerFSM.h"
+#include "Throttle.h"
#include "configuration.h"
#include "time.h"
@@ -47,7 +49,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
#if defined(ARCH_NRF52) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(ARCH_RP2040)
time_t timeout = millis();
while (!Port) {
- if ((millis() - timeout) < 5000) {
+ if (Throttle::isWithinTimespanMs(timeout, FIVE_SECONDS_MS)) {
delay(100);
} else {
break;
@@ -73,7 +75,7 @@ void SerialConsole::flush()
bool SerialConsole::checkIsConnected()
{
uint32_t now = millis();
- return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
+ return Throttle::isWithinTimespanMs(lastContactMsec, SERIAL_CONNECTION_TIMEOUT);
}
/**
diff --git a/src/configuration.h b/src/configuration.h
index 349bd2870..7416e0a3e 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -210,6 +210,16 @@ along with this program. If not, see .
#define MINIMUM_SAFE_FREE_HEAP 1500
#endif
+#ifndef WIRE_INTERFACES_COUNT
+// Officially an NRF52 macro
+// Repurposed cross-platform to identify devices using Wire1
+#if defined(I2C_SDA1) || defined(PIN_WIRE_SDA)
+#define WIRE_INTERFACES_COUNT 2
+#elif HAS_WIRE
+#define WIRE_INTERFACES_COUNT 1
+#endif
+#endif
+
/* Step #3: mop up with disabled values for HAS_ options not handled by the above two */
#ifndef HAS_WIFI
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index f09eb3b95..98f40be76 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -162,13 +162,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
Melopero_RV3028 rtc;
#endif
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
if (port == I2CPort::WIRE1) {
i2cBus = &Wire1;
} else {
#endif
i2cBus = &Wire;
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
}
#endif
@@ -423,7 +423,7 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
if (address.port == ScanI2C::I2CPort::WIRE) {
return &Wire;
} else {
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
return &Wire1;
#else
return &Wire;
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 01fa65816..4fa676913 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -6,6 +6,7 @@
#include "NodeDB.h"
#include "PowerMon.h"
#include "RTC.h"
+#include "Throttle.h"
#include "main.h" // pmu_found
#include "sleep.h"
@@ -206,7 +207,7 @@ GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMilli
// ACK-NACK| 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x00 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
// ACK-ACK | 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x01 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
- while (millis() - startTime < waitMillis) {
+ while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (_serial_gps->available()) {
buffer[bufferPos++] = _serial_gps->read();
@@ -275,7 +276,7 @@ GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
buf[9] += buf[8];
}
- while (millis() - startTime < waitMillis) {
+ while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (ack > 9) {
#ifdef GPS_DEBUG
LOG_DEBUG("\n");
@@ -332,7 +333,7 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
uint32_t startTime = millis();
uint16_t needRead;
- while (millis() - startTime < waitMillis) {
+ while (Throttle::isWithinTimespanMs(startTime, waitMillis)) {
if (_serial_gps->available()) {
int c = _serial_gps->read();
switch (ubxFrameCounter) {
@@ -525,268 +526,144 @@ bool GPS::setup()
delay(250);
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
+ } else if (gnssModel == GNSS_MODEL_UBLOX6) {
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x02, _message_DISABLE_TXT_INFO, "Unable to disable text info messages.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x39, _message_JAM_6_7, "Unable to enable interference resistance.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5, "Unable to configure NAVX5 settings.\n", 500);
- } else if (gnssModel == GNSS_MODEL_UBLOX) {
- // Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
- // We need set it because by default it is GPS only, and we want to use GLONASS too
- // Also we need SBAS for better accuracy and extra features
- // ToDo: Dynamic configure GNSS systems depending of LoRa region
+ // Turn off unwanted NMEA messages, set update rate
+ SEND_UBX_PACKET(0x06, 0x08, _message_1HZ, "Unable to set GPS update rate.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GLL, "Unable to disable NMEA GLL.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GSA, "Unable to Enable NMEA GSA.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GSV, "Unable to disable NMEA GSV.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_VTG, "Unable to disable NMEA VTG.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "Unable to enable NMEA RMC.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "Unable to enable NMEA GGA.\n", 500);
- if (strncmp(info.hwVersion, "000A0000", 8) != 0) {
- if (strncmp(info.hwVersion, "00040007", 8) != 0) {
- // The original ublox Neo-6 is GPS only and doesn't support the UBX-CFG-GNSS message
- // Max7 seems to only support GPS *or* GLONASS
- // Neo-7 is supposed to support GPS *and* GLONASS but NAKs the CFG-GNSS command to do it
- // So treat all the u-blox 7 series as GPS only
- // M8 can support 3 constallations at once so turn on GPS, GLONASS and Galileo (or BeiDou)
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_ECO, "Unable to enable powersaving ECO mode for Neo-6.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_AID, "Unable to disable UBX-AID.\n", 500);
- if (strncmp(info.hwVersion, "00070000", 8) == 0) {
- LOG_DEBUG("Setting GPS+SBAS\n");
- msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
- _serial_gps->write(UBXscratch, msglen);
- } else {
- msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_8), _message_GNSS_8);
- _serial_gps->write(UBXscratch, msglen);
- }
+ msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to save GNSS module configuration.\n");
+ } else {
+ LOG_INFO("GNSS module configuration saved!\n");
+ }
+ } else if (gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 || gnssModel == GNSS_MODEL_UBLOX9) {
+ if (gnssModel == GNSS_MODEL_UBLOX7) {
+ LOG_DEBUG("Setting GPS+SBAS\n");
+ msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_7), _message_GNSS_7);
+ _serial_gps->write(UBXscratch, msglen);
+ } else { // 8,9
+ msglen = makeUBXPacket(0x06, 0x3e, sizeof(_message_GNSS_8), _message_GNSS_8);
+ _serial_gps->write(UBXscratch, msglen);
+ }
- if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
- // It's not critical if the module doesn't acknowledge this configuration.
- LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
- } else {
- if (strncmp(info.hwVersion, "00070000", 8) == 0) {
- LOG_INFO("GNSS configured for GPS+SBAS. Pause for 0.75s before sending next command.\n");
- } else {
- LOG_INFO(
- "GNSS configured for GPS+SBAS+GLONASS+Galileo. Pause for 0.75s before sending next command.\n");
- }
- // Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
- // commands for the M8 it tends to be more... 1 sec should be enough ;>)
- delay(1000);
- }
+ if (getACK(0x06, 0x3e, 800) == GNSS_RESPONSE_NAK) {
+ // It's not critical if the module doesn't acknowledge this configuration.
+ LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
+ } else {
+ if (gnssModel == GNSS_MODEL_UBLOX7) {
+ LOG_INFO("GNSS configured for GPS+SBAS.\n");
+ } else { // 8,9
+ LOG_INFO("GNSS configured for GPS+SBAS+GLONASS+Galileo.\n");
}
- // Disable Text Info messages
- msglen = makeUBXPacket(0x06, 0x02, sizeof(_message_DISABLE_TXT_INFO), _message_DISABLE_TXT_INFO);
+ // Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
+ // commands for the M8 it tends to be more... 1 sec should be enough ;>)
+ delay(1000);
+ }
+
+ // Disable Text Info messages //6,7,8,9
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x02, _message_DISABLE_TXT_INFO, "Unable to disable text info messages.\n", 500);
+
+ if (gnssModel == GNSS_MODEL_UBLOX8) { // 8
clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x02, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable text info messages.\n");
- }
- // ToDo add M10 tests for below
- if (strncmp(info.hwVersion, "00080000", 8) == 0) {
- msglen = makeUBXPacket(0x06, 0x39, sizeof(_message_JAM_8), _message_JAM_8);
+ SEND_UBX_PACKET(0x06, 0x39, _message_JAM_8, "Unable to enable interference resistance.\n", 500);
+
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5_8, "Unable to configure NAVX5_8 settings.\n", 500);
+ } else { // 6,7,9
+ SEND_UBX_PACKET(0x06, 0x39, _message_JAM_6_7, "Unable to enable interference resistance.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x23, _message_NAVX5, "Unable to configure NAVX5 settings.\n", 500);
+ }
+ // Turn off unwanted NMEA messages, set update rate
+ SEND_UBX_PACKET(0x06, 0x08, _message_1HZ, "Unable to set GPS update rate.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GLL, "Unable to disable NMEA GLL.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GSA, "Unable to Enable NMEA GSA.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GSV, "Unable to disable NMEA GSV.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_VTG, "Unable to disable NMEA VTG.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "Unable to enable NMEA RMC.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "Unable to enable NMEA GGA.\n", 500);
+
+ if (uBloxProtocolVersion >= 18) {
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "Unable to enable powersaving for GPS.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
+
+ // For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
+ if (gnssModel == GNSS_MODEL_UBLOX8) {
clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x39, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable interference resistance.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x23, sizeof(_message_NAVX5_8), _message_NAVX5_8);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x23, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to configure NAVX5_8 settings.\n");
- }
- } else {
- msglen = makeUBXPacket(0x06, 0x39, sizeof(_message_JAM_6_7), _message_JAM_6_7);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x39, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable interference resistance.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x23, sizeof(_message_NAVX5), _message_NAVX5);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x23, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to configure NAVX5 settings.\n");
- }
- }
- // Turn off unwanted NMEA messages, set update rate
-
- msglen = makeUBXPacket(0x06, 0x08, sizeof(_message_1HZ), _message_1HZ);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x08, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to set GPS update rate.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GLL), _message_GLL);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable NMEA GLL.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GSA), _message_GSA);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to Enable NMEA GSA.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GSV), _message_GSV);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable NMEA GSV.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_VTG), _message_VTG);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable NMEA VTG.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_RMC), _message_RMC);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable NMEA RMC.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GGA), _message_GGA);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable NMEA GGA.\n");
- }
-
- if (uBloxProtocolVersion >= 18) {
- msglen = makeUBXPacket(0x06, 0x86, sizeof(_message_PMS), _message_PMS);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x86, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving for GPS.\n");
- }
- msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving details for GPS.\n");
- }
- // For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
- if (strncmp(info.hwVersion, "00080000", 8) == 0) {
- msglen = makeUBXPacket(0x06, 0x17, sizeof(_message_NMEA), _message_NMEA);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x17, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable NMEA 4.10.\n");
- }
- }
- } else {
- if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode is only for Neo-6
- msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x11, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving ECO mode for Neo-6.\n");
- }
- msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving details for GPS.\n");
- }
- msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_AID), _message_AID);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x01, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable UBX-AID.\n");
- }
- } else {
- msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x11, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving mode for GPS.\n");
- }
-
- msglen = makeUBXPacket(0x06, 0x3B, sizeof(_message_CFG_PM2), _message_CFG_PM2);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x3B, 500) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving details for GPS.\n");
- }
- }
+ SEND_UBX_PACKET(0x06, 0x17, _message_NMEA, "Unable to enable NMEA 4.10.\n", 500);
}
} else {
- // LOG_INFO("u-blox M10 hardware found.\n");
- delay(1000);
- // First disable all NMEA messages in RAM layer
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_NMEA_RAM), _message_VALSET_DISABLE_NMEA_RAM);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable NMEA messages for M10 GPS RAM.\n");
- }
- delay(250);
- // Next disable unwanted NMEA messages in BBR layer
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_NMEA_BBR), _message_VALSET_DISABLE_NMEA_BBR);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable NMEA messages for M10 GPS BBR.\n");
- }
- delay(250);
- // Disable Info txt messages in RAM layer
- msglen =
- makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_TXT_INFO_RAM), _message_VALSET_DISABLE_TXT_INFO_RAM);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable Info messages for M10 GPS RAM.\n");
- }
- delay(250);
- // Next disable Info txt messages in BBR layer
- msglen =
- makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_TXT_INFO_BBR), _message_VALSET_DISABLE_TXT_INFO_BBR);
- clearBuffer();
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable Info messages for M10 GPS BBR.\n");
- }
- // Do M10 configuration for Power Management.
-
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_PM_RAM), _message_VALSET_PM_RAM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving for M10 GPS RAM.\n");
- }
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_PM_BBR), _message_VALSET_PM_BBR);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving for M10 GPS BBR.\n");
- }
-
- delay(250);
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ITFM_RAM), _message_VALSET_ITFM_RAM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable Jamming detection M10 GPS RAM.\n");
- }
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ITFM_BBR), _message_VALSET_ITFM_BBR);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable Jamming detection M10 GPS BBR.\n");
- }
-
- // Here is where the init commands should go to do further M10 initialization.
- delay(250);
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_SBAS_RAM), _message_VALSET_DISABLE_SBAS_RAM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable SBAS M10 GPS RAM.\n");
- }
- delay(750); // will cause a receiver restart so wait a bit
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_DISABLE_SBAS_BBR), _message_VALSET_DISABLE_SBAS_BBR);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to disable SBAS M10 GPS BBR.\n");
- }
- delay(750); // will cause a receiver restart so wait a bit
- // Done with initialization, Now enable wanted NMEA messages in BBR layer so they will survive a periodic sleep.
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ENABLE_NMEA_BBR), _message_VALSET_ENABLE_NMEA_BBR);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable messages for M10 GPS BBR.\n");
- }
- delay(250);
- // Next enable wanted NMEA messages in RAM layer
- msglen = makeUBXPacket(0x06, 0x8A, sizeof(_message_VALSET_ENABLE_NMEA_RAM), _message_VALSET_ENABLE_NMEA_RAM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x8A, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable messages for M10 GPS RAM.\n");
- }
- // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
- // BBR will survive a restart, and power off for a while, but modules with small backup
- // batteries or super caps will not retain the config for a long power off time.
+ SEND_UBX_PACKET(0x06, 0x11, _message_CFG_RXM_PSM, "Unable to enable powersaving mode for GPS.\n", 500);
+ SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "Unable to enable powersaving details for GPS.\n", 500);
}
+
+ msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to save GNSS module configuration.\n");
+ } else {
+ LOG_INFO("GNSS module configuration saved!\n");
+ }
+ } else if (gnssModel == GNSS_MODEL_UBLOX10) {
+ delay(1000);
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_NMEA_RAM, "Unable to disable NMEA messages in M10 RAM.\n", 300);
+ delay(750);
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_NMEA_BBR, "Unable to disable NMEA messages in M10 BBR.\n", 300);
+ delay(750);
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_TXT_INFO_RAM,
+ "Unable to disable Info messages for M10 GPS RAM.\n", 300);
+ delay(750);
+ // Next disable Info txt messages in BBR layer
+ clearBuffer();
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_TXT_INFO_BBR,
+ "Unable to disable Info messages for M10 GPS BBR.\n", 300);
+ delay(750);
+ // Do M10 configuration for Power Management.
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_RAM, "Unable to enable powersaving for M10 GPS RAM.\n", 300);
+ delay(750);
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_PM_BBR, "Unable to enable powersaving for M10 GPS BBR.\n", 300);
+ delay(750);
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_RAM, "Unable to enable Jamming detection M10 GPS RAM.\n", 300);
+ delay(750);
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ITFM_BBR, "Unable to enable Jamming detection M10 GPS BBR.\n", 300);
+ delay(750);
+ // Here is where the init commands should go to do further M10 initialization.
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_SBAS_RAM, "Unable to disable SBAS M10 GPS RAM.\n", 300);
+ delay(750); // will cause a receiver restart so wait a bit
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_DISABLE_SBAS_BBR, "Unable to disable SBAS M10 GPS BBR.\n", 300);
+ delay(750); // will cause a receiver restart so wait a bit
+
+ // Done with initialization, Now enable wanted NMEA messages in BBR layer so they will survive a periodic sleep.
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ENABLE_NMEA_BBR, "Unable to enable messages for M10 GPS BBR.\n", 300);
+ delay(750);
+ // Next enable wanted NMEA messages in RAM layer
+ SEND_UBX_PACKET(0x06, 0x8A, _message_VALSET_ENABLE_NMEA_RAM, "Unable to enable messages for M10 GPS RAM.\n", 500);
+ delay(750);
+
+ // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
+ // BBR will survive a restart, and power off for a while, but modules with small backup
+ // batteries or super caps will not retain the config for a long power off time.
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
@@ -949,7 +826,8 @@ void GPS::setPowerPMU(bool on)
void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
{
// Abort: if not UBLOX hardware
- if (gnssModel != GNSS_MODEL_UBLOX)
+ if (!(gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
+ gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10))
return;
// If waking
@@ -972,7 +850,7 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs)
}
// Determine hardware version
- if (strncmp(info.hwVersion, "000A0000", 8) != 0) {
+ if (gnssModel == GNSS_MODEL_UBLOX10) {
// Encode the sleep time in millis into the packet
for (int i = 0; i < 4; i++)
gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8);
@@ -1031,7 +909,9 @@ void GPS::down()
// Check whether the GPS hardware is capable of GPS_SOFTSLEEP
// If not, fallback to GPS_HARDSLEEP instead
bool softsleepSupported = false;
- if (gnssModel == GNSS_MODEL_UBLOX) // U-blox is supported via PMREQ
+ // U-blox is supported via PMREQ
+ if (gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
+ gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10)
softsleepSupported = true;
#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
softsleepSupported = true;
@@ -1106,7 +986,9 @@ int32_t GPS::runOnce()
// if we have received valid NMEA claim we are connected
setConnected();
} else {
- if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) {
+ if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) &&
+ (gnssModel == GNSS_MODEL_UBLOX6 || gnssModel == GNSS_MODEL_UBLOX7 || gnssModel == GNSS_MODEL_UBLOX8 ||
+ gnssModel == GNSS_MODEL_UBLOX9 || gnssModel == GNSS_MODEL_UBLOX10)) {
// reset the GPS on next bootup
if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) {
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
@@ -1335,9 +1217,9 @@ GnssModel_t GPS::probe(int serialSpeed)
strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer));
// LOG_DEBUG("GetModel:%s\n", (char *)buffer);
if (strlen((char *)buffer)) {
- LOG_INFO("UBlox GNSS probe succeeded, using UBlox %s GNSS Module\n", (char *)buffer);
+ LOG_INFO("%s detected, using GNSS_MODEL_UBLOX\n", (char *)buffer);
} else {
- LOG_INFO("UBlox GNSS probe succeeded, using UBlox GNSS Module\n");
+ LOG_INFO("Generic Ublox detected, using GNSS_MODEL_UBLOX\n");
}
} else if (!strncmp(info.extension[i], "PROTVER", 7)) {
char *ptr = nullptr;
@@ -1352,9 +1234,20 @@ GnssModel_t GPS::probe(int serialSpeed)
}
}
}
+ if (strncmp(info.hwVersion, "00040007", 8) == 0) {
+ return GNSS_MODEL_UBLOX6;
+ } else if (strncmp(info.hwVersion, "00070000", 8) == 0) {
+ return GNSS_MODEL_UBLOX7;
+ } else if (strncmp(info.hwVersion, "00080000", 8) == 0) {
+ return GNSS_MODEL_UBLOX8;
+ } else if (strncmp(info.hwVersion, "00190000", 8) == 0) {
+ return GNSS_MODEL_UBLOX9;
+ } else if (strncmp(info.hwVersion, "000A0000", 8) == 0) {
+ return GNSS_MODEL_UBLOX10;
+ }
}
- return GNSS_MODEL_UBLOX;
+ return GNSS_MODEL_UNKNOWN;
}
GPS *GPS::createGps()
@@ -1528,16 +1421,15 @@ bool GPS::lookForTime()
#ifdef GNSS_AIROHA
uint8_t fix = reader.fixQuality();
- uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
- if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
+ if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
- lastFixStartMsec = now;
+ lastFixStartMsec = millis();
return false;
}
} else {
@@ -1581,16 +1473,15 @@ bool GPS::lookForLocation()
#ifdef GNSS_AIROHA
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
uint8_t fix = reader.fixQuality();
- uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
- if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
+ if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
- lastFixStartMsec = now;
+ lastFixStartMsec = millis();
return false;
}
} else {
@@ -1820,4 +1711,4 @@ void GPS::toggleGpsMode()
enable();
}
}
-#endif // Exclude GPS
+#endif // Exclude GPS
\ No newline at end of file
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 3423edb68..48aecc8b9 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -26,7 +26,11 @@ struct uBloxGnssModelInfo {
typedef enum {
GNSS_MODEL_ATGM336H,
GNSS_MODEL_MTK,
- GNSS_MODEL_UBLOX,
+ GNSS_MODEL_UBLOX6,
+ GNSS_MODEL_UBLOX7,
+ GNSS_MODEL_UBLOX8,
+ GNSS_MODEL_UBLOX9,
+ GNSS_MODEL_UBLOX10,
GNSS_MODEL_UC6580,
GNSS_MODEL_UNKNOWN,
GNSS_MODEL_MTK_L76B,
@@ -310,4 +314,4 @@ class GPS : private concurrency::OSThread
};
extern GPS *gps;
-#endif // Exclude GPS
+#endif // Exclude GPS
\ No newline at end of file
diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp
index 728284242..d9ac56b74 100644
--- a/src/gps/RTC.cpp
+++ b/src/gps/RTC.cpp
@@ -2,6 +2,7 @@
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h"
+#include
#include
#include
@@ -29,7 +30,7 @@ void readFromRTC()
if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
@@ -58,7 +59,7 @@ void readFromRTC()
uint32_t now = millis();
PCF8563_Class rtc;
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
@@ -127,7 +128,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
} else if (q == RTCQualityGPS) {
shouldSet = true;
LOG_DEBUG("Reapplying GPS time: %ld secs\n", printableEpoch);
- } else if (q == RTCQualityNTP && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
+ } else if (q == RTCQualityNTP && !Throttle::isWithinTimespanMs(lastSetMsec, (12 * 60 * 60 * 1000UL))) {
// Every 12 hrs we will slam in a new NTP or Phone GPS / NTP time, to correct for local RTC clock drift
shouldSet = true;
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", printableEpoch);
@@ -150,7 +151,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
#ifdef RV3028_RTC
if (rtc_found.address == RV3028_RTC) {
Melopero_RV3028 rtc;
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
@@ -164,7 +165,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
if (rtc_found.address == PCF8563_RTC) {
PCF8563_Class rtc;
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
diff --git a/src/gps/ubx.h b/src/gps/ubx.h
index 0852c331d..64e45f160 100644
--- a/src/gps/ubx.h
+++ b/src/gps/ubx.h
@@ -1,3 +1,10 @@
+#define SEND_UBX_PACKET(TYPE, ID, DATA, ERRMSG, TIMEOUT) \
+ msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \
+ _serial_gps->write(UBXscratch, msglen); \
+ if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \
+ LOG_WARN(#ERRMSG); \
+ }
+
// Power Management
uint8_t GPS::_message_PMREQ[] PROGMEM = {
diff --git a/src/graphics/EInkDynamicDisplay.cpp b/src/graphics/EInkDynamicDisplay.cpp
index c31941a60..ca994b2c9 100644
--- a/src/graphics/EInkDynamicDisplay.cpp
+++ b/src/graphics/EInkDynamicDisplay.cpp
@@ -1,3 +1,4 @@
+#include "Throttle.h"
#include "configuration.h"
#if defined(USE_EINK) && defined(USE_EINK_DYNAMICDISPLAY)
@@ -231,15 +232,13 @@ void EInkDynamicDisplay::checkForPromotion()
// Is it too soon for another frame of this type?
void EInkDynamicDisplay::checkRateLimiting()
{
- uint32_t now = millis();
-
// Sanity check: millis() overflow - just let the update run..
- if (previousRunMs > now)
+ if (previousRunMs > millis())
return;
// Skip update: too soon for BACKGROUND
if (frameFlags == BACKGROUND) {
- if (now - previousRunMs < EINK_LIMIT_RATE_BACKGROUND_SEC * 1000) {
+ if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_BACKGROUND_SEC * 1000)) {
refresh = SKIPPED;
reason = EXCEEDED_RATELIMIT_FULL;
return;
@@ -252,7 +251,7 @@ void EInkDynamicDisplay::checkRateLimiting()
// Skip update: too soon for RESPONSIVE
if (frameFlags & RESPONSIVE) {
- if (now - previousRunMs < EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000) {
+ if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000)) {
refresh = SKIPPED;
reason = EXCEEDED_RATELIMIT_FAST;
LOG_DEBUG("refresh=SKIPPED, reason=EXCEEDED_RATELIMIT_FAST, frameFlags=0x%x\n", frameFlags);
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index ae09ee408..19b20e8dc 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -22,6 +22,7 @@ along with this program. If not, see .
#include "Screen.h"
#include "../userPrefs.h"
#include "PowerMon.h"
+#include "Throttle.h"
#include "configuration.h"
#if HAS_SCREEN
#include
@@ -117,6 +118,7 @@ static bool heartbeat = false;
#define SCREEN_HEIGHT display->getHeight()
#include "graphics/ScreenFonts.h"
+#include
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
@@ -1670,6 +1672,11 @@ void Screen::setup()
static_cast(dispdev)->setSubtype(7);
#endif
+#if defined(USE_ST7789) && defined(TFT_MESH)
+ // Heltec T114 and T190: honor a custom text color, if defined in variant.h
+ static_cast(dispdev)->setRGB(TFT_MESH);
+#endif
+
// Initialising the UI will init the display too.
ui->init();
@@ -1726,6 +1733,8 @@ void Screen::setup()
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
defined(RAK14014) || defined(HX8357_CS)
static_cast(dispdev)->flipScreenVertically();
+#elif defined(USE_ST7789)
+ static_cast(dispdev)->flipScreenVertically();
#else
dispdev->flipScreenVertically();
#endif
@@ -1942,7 +1951,7 @@ int32_t Screen::runOnce()
if (showingNormalScreen) {
// standard screen loop handling here
if (config.display.auto_screen_carousel_secs > 0 &&
- (millis() - lastScreenTransition) > (config.display.auto_screen_carousel_secs * 1000)) {
+ !Throttle::isWithinTimespanMs(lastScreenTransition, config.display.auto_screen_carousel_secs * 1000)) {
// If an E-Ink display struggles with fast refresh, force carousel to use full refresh instead
// Carousel is potentially a major source of E-Ink display wear
@@ -2435,8 +2444,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
if (moduleConfig.store_forward.enabled) {
#ifdef ARCH_ESP32
- if (millis() - storeForwardModule->lastHeartbeat >
- (storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
+ if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
+ (storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || \
defined(USE_ST7789) || defined(HX8357_CS)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
diff --git a/src/input/ExpressLRSFiveWay.cpp b/src/input/ExpressLRSFiveWay.cpp
index c444800ba..af4433dae 100644
--- a/src/input/ExpressLRSFiveWay.cpp
+++ b/src/input/ExpressLRSFiveWay.cpp
@@ -1,5 +1,5 @@
-
#include "ExpressLRSFiveWay.h"
+#include "Throttle.h"
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
@@ -76,11 +76,10 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
*keyValue = NO_PRESS;
int newKey = readKey();
- uint32_t now = millis();
if (keyInProcess == NO_PRESS) {
// New key down
if (newKey != NO_PRESS) {
- keyDownStart = now;
+ keyDownStart = millis();
// DBGLN("down=%u", newKey);
}
} else {
@@ -88,7 +87,7 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
if (newKey == NO_PRESS) {
// DBGLN("up=%u", keyInProcess);
if (!isLongPressed) {
- if ((now - keyDownStart) > KEY_DEBOUNCE_MS) {
+ if (!Throttle::isWithinTimespanMs(keyDownStart, KEY_DEBOUNCE_MS)) {
*keyValue = keyInProcess;
*keyLongPressed = false;
}
@@ -101,7 +100,7 @@ void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed)
}
// else still pressing, waiting for long if not already signaled
else if (!isLongPressed) {
- if ((now - keyDownStart) > KEY_LONG_PRESS_MS) {
+ if (!Throttle::isWithinTimespanMs(keyDownStart, KEY_LONG_PRESS_MS)) {
*keyValue = keyInProcess;
*keyLongPressed = true;
isLongPressed = true;
diff --git a/src/input/ScanAndSelect.cpp b/src/input/ScanAndSelect.cpp
index d693d768c..65ca7e332 100644
--- a/src/input/ScanAndSelect.cpp
+++ b/src/input/ScanAndSelect.cpp
@@ -6,6 +6,7 @@
#include "ScanAndSelect.h"
#include "modules/CannedMessageModule.h"
+#include
// Config
static const char name[] = "scanAndSelect"; // should match "allow input source" string
@@ -75,7 +76,7 @@ int32_t ScanAndSelectInput::runOnce()
else {
// Duration enough for long press
// Long press not yet fired (prevent repeat firing while held)
- if (!longPressFired && now - downSinceMs > durationLongMs) {
+ if (!longPressFired && Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
longPressFired = true;
longPress();
}
@@ -91,7 +92,7 @@ int32_t ScanAndSelectInput::runOnce()
// Long press event didn't already fire
if (held && !longPressFired) {
// Duration enough for short press
- if (now - downSinceMs > durationShortMs) {
+ if (!Throttle::isWithinTimespanMs(downSinceMs, durationShortMs)) {
shortPress();
}
}
diff --git a/src/input/SerialKeyboard.cpp b/src/input/SerialKeyboard.cpp
index 7b7a2f3ec..4827e8995 100644
--- a/src/input/SerialKeyboard.cpp
+++ b/src/input/SerialKeyboard.cpp
@@ -1,5 +1,6 @@
#include "SerialKeyboard.h"
#include "configuration.h"
+#include
#ifdef INPUTBROKER_SERIAL_TYPE
#define CANNED_MESSAGE_MODULE_ENABLE 1 // in case it's not set in the variant file
@@ -73,7 +74,7 @@ int32_t SerialKeyboard::runOnce()
// Serial.print ("X");
// Serial.println (shiftRegister2, BIN);
- if (millis() - lastPressTime > 500) {
+ if (!Throttle::isWithinTimespanMs(lastPressTime, 500)) {
quickPress = 0;
}
diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp
index 8aaebcb45..f1df6b137 100644
--- a/src/input/cardKbI2cImpl.cpp
+++ b/src/input/cardKbI2cImpl.cpp
@@ -16,7 +16,7 @@ void CardKbI2cImpl::init()
uint8_t i2caddr_asize = 3;
auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire());
-#if defined(I2C_SDA1)
+#if WIRE_INTERFACES_COUNT == 2
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize);
#endif
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize);
diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp
index 2692fc80d..1d8154bcf 100644
--- a/src/input/kbI2cBase.cpp
+++ b/src/input/kbI2cBase.cpp
@@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce()
if (!i2cBus) {
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
-#ifdef I2C_SDA1
+#if WIRE_INTERFACES_COUNT == 2
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
diff --git a/src/main.cpp b/src/main.cpp
index e24ba68b3..01fccf2b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,6 +18,7 @@
#include "Led.h"
#include "RTC.h"
#include "SPILock.h"
+#include "Throttle.h"
#include "concurrency/OSThread.h"
#include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
@@ -360,6 +361,8 @@ void setup()
Wire1.begin();
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1);
+#elif WIRE_INTERFACES_COUNT == 2
+ Wire1.begin();
#endif
#if defined(I2C_SDA) && defined(ARCH_RP2040)
@@ -427,6 +430,8 @@ void setup()
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
Wire1.begin(I2C_SDA1, I2C_SCL1);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
+#elif defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2)
+ i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#endif
#if defined(I2C_SDA) && defined(ARCH_RP2040)
@@ -1118,7 +1123,7 @@ void loop()
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
- if (millis() - lastPrint > 10 * 1000L) {
+ if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {
lastPrint = millis();
meshtastic::printThreadInfo("main");
}
diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp
index c0742f241..e237c354f 100644
--- a/src/mesh/LR11x0Interface.cpp
+++ b/src/mesh/LR11x0Interface.cpp
@@ -1,7 +1,9 @@
#include "LR11x0Interface.h"
+#include "Throttle.h"
#include "configuration.h"
#include "error.h"
#include "mesh/NodeDB.h"
+
#ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h"
#endif
@@ -275,15 +277,15 @@ template bool LR11x0Interface::isActivelyReceiving()
bool detected = (irq & (RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
// Handle false detections
if (detected) {
- uint32_t now = millis();
if (!activeReceiveStart) {
- activeReceiveStart = now;
- } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID)) {
+ activeReceiveStart = millis();
+ } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
+ !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection.\n");
return false;
- } else if (now - activeReceiveStart > maxPacketTimeMsec) {
+ } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection.\n");
diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp
index 26a73a3fe..ed1c3c59c 100644
--- a/src/mesh/PacketHistory.cpp
+++ b/src/mesh/PacketHistory.cpp
@@ -5,6 +5,7 @@
#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
+#include "Throttle.h"
PacketHistory::PacketHistory()
{
@@ -22,18 +23,17 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
return false; // Not a floodable message ID, so we don't care
}
- uint32_t now = millis();
-
PacketRecord r;
r.id = p->id;
r.sender = getFrom(p);
- r.rxTimeMsec = now;
+ r.rxTimeMsec = millis();
auto found = recentPackets.find(r);
bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently
- if (seenRecently && (now - found->rxTimeMsec) >= FLOOD_EXPIRE_TIME) { // Check whether found packet has already expired
- recentPackets.erase(found); // Erase and pretend packet has not been seen recently
+ if (seenRecently &&
+ !Throttle::isWithinTimespanMs(found->rxTimeMsec, FLOOD_EXPIRE_TIME)) { // Check whether found packet has already expired
+ recentPackets.erase(found); // Erase and pretend packet has not been seen recently
found = recentPackets.end();
seenRecently = false;
}
@@ -64,12 +64,10 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
*/
void PacketHistory::clearExpiredRecentPackets()
{
- uint32_t now = millis();
-
LOG_DEBUG("recentPackets size=%ld\n", recentPackets.size());
for (auto it = recentPackets.begin(); it != recentPackets.end();) {
- if ((now - it->rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
+ if (!Throttle::isWithinTimespanMs(it->rxTimeMsec, FLOOD_EXPIRE_TIME)) {
it = recentPackets.erase(it); // erase returns iterator pointing to element immediately following the one erased
} else {
++it;
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 121687c49..2ed7a69db 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -25,6 +25,7 @@
#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
#endif
+#include "Throttle.h"
#include
PhoneAPI::PhoneAPI()
@@ -561,12 +562,12 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
{
printPacket("PACKET FROM PHONE", &p);
if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] &&
- (millis() - lastPortNumToRadio[p.decoded.portnum]) < (THIRTY_SECONDS_MS)) {
+ Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) {
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "TraceRoute can only be sent once every 30 seconds");
return false;
} else if (p.decoded.portnum == meshtastic_PortNum_POSITION_APP && lastPortNumToRadio[p.decoded.portnum] &&
- (millis() - lastPortNumToRadio[p.decoded.portnum]) < (FIVE_SECONDS_MS)) {
+ Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], FIVE_SECONDS_MS)) {
LOG_WARN("Rate limiting portnum %d\n", p.decoded.portnum);
sendNotification(meshtastic_LogRecord_Level_WARNING, p.id, "Position can only be sent once every 5 seconds");
return false;
diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h
index f1016e3d8..d0d20926c 100644
--- a/src/mesh/RadioInterface.h
+++ b/src/mesh/RadioInterface.h
@@ -10,6 +10,7 @@
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
#define MAX_RHPACKETLEN 256
+#define LORA_HEADER_LENGTH 16
#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index f299ebff2..6cdb3b99e 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -3,6 +3,7 @@
#include "NodeDB.h"
#include "PowerMon.h"
#include "SPILock.h"
+#include "Throttle.h"
#include "configuration.h"
#include "error.h"
#include "main.h"
@@ -41,7 +42,7 @@ void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
uint32_t start = millis();
while (digitalRead(busy)) {
- if (millis() - start >= 2000) {
+ if (!Throttle::isWithinTimespanMs(start, 2000)) {
LOG_ERROR("GPIO mid-transfer timeout, is it connected?");
return;
}
@@ -114,7 +115,7 @@ bool RadioLibInterface::canSendImmediately()
}
// If we've been trying to send the same packet more than one minute and we haven't gotten a
// TX IRQ from the radio, the radio is probably broken.
- if (busyTx && (millis() - lastTxStart > 60000)) {
+ if (busyTx && !Throttle::isWithinTimespanMs(lastTxStart, 60000)) {
LOG_ERROR("Hardware Failure! busyTx for more than 60s\n");
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_TRANSMIT_FAILED);
// reboot in 5 seconds when this condition occurs.
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 3cf30519b..a6b946761 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -475,7 +475,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
}
} */
- if (numbytes > MAX_RHPACKETLEN)
+ if (numbytes + LORA_HEADER_LENGTH > MAX_RHPACKETLEN)
return meshtastic_Routing_Error_TOO_LARGE;
// printBytes("plaintext", bytes, numbytes);
@@ -499,7 +499,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
p->decoded.portnum != meshtastic_PortNum_TRACEROUTE_APP && p->decoded.portnum != meshtastic_PortNum_NODEINFO_APP &&
p->decoded.portnum != meshtastic_PortNum_ROUTING_APP && p->decoded.portnum != meshtastic_PortNum_POSITION_APP) {
LOG_DEBUG("Using PKI!\n");
- if (numbytes + 12 > MAX_RHPACKETLEN)
+ if (numbytes + LORA_HEADER_LENGTH + 12 > MAX_RHPACKETLEN)
return meshtastic_Routing_Error_TOO_LARGE;
if (p->pki_encrypted && !memfll(p->public_key.bytes, 0, 32) &&
memcmp(p->public_key.bytes, node->user.public_key.bytes, 32) != 0) {
diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp
index 6d23206bd..2c6096062 100644
--- a/src/mesh/SX126xInterface.cpp
+++ b/src/mesh/SX126xInterface.cpp
@@ -6,6 +6,8 @@
#include "PortduinoGlue.h"
#endif
+#include "Throttle.h"
+
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
// specified (may be dangerous if using external PA and SX126x power config forgotten)
#ifndef SX126X_MAX_POWER
@@ -319,15 +321,15 @@ template bool SX126xInterface::isActivelyReceiving()
bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED));
// Handle false detections
if (detected) {
- uint32_t now = millis();
if (!activeReceiveStart) {
- activeReceiveStart = now;
- } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID)) {
+ activeReceiveStart = millis();
+ } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
+ !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection.\n");
return false;
- } else if (now - activeReceiveStart > maxPacketTimeMsec) {
+ } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection.\n");
@@ -359,4 +361,4 @@ template bool SX126xInterface::sleep()
#endif
return true;
-}
+}
\ No newline at end of file
diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp
index 9ff9ac2d7..270356e26 100644
--- a/src/mesh/SX128xInterface.cpp
+++ b/src/mesh/SX128xInterface.cpp
@@ -1,4 +1,5 @@
#include "SX128xInterface.h"
+#include "Throttle.h"
#include "configuration.h"
#include "error.h"
#include "mesh/NodeDB.h"
@@ -294,15 +295,15 @@ template bool SX128xInterface::isActivelyReceiving()
// Handle false detections
if (detected) {
- uint32_t now = millis();
if (!activeReceiveStart) {
- activeReceiveStart = now;
- } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID)) {
+ activeReceiveStart = millis();
+ } else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) &&
+ !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection.\n");
return false;
- } else if (now - activeReceiveStart > maxPacketTimeMsec) {
+ } else if (Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection.\n");
diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp
index 9f59aa971..c3d85ed33 100644
--- a/src/mesh/StreamAPI.cpp
+++ b/src/mesh/StreamAPI.cpp
@@ -1,6 +1,7 @@
#include "StreamAPI.h"
#include "PowerFSM.h"
#include "RTC.h"
+#include "Throttle.h"
#include "configuration.h"
#define START1 0x94
@@ -20,10 +21,9 @@ int32_t StreamAPI::runOncePart()
*/
int32_t StreamAPI::readStream()
{
- uint32_t now = millis();
if (!stream->available()) {
// Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
- bool recentRx = (now - lastRxMsec) < 2000;
+ bool recentRx = Throttle::isWithinTimespanMs(lastRxMsec, 2000);
return recentRx ? 5 : 250;
} else {
while (stream->available()) { // Currently we never want to block
@@ -71,7 +71,7 @@ int32_t StreamAPI::readStream()
}
// we had bytes available this time, so assume we might have them next time also
- lastRxMsec = now;
+ lastRxMsec = millis();
return 0;
}
}
diff --git a/src/mesh/Throttle.cpp b/src/mesh/Throttle.cpp
index d8f23f9dc..f278cc843 100644
--- a/src/mesh/Throttle.cpp
+++ b/src/mesh/Throttle.cpp
@@ -24,4 +24,12 @@ bool Throttle::execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, vo
onDefer();
}
return false;
+}
+
+/// @brief Check if the last execution time is within the interval
+/// @param lastExecutionMs The last execution time in milliseconds
+/// @param timeSpanMs The interval in milliseconds of the timespan
+bool Throttle::isWithinTimespanMs(uint32_t lastExecutionMs, uint32_t timeSpanMs)
+{
+ return (millis() - lastExecutionMs) < timeSpanMs;
}
\ No newline at end of file
diff --git a/src/mesh/Throttle.h b/src/mesh/Throttle.h
index 8115595a4..8b4bb5d30 100644
--- a/src/mesh/Throttle.h
+++ b/src/mesh/Throttle.h
@@ -6,4 +6,5 @@ class Throttle
{
public:
static bool execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, void (*func)(void), void (*onDefer)(void) = NULL);
+ static bool isWithinTimespanMs(uint32_t lastExecutionMs, uint32_t intervalMs);
};
\ No newline at end of file
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index 921dfa55b..aa83ff27a 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -71,6 +71,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_RAK2560 = 22,
/* Heltec HRU-3601: https://heltec.org/project/hru-3601/ */
meshtastic_HardwareModel_HELTEC_HRU_3601 = 23,
+ /* Heltec Wireless Bridge */
+ meshtastic_HardwareModel_HELTEC_WIRELESS_BRIDGE = 24,
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
meshtastic_HardwareModel_STATION_G1 = 25,
/* RAK11310 (RP2040 + SX1262) */
@@ -199,6 +201,8 @@ typedef enum _meshtastic_HardwareModel {
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */
meshtastic_HardwareModel_M5STACK_COREBASIC = 77,
meshtastic_HardwareModel_M5STACK_CORE2 = 78,
+ /* Pico2 with Waveshare Hat, same as Pico */
+ meshtastic_HardwareModel_RPI_PICO2 = 79,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp
index 07b03222e..d1169dc3b 100644
--- a/src/mesh/wifi/WiFiAPClient.cpp
+++ b/src/mesh/wifi/WiFiAPClient.cpp
@@ -23,6 +23,7 @@ static void WiFiEvent(WiFiEvent_t event);
#endif
#ifndef DISABLE_NTP
+#include "Throttle.h"
#include
#endif
@@ -142,7 +143,7 @@ static int32_t reconnectWiFi()
}
#ifndef DISABLE_NTP
- if (WiFi.isConnected() && (((millis() - lastrun_ntp) > 43200000) || (lastrun_ntp == 0))) { // every 12 hours
+ if (WiFi.isConnected() && (!Throttle::isWithinTimespanMs(lastrun_ntp, 43200000) || (lastrun_ntp == 0))) { // every 12 hours
LOG_DEBUG("Updating NTP time from %s\n", config.network.ntp_server);
if (timeClient.update()) {
LOG_DEBUG("NTP Request Success - Setting RTCQualityNTP if needed\n");
@@ -420,4 +421,4 @@ uint8_t getWifiDisconnectReason()
{
return wifiDisconnectReason;
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 87a3e8927..a1b9c4dc0 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -27,6 +27,7 @@
#endif
#include "graphics/ScreenFonts.h"
+#include
// Remove Canned message screen if no action is taken for some milliseconds
#define INACTIVATE_AFTER_MS 20000
@@ -422,7 +423,7 @@ int32_t CannedMessageModule::runOnce()
this->notifyObservers(&e);
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) &&
- ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
+ !Throttle::isWithinTimespanMs(this->lastTouchMillis, INACTIVATE_AFTER_MS)) {
// Reset module
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->currentMessageIndex = -1;
diff --git a/src/modules/DetectionSensorModule.cpp b/src/modules/DetectionSensorModule.cpp
index 20aa6d8e9..de782b2ba 100644
--- a/src/modules/DetectionSensorModule.cpp
+++ b/src/modules/DetectionSensorModule.cpp
@@ -5,6 +5,7 @@
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"
+#include
DetectionSensorModule *detectionSensorModule;
#define GPIO_POLLING_INTERVAL 100
diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp
index 218fb8801..a3a3b9bb4 100644
--- a/src/modules/NeighborInfoModule.cpp
+++ b/src/modules/NeighborInfoModule.cpp
@@ -3,6 +3,7 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
+#include
NeighborInfoModule *neighborInfoModule;
@@ -87,7 +88,8 @@ void NeighborInfoModule::cleanUpNeighbors()
NodeNum my_node_id = nodeDB->getNodeNum();
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
- if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
+ if (!Throttle::isWithinTimespanMs(it->last_rx_time, it->node_broadcast_interval_secs * 2) &&
+ (it->node_id != my_node_id)) {
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", it->node_id);
it = std::vector::reverse_iterator(
neighbors.erase(std::next(it).base())); // Erase the element and update the iterator
diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp
index cb047a4dc..41f008fb0 100644
--- a/src/modules/NodeInfoModule.cpp
+++ b/src/modules/NodeInfoModule.cpp
@@ -6,6 +6,7 @@
#include "Router.h"
#include "configuration.h"
#include "main.h"
+#include
NodeInfoModule *nodeInfoModule;
@@ -67,13 +68,12 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
LOG_DEBUG("Skip sending NodeInfo due to > 40 percent channel util.\n");
return NULL;
}
- uint32_t now = millis();
// If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway.
- if (!shorterTimeout && lastSentToMesh && (now - lastSentToMesh) < (5 * 60 * 1000)) {
+ if (!shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 5 * 60 * 1000)) {
LOG_DEBUG("Skip sending NodeInfo since we just sent it less than 5 minutes ago.\n");
ignoreRequest = true; // Mark it as ignored for MeshModule
return NULL;
- } else if (shorterTimeout && lastSentToMesh && (now - lastSentToMesh) < (60 * 1000)) {
+ } else if (shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 60 * 1000)) {
LOG_DEBUG("Skip sending actively requested NodeInfo since we just sent it less than 60 seconds ago.\n");
ignoreRequest = true; // Mark it as ignored for MeshModule
return NULL;
@@ -82,7 +82,7 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
meshtastic_User &u = owner;
LOG_INFO("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
- lastSentToMesh = now;
+ lastSentToMesh = millis();
return allocDataProtobuf(u);
}
}
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index cb6a58b2e..4ba09385d 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -145,7 +145,7 @@ void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal, bool forceUp
bool PositionModule::hasQualityTimesource()
{
bool setFromPhoneOrNtpToday =
- lastSetFromPhoneNtpOrGps == 0 ? false : (millis() - lastSetFromPhoneNtpOrGps) <= (SEC_PER_DAY * 1000UL);
+ lastSetFromPhoneNtpOrGps == 0 ? false : Throttle::isWithinTimespanMs(lastSetFromPhoneNtpOrGps, SEC_PER_DAY * 1000UL);
#if MESHTASTIC_EXCLUDE_GPS
bool hasGpsOrRtc = (rtc_found.address != ScanI2C::ADDRESS_NONE.address);
#else
diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp
index 4c9f0df88..48159ba54 100644
--- a/src/modules/PowerStressModule.cpp
+++ b/src/modules/PowerStressModule.cpp
@@ -9,6 +9,7 @@
#include "main.h"
#include "sleep.h"
#include "target_specific.h"
+#include
extern void printInfo();
@@ -114,7 +115,7 @@ int32_t PowerStressModule::runOnce()
break;
case meshtastic_PowerStressMessage_Opcode_CPU_FULLON: {
uint32_t start_msec = millis();
- while ((millis() - start_msec) < (uint32_t)sleep_msec)
+ while (Throttle::isWithinTimespanMs(start_msec, sleep_msec))
; // Don't let CPU idle at all
sleep_msec = 0; // we already slept
break;
diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp
index 8154a661e..b02494ef3 100644
--- a/src/modules/RangeTestModule.cpp
+++ b/src/modules/RangeTestModule.cpp
@@ -19,6 +19,7 @@
#include "configuration.h"
#include "gps/GeoCoord.h"
#include
+#include
RangeTestModule *rangeTestModule;
RangeTestModuleRadio *rangeTestModuleRadio;
@@ -79,7 +80,7 @@ int32_t RangeTestModule::runOnce()
}
// If we have been running for more than 8 hours, turn module back off
- if (millis() - started > 28800000) {
+ if (!Throttle::isWithinTimespanMs(started, 28800000)) {
LOG_INFO("Range Test Module - Disabling after 8 hours\n");
return disable();
} else {
diff --git a/src/modules/RemoteHardwareModule.cpp b/src/modules/RemoteHardwareModule.cpp
index 0242b59bc..f6b8b2e90 100644
--- a/src/modules/RemoteHardwareModule.cpp
+++ b/src/modules/RemoteHardwareModule.cpp
@@ -5,6 +5,7 @@
#include "Router.h"
#include "configuration.h"
#include "main.h"
+#include
#define NUM_GPIOS 64
@@ -118,11 +119,10 @@ bool RemoteHardwareModule::handleReceivedProtobuf(const meshtastic_MeshPacket &r
int32_t RemoteHardwareModule::runOnce()
{
if (moduleConfig.remote_hardware.enabled && watchGpios) {
- uint32_t now = millis();
- if (now - lastWatchMsec >= WATCH_INTERVAL_MSEC) {
+ if (!Throttle::isWithinTimespanMs(lastWatchMsec, WATCH_INTERVAL_MSEC)) {
uint64_t curVal = digitalReads(watchGpios);
- lastWatchMsec = now;
+ lastWatchMsec = millis();
if (curVal != previousWatch) {
previousWatch = curVal;
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index f0ba64f65..a4dbb072f 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -7,6 +7,7 @@
#include "Router.h"
#include "configuration.h"
#include
+#include
/*
SerialModule
@@ -97,8 +98,7 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
*/
bool SerialModule::checkIsConnected()
{
- uint32_t now = millis();
- return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
+ return Throttle::isWithinTimespanMs(lastContactMsec, SERIAL_CONNECTION_TIMEOUT);
}
int32_t SerialModule::runOnce()
@@ -182,13 +182,13 @@ int32_t SerialModule::runOnce()
return runOncePart();
} else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA) && HAS_GPS) {
// in NMEA mode send out GGA every 2 seconds, Don't read from Port
- if (millis() - lastNmeaTime > 2000) {
+ if (!Throttle::isWithinTimespanMs(lastNmeaTime, 2000)) {
lastNmeaTime = millis();
printGGA(outbuf, sizeof(outbuf), localPosition);
serialPrint->printf("%s", outbuf);
}
} else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO) && HAS_GPS) {
- if (millis() - lastNmeaTime > 10000) {
+ if (!Throttle::isWithinTimespanMs(lastNmeaTime, 10000)) {
lastNmeaTime = millis();
uint32_t readIndex = 0;
const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex);
@@ -500,7 +500,7 @@ void SerialModule::processWXSerial()
LOG_INFO("WS85 : %i %.1fg%.1f %.1fv %.1fv\n", atoi(windDir), strtof(windVel, nullptr), strtof(windGust, nullptr),
batVoltageF, capVoltageF);
}
- if (gotwind && millis() - lastAveraged > averageIntervalMillis) {
+ if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis)) {
// calulate averages and send to the mesh
float velAvg = 1.0 * velSum / velCount;
diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp
index 56d308cfa..0b6be1b7e 100644
--- a/src/modules/Telemetry/AirQualityTelemetry.cpp
+++ b/src/modules/Telemetry/AirQualityTelemetry.cpp
@@ -12,6 +12,7 @@
#include "Router.h"
#include "detect/ScanI2CTwoWire.h"
#include "main.h"
+#include
int32_t AirQualityTelemetryModule::runOnce()
{
@@ -60,15 +61,14 @@ int32_t AirQualityTelemetryModule::runOnce()
if (!moduleConfig.telemetry.air_quality_enabled)
return disable();
- uint32_t now = millis();
if (((lastSentToMesh == 0) ||
- ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
- default_telemetry_broadcast_interval_secs,
- numOnlineNodes))) &&
+ !Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
+ moduleConfig.telemetry.air_quality_interval,
+ default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
- lastSentToMesh = now;
+ lastSentToMesh = millis();
} else if (service->isToPhoneQueueEmpty()) {
// Just send to phone when it's not our time to send to mesh yet
// Only send while queue is empty (phone assumed connected)
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 31cb2f838..f94f7956b 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -64,6 +64,7 @@ T1000xSensor t1000xSensor;
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
#include "graphics/ScreenFonts.h"
+#include
int32_t EnvironmentTelemetryModule::runOnce()
{
@@ -155,21 +156,20 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = bme680Sensor.runTrigger();
}
- uint32_t now = millis();
if (((lastSentToMesh == 0) ||
- ((now - lastSentToMesh) >=
- Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.environment_update_interval,
- default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
+ !Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
+ moduleConfig.telemetry.environment_update_interval,
+ default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
- lastSentToMesh = now;
- } else if (((lastSentToPhone == 0) || ((now - lastSentToPhone) >= sendToPhoneIntervalMs)) &&
+ lastSentToMesh = millis();
+ } else if (((lastSentToPhone == 0) || !Throttle::isWithinTimespanMs(lastSentToPhone, sendToPhoneIntervalMs)) &&
(service->isToPhoneQueueEmpty())) {
// Just send to phone when it's not our time to send to mesh yet
// Only send while queue is empty (phone assumed connected)
sendTelemetry(NODENUM_BROADCAST, true);
- lastSentToPhone = now;
+ lastSentToPhone = millis();
}
}
return min(sendToPhoneIntervalMs, result);
diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp
index 318acf456..a493042a0 100644
--- a/src/modules/Telemetry/PowerTelemetry.cpp
+++ b/src/modules/Telemetry/PowerTelemetry.cpp
@@ -19,6 +19,7 @@
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
#include "graphics/ScreenFonts.h"
+#include
int32_t PowerTelemetryModule::runOnce()
{
@@ -69,20 +70,19 @@ int32_t PowerTelemetryModule::runOnce()
if (!moduleConfig.telemetry.power_measurement_enabled)
return disable();
- uint32_t now = millis();
if (((lastSentToMesh == 0) ||
- ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.power_update_interval,
- default_telemetry_broadcast_interval_secs,
- numOnlineNodes))) &&
+ !Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
+ moduleConfig.telemetry.power_update_interval,
+ default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
- lastSentToMesh = now;
- } else if (((lastSentToPhone == 0) || ((now - lastSentToPhone) >= sendToPhoneIntervalMs)) &&
+ lastSentToMesh = millis();
+ } else if (((lastSentToPhone == 0) || !Throttle::isWithinTimespanMs(lastSentToPhone, sendToPhoneIntervalMs)) &&
(service->isToPhoneQueueEmpty())) {
// Just send to phone when it's not our time to send to mesh yet
// Only send while queue is empty (phone assumed connected)
sendTelemetry(NODENUM_BROADCAST, true);
- lastSentToPhone = now;
+ lastSentToPhone = millis();
}
}
return min(sendToPhoneIntervalMs, result);
diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
index d7dcbd09f..59f310a24 100644
--- a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
@@ -7,6 +7,7 @@
#include "NAU7802Sensor.h"
#include "SafeFile.h"
#include "TelemetrySensor.h"
+#include
#include
#include
@@ -40,7 +41,7 @@ bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement)
uint32_t start = millis();
while (!nau7802.available()) {
delay(100);
- if (millis() - start > 1000) {
+ if (!Throttle::isWithinTimespanMs(start, 1000)) {
nau7802.powerDown();
return false;
}
diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp
index c696d342a..51ec2a942 100644
--- a/src/modules/esp32/StoreForwardModule.cpp
+++ b/src/modules/esp32/StoreForwardModule.cpp
@@ -17,6 +17,7 @@
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
+#include "Throttle.h"
#include "airtime.h"
#include "configuration.h"
#include "memGet.h"
@@ -29,6 +30,9 @@
StoreForwardModule *storeForwardModule;
+uint32_t lastHeartbeat = 0;
+uint32_t heartbeatInterval = 60; // Default to 60 seconds, adjust as needed
+
int32_t StoreForwardModule::runOnce()
{
#ifdef ARCH_ESP32
@@ -42,7 +46,7 @@ int32_t StoreForwardModule::runOnce()
this->busy = false;
}
}
- } else if (this->heartbeat && (millis() - lastHeartbeat > (heartbeatInterval * 1000)) &&
+ } else if (this->heartbeat && (!Throttle::isWithinTimespanMs(lastHeartbeat, heartbeatInterval * 1000)) &&
airTime->isTxAllowedChannelUtil(true)) {
lastHeartbeat = millis();
LOG_INFO("*** Sending heartbeat\n");
@@ -127,7 +131,7 @@ uint32_t StoreForwardModule::getNumAvailablePackets(NodeNum dest, uint32_t last_
{
uint32_t count = 0;
if (lastRequest.find(dest) == lastRequest.end()) {
- lastRequest[dest] = 0;
+ lastRequest.emplace(dest, 0);
}
for (uint32_t i = lastRequest[dest]; i < this->packetHistoryTotalCount; i++) {
if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) {
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 0f4c5a8c5..56af9f663 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -21,6 +21,7 @@
#include "Default.h"
#include "serialization/JSON.h"
#include "serialization/MeshPacketSerializer.h"
+#include
#include
const int reconnectMax = 5;
@@ -158,7 +159,22 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
meshtastic_MeshPacket *p = packetPool.allocCopy(*e.packet);
p->via_mqtt = true; // Mark that the packet was received via MQTT
+ if (p->from == 0 || p->from == nodeDB->getNodeNum()) {
+ LOG_INFO("Ignoring downlink message we originally sent.\n");
+ packetPool.release(p);
+ return;
+ }
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ if (moduleConfig.mqtt.encryption_enabled) {
+ LOG_INFO("Ignoring decoded message on MQTT, encryption is enabled.\n");
+ packetPool.release(p);
+ return;
+ }
+ if (p->decoded.portnum == meshtastic_PortNum_ADMIN_APP) {
+ LOG_INFO("Ignoring decoded admin packet.\n");
+ packetPool.release(p);
+ return;
+ }
p->channel = ch.index;
}
@@ -595,7 +611,7 @@ void MQTT::perhapsReportToMap()
if (!moduleConfig.mqtt.map_reporting_enabled || !(moduleConfig.mqtt.proxy_to_client_enabled || isConnectedDirectly()))
return;
- if (millis() - last_report_to_map < map_publish_interval_msecs) {
+ if (Throttle::isWithinTimespanMs(last_report_to_map, map_publish_interval_msecs)) {
return;
} else {
if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) {
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index 93630aa8a..90c4c392d 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -76,6 +76,8 @@
#ifdef HELTEC_V2_1
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_V2_1
#endif
+#elif defined(HELTEC_WIRELESS_BRIDGE)
+#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_BRIDGE
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_V1
#elif defined(TLORA_V1)
diff --git a/src/platform/rp2040/architecture.h b/src/platform/rp2xx0/architecture.h
similarity index 90%
rename from src/platform/rp2040/architecture.h
rename to src/platform/rp2xx0/architecture.h
index 3f75735d3..8c7dfc0cd 100644
--- a/src/platform/rp2040/architecture.h
+++ b/src/platform/rp2xx0/architecture.h
@@ -23,6 +23,8 @@
#if defined(RPI_PICO)
#define HW_VENDOR meshtastic_HardwareModel_RPI_PICO
+#elif defined(RPI_PICO2)
+#define HW_VENDOR meshtastic_HardwareModel_RPI_PICO2
#elif defined(RAK11310)
#define HW_VENDOR meshtastic_HardwareModel_RAK11310
#elif defined(SENSELORA_RP2040)
diff --git a/src/platform/rp2040/main-rp2040.cpp b/src/platform/rp2xx0/main-rp2xx0.cpp
similarity index 100%
rename from src/platform/rp2040/main-rp2040.cpp
rename to src/platform/rp2xx0/main-rp2xx0.cpp
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 27e81ce54..f32d24caa 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -5,6 +5,7 @@
#endif
#include "ButtonThread.h"
+#include "Default.h"
#include "Led.h"
#include "MeshRadio.h"
#include "MeshService.h"
@@ -28,6 +29,7 @@
esp_sleep_source_t wakeCause; // the reason we booted this time
#endif
+#include "Throttle.h"
#ifndef INCLUDE_vTaskSuspend
#define INCLUDE_vTaskSuspend 0
@@ -168,7 +170,8 @@ static void waitEnterSleep(bool skipPreflight = false)
while (!doPreflightSleep()) {
delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
- if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
+ if (!Throttle::isWithinTimespanMs(now,
+ THIRTY_SECONDS_MS)) { // If we wait too long just report an error and go to sleep
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT);
assert(0); // FIXME - for now we just restart, need to fix bug #167
break;
@@ -271,13 +274,6 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
digitalWrite(LORA_CS, HIGH);
gpio_hold_en((gpio_num_t)LORA_CS);
}
-
-#if defined(I2C_SDA)
- Wire.end();
- pinMode(I2C_SDA, ANALOG);
- pinMode(I2C_SCL, ANALOG);
-#endif
-
#endif
#ifdef HAS_PMU
@@ -315,6 +311,14 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
}
#endif
+#if defined(ARCH_ESP32) && defined(I2C_SDA)
+ // Added by https://github.com/meshtastic/firmware/pull/4418
+ // Possibly to support Heltec Capsule Sensor?
+ Wire.end();
+ pinMode(I2C_SDA, ANALOG);
+ pinMode(I2C_SCL, ANALOG);
+#endif
+
console->flush();
cpuDeepSleep(msecToWake);
}
diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini
index 2a55f7a79..f3c22b7a8 100644
--- a/variants/diy/platformio.ini
+++ b/variants/diy/platformio.ini
@@ -69,4 +69,22 @@ build_flags = ${nrf52840_base.build_flags}
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/nrf52_promicro_diy_tcxo>
lib_deps =
${nrf52840_base.lib_deps}
-debug_tool = jlink
\ No newline at end of file
+debug_tool = jlink
+
+; NanoVHF T-Energy-S3 + E22(0)-xxxM - DIY
+[env:t-energy-s3_e22]
+extends = esp32s3_base
+board = esp32-s3-devkitc-1
+board_level = extra
+board_upload.flash_size = 16MB ;Specify the FLASH capacity as 16MB
+board_build.arduino.memory_type = qio_opi ;Enable internal PSRAM
+build_unflags =
+ ${esp32s3_base.build_unflags}
+ -D ARDUINO_USB_MODE=1
+build_flags =
+ ${esp32s3_base.build_flags}
+ -D EBYTE_ESP32_S3
+ -D BOARD_HAS_PSRAM
+ -D ARDUINO_USB_MODE=0
+ -D ARDUINO_USB_CDC_ON_BOOT=1
+ -I variants/diy/t-energy-s3_e22
diff --git a/variants/diy/t-energy-s3_e22/variant.h b/variants/diy/t-energy-s3_e22/variant.h
new file mode 100644
index 000000000..6933d7715
--- /dev/null
+++ b/variants/diy/t-energy-s3_e22/variant.h
@@ -0,0 +1,46 @@
+// NanoVHF T-Energy-S3 + E22(0)-xxxM - DIY
+// https://github.com/NanoVHF/Meshtastic-DIY/tree/main/PCB/ESP-32-devkit_EBYTE-E22/Mesh-v1.06-TTGO-T18
+
+// Battery
+#define BATTERY_PIN 3
+#define ADC_MULTIPLIER 2.0
+#define ADC_CHANNEL ADC1_GPIO3_CHANNEL
+
+// Button on NanoVHF PCB
+#define BUTTON_PIN 39
+
+// I2C via connectors on NanoVHF PCB
+#define I2C_SCL 2
+#define I2C_SDA 42
+
+// Screen (disabled)
+#define HAS_SCREEN 0 // Assume no screen present by default to prevent crash...
+
+// GPS via T-Energy-S3 onboard connector
+#define HAS_GPS 1
+#define GPS_TX_PIN 43
+#define GPS_RX_PIN 44
+
+// LoRa
+#define USE_SX1262 // E22-900M30S, E22-900M22S, and E22-900MM22S (not E220!) use SX1262
+#define USE_SX1268 // E22-400M30S, E22-400M33S, E22-400M22S, and E22-400MM22S use SX1268
+
+#define SX126X_MAX_POWER 22 // SX126xInterface.cpp defaults to 22 if not defined, but here we define it for good practice
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V
+
+#define SX126X_CS 5 // EBYTE module's NSS pin // FIXME: rename to SX126X_SS
+#define SX126X_SCK 6 // EBYTE module's SCK pin
+#define SX126X_MOSI 13 // EBYTE module's MOSI pin
+#define SX126X_MISO 4 // EBYTE module's MISO pin
+#define SX126X_RESET 1 // EBYTE module's NRST pin
+#define SX126X_BUSY 48 // EBYTE module's BUSY pin
+#define SX126X_DIO1 47 // EBYTE module's DIO1 pin
+
+#define SX126X_TXEN 10 // Schematic connects EBYTE module's TXEN pin to MCU
+#define SX126X_RXEN 12 // Schematic connects EBYTE module's RXEN pin to MCU
+
+#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure
+#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure
+#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure
+#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure
+#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure
diff --git a/variants/heltec_mesh_node_t114/platformio.ini b/variants/heltec_mesh_node_t114/platformio.ini
index e0d8ca0cc..1b06c7f5e 100644
--- a/variants/heltec_mesh_node_t114/platformio.ini
+++ b/variants/heltec_mesh_node_t114/platformio.ini
@@ -14,4 +14,4 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_node
lib_deps =
${nrf52840_base.lib_deps}
lewisxhe/PCF8563_Library@^1.0.1
- https://github.com/meshtastic/st7789#7181320e7ed05c7fb5fd2d32f14723bce6088b7b
\ No newline at end of file
+ https://github.com/meshtastic/st7789#bd33ea58ddfe4a5e4a66d53300ccbd38d66ac21f
\ No newline at end of file
diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h
index 454e66931..2cea3ef2f 100644
--- a/variants/heltec_mesh_node_t114/variant.h
+++ b/variants/heltec_mesh_node_t114/variant.h
@@ -92,13 +92,22 @@ No longer populated on PCB
#define PIN_SERIAL2_TX (0 + 10)
// #define PIN_SERIAL2_EN (0 + 17)
-/**
- Wire Interfaces
- */
-#define WIRE_INTERFACES_COUNT 1
+/*
+ * I2C
+ */
-#define PIN_WIRE_SDA (26)
-#define PIN_WIRE_SCL (27)
+#define WIRE_INTERFACES_COUNT 2
+
+// I2C bus 0
+// Routed to footprint for PCF8563TS RTC
+// Not populated on T114 V1, maybe in future?
+#define PIN_WIRE_SDA (0 + 26) // P0.26
+#define PIN_WIRE_SCL (0 + 27) // P0.27
+
+// I2C bus 1
+// Available on header pins, for general use
+#define PIN_WIRE1_SDA (0 + 16) // P0.16
+#define PIN_WIRE1_SCL (0 + 13) // P0.13
// QSPI Pins
#define PIN_QSPI_SCK (32 + 14)
diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_vision_master_t190/platformio.ini
index fd0001439..0c504d62b 100644
--- a/variants/heltec_vision_master_t190/platformio.ini
+++ b/variants/heltec_vision_master_t190/platformio.ini
@@ -9,5 +9,5 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
lewisxhe/PCF8563_Library@^1.0.1
- https://github.com/meshtastic/st7789#7181320e7ed05c7fb5fd2d32f14723bce6088b7b
+ https://github.com/meshtastic/st7789#bd33ea58ddfe4a5e4a66d53300ccbd38d66ac21f
upload_speed = 921600
\ No newline at end of file
diff --git a/variants/heltec_wireless_bridge/platformio.ini b/variants/heltec_wireless_bridge/platformio.ini
new file mode 100644
index 000000000..45c3aba74
--- /dev/null
+++ b/variants/heltec_wireless_bridge/platformio.ini
@@ -0,0 +1,6 @@
+[env:heltec-wireless-bridge]
+;build_type = debug ; to make it possible to step through our jtag debugger
+extends = esp32_base
+board = heltec_wifi_lora_32
+build_flags =
+ ${esp32_base.build_flags} -D HELTEC_WIRELESS_BRIDGE -I variants/heltec_wireless_bridge
\ No newline at end of file
diff --git a/variants/heltec_wireless_bridge/variant.h b/variants/heltec_wireless_bridge/variant.h
new file mode 100644
index 000000000..7c4f41660
--- /dev/null
+++ b/variants/heltec_wireless_bridge/variant.h
@@ -0,0 +1,29 @@
+// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
+// Tested on Neo6m module.
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+#define GPS_RX_PIN 36
+#define GPS_TX_PIN 33
+
+#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
+#define I2C_SDA 4 // I2C pins for this board
+#define I2C_SCL 15
+#endif
+
+#define LED_PIN 25 // If defined we will blink this LED
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses
+
+#define USE_RF95
+#define LORA_DIO0 26 // a No connect on the SX1262 module
+#ifndef USE_JTAG
+#define LORA_RESET 14
+#endif
+#define LORA_DIO1 35
+#define LORA_DIO2 34 // Not really used
+
+// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
+#define ADC_MULTIPLIER 3.2
+
+#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+#define ADC_CHANNEL ADC2_GPIO13_CHANNEL
+#define BAT_MEASURE_ADC_UNIT 2
\ No newline at end of file
diff --git a/variants/rpipico2/platformio.ini b/variants/rpipico2/platformio.ini
new file mode 100644
index 000000000..a63414418
--- /dev/null
+++ b/variants/rpipico2/platformio.ini
@@ -0,0 +1,16 @@
+[env:pico2]
+extends = rp2350_base
+board = rpipico2
+upload_protocol = picotool
+
+# add our variants files to the include and src paths
+build_flags = ${rp2350_base.build_flags}
+ -DRPI_PICO2
+ -Ivariants/rpipico2
+ -DDEBUG_RP2040_PORT=Serial
+ -DHW_SPI1_DEVICE
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
+lib_deps =
+ ${rp2350_base.lib_deps}
+debug_build_flags = ${rp2350_base.build_flags}
+debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/rpipico2/variant.h b/variants/rpipico2/variant.h
new file mode 100644
index 000000000..7efaeaf7a
--- /dev/null
+++ b/variants/rpipico2/variant.h
@@ -0,0 +1,50 @@
+// #define RADIOLIB_CUSTOM_ARDUINO 1
+// #define RADIOLIB_TONE_UNSUPPORTED 1
+// #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED 1
+
+#define ARDUINO_ARCH_AVR
+
+// default I2C pins:
+// SDA = 4
+// SCL = 5
+
+// Recommended pins for SerialModule:
+// txd = 8
+// rxd = 9
+
+#define EXT_NOTIFY_OUT 22
+#define BUTTON_PIN 17
+
+#define LED_PIN PIN_LED
+
+#define BATTERY_PIN 26
+// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
+#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
+#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
+
+#define USE_SX1262
+
+#undef LORA_SCK
+#undef LORA_MISO
+#undef LORA_MOSI
+#undef LORA_CS
+
+#define LORA_SCK 10
+#define LORA_MISO 12
+#define LORA_MOSI 11
+#define LORA_CS 3
+
+#define LORA_DIO0 RADIOLIB_NC
+#define LORA_RESET 15
+#define LORA_DIO1 20
+#define LORA_DIO2 2
+#define LORA_DIO3 RADIOLIB_NC
+
+#ifdef USE_SX1262
+#define SX126X_CS LORA_CS
+#define SX126X_DIO1 LORA_DIO1
+#define SX126X_BUSY LORA_DIO2
+#define SX126X_RESET LORA_RESET
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#endif
diff --git a/version.properties b/version.properties
index 69c478482..b30827191 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 5
-build = 1
+build = 2