Merge branch 'master' into master

This commit is contained in:
Tom Fifield
2024-09-25 15:10:48 +08:00
committed by GitHub
co-authored by GitHub
87 changed files with 959 additions and 694 deletions
+90
View File
@@ -0,0 +1,90 @@
name: Setup Build Variant Composite Action
description: Variant build actions for Meshtastic Platform IO steps
inputs:
board:
description: The board to build for
required: true
github_token:
description: GitHub token
required: true
build-script-path:
description: Path to the build script
required: true
remove-debug-flags:
description: A space separated list of files to remove debug flags from
required: false
default: ""
ota-firmware-source:
description: The OTA firmware file to pull
required: false
default: ""
ota-firmware-target:
description: The target path to store the OTA firmware file
required: false
default: ""
artifact-paths:
description: A newline separated list of paths to store as artifacts
required: false
default: ""
include-web-ui:
description: Include the web UI in the build
required: false
default: "false"
runs:
using: composite
steps:
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
if: inputs.include-web-ui == 'true'
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
- name: Unpack web ui
if: inputs.include-web-ui == 'true'
shell: bash
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
shell: bash
if: inputs.remove-debug-flags != ''
run: |
for INI_FILE in ${{ inputs.remove-debug-flags }}; do
sed -i '/DDEBUG_HEAP/d' ${INI_FILE}
done
- name: Build ${{ inputs.board }}
shell: bash
run: ${{ inputs.build-script-path }} ${{ inputs.board }}
- name: Pull OTA Firmware
if: inputs.ota-firmware-source != '' && inputs.ota-firmware-target != ''
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: ${{ inputs.ota-firmware-source }}
target: ${{ inputs.ota-firmware-target }}
token: ${{ inputs.github_token }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
${{ inputs.artifact-paths }}
+26
View File
@@ -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
+14 -44
View File
@@ -12,52 +12,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/firmware-ota
file: firmware.bin
target: release/bleota.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware.bin
ota-firmware-target: release/bleota.bin
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true
+14 -43
View File
@@ -14,50 +14,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
- name: Build ESP32-C3
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-c3.bin
target: release/bleota-c3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-c3.bin
ota-firmware-target: release/bleota-c3.bin
artifact-paths: |
release/*.bin
release/*.elf
+15 -43
View File
@@ -12,50 +12,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
- name: Build ESP32-S3
id: build
uses: ./.github/actions/build-variant
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-s3.bin
target: release/bleota-s3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
remove-debug-flags: >-
./arch/esp32/esp32.ini
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-s3.bin
ota-firmware-target: release/bleota-s3.bin
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true
+2 -2
View File
@@ -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
+6 -14
View File
@@ -12,23 +12,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build NRF52
run: bin/build-nrf52.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-nrf52.sh
artifact-paths: |
release/*.hex
release/*.uf2
release/*.elf
+6 -14
View File
@@ -12,22 +12,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build Raspberry Pi 2040
run: ./bin/build-rpi2040.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-rpi2040.sh
artifact-paths: |
release/*.uf2
release/*.elf
+7 -15
View File
@@ -12,22 +12,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build STM32
run: bin/build-stm32.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
- name: Build Raspberry Pi 2040
id: build
uses: ./.github/actions/build-variant
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
github_token: ${{ secrets.GITHUB_TOKEN }}
board: ${{ inputs.board }}
build-script-path: bin/build-stm32.sh
artifact-paths: |
release/*.hex
release/*.bin
+38 -8
View File
@@ -51,6 +51,7 @@ jobs:
matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Build base
@@ -124,6 +125,7 @@ jobs:
after-checks:
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
needs: [check]
steps:
- name: Checkout code
@@ -231,7 +233,7 @@ jobs:
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [gather-artifacts, after-checks]
needs: [gather-artifacts]
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -251,12 +253,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 +310,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 +351,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
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
semgrep-full:
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
image: semgrep/semgrep
steps:
# step 1
+1 -1
View File
@@ -6,7 +6,7 @@ jobs:
semgrep-diff:
runs-on: ubuntu-22.04
container:
image: returntocorp/semgrep
image: semgrep/semgrep
steps:
# step 1
+30 -15
View File
@@ -57,35 +57,50 @@ jobs:
reporter: java-junit
hardware-tests:
runs-on: ubuntu-latest
runs-on: test-runner
steps:
- name: Checkout code
uses: actions/checkout@v4
# - uses: actions/setup-python@v5
# with:
# python-version: '3.10'
# pipx install "setuptools<72"
- name: Upgrade python tools
shell: bash
run: |
python -m pip install --upgrade pip
pip install -U --no-build-isolation --no-cache-dir "setuptools<72"
pip install -U platformio adafruit-nrfutil --no-build-isolation
pip install -U poetry --no-build-isolation
pip install -U meshtastic --pre --no-build-isolation
pipx install adafruit-nrfutil
pipx install poetry
pipx install meshtastic --pip-args=--pre
- name: Install PlatformIO from script
shell: bash
run: |
curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
python3 get-platformio.py
- name: Upgrade platformio
shell: bash
run: |
export PATH=$PATH:$HOME/.local/bin
pio upgrade
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 18
- name: Setup pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v4
with:
version: latest
- name: Install Dependencies
run: pnpm install
- name: Setup devices
run: pnpm run setup
- name: Execute end to end tests on connected hardware
run: pnpm run test
- name: Install dependencies, setup devices and run
shell: bash
run: |
git submodule update --init --recursive
cd meshtestic/
pnpm install
pnpm run setup
pnpm run test
+3 -2
View File
@@ -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
+1 -1
View File
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
platform = platformio/espressif32@6.7.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
upload_speed = 921600
debug_init_break = tbreak setup
+1 -1
View File
@@ -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} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
lib_deps=
${arduino_base.lib_deps}
+2 -2
View File
@@ -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 =
-<nimble/>
-<platform/nrf52/>
-<platform/stm32wl/>
-<platform/rp2040>
-<platform/rp2xx0>
-<mesh/wifi/>
-<mesh/http/>
+<mesh/raspihttp/>
@@ -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 =
+23
View File
@@ -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} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp>
lib_ignore =
BluetoothOTA
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
rweather/Crypto
+1 -1
View File
@@ -22,7 +22,7 @@ build_flags =
-fdata-sections
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2xx0> -<mesh/raspihttp>
board_upload.offset_address = 0x08000000
upload_protocol = stlink
+3 -1
View File
@@ -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 <WiFi.h>
#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;
+5 -4
View File
@@ -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;
@@ -72,8 +74,7 @@ void SerialConsole::flush()
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
bool SerialConsole::checkIsConnected()
{
uint32_t now = millis();
return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
return Throttle::isWithinTimespanMs(lastContactMsec, SERIAL_CONNECTION_TIMEOUT);
}
/**
@@ -120,4 +121,4 @@ void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_l
emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg);
} else
RedirectablePrint::log_to_serial(logLevel, format, arg);
}
}
+10
View File
@@ -210,6 +210,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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_WIRE1_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
+5 -6
View File
@@ -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
@@ -334,11 +334,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
// Check register 0x0F for 0x3300 response to ID LIS3DH chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
if (registerValue == 0x3300) {
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
type = LIS3DH;
LOG_INFO("LIS3DH accelerometer found\n");
}
break;
}
case SHT31_4x_ADDR:
@@ -423,7 +422,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;
@@ -435,4 +434,4 @@ size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
#endif
#endif
+160 -269
View File
@@ -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,95 @@ 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) {
@@ -794,6 +622,55 @@ bool GPS::setup()
} 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_10), _message_SAVE_10);
_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");
}
}
didSerialInit = true;
}
@@ -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
+7 -2
View File
@@ -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,
@@ -130,6 +134,7 @@ class GPS : private concurrency::OSThread
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
static const uint8_t _message_SAVE_10[];
// VALSET Commands for M10
static const uint8_t _message_VALSET_PM[];
@@ -310,4 +315,4 @@ class GPS : private concurrency::OSThread
};
extern GPS *gps;
#endif // Exclude GPS
#endif // Exclude GPS
+6 -5
View File
@@ -2,6 +2,7 @@
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h"
#include <Throttle.h>
#include <sys/time.h>
#include <time.h>
@@ -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();
+39 -25
View File
@@ -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 = {
@@ -316,6 +323,13 @@ const uint8_t GPS::_message_SAVE[] = {
0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};
const uint8_t GPS::_message_SAVE_10[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x01 // deviceMask: only save to BBR
};
// 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.
@@ -335,36 +349,36 @@ const uint8_t GPS::_message_SAVE[] = {
// has details on low-power modes
/*
CFG-PM2 has been replaced by many CFG-PM commands
CFG-PMS has been removed
CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s
(PSMCT) CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby
mode" by legacy UBX-RXM-PMREQ request CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby
mode" by legacy UBX-RXM-PMREQ request CFG-PM-ONTIME U4 -> 0ms, optional I guess CFG-PM-EXTINTBACKUP L -> 1, force receiver into
BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low"
This is required because the receiver never enters low power mode if microcontroller is in deep-sleep.
Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled)
the receivcer remains in aquisition state -> potentially a bug
Workaround: Control the EXTINT pin by the GPS_EN_PIN signal
As mentioned in the M10 operational issues down below, power save won't allow the use of BDS B1C.
CFG-SIGNAL-BDS_B1C_ENA L -> 0
OPERATEMODE E1 2 (0 | 1 | 2)
POSUPDATEPERIOD U4 5
ACQPERIOD U4 10
GRIDOFFSET U4 0
ONTIME U2 1
MINACQTIME U1 0
MAXACQTIME U1 0
DONOTENTEROFF L 1
WAITTIMEFIX L 1
UPDATEEPH L 1
EXTINTWAKE L 0 no ext ints
EXTINTBACKUP L 0 no ext ints
EXTINTINACTIVE L 0 no ext ints
EXTINTACTIVITY U4 0 no ext ints
LIMITPEAKCURRENT L 1
// Ram layer config message:
// 01 01 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
// b5 62 06 8a 26 00 00 01 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
// 10 01 8b de
// BBR layer config message:
// 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
// 10 01 8c 03
*/
const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
/*
CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR
+4 -5
View File
@@ -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);
+12 -3
View File
@@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "Screen.h"
#include "../userPrefs.h"
#include "PowerMon.h"
#include "Throttle.h"
#include "configuration.h"
#if HAS_SCREEN
#include <OLEDDisplay.h>
@@ -117,6 +118,7 @@ static bool heartbeat = false;
#define SCREEN_HEIGHT display->getHeight()
#include "graphics/ScreenFonts.h"
#include <Throttle.h>
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
@@ -1670,6 +1672,11 @@ void Screen::setup()
static_cast<SH1106Wire *>(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<ST7789Spi *>(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<TFTDisplay *>(dispdev)->flipScreenVertically();
#elif defined(USE_ST7789)
static_cast<ST7789Spi *>(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)
+4 -5
View File
@@ -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;
+3 -2
View File
@@ -6,6 +6,7 @@
#include "ScanAndSelect.h"
#include "modules/CannedMessageModule.h"
#include <Throttle.h>
// 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();
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
#include "SerialKeyboard.h"
#include "configuration.h"
#include <Throttle.h>
#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;
}
+1 -1
View File
@@ -16,7 +16,7 @@ void CardKbI2cImpl::init()
uint8_t i2caddr_asize = 3;
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(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);
+1 -1
View File
@@ -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) {
+15 -22
View File
@@ -11,16 +11,16 @@
#include "airtime.h"
#include "buzz.h"
#include "error.h"
#include "power.h"
// #include "debug.h"
#include "FSCommon.h"
#include "Led.h"
#include "RTC.h"
#include "SPILock.h"
#include "Throttle.h"
#include "concurrency/OSThread.h"
#include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
#include "error.h"
#include "power.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "detect/ScanI2CTwoWire.h"
@@ -38,7 +38,6 @@
#include "target_specific.h"
#include <memory>
#include <utility>
// #include <driver/rtc_io.h>
#ifdef ARCH_ESP32
#if !MESHTASTIC_EXCLUDE_WEBSERVER
@@ -360,6 +359,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 +428,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)
@@ -621,7 +624,13 @@ void setup()
buttonThread = new ButtonThread();
#endif
playStartMelody();
// only play start melody when role is not tracker or sensor
if (config.power.is_power_saving == true && (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR))
LOG_DEBUG("Tracker/Sensor: Skipping start melody\n");
else
playStartMelody();
// fixed screen override?
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
@@ -1101,10 +1110,6 @@ void loop()
{
runASAP = false;
// axpDebugOutput.loop();
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
#ifdef ARCH_ESP32
esp32Loop();
#endif
@@ -1113,33 +1118,21 @@ void loop()
#endif
powerCommandsCheck();
// For debugging
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 10 * 1000L) {
if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {
lastPrint = millis();
meshtastic::printThreadInfo("main");
}
#endif
// TODO: This should go into a thread handled by FreeRTOS.
// handleWebResponse();
service->loop();
long delayMsec = mainController.runOrDelay();
/* if (mainController.nextThread && delayMsec)
LOG_DEBUG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(),
mainController.nextThread->tillRun(millis())); */
// We want to sleep as long as possible here - because it saves power
if (!runASAP && loopCanSleep()) {
// if(delayMsec > 100) LOG_DEBUG("sleeping %ld\n", delayMsec);
mainDelay.delay(delayMsec);
}
// if (didWake) LOG_DEBUG("wake!\n");
}
#endif
+6 -4
View File
@@ -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 <typename T> bool LR11x0Interface<T>::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");
+3
View File
@@ -92,6 +92,9 @@ class MeshService
/// Return the next MqttClientProxyMessage packet destined to the phone.
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
/// Return the next ClientNotification packet destined to the phone.
meshtastic_ClientNotification *getClientNotificationForPhone() { return toPhoneClientNotificationQueue.dequeuePtr(0); }
// search the queue for a request id and return the matching nodenum
NodeNum getNodenumFromRequestId(uint32_t request_id);
+4 -3
View File
@@ -657,9 +657,10 @@ void NodeDB::pickNewNodeNum()
while (((found = getMeshNode(nodeNum)) && memcmp(found->user.macaddr, ourMacAddr, sizeof(ourMacAddr)) != 0) ||
(nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED)) {
NodeNum candidate = random(NUM_RESERVED, LONG_MAX); // try a new random choice
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, by MAC ending in 0x%02x%02x vs our 0x%02x%02x, so "
"trying for 0x%x\n",
nodeNum, found->user.macaddr[4], found->user.macaddr[5], ourMacAddr[4], ourMacAddr[5], candidate);
if (found)
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, by MAC ending in 0x%02x%02x vs our 0x%02x%02x, so "
"trying for 0x%x\n",
nodeNum, found->user.macaddr[4], found->user.macaddr[5], ourMacAddr[4], ourMacAddr[5], candidate);
nodeNum = candidate;
}
LOG_DEBUG("Using nodenum 0x%x \n", nodeNum);
+6 -8
View File
@@ -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;
+31 -13
View File
@@ -25,6 +25,7 @@
#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
#endif
#include "Throttle.h"
#include <RTC.h>
PhoneAPI::PhoneAPI()
@@ -61,9 +62,11 @@ void PhoneAPI::handleStartConfig()
void PhoneAPI::close()
{
LOG_INFO("PhoneAPI::close()\n");
if (state != STATE_SEND_NOTHING) {
state = STATE_SEND_NOTHING;
resetReadIndex();
unobserve(&service->fromNumChanged);
#ifdef FSCom
unobserve(&xModem.packetReady);
@@ -71,8 +74,17 @@ void PhoneAPI::close()
releasePhonePacket(); // Don't leak phone packets on shutdown
releaseQueueStatusPhonePacket();
releaseMqttClientProxyPhonePacket();
releaseClientNotification();
onConnectionChanged(false);
fromRadioScratch = {};
toRadioScratch = {};
nodeInfoForPhone = {};
packetForPhone = NULL;
filesManifest.clear();
fromRadioNum = 0;
config_nonce = 0;
config_state = 0;
pauseBluetoothLogging = false;
}
}
@@ -404,6 +416,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag;
fromRadioScratch.xmodemPacket = xmodemPacketForPhone;
xmodemPacketForPhone = meshtastic_XModem_init_zero;
} else if (clientNotification) {
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_clientNotification_tag;
fromRadioScratch.clientNotification = *clientNotification;
releaseClientNotification();
} else if (packetForPhone) {
printPacket("phone downloaded packet", packetForPhone);
@@ -443,13 +459,6 @@ void PhoneAPI::sendConfigComplete()
pauseBluetoothLogging = false;
}
void PhoneAPI::handleDisconnect()
{
filesManifest.clear();
pauseBluetoothLogging = false;
LOG_INFO("PhoneAPI disconnect\n");
}
void PhoneAPI::releasePhonePacket()
{
if (packetForPhone) {
@@ -474,6 +483,14 @@ void PhoneAPI::releaseMqttClientProxyPhonePacket()
}
}
void PhoneAPI::releaseClientNotification()
{
if (clientNotification) {
service->releaseClientNotificationToPool(clientNotification);
clientNotification = NULL;
}
}
/**
* Return true if we have data available to send to the phone
*/
@@ -508,7 +525,9 @@ bool PhoneAPI::available()
queueStatusPacketForPhone = service->getQueueStatusForPhone();
if (!mqttClientProxyMessageForPhone)
mqttClientProxyMessageForPhone = service->getMqttClientProxyMessageForPhone();
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone;
if (!clientNotification)
clientNotification = service->getClientNotificationForPhone();
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone || !!clientNotification;
if (hasPacket)
return true;
@@ -551,7 +570,6 @@ void PhoneAPI::sendNotification(meshtastic_LogRecord_Level level, uint32_t reply
cn->time = getValidTime(RTCQualityFromNet);
strncpy(cn->message, message, sizeof(cn->message));
service->sendClientNotification(cn);
delete cn;
}
/**
@@ -561,12 +579,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;
+2 -5
View File
@@ -147,11 +147,6 @@ class PhoneAPI
*/
virtual void onNowHasData(uint32_t fromRadioNum) {}
/**
* Subclasses can use this to find out when a client drops the link
*/
virtual void handleDisconnect();
private:
void releasePhonePacket();
@@ -159,6 +154,8 @@ class PhoneAPI
void releaseMqttClientProxyPhonePacket();
void releaseClientNotification();
/// begin a new connection
void handleStartConfig();
+2 -2
View File
@@ -151,7 +151,7 @@ const RegionInfo regions[] = {
const RegionInfo *myRegion;
bool RadioInterface::uses_default_frequency_slot = true;
static uint8_t bytes[MAX_RHPACKETLEN];
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1];
void initRegion()
{
@@ -326,7 +326,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
RadioInterface::RadioInterface()
{
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
assert(sizeof(PacketHeader) == MESHTASTIC_HEADER_LENGTH); // make sure the compiler did what we expected
}
bool RadioInterface::reconfigure()
+4 -2
View File
@@ -9,7 +9,9 @@
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
#define MAX_RHPACKETLEN 256
#define MAX_LORA_PAYLOAD_LEN 255 // max length of 255 per Semtech's datasheets on SX12xx
#define MESHTASTIC_HEADER_LENGTH 16
#define MESHTASTIC_PKC_OVERHEAD 12
#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
@@ -89,7 +91,7 @@ class RadioInterface
/**
* A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need
* */
uint8_t radiobuf[MAX_RHPACKETLEN];
uint8_t radiobuf[MAX_LORA_PAYLOAD_LEN + 1];
/**
* Enqueue a received packet for the registered receiver
+3 -2
View File
@@ -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.
+7 -7
View File
@@ -36,8 +36,8 @@ static MemoryDynamic<meshtastic_MeshPacket> staticPool;
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
static uint8_t bytes[MAX_RHPACKETLEN];
static uint8_t ScratchEncrypted[MAX_RHPACKETLEN];
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1];
static uint8_t ScratchEncrypted[MAX_LORA_PAYLOAD_LEN + 1];
/**
* Constructor
@@ -330,13 +330,13 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
// Attempt PKI decryption first
if (p->channel == 0 && p->to == nodeDB->getNodeNum() && p->to > 0 && p->to != NODENUM_BROADCAST &&
nodeDB->getMeshNode(p->from) != nullptr && nodeDB->getMeshNode(p->from)->user.public_key.size > 0 &&
nodeDB->getMeshNode(p->to)->user.public_key.size > 0 && rawSize > 12) {
nodeDB->getMeshNode(p->to)->user.public_key.size > 0 && rawSize > MESHTASTIC_PKC_OVERHEAD) {
LOG_DEBUG("Attempting PKI decryption\n");
if (crypto->decryptCurve25519(p->from, p->id, rawSize, ScratchEncrypted, bytes)) {
LOG_INFO("PKI Decryption worked!\n");
memset(&p->decoded, 0, sizeof(p->decoded));
rawSize -= 12;
rawSize -= MESHTASTIC_PKC_OVERHEAD;
if (pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded) &&
p->decoded.portnum != meshtastic_PortNum_UNKNOWN_APP) {
decrypted = true;
@@ -475,7 +475,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
}
} */
if (numbytes > MAX_RHPACKETLEN)
if (numbytes + MESHTASTIC_HEADER_LENGTH > MAX_LORA_PAYLOAD_LEN)
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 + MESHTASTIC_HEADER_LENGTH + MESHTASTIC_PKC_OVERHEAD > MAX_LORA_PAYLOAD_LEN)
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) {
@@ -508,7 +508,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
return meshtastic_Routing_Error_PKI_FAILED;
}
crypto->encryptCurve25519(p->to, getFrom(p), p->id, numbytes, bytes, ScratchEncrypted);
numbytes += 12;
numbytes += MESHTASTIC_PKC_OVERHEAD;
memcpy(p->encrypted.bytes, ScratchEncrypted, numbytes);
p->channel = 0;
p->pki_encrypted = true;
+7 -5
View File
@@ -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 <typename T> bool SX126xInterface<T>::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 <typename T> bool SX126xInterface<T>::sleep()
#endif
return true;
}
}
+5 -4
View File
@@ -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 <typename T> bool SX128xInterface<T>::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");
+3 -3
View File
@@ -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;
}
}
+8
View File
@@ -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;
}
+1
View File
@@ -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);
};
+8 -2
View File
@@ -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) */
@@ -107,7 +109,7 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_NRF52840_PCA10059 = 40,
/* Custom Disaster Radio esp32 v3 device https://github.com/sudomesh/disaster-radio/tree/master/hardware/board_esp32_v3 */
meshtastic_HardwareModel_DR_DEV = 41,
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */
meshtastic_HardwareModel_M5STACK = 42,
/* New Heltec LoRA32 with ESP32-S3 CPU */
meshtastic_HardwareModel_HELTEC_V3 = 43,
@@ -196,9 +198,13 @@ typedef enum _meshtastic_HardwareModel {
https://www.adafruit.com/product/938
^^^ short A0 to switch to I2C address 0x3C */
meshtastic_HardwareModel_RP2040_FEATHER_RFM95 = 76,
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, 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,
/* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, CoreS3, Paper) https://m5stack.com/ */
meshtastic_HardwareModel_M5STACK_CORES3 = 80,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------------------------------------------------------------ */
+3 -2
View File
@@ -23,6 +23,7 @@ static void WiFiEvent(WiFiEvent_t event);
#endif
#ifndef DISABLE_NTP
#include "Throttle.h"
#include <NTPClient.h>
#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
+11 -4
View File
@@ -60,10 +60,17 @@ char *strnstr(const char *s, const char *find, size_t slen)
void printBytes(const char *label, const uint8_t *p, size_t numbytes)
{
LOG_DEBUG("%s: ", label);
for (size_t i = 0; i < numbytes; i++)
LOG_DEBUG("%02x ", p[i]);
LOG_DEBUG("\n");
char *messageBuffer;
int labelSize = strlen(label);
if (labelSize < 100 && numbytes < 64) {
messageBuffer = new char[labelSize + (numbytes * 3) + 2];
strncpy(messageBuffer, label, labelSize);
for (size_t i = 0; i < numbytes; i++)
snprintf(messageBuffer + labelSize + i * 3, 4, " %02x", p[i]);
strcpy(messageBuffer + labelSize + numbytes * 3, "\n");
LOG_DEBUG(messageBuffer);
delete messageBuffer;
}
}
bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes)
+2 -1
View File
@@ -27,6 +27,7 @@
#endif
#include "graphics/ScreenFonts.h"
#include <Throttle.h>
// 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;
+6 -3
View File
@@ -5,6 +5,7 @@
#include "PowerFSM.h"
#include "configuration.h"
#include "main.h"
#include <Throttle.h>
DetectionSensorModule *detectionSensorModule;
#define GPIO_POLLING_INTERVAL 100
@@ -49,7 +50,8 @@ int32_t DetectionSensorModule::runOnce()
// LOG_DEBUG("Detection Sensor Module: Current pin state: %i\n", digitalRead(moduleConfig.detection_sensor.monitor_pin));
if ((millis() - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs) &&
if (!Throttle::isWithinTimespanMs(lastSentToMesh,
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.minimum_broadcast_secs)) &&
hasDetectionEvent()) {
sendDetectionMessage();
return DELAYED_INTERVAL;
@@ -58,8 +60,9 @@ int32_t DetectionSensorModule::runOnce()
// of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state
// change detections.
else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 &&
(millis() - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
default_telemetry_broadcast_interval_secs)) {
!Throttle::isWithinTimespanMs(lastSentToMesh,
Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs,
default_telemetry_broadcast_interval_secs))) {
sendCurrentStateMessage();
return DELAYED_INTERVAL;
}
+3 -2
View File
@@ -3,6 +3,7 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
#include <Throttle.h>
NeighborInfoModule *neighborInfoModule;
@@ -83,11 +84,11 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
*/
void NeighborInfoModule::cleanUpNeighbors()
{
uint32_t now = getTime();
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<meshtastic_Neighbor>::reverse_iterator(
neighbors.erase(std::next(it).base())); // Erase the element and update the iterator
+4 -4
View File
@@ -6,6 +6,7 @@
#include "Router.h"
#include "configuration.h"
#include "main.h"
#include <Throttle.h>
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);
}
}
+1 -1
View File
@@ -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
+2 -1
View File
@@ -9,6 +9,7 @@
#include "main.h"
#include "sleep.h"
#include "target_specific.h"
#include <Throttle.h>
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;
+3 -2
View File
@@ -19,6 +19,7 @@
#include "configuration.h"
#include "gps/GeoCoord.h"
#include <Arduino.h>
#include <Throttle.h>
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 {
@@ -114,7 +115,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
packetSequence++;
static char heartbeatString[MAX_RHPACKETLEN];
static char heartbeatString[MAX_LORA_PAYLOAD_LEN + 1];
snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence);
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
+3 -3
View File
@@ -5,6 +5,7 @@
#include "Router.h"
#include "configuration.h"
#include "main.h"
#include <Throttle.h>
#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;
+5 -5
View File
@@ -7,6 +7,7 @@
#include "Router.h"
#include "configuration.h"
#include <Arduino.h>
#include <Throttle.h>
/*
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;
@@ -12,6 +12,7 @@
#include "Router.h"
#include "detect/ScanI2CTwoWire.h"
#include "main.h"
#include <Throttle.h>
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)
@@ -64,6 +64,7 @@ T1000xSensor t1000xSensor;
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
#include "graphics/ScreenFonts.h"
#include <Throttle.h>
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);
+7 -7
View File
@@ -19,6 +19,7 @@
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
#include "graphics/ScreenFonts.h"
#include <Throttle.h>
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);
@@ -7,6 +7,7 @@
#include "NAU7802Sensor.h"
#include "SafeFile.h"
#include "TelemetrySensor.h"
#include <Throttle.h>
#include <pb_decode.h>
#include <pb_encode.h>
@@ -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;
}
+6 -2
View File
@@ -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)) {
+17 -1
View File
@@ -21,6 +21,7 @@
#include "Default.h"
#include "serialization/JSON.h"
#include "serialization/MeshPacketSerializer.h"
#include <Throttle.h>
#include <assert.h>
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;
}
@@ -598,7 +614,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)) {
+8 -1
View File
@@ -124,7 +124,14 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
}
}
virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc) { LOG_INFO("BLE disconnect\n"); }
virtual void onDisconnect(NimBLEServer *pServer, ble_gap_conn_desc *desc)
{
LOG_INFO("BLE disconnect\n");
if (bluetoothPhoneAPI) {
bluetoothPhoneAPI->close();
}
}
};
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
+2
View File
@@ -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)
+3 -2
View File
@@ -55,7 +55,6 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI;
void onConnect(uint16_t conn_handle)
{
// Get the reference to current connection
BLEConnection *connection = Bluefruit.Connection(conn_handle);
connectionHandle = conn_handle;
@@ -70,8 +69,10 @@ void onConnect(uint16_t conn_handle)
*/
void onDisconnect(uint16_t conn_handle, uint8_t reason)
{
// FIXME - we currently assume only one active connection
LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason);
if (bluetoothPhoneAPI) {
bluetoothPhoneAPI->close();
}
}
void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
{
@@ -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)
+12 -8
View File
@@ -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);
}
+19 -1
View File
@@ -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
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
+46
View File
@@ -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
@@ -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
https://github.com/meshtastic/st7789#bd33ea58ddfe4a5e4a66d53300ccbd38d66ac21f
+15 -6
View File
@@ -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)
@@ -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
@@ -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
+29
View File
@@ -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
+16
View File
@@ -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
+50
View File
@@ -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
+1 -1
View File
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 5
build = 1
build = 3