Compare commits

..

40 Commits

Author SHA1 Message Date
mverch67
6b05f090dc reduce PSRAM allocated to lvgl 2025-09-18 10:17:58 +02:00
Manuel
e9b87f7a81 Merge branch 'master' into arduino-esp32-v3.2 2025-09-18 09:48:51 +02:00
Manuel
d47d249550 Merge branch 'master' into arduino-esp32-v3.2 2025-09-12 21:15:43 +02:00
Manuel
ff28355e16 Merge branch 'master' into arduino-esp32-v3.2 2025-09-08 19:20:15 +02:00
Manuel
351cbd723b Merge branch 'master' into arduino-esp32-v3.2 2025-09-08 10:41:14 +02:00
Manuel
be1a724ab4 Merge branch 'master' into arduino-esp32-v3.2 2025-08-10 00:11:27 +02:00
mverch67
04f98cf20e update config; include wifi 2025-08-09 23:49:16 +02:00
mverch67
75a1a41d8c fix duplicate Syslog classes 2025-08-09 23:43:45 +02:00
mverch67
344efa6675 update device-ui (fix native compilation) 2025-08-08 17:29:02 +02:00
mverch67
e919b3da9c cleanup 2025-08-06 10:36:04 +02:00
Manuel
155783c782 Merge branch 'master' into arduino-esp32-v3.2 2025-08-06 09:15:44 +02:00
Manuel
76bcd05259 Merge branch 'master' into arduino-esp32-v3.2 2025-08-06 00:09:37 +02:00
mverch67
2d29cbc34c device-ui: use fast mem for critical draw functions 2025-08-06 00:08:54 +02:00
mverch67
2b77864192 fix attachInterrupt issue 2025-08-05 23:59:37 +02:00
mverch67
10aa4cbfee don't exclude I2C 2025-08-02 19:07:34 +02:00
mverch67
c24a174490 don't exclude I2C 2025-08-02 19:05:07 +02:00
Manuel
3e5e19efec Merge branch 'master' into arduino-esp32-v3.2 2025-08-01 21:50:40 +02:00
mverch67
ea2c247024 pr: update device-ui for indicator 2025-08-01 21:45:40 +02:00
mverch67
0b463b6443 update references to fixed io expander 2025-08-01 20:54:57 +02:00
mverch67
7d3c804279 update wdt task 2025-08-01 20:54:15 +02:00
mverch67
1fa7d9f40e try-fix watchdog trigger 2025-08-01 09:23:01 +02:00
mverch67
aa7abb1d3e use ng-io-expander 3.3.0 2025-07-30 23:37:09 +02:00
mverch67
effb454af0 comment out assert on watchdog creation 2025-07-30 23:24:31 +02:00
mverch67
27bb42ed3b git ignore new toolchain tmp files 2025-07-29 22:08:07 +02:00
mverch67
05dc8caed8 platformio updates 2025-07-29 22:07:18 +02:00
mverch67
f3734d407d remove OTA partition for now until fw size got smaller again 2025-07-29 22:06:21 +02:00
mverch67
bc8e509a8c fix copy&paste 2025-07-29 22:05:29 +02:00
mverch67
74d0472834 fix merge again 2025-07-29 21:55:34 +02:00
mverch67
5afc43ebc1 try-out WDT timer issue --> needs revert 2025-07-29 21:07:28 +02:00
mverch67
6cdb92b7a8 fix merge error 2025-07-29 21:06:19 +02:00
Thomas Göttgens
0e1872398a Merge remote-tracking branch 'remotes/origin/master' into arduino-esp32-v3.2
# Conflicts:
#	arch/esp32/esp32.ini
#	src/graphics/draw/MenuHandler.cpp
#	src/modules/Modules.cpp
#	variants/esp32s3/seeed-sensecap-indicator/platformio.ini
2025-07-29 13:06:13 +02:00
mverch67
f25544c7e0 updated platform references 2025-07-18 03:16:54 +02:00
mverch67
f40b2ba153 temp workaround for nimble compile 2025-07-18 03:14:45 +02:00
mverch67
5033fd1f9f fix MESHTASTIC_EXCLUDE_I2C compile errors 2025-07-17 12:40:02 +02:00
mverch67
cd170fb011 boot_freq 120MHz 2025-07-16 20:50:25 +02:00
mverch67
fa169a5e43 compare IDF versions 2025-07-14 17:14:21 +02:00
mverch67
c6e2a53a02 exclude not needed modules 2025-07-03 17:08:29 +02:00
Ben Meadors
a286c06271 Merge branch 'master' into arduino-esp32-v3.2 2025-07-02 06:00:44 -05:00
Manuel
dda4b90e34 Merge branch 'master' into arduino-esp32-v3.2 2025-07-01 00:56:56 +02:00
mverch67
cc5dc5046c indicator: adaptations for arduino-esp32 v3.2 2025-07-01 00:48:11 +02:00
475 changed files with 14575 additions and 48158 deletions

View File

@@ -76,7 +76,7 @@ bool loopCanSleep()
// Called just prior to starting Meshtastic. Allows for setting config values before startup.
void lateInitVariant()
{
portduino_config.logoutputlevel = level_error;
settingsMap[logoutputlevel] = level_error;
channelFile.channels[0] = meshtastic_Channel{
.has_settings = true,
.settings =
@@ -132,7 +132,7 @@ int portduino_main(int argc, char **argv); // Renamed "main" function from Mesht
// Start Meshtastic in a thread and wait till it has reached the ON state.
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
portduino_config.maxtophone = 5;
settingsMap[maxtophone] = 5;
meshtasticThread = std::thread([program = *argv[0]]() {
char nodeIdStr[12];

View File

@@ -1,7 +1,7 @@
# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM mcr.microsoft.com/devcontainers/cpp:2-debian-13
FROM mcr.microsoft.com/devcontainers/cpp:1-debian-12
USER root

View File

@@ -8,7 +8,7 @@
"features": {
"ghcr.io/devcontainers/features/python:1": {
"installTools": true,
"version": "3.14"
"version": "latest"
}
},
"customizations": {

View File

@@ -100,7 +100,7 @@ runs:
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
overwrite: true

View File

@@ -5,7 +5,7 @@ runs:
using: composite
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}

View File

@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
path: meshtasticd
@@ -64,7 +64,7 @@ jobs:
PKG_VERSION: ${{ steps.version.outputs.deb }}
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
overwrite: true

View File

@@ -19,10 +19,8 @@ jobs:
pio-build:
name: build-${{ inputs.platform }}
runs-on: ubuntu-24.04
outputs:
artifact-id: ${{ steps.upload.outputs.artifact-id }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
@@ -56,8 +54,7 @@ jobs:
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
id: upload
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}.zip
overwrite: true

View File

@@ -1,161 +0,0 @@
name: Build One Target
on:
workflow_dispatch:
inputs:
# trunk-ignore(checkov/CKV_GHA_7)
arch:
type: choice
options:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
target:
type: string
required: false
description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets.
# find-target:
# type: boolean
# default: true
# description: 'Find the available targets'
permissions: read-all
jobs:
find-targets:
if: ${{ inputs.target == '' }}
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
cache: pip
- run: pip install -U platformio
- name: Generate matrix
id: jsonStep
run: |
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level extra)
echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY
echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY
echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY
echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY
echo "Targets:" >> $GITHUB_STEP_SUMMARY
echo $TARGETS | jq -r 'sort_by(.board) |.[] | "- " + .board' >> $GITHUB_STEP_SUMMARY
version:
if: ${{ inputs.target != '' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
id: version
env:
BUILD_LOCATION: local
outputs:
long: ${{ steps.version.outputs.long }}
deb: ${{ steps.version.outputs.deb }}
build:
if: ${{ inputs.target != '' && inputs.arch != 'native' }}
needs: [version]
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ inputs.target }}
platform: ${{ inputs.arch }}
gather-artifacts:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
needs: [version, build]
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
with:
path: ./
pattern: firmware-*-*
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: Move files up
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
with:
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
overwrite: true
path: |
./firmware-*.bin
./firmware-*.uf2
./firmware-*.hex
./firmware-*-ota.zip
./device-*.sh
./device-*.bat
./littlefs-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v6
with:
pattern: firmware-*-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
with:
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
overwrite: true
path: ./*.elf
retention-days: 30
- uses: scruplelesswizard/comment-artifact@main
if: ${{ github.event_name == 'pull_request' }}
with:
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
description: "Download firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -21,20 +21,18 @@ permissions:
jobs:
docker-multiarch:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/docker_manifest.yml
with:
release_channel: daily
secrets: inherit
package-ppa:
if: github.repository == 'meshtastic/firmware'
strategy:
fail-fast: false
matrix:
series:
- jammy # 22.04 LTS
- noble # 24.04 LTS
- jammy # 22.04
- noble # 24.04
- plucky # 25.04
- questing # 25.10
uses: ./.github/workflows/package_ppa.yml
@@ -44,7 +42,6 @@ jobs:
secrets: inherit
package-obs:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/package_obs.yml
with:
obs_project: network:Meshtastic:daily
@@ -52,7 +49,6 @@ jobs:
secrets: inherit
hook-copr:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/hook_copr.yml
with:
copr_project: daily

View File

@@ -47,7 +47,7 @@ jobs:
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}

View File

@@ -83,7 +83,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{ github.ref }}

View File

@@ -28,14 +28,21 @@ on:
jobs:
setup:
strategy:
fail-fast: true
fail-fast: false
matrix:
arch:
- all
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
- check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: 3.x
@@ -47,19 +54,25 @@ jobs:
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr)
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr)
fi
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT
echo "$TARGETS" >> $GITHUB_STEP_SUMMARY
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS"
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
outputs:
all: ${{ steps.jsonStep.outputs.all }}
esp32: ${{ steps.jsonStep.outputs.esp32 }}
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }}
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
rp2350: ${{ steps.jsonStep.outputs.rp2350 }}
stm32: ${{ steps.jsonStep.outputs.stm32 }}
check: ${{ steps.jsonStep.outputs.check }}
version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -75,30 +88,105 @@ jobs:
needs: setup
strategy:
fail-fast: false
matrix:
check: ${{ fromJson(needs.setup.outputs.check) }}
matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Check ${{ matrix.check.board }}
run: bin/check-all.sh ${{ matrix.check.board }}
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
build:
build-esp32:
needs: [setup, version]
strategy:
fail-fast: false
matrix:
build: ${{ fromJson(needs.setup.outputs.all) }}
matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.build.board }}
platform: ${{ matrix.build.platform }}
pio_env: ${{ matrix.board }}
platform: esp32
build-esp32s3:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32s3
build-esp32c3:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32c3
build-esp32c6:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32c6
build-nrf52840:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: nrf52840
build-rp2040:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: rp2040
build-rp2350:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.rp2350) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: rp2350
build-stm32:
needs: [setup, version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.stm32) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: stm32
build-debian-src:
if: github.repository == 'meshtastic/firmware'
@@ -109,41 +197,68 @@ jobs:
secrets: inherit
package-pio-deps-native-tft:
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name == 'workflow_dispatch' }}
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/package_pio_deps.yml
with:
pio_env: native-tft
secrets: inherit
test-native:
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }}
if: ${{ !contains(github.ref_name, 'event/') }}
uses: ./.github/workflows/test_native.yml
docker:
strategy:
fail-fast: false
matrix:
distro: [debian, alpine]
platform: [linux/amd64, linux/arm64, linux/arm/v7]
pio_env: [native, native-tft]
exclude:
- distro: alpine
platform: linux/arm/v7
- pio_env: native-tft
platform: linux/arm64
- pio_env: native-tft
platform: linux/arm/v7
docker-deb-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: ${{ matrix.distro }}
platform: ${{ matrix.platform }}
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
pio_env: ${{ matrix.pio_env }}
distro: debian
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
docker-deb-amd64-tft:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
pio_env: native-tft
docker-alp-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
docker-alp-amd64-tft:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
pio_env: native-tft
docker-deb-arm64:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm64
runs-on: ubuntu-24.04-arm
push: false
docker-deb-armv7:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm/v7
runs-on: ubuntu-24.04-arm
push: false
gather-artifacts:
# trunk-ignore(checkov/CKV2_GHA_1)
if: github.repository == 'meshtastic/firmware'
permissions:
contents: write
pull-requests: write
@@ -160,15 +275,26 @@ jobs:
- rp2350
- stm32
runs-on: ubuntu-latest
needs: [version, build]
needs:
[
version,
build-esp32,
build-esp32s3,
build-esp32c3,
build-esp32c6,
build-nrf52840,
build-rp2040,
build-rp2350,
build-stm32,
]
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
@@ -181,7 +307,7 @@ jobs:
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
@@ -197,7 +323,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -216,7 +342,7 @@ jobs:
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
overwrite: true
@@ -232,7 +358,7 @@ jobs:
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
if: ${{ github.event_name == 'workflow_dispatch' }}
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
needs:
@@ -242,7 +368,7 @@ jobs:
- package-pio-deps-native-tft
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Python
uses: actions/setup-python@v6
@@ -261,14 +387,14 @@ jobs:
Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -307,18 +433,18 @@ jobs:
- rp2350
- stm32
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware'}}
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [release-artifacts, version]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -335,7 +461,7 @@ jobs:
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
merge-multiple: true
@@ -366,14 +492,14 @@ jobs:
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v5
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true

View File

@@ -7,18 +7,28 @@ on:
# Merge group is a special trigger that is used to trigger the workflow when a merge group is created.
merge_group:
env:
FAIL_FAST_PER_ARCH: true
jobs:
setup:
strategy:
fail-fast: true
matrix:
arch:
- all
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
- check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
cache: pip
@@ -29,18 +39,25 @@ jobs:
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr)
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr)
fi
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS"
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
outputs:
all: ${{ steps.jsonStep.outputs.all }}
esp32: ${{ steps.jsonStep.outputs.esp32 }}
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }}
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
rp2350: ${{ steps.jsonStep.outputs.rp2350 }}
stm32: ${{ steps.jsonStep.outputs.stm32 }}
check: ${{ steps.jsonStep.outputs.check }}
version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -56,29 +73,105 @@ jobs:
needs: setup
strategy:
fail-fast: true
matrix:
check: ${{ fromJson(needs.setup.outputs.check) }}
matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Check ${{ matrix.check.board }}
run: bin/check-all.sh ${{ matrix.check.board }}
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
build:
build-esp32:
needs: [setup, version]
strategy:
matrix:
build: ${{ fromJson(needs.setup.outputs.all) }}
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.build.board }}
platform: ${{ matrix.build.platform }}
pio_env: ${{ matrix.board }}
platform: esp32
build-esp32s3:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32s3
build-esp32c3:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32c3
build-esp32c6:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: esp32c6
build-nrf52840:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: nrf52840
build-rp2040:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: rp2040
build-rp2350:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.rp2350) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: rp2350
build-stm32:
needs: [setup, version]
strategy:
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
matrix: ${{ fromJson(needs.setup.outputs.stm32) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.board }}
platform: stm32
build-debian-src:
if: github.repository == 'meshtastic/firmware'
@@ -99,26 +192,54 @@ jobs:
if: ${{ !contains(github.ref_name, 'event/') }}
uses: ./.github/workflows/test_native.yml
docker:
strategy:
fail-fast: false
matrix:
distro: [debian, alpine]
platform: [linux/amd64, linux/arm64, linux/arm/v7]
pio_env: [native, native-tft]
exclude:
- distro: alpine
platform: linux/arm/v7
- pio_env: native-tft
platform: linux/arm64
- pio_env: native-tft
platform: linux/arm/v7
docker-deb-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: ${{ matrix.distro }}
platform: ${{ matrix.platform }}
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
pio_env: ${{ matrix.pio_env }}
distro: debian
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
docker-deb-amd64-tft:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
pio_env: native-tft
docker-alp-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
docker-alp-amd64-tft:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/amd64
runs-on: ubuntu-24.04
push: false
pio_env: native-tft
docker-deb-arm64:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm64
runs-on: ubuntu-24.04-arm
push: false
docker-deb-armv7:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm/v7
runs-on: ubuntu-24.04-arm
push: false
gather-artifacts:
@@ -139,15 +260,26 @@ jobs:
- rp2350
- stm32
runs-on: ubuntu-latest
needs: [version, build]
needs:
[
version,
build-esp32,
build-esp32s3,
build-esp32c3,
build-esp32c6,
build-nrf52840,
build-rp2040,
build-rp2350,
build-stm32,
]
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
@@ -160,7 +292,7 @@ jobs:
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
@@ -176,7 +308,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -195,7 +327,7 @@ jobs:
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
overwrite: true
@@ -221,10 +353,10 @@ jobs:
- package-pio-deps-native-tft
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: 3.x
@@ -240,14 +372,14 @@ jobs:
Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb
uses: actions/download-artifact@v6
uses: actions/download-artifact@v4
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v6
uses: actions/download-artifact@v4
with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -290,14 +422,14 @@ jobs:
needs: [release-artifacts, version]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: 3.x
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -314,7 +446,7 @@ jobs:
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
merge-multiple: true
@@ -345,14 +477,14 @@ jobs:
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: 3.x
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Trunk Check
uses: trunk-io/trunk-action@v1
@@ -31,7 +31,7 @@ jobs:
pull-requests: write # For trunk to create PRs
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Trunk Upgrade
uses: trunk-io/trunk-action/upgrade@v1

View File

@@ -34,7 +34,7 @@ jobs:
needs: build-debian-src
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
path: meshtasticd
@@ -58,7 +58,7 @@ jobs:
id: version
- name: Download artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true

View File

@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
@@ -56,7 +56,7 @@ jobs:
PLATFORMIO_CORE_DIR: pio/core
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
overwrite: true

View File

@@ -32,7 +32,7 @@ jobs:
needs: build-debian-src
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: recursive
path: meshtasticd
@@ -60,7 +60,7 @@ jobs:
id: version
- name: Download artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true

View File

@@ -10,7 +10,7 @@ permissions:
jobs:
check-label:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Check for PR labels
uses: actions/github-script@v8

View File

@@ -40,7 +40,7 @@ jobs:
checks: write
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -50,7 +50,7 @@ jobs:
- name: Download test artifacts
if: needs.native-tests.result != 'skipped'
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
merge-multiple: true

View File

@@ -21,10 +21,10 @@ jobs:
fail-fast: false
matrix:
series:
- jammy # 22.04 LTS
- noble # 24.04 LTS
- jammy # 22.04
- noble # 24.04
- plucky # 25.04
- questing # 25.10
# - questing # 25.10
uses: ./.github/workflows/package_ppa.yml
with:
ppa_repo: |-
@@ -60,10 +60,7 @@ jobs:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Always use master branch for version bumps
ref: master
uses: actions/checkout@v5
- name: Setup Python
uses: actions/setup-python@v6

View File

@@ -21,7 +21,7 @@ jobs:
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v6
uses: actions/checkout@v5
# step 2
- name: full scan
@@ -33,7 +33,7 @@ jobs:
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: report.sarif
overwrite: true
@@ -41,7 +41,7 @@ jobs:
# step 4
- name: publish code scanning alerts
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: report.sarif
category: semgrep

View File

@@ -13,7 +13,7 @@ jobs:
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
fetch-depth: 0

View File

@@ -17,10 +17,8 @@ jobs:
steps:
- name: Stale PR+Issues
uses: actions/stale@v10.1.0
uses: actions/stale@v10.0.0
with:
days-before-stale: 45
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
close-issue-message: This issue has not had any comment since the last notice. It has been closed automatically. If this is incorrect, or the issue becomes relevant again, please request that it is reopened.
exempt-issue-labels: pinned,3.0,triaged,backlog
exempt-pr-labels: pinned,3.0,triaged,backlog
exempt-issue-labels: pinned,3.0
exempt-pr-labels: pinned,3.0

View File

@@ -14,7 +14,7 @@ jobs:
name: Native Simulator Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -40,7 +40,7 @@ jobs:
- name: Integration test
run: |
.pio/build/coverage/program -s &
.pio/build/coverage/program &
PID=$!
timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
echo "Simulator started, launching python test..."
@@ -59,7 +59,7 @@ jobs:
id: version
- name: Save coverage information
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}.zip
@@ -70,7 +70,7 @@ jobs:
name: Native PlatformIO Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -94,7 +94,7 @@ jobs:
- name: Save test results
if: always() # run this step even if previous step failed
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
overwrite: true
@@ -108,7 +108,7 @@ jobs:
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
- name: Save coverage information
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}.zip
@@ -127,7 +127,7 @@ jobs:
- platformio-tests
if: always()
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -137,20 +137,20 @@ jobs:
id: version
- name: Download test artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
merge-multiple: true
- name: Test Report
uses: dorny/test-reporter@v2.3.0
uses: dorny/test-reporter@v2.1.1
with:
name: PlatformIO Tests
path: testreport.xml
reporter: java-junit
- name: Download coverage artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}.zip
path: code-coverage-report
@@ -163,7 +163,7 @@ jobs:
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
- name: Save Code Coverage Report
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: code-coverage-report-${{ steps.version.outputs.long }}.zip
path: code-coverage-report

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: test-runner
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
# - uses: actions/setup-python@v5
# with:
@@ -47,9 +47,9 @@ jobs:
pio upgrade
- name: Setup Node
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v4

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Trunk Check
uses: trunk-io/trunk-action@v1

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Trunk Check
uses: trunk-io/trunk-action@v1

View File

@@ -15,7 +15,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}

View File

@@ -11,7 +11,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
submodules: true

9
.gitignore vendored
View File

@@ -39,5 +39,14 @@ release/
src/mesh/raspihttp/certificate.pem
src/mesh/raspihttp/private_key.pem
# pioarduino platform
managed_components/*
arduino-lib-builder*
dependencies.lock
idf_component.yml
CMakeLists.txt
sdkconfig.*
.dummy/*
# Ignore logo (set at build time with platformio-custom.py)
data/boot/logo.*

View File

@@ -4,31 +4,31 @@ cli:
plugins:
sources:
- id: trunk
ref: v1.7.4
ref: v1.7.2
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- checkov@3.2.495
- renovate@42.27.1
- prettier@3.7.3
- trufflehog@3.91.1
- checkov@3.2.471
- renovate@41.115.2
- prettier@3.6.2
- trufflehog@3.90.6
- yamllint@1.37.1
- bandit@1.9.2
- trivy@0.67.2
- bandit@1.8.6
- trivy@0.66.0
- taplo@0.10.0
- ruff@0.14.7
- isort@7.0.0
- markdownlint@0.46.0
- ruff@0.13.0
- isort@6.0.1
- markdownlint@0.45.0
- oxipng@9.1.5
- svgo@4.0.0
- actionlint@1.7.9
- actionlint@1.7.7
- flake8@7.3.0
- hadolint@2.14.0
- hadolint@2.13.1
- shfmt@3.6.0
- shellcheck@0.11.0
- black@25.11.0
- black@25.1.0
- git-diff-check
- gitleaks@8.30.0
- gitleaks@8.28.0
- clang-format@16.0.3
ignore:
- linters: [ALL]

6
8MB_no_ota.csv Normal file
View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x660000,
spiffs, data, spiffs, 0x670000,0x180000,
coredump, data, coredump,0x7F0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x660000
5 spiffs data spiffs 0x670000 0x180000
6 coredump data coredump 0x7F0000 0x10000

View File

@@ -3,7 +3,7 @@
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM python:3.14-slim-trixie AS builder
FROM python:3.13-slim-trixie AS builder
ARG PIO_ENV=native
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC

View File

@@ -37,3 +37,4 @@ Join our community and help improve Meshtastic! 🚀
## Stats
![Alt](https://repobeats.axiom.co/api/embed/8025e56c482ec63541593cc5bd322c19d5c0bdcf.svg "Repobeats analytics image")

View File

@@ -3,13 +3,12 @@
# trunk-ignore-all(hadolint/DL3018): Do not pin apk package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM python:3.14-alpine3.22 AS builder
FROM python:3.13-alpine3.22 AS builder
ARG PIO_ENV=native
ENV PIP_ROOT_USER_ACTION=ignore
RUN apk --no-cache add \
bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \
libgpiod-dev yaml-cpp-dev bluez-dev \
bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
libx11-dev libinput-dev libxkbcommon-dev \
&& rm -rf /var/cache/apk/* \
@@ -41,8 +40,8 @@ LABEL org.opencontainers.image.title="Meshtastic" \
USER root
RUN apk --no-cache add \
shadow libstdc++ libbsd libgpiod yaml-cpp libusb \
i2c-tools libuv libx11 libinput libxkbcommon \
shadow libstdc++ libgpiod yaml-cpp libusb i2c-tools libuv \
libx11 libinput libxkbcommon \
&& rm -rf /var/cache/apk/* \
&& mkdir -p /var/lib/meshtasticd \
&& mkdir -p /etc/meshtasticd/config.d \

View File

@@ -31,13 +31,11 @@ build_flags =
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096
-DSERIAL_HAS_ON_RECEIVE
-DLIBPAX_ARDUINO
-DLIBPAX_WIFI
-DLIBPAX_BLE
@@ -54,10 +52,10 @@ lib_deps =
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
h2zero/NimBLE-Arduino@^1.4.3
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/mverch67/libpax gitBranch=master
https://github.com/mverch67/libpax/archive/6f52ee989301cdabaeef00bcbf93bff55708ce2f.zip
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
https://github.com/lewisxhe/XPowersLib/archive/v0.3.2.zip
https://github.com/lewisxhe/XPowersLib/archive/v0.3.0.zip
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto

View File

@@ -28,7 +28,7 @@ lib_deps =
${environmental_extra.lib_deps}
${radiolib_base.lib_deps}
# renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
lewisxhe/XPowersLib@0.3.2
lewisxhe/XPowersLib@0.3.0
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto

View File

@@ -7,13 +7,13 @@ extends = arduino_base
platform_packages =
; our custom Git version until they merge our PR
# TODO renovate
platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino#c770c8a16a351b55b86e347a3d9d7b74ad0bbf39
platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino#e13f5820002a4fb2a5e6754b42ace185277e5adf
; Don't renovate toolchain-gccarmnoneeabi
platformio/toolchain-gccarmnoneeabi@~1.90301.0
build_type = release
build_type = debug
build_flags =
-include variants/nrf52840/cpp_overrides/lfs_util.h
-include arch/nrf52/cpp_overrides/lfs_util.h
${arduino_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
-Wno-unused-variable
@@ -21,17 +21,6 @@ build_flags =
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
-DMESHTASTIC_EXCLUDE_AUDIO=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
-Os
build_unflags =
-Ofast
-Og
-ggdb3
-ggdb2
-g3
-g2
-g
-g1
-g0
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp> -<serialization/>

View File

@@ -8,7 +8,7 @@ lib_deps =
${environmental_base.lib_deps}
${environmental_extra.lib_deps}
# renovate: datasource=git-refs depName=Kongduino-Adafruit_nRFCrypto packageName=https://github.com/Kongduino/Adafruit_nRFCrypto gitBranch=master
https://github.com/Kongduino/Adafruit_nRFCrypto/archive/8cde7189b5ead9dcd49f72601b43b969c0bbc06e.zip
https://github.com/Kongduino/Adafruit_nRFCrypto/archive/5f838d2709461a2c981f642917aa50254a25c14c.zip
; Common NRF52 debugging settings follow. See the Meshtastic developer docs for how to connect SWD debugging probes to your board.

View File

@@ -2,7 +2,7 @@
[portduino_base]
platform =
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
https://github.com/meshtastic/platform-native/archive/f566d364204416cdbf298e349213f7d551f793d9.zip
https://github.com/meshtastic/platform-native/archive/c490bcd019e0658404088a61b96e653c9da22c45.zip
framework = arduino
build_src_filter =

View File

@@ -2,7 +2,7 @@
extends = arduino_base
platform =
# renovate: datasource=custom.pio depName=platformio/ststm32 packageName=platformio/platform/ststm32
platformio/ststm32@19.4.0
platformio/ststm32@19.3.0
platform_packages =
# TODO renovate
platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
@@ -37,9 +37,6 @@ build_flags =
-DRADIOLIB_EXCLUDE_LR11X0=1
-DHAL_DAC_MODULE_ONLY
-DHAL_RNG_MODULE_ENABLED
-Wl,--wrap=__assert_func
-Wl,--wrap=strerror
-Wl,--wrap=_tzset_unlocked_r
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/rp2xx0> -<mesh/raspihttp>

View File

@@ -1,165 +0,0 @@
#!/usr/bin/env python3
"""Summarise linker map output to highlight heavy object files and libraries.
Usage:
python bin/analyze_map.py --map .pio/build/rak4631/output.map --top 20
The script parses GNU ld map files and aggregates section sizes per object file
and per archive/library, then prints sortable tables that make it easy to spot
modules worth trimming or hiding behind feature flags.
"""
from __future__ import annotations
import argparse
import collections
import os
import re
import sys
from typing import DefaultDict, Dict, Tuple
SECTION_LINE_RE = re.compile(r"^\s+(?P<section>\S+)\s+0x[0-9A-Fa-f]+\s+0x(?P<size>[0-9A-Fa-f]+)\s+(?P<object>.+)$")
ARCHIVE_MEMBER_RE = re.compile(r"^(?P<archive>.+)\((?P<object>[^)]+)\)$")
def human_size(num_bytes: int) -> str:
"""Return a friendly size string with one decimal place."""
if num_bytes < 1024:
return f"{num_bytes:,} B"
num = float(num_bytes)
for unit in ("KB", "MB", "GB"):
num /= 1024.0
if num < 1024.0:
return f"{num:.1f} {unit}"
return f"{num:.1f} TB"
def shorten_path(path: str, root: str) -> str:
"""Prefer repository-relative paths for readability."""
path = path.strip()
if not path:
return path
# Normalise Windows archives (backslashes) to POSIX style for consistency.
path = path.replace("\\", "/")
# Attempt to strip the root when an absolute path lives inside the repo.
if os.path.isabs(path):
try:
rel = os.path.relpath(path, root)
if not rel.startswith(".."):
return rel
except ValueError:
# relpath can fail on mixed drives on Windows; fall back to basename.
pass
return path
def describe_object(raw_object: str, root: str) -> Tuple[str, str]:
"""Return a human friendly object label and the library it belongs to."""
raw_object = raw_object.strip()
lib_label = "[app]"
match = ARCHIVE_MEMBER_RE.match(raw_object)
if match:
archive = shorten_path(match.group("archive"), root)
obj = match.group("object")
lib_label = os.path.basename(archive) or archive
label = f"{archive}:{obj}"
else:
label = shorten_path(raw_object, root)
# If the object lives under libs, hint at the containing directory.
parent = os.path.basename(os.path.dirname(label))
if parent:
lib_label = parent
return label, lib_label
def parse_map(map_path: str, repo_root: str) -> Tuple[Dict[str, int], Dict[str, int], Dict[str, Dict[str, int]]]:
per_object: DefaultDict[str, int] = collections.defaultdict(int)
per_library: DefaultDict[str, int] = collections.defaultdict(int)
per_object_sections: DefaultDict[str, DefaultDict[str, int]] = collections.defaultdict(lambda: collections.defaultdict(int))
try:
with open(map_path, "r", encoding="utf-8", errors="ignore") as handle:
for line in handle:
match = SECTION_LINE_RE.match(line)
if not match:
continue
section = match.group("section")
if section.startswith("*") or section in {"LOAD", "ORIGIN"}:
continue
size = int(match.group("size"), 16)
if size == 0:
continue
obj_token = match.group("object").strip()
if not obj_token or obj_token.startswith("*") or "load address" in obj_token:
continue
label, lib_label = describe_object(obj_token, repo_root)
per_object[label] += size
per_library[lib_label] += size
per_object_sections[label][section] += size
except FileNotFoundError:
raise SystemExit(f"error: map file '{map_path}' not found. Run a build first.")
return per_object, per_library, per_object_sections
def format_section_breakdown(section_sizes: Dict[str, int], total: int, limit: int = 3) -> str:
items = sorted(section_sizes.items(), key=lambda kv: kv[1], reverse=True)
parts = []
for section, size in items[:limit]:
pct = (size / total) * 100 if total else 0
parts.append(f"{section} {pct:.1f}%")
if len(items) > limit:
remainder = total - sum(size for _, size in items[:limit])
pct = (remainder / total) * 100 if total else 0
parts.append(f"other {pct:.1f}%")
return ", ".join(parts)
def print_report(map_path: str, top_n: int, per_object: Dict[str, int], per_library: Dict[str, int], per_object_sections: Dict[str, Dict[str, int]]):
total_bytes = sum(per_object.values())
if total_bytes == 0:
print("No section data found in map file.")
return
print(f"Map file: {map_path}")
print(f"Accounted size: {human_size(total_bytes)} across {len(per_object)} object files\n")
sorted_objects = sorted(per_object.items(), key=lambda kv: kv[1], reverse=True)
print(f"Top {min(top_n, len(sorted_objects))} object files by linked size:")
for idx, (obj, size) in enumerate(sorted_objects[:top_n], 1):
pct = (size / total_bytes) * 100
breakdown = format_section_breakdown(per_object_sections[obj], size)
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size)")
print(f" {obj}")
if breakdown:
print(f" sections: {breakdown}")
print()
sorted_libs = sorted(per_library.items(), key=lambda kv: kv[1], reverse=True)
print(f"Top {min(top_n, len(sorted_libs))} libraries or source roots:")
for idx, (lib, size) in enumerate(sorted_libs[:top_n], 1):
pct = (size / total_bytes) * 100
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size) {lib}")
def main() -> None:
parser = argparse.ArgumentParser(description="Highlight heavy object files from a GNU ld map file.")
parser.add_argument("--map", default=".pio/build/rak4631/output.map", help="Path to the map file (default: %(default)s)")
parser.add_argument("--top", type=int, default=20, help="Number of entries to display per table (default: %(default)s)")
args = parser.parse_args()
map_path = os.path.abspath(args.map)
repo_root = os.path.abspath(os.getcwd())
per_object, per_library, per_object_sections = parse_map(map_path, repo_root)
print_report(os.path.relpath(map_path, repo_root), args.top, per_object, per_library, per_object_sections)
if __name__ == "__main__":
main()

View File

@@ -15,12 +15,12 @@ SET "LOGCOUNTER=0"
SET "BPS_RESET=0"
@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable.
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone t-eth-elite tlora-pager mesh-tab dreamcatcher ESP32-S3-Pico seeed-sensecap-indicator heltec_capsule_sensor_v3 vision-master icarus tracksenger elecrow-adv heltec-v4"
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone t-eth-elite tlora-pager mesh-tab dreamcatcher ESP32-S3-Pico seeed-sensecap-indicator heltec_capsule_sensor_v3 vision-master icarus tracksenger elecrow-adv"
SET "C3=esp32c3"
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
SET "BIGDB_8MB=crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
SET "MUIDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator"
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite tlora-pager t-watch-s3 elecrow-adv heltec-v4"
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite tlora-pager t-watch-s3 elecrow-adv"
GOTO getopts
:help

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
BPS_RESET=false
@@ -31,23 +31,21 @@ MUIDB_8MB=(
"seeed-sensecap-indicator"
)
BIGDB_16MB=(
"dreamcatcher"
"elecrow-adv"
"ESP32-S3-Pico"
"heltec-v4"
"m5stack-cores3"
"mesh-tab"
"station-g2"
"t-deck"
"mesh-tab"
"t-energy-s3"
"dreamcatcher"
"ESP32-S3-Pico"
"m5stack-cores3"
"station-g2"
"t-eth-elite"
"t-watch-s3"
"tlora-pager"
"t-watch-s3"
"elecrow-adv"
)
S3_VARIANTS=(
"s3"
"-v3"
"-v4"
"t-deck"
"wireless-paper"
"wireless-tracker"

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
CHANGE_MODE=false

View File

@@ -1,32 +1,28 @@
#!/usr/bin/env python3
#!/usr/bin/env python
"""Generate the CI matrix."""
import argparse
import json
import sys
import random
import re
from platformio.project.config import ProjectConfig
parser = argparse.ArgumentParser(description="Generate the CI matrix")
parser.add_argument("platform", help="Platform to build for")
parser.add_argument(
"--level",
choices=["extra", "pr"],
nargs="*",
default=[],
help="Board level to build for (omit for full release boards)",
)
args = parser.parse_args()
options = sys.argv[1:]
outlist = []
if len(options) < 1:
print(json.dumps(outlist))
exit(1)
cfg = ProjectConfig.get_instance()
pio_envs = cfg.envs()
# Gather all PlatformIO environments for filtering later
all_envs = []
for pio_env in pio_envs:
env_build_flags = cfg.get(f"env:{pio_env}", "build_flags")
env_build_flags = cfg.get(f"env:{pio_env}", 'build_flags')
env_platform = None
for flag in env_build_flags:
# Extract the platform from the build flags
@@ -41,35 +37,36 @@ for pio_env in pio_envs:
exit(1)
# Store env details as a dictionary, and add to 'all_envs' list
env = {
"ci": {"board": pio_env, "platform": env_platform},
"board_level": cfg.get(f"env:{pio_env}", "board_level", default=None),
"board_check": bool(cfg.get(f"env:{pio_env}", "board_check", default=False)),
'name': pio_env,
'platform': env_platform,
'board_level': cfg.get(f"env:{pio_env}", 'board_level', default=None),
'board_check': bool(cfg.get(f"env:{pio_env}", 'board_check', default=False))
}
all_envs.append(env)
# Filter outputs based on options
# Check is mutually exclusive with other options (except 'pr')
if "check" in args.platform:
if "check" in options:
for env in all_envs:
if env["board_check"]:
if "pr" in args.level:
if env["board_level"] == "pr":
outlist.append(env["ci"])
if env['board_check']:
if "pr" in options:
if env['board_level'] == 'pr':
outlist.append(env['name'])
else:
outlist.append(env["ci"])
outlist.append(env['name'])
# Filter (non-check) builds by platform
else:
for env in all_envs:
if args.platform == env["ci"]["platform"] or args.platform == "all":
if options[0] == env['platform']:
# Always include board_level = 'pr'
if env["board_level"] == "pr":
outlist.append(env["ci"])
if env['board_level'] == 'pr':
outlist.append(env['name'])
# Include board_level = 'extra' when requested
elif "extra" in args.level and env["board_level"] == "extra":
outlist.append(env["ci"])
elif "extra" in options and env['board_level'] == "extra":
outlist.append(env['name'])
# If no board level is specified, include in release builds (not PR)
elif "pr" not in args.level and not env["board_level"]:
outlist.append(env["ci"])
elif "pr" not in options and not env['board_level']:
outlist.append(env['name'])
# Return as a JSON list
print(json.dumps(outlist))

View File

@@ -1,116 +0,0 @@
#!/bin/bash
# Script to cancel all running GitHub Actions workflows
# Requires GitHub CLI (gh) to be installed and authenticated
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if gh CLI is installed
if ! command -v gh &> /dev/null; then
print_error "GitHub CLI (gh) is not installed. Please install it first:"
echo " brew install gh"
echo " Or visit: https://cli.github.com/"
exit 1
fi
# Check if authenticated
if ! gh auth status &> /dev/null; then
print_error "GitHub CLI is not authenticated. Please run:"
echo " gh auth login"
exit 1
fi
# Get repository info
REPO=$(gh repo view --json owner,name -q '.owner.login + "/" + .name')
if [[ -z "$REPO" ]]; then
print_error "Could not determine repository. Make sure you're in a GitHub repository."
exit 1
fi
print_status "Working with repository: $REPO"
# Get all active workflows (both queued and in-progress)
print_status "Fetching active workflows (queued and in-progress)..."
QUEUED_WORKFLOWS=$(gh run list --status queued --json databaseId,displayTitle,headBranch,status --limit 100)
IN_PROGRESS_WORKFLOWS=$(gh run list --status in_progress --json databaseId,displayTitle,headBranch,status --limit 100)
# Combine both lists
ALL_WORKFLOWS=$(echo "$QUEUED_WORKFLOWS $IN_PROGRESS_WORKFLOWS" | jq -s 'add | unique_by(.databaseId)')
if [[ "$ALL_WORKFLOWS" == "[]" ]]; then
print_status "No active workflows found."
exit 0
fi
# Parse and display active workflows
echo
print_warning "Found active workflows:"
echo "$ALL_WORKFLOWS" | jq -r '.[] | " - \(.displayTitle) (Branch: \(.headBranch), Status: \(.status), ID: \(.databaseId))"'
echo
read -p "Do you want to cancel ALL these workflows? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_status "Cancelled by user."
exit 0
fi
# Cancel each workflow
print_status "Cancelling workflows..."
CANCELLED_COUNT=0
FAILED_COUNT=0
while IFS= read -r WORKFLOW_ID; do
if [[ -n "$WORKFLOW_ID" ]]; then
print_status "Cancelling workflow ID: $WORKFLOW_ID"
if gh run cancel "$WORKFLOW_ID" 2>/dev/null; then
((CANCELLED_COUNT++))
else
print_error "Failed to cancel workflow ID: $WORKFLOW_ID"
((FAILED_COUNT++))
fi
fi
done < <(echo "$ALL_WORKFLOWS" | jq -r '.[].databaseId')
echo
print_status "Summary:"
echo " - Cancelled: $CANCELLED_COUNT workflows"
if [[ $FAILED_COUNT -gt 0 ]]; then
echo " - Failed: $FAILED_COUNT workflows"
fi
print_status "Done!"
# Optional: Show remaining active workflows
echo
print_status "Checking for any remaining active workflows..."
REMAINING_QUEUED=$(gh run list --status queued --json databaseId --limit 10)
REMAINING_IN_PROGRESS=$(gh run list --status in_progress --json databaseId --limit 10)
REMAINING_ALL=$(echo "$REMAINING_QUEUED $REMAINING_IN_PROGRESS" | jq -s 'add | unique_by(.databaseId)')
if [[ "$REMAINING_ALL" == "[]" ]]; then
print_status "All workflows successfully cancelled."
else
REMAINING_COUNT=$(echo "$REMAINING_ALL" | jq '. | length')
print_warning "Still $REMAINING_COUNT workflows active (may take a moment to update status)"
fi

View File

@@ -87,30 +87,6 @@
</screenshots>
<releases>
<release version="2.7.17" date="2025-11-28">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.17</url>
</release>
<release version="2.7.16" date="2025-11-19">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.16</url>
</release>
<release version="2.7.15" date="2025-11-13">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
</release>
<release version="2.7.14" date="2025-11-03">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.14</url>
</release>
<release version="2.7.13" date="2025-10-11">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.13</url>
</release>
<release version="2.7.12" date="2025-10-01">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.12</url>
</release>
<release version="2.7.11" date="2025-09-24">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.11</url>
</release>
<release version="2.7.10" date="2025-09-18">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.10</url>
</release>
<release version="2.7.9" date="2025-09-03">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.9</url>
</release>

View File

@@ -86,7 +86,7 @@ if platform.name == "espressif32":
if platform.name == "nordicnrf52":
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex",
env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py \"$BUILD_DIR/firmware.hex\" -c -f 0xADA52840 -o \"$BUILD_DIR/firmware.uf2\"",
env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py $BUILD_DIR/firmware.hex -c -f 0xADA52840 -o $BUILD_DIR/firmware.uf2",
"Generating UF2 file"))
Import("projenv")

View File

@@ -1 +1 @@
2.6.7
2.6.4

View File

@@ -1,53 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x4405"],
["0x239A", "0x0029"],
["0x239A", "0x002A"]
],
"usb_product": "elecrow_eink",
"mcu": "nrf52840",
"variant": "ELECROW-ThinkNode-M3",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "elecrow nrf",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "",
"vendor": "ELECROW"
}

View File

@@ -1,53 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_ELECROW_M6 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x4405"],
["0x239A", "0x0029"],
["0x239A", "0x002A"]
],
"usb_product": "elecrow_thinknode_m6",
"mcu": "nrf52840",
"variant": "ELECROW-ThinkNode-M6",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "ELECROW ThinkNode M6",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://www.elecrow.com/thinknode-m6-outdoor-solar-power-for-lora-powered-by-nrf52840-supports-gps.html",
"vendor": "ELECROW"
}

View File

@@ -1,41 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "hackaday-communicator"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "hackaday-communicator (16 MB FLASH, 8 MB PSRAM)",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 1500000
},
"url": "hackaday.com",
"vendor": "hackaday"
}

View File

@@ -1,43 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_16MB.csv",
"memory_type": "qio_qspi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"psram_type": "qspi",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "heltec_v4"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "heltec_wifi_lora_32 v4 (16 MB FLASH, 2 MB PSRAM)",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 2097152,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://heltec.org/",
"vendor": "heltec"
}

View File

@@ -1,37 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "heltec_wireless_tracker_v2"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Heltec Wireless Tracker V2",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://heltec.org",
"vendor": "Heltec"
}

View File

@@ -1,56 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_MUZI_BASE -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0xcafe"]],
"mcu": "nrf52840",
"variant": "muzi-base",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "Muzi Base",
"url": "https://muzi.works/",
"vendor": "MuziWorks",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"blackmagic",
"cmsis-dap",
"mbed",
"stlink"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
}
}

View File

@@ -1,52 +0,0 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],
["0x239A", "0x0029"],
["0x239A", "0x002A"],
["0x239A", "0x802A"]
],
"usb_product": "Muzi R1 Neo",
"mcu": "nrf52840",
"variant": "r1-neo",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino", "freertos"],
"name": "WisCore RAK4631 Board",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://muzi.works/",
"vendor": "Muzi Works"
}

View File

@@ -16,6 +16,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"f_boot": "120000000L",
"boot_freq": "120000000L",
"boot": "qio",
"flash_mode": "qio",
"psram_type": "opi",

78
debian/changelog vendored
View File

@@ -1,44 +1,50 @@
meshtasticd (2.7.17.0) unstable; urgency=medium
* Version 2.7.17
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Fri, 28 Nov 2025 15:11:34 +0000
meshtasticd (2.7.16.0) unstable; urgency=medium
* Version 2.7.16
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 19 Nov 2025 16:12:32 +0000
meshtasticd (2.7.15.0) unstable; urgency=medium
* Version 2.7.15
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Thu, 13 Nov 2025 12:31:57 +0000
meshtasticd (2.7.14.0) unstable; urgency=medium
* Version 2.7.14
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Mon, 03 Nov 2025 16:11:31 +0000
meshtasticd (2.7.13.0) unstable; urgency=medium
* Version 2.7.13
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 11 Oct 2025 15:27:28 +0000
meshtasticd (2.7.12.0) unstable; urgency=medium
meshtasticd (2.7.9.0) UNRELEASED; urgency=medium
[ Austin Lane ]
* Initial packaging
* Version 2.5.19
* GitHub Actions Automatic version bump
* GitHub Actions Automatic version bump
* GitHub Actions Automatic version bump
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ GitHub Actions ]
* Version 2.7.12
[ ]
* GitHub Actions Automatic version bump
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 01 Oct 2025 19:51:41 +0000
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ Ubuntu ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
[ ]
* GitHub Actions Automatic version bump
-- <github-actions[bot]@users.noreply.github.com> Wed, 03 Sep 2025 23:39:17 +0000

View File

@@ -1,8 +1,7 @@
#!/usr/bin/bash
export DEBFULLNAME="GitHub Actions"
export DEBEMAIL="github-actions[bot]@users.noreply.github.com"
PKG_VERSION=$(python3 bin/buildinfo.py short)
dch --newversion "$PKG_VERSION.0" \
--distribution unstable \
"Version $PKG_VERSION"
--distribution UNRELEASED \
"GitHub Actions Automatic version bump"

1
debian/control vendored
View File

@@ -3,7 +3,6 @@ Section: misc
Priority: optional
Maintainer: Austin Lane <vidplace7@gmail.com>
Build-Depends: debhelper-compat (= 13),
libc6-dev (>= 2.38) | libbsd-dev,
lsb-release,
tar,
gzip,

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# postinst script for meshtasticd
#
# see: dh_installdeb(1)

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# postrm script for meshtasticd
#
# see: dh_installdeb(1)

View File

@@ -49,13 +49,6 @@ BuildRequires: pkgconfig(x11)
BuildRequires: pkgconfig(libinput)
BuildRequires: pkgconfig(xkbcommon-x11)
# libbsd is needed on older Fedora/RHEL to provide 'strlcpy'
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
BuildRequires: glibc-devel >= 2.38
%else
BuildRequires: pkgconfig(libbsd-overlay)
%endif
Requires: systemd-udev
%description

View File

@@ -5,7 +5,7 @@
default_envs = tbeam
extra_configs =
variants/*/*.ini
arch/*/*.ini
variants/*/*/platformio.ini
variants/*/diy/*/platformio.ini
src/graphics/niche/InkHUD/PlatformioConfig.ini
@@ -55,14 +55,12 @@ build_flags = -Wno-missing-field-initializers
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
#-D OLED_PL=1
#-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs
#-D DEBUG_LOOP_TIMING=1 ; uncomment to add main loop timing logs
monitor_speed = 115200
monitor_filters = direct
lib_deps =
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2887bf4a19f64d92c984dcc8fd5ca7429e425e4a.zip
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/0cbc26b1f8f61957af0475f486b362eafe7cc4e2.zip
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
@@ -70,7 +68,7 @@ lib_deps =
# renovate: datasource=git-refs depName=meshtastic-TinyGPSPlus packageName=https://github.com/meshtastic/TinyGPSPlus gitBranch=master
https://github.com/meshtastic/TinyGPSPlus/archive/71a82db35f3b973440044c476d4bcdc673b104f4.zip
# renovate: datasource=git-refs depName=meshtastic-ArduinoThread packageName=https://github.com/meshtastic/ArduinoThread gitBranch=master
https://github.com/meshtastic/ArduinoThread/archive/b841b0415721f1341ea41cccfb4adccfaf951567.zip
https://github.com/meshtastic/ArduinoThread/archive/7c3ee9e1951551b949763b1f5280f8db1fa4068d.zip
# renovate: datasource=custom.pio depName=Nanopb packageName=nanopb/library/Nanopb
nanopb/Nanopb@0.4.91
# renovate: datasource=custom.pio depName=ErriezCRC32 packageName=erriez/library/ErriezCRC32
@@ -89,8 +87,9 @@ check_flags =
framework = arduino
lib_deps =
${env.lib_deps}
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=end2endzone/library/NonBlockingRTTTL
end2endzone/NonBlockingRTTTL@1.4.0
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=mverch67/library/NonBlockingRTTTL
https://github.com/mverch67/NonBlockingRTTTL/archive/ad1c2fb12bc81db546c6a94e963acb3382d3689e.zip ; TODO
build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} -<platform/portduino/> -<graphics/niche/>
@@ -101,8 +100,6 @@ lib_deps =
thingsboard/TBPubSubClient@2.12.1
# renovate: datasource=custom.pio depName=NTPClient packageName=arduino-libraries/library/NTPClient
arduino-libraries/NTPClient@3.2.1
# renovate: datasource=custom.pio depName=Syslog packageName=arcao/library/Syslog
arcao/Syslog@2.0.0
; Minimal networking libs for nrf52 (excludes Syslog to save flash)
[nrf52_networking_base]
@@ -115,19 +112,18 @@ lib_deps =
[radiolib_base]
lib_deps =
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
# jgromes/RadioLib@7.4.0
https://github.com/jgromes/RadioLib/archive/536c7267362e2c1345be7054ba45e503252975ff.zip
jgromes/RadioLib@7.2.1
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/3bf332240416c5cb8c919fac2a0ec7260eb3be75.zip
https://github.com/meshtastic/device-ui/archive/9ed5355a24059750e9b2eb5d669574d9ea42a37b.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]
lib_deps =
# renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO
adafruit/Adafruit BusIO@1.17.4
adafruit/Adafruit BusIO@1.17.2
# renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor
adafruit/Adafruit Unified Sensor@1.1.15
# renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library
@@ -165,11 +161,11 @@ lib_deps =
# renovate: datasource=custom.pio depName=QMC5883L Compass packageName=mprograms/library/QMC5883LCompass
mprograms/QMC5883LCompass@1.2.3
# renovate: datasource=custom.pio depName=DFRobot_RTU packageName=dfrobot/library/DFRobot_RTU
dfrobot/DFRobot_RTU@1.0.6
dfrobot/DFRobot_RTU@1.0.3
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
# renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226
robtillaart/INA226@0.6.5
robtillaart/INA226@0.6.4
# renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
# renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library
@@ -177,13 +173,11 @@ lib_deps =
# renovate: datasource=custom.pio depName=Adafruit LTR390 Library packageName=adafruit/library/Adafruit LTR390 Library
adafruit/Adafruit LTR390 Library@1.1.2
# renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/library/Adafruit PCT2075
adafruit/Adafruit PCT2075@1.0.6
adafruit/Adafruit PCT2075@1.0.5
# renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150
dfrobot/DFRobot_BMM150@1.0.0
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
adafruit/Adafruit TSL2561@1.1.2
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/BH1750_WE@^1.1.10
wollewald/BH1750_WE@^1.1.10
; (not included in native / portduino)
[environmental_extra]
@@ -213,6 +207,6 @@ lib_deps =
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
sensirion/Sensirion Core@0.7.2
sensirion/Sensirion Core@0.7.1
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C SCD4x@1.1.0

View File

@@ -8,7 +8,6 @@
"replacements:all",
"workarounds:all"
],
"baseBranchPatterns": ["master"],
"forkProcessing": "enabled",
"ignoreDeps": [
"protobufs"

View File

@@ -11,11 +11,6 @@
#include <AudioOutputI2S.h>
#include <ESP8266SAM.h>
#ifdef USE_XL9555
#include "ExtensionIOXL9555.hpp"
extern ExtensionIOXL9555 io;
#endif
#define AUDIO_THREAD_INTERVAL_MS 100
class AudioThread : public concurrency::OSThread
@@ -25,16 +20,12 @@ class AudioThread : public concurrency::OSThread
void beginRttl(const void *data, uint32_t len)
{
#ifdef T_LORA_PAGER
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
#endif
setCPUFast(true);
rtttlFile = new AudioFileSourcePROGMEM(data, len);
i2sRtttl = new AudioGeneratorRTTTL();
i2sRtttl->begin(rtttlFile, audioOut);
}
// Also handles actually playing the RTTTL, needs to be called in loop
bool isPlaying()
{
if (i2sRtttl != nullptr) {
@@ -50,16 +41,10 @@ class AudioThread : public concurrency::OSThread
delete i2sRtttl;
i2sRtttl = nullptr;
}
if (rtttlFile != nullptr) {
delete rtttlFile;
rtttlFile = nullptr;
}
delete rtttlFile;
rtttlFile = nullptr;
setCPUFast(false);
#ifdef T_LORA_PAGER
io.digitalWrite(EXPANDS_AMP_EN, LOW);
#endif
}
void readAloud(const char *text)
@@ -70,16 +55,10 @@ class AudioThread : public concurrency::OSThread
i2sRtttl = nullptr;
}
#ifdef T_LORA_PAGER
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
#endif
ESP8266SAM *sam = new ESP8266SAM;
sam->Say(audioOut, text);
delete sam;
setCPUFast(false);
#ifdef T_LORA_PAGER
io.digitalWrite(EXPANDS_AMP_EN, LOW);
#endif
}
protected:
@@ -102,9 +81,9 @@ class AudioThread : public concurrency::OSThread
};
AudioGeneratorRTTTL *i2sRtttl = nullptr;
AudioOutputI2S *audioOut = nullptr;
AudioOutputI2S *audioOut;
AudioFileSourcePROGMEM *rtttlFile = nullptr;
AudioFileSourcePROGMEM *rtttlFile;
};
#endif

View File

@@ -146,7 +146,7 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess
{
int result;
#ifdef ARCH_PORTDUINO
bool utf = !portduino_config.ascii_logs;
bool utf = !settingsMap[ascii_logs];
#else
bool utf = true;
#endif

View File

@@ -38,46 +38,4 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
return useShortName ? "Custom" : "Invalid";
break;
}
}
const char *DisplayFormatters::getDeviceRole(meshtastic_Config_DeviceConfig_Role role)
{
switch (role) {
case meshtastic_Config_DeviceConfig_Role_CLIENT:
return "Client";
break;
case meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE:
return "Client Mute";
break;
case meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN:
return "Client Hidden";
break;
case meshtastic_Config_DeviceConfig_Role_CLIENT_BASE:
return "Client Base";
break;
case meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND:
return "Lost and Found";
break;
case meshtastic_Config_DeviceConfig_Role_TRACKER:
return "Tracker";
break;
case meshtastic_Config_DeviceConfig_Role_SENSOR:
return "Sensor";
break;
case meshtastic_Config_DeviceConfig_Role_TAK:
return "TAK";
break;
case meshtastic_Config_DeviceConfig_Role_TAK_TRACKER:
return "TAK Tracker";
break;
case meshtastic_Config_DeviceConfig_Role_ROUTER:
return "Router";
break;
case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE:
return "Router Late";
break;
default:
return "Unknown";
break;
}
}

View File

@@ -6,5 +6,4 @@ class DisplayFormatters
public:
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
bool usePreset);
static const char *getDeviceRole(meshtastic_Config_DeviceConfig_Role role);
};

View File

@@ -22,9 +22,6 @@ class GPSStatus : public Status
meshtastic_Position p = meshtastic_Position_init_default;
/// Time of last valid GPS fix (millis since boot)
uint32_t lastFixMillis = 0;
public:
GPSStatus() { statusType = STATUS_TYPE_GPS; }
@@ -86,9 +83,6 @@ class GPSStatus : public Status
uint32_t getNumSatellites() const { return p.sats_in_view; }
/// Return millis() when the last GPS fix occurred (0 = never)
uint32_t getLastFixMillis() const { return lastFixMillis; }
bool matches(const GPSStatus *newStatus) const
{
#ifdef GPS_DEBUG
@@ -120,9 +114,6 @@ class GPSStatus : public Status
if (isDirty) {
if (hasLock) {
// Record time of last valid GPS fix
lastFixMillis = millis();
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d", p.timestamp,
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,

View File

@@ -14,16 +14,16 @@ class NodeStatus : public Status
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
uint16_t numOnline = 0;
uint16_t numTotal = 0;
uint8_t numOnline = 0;
uint8_t numTotal = 0;
uint16_t lastNumTotal = 0;
uint8_t lastNumTotal = 0;
public:
bool forceUpdate = false;
NodeStatus() { statusType = STATUS_TYPE_NODE; }
NodeStatus(uint16_t numOnline, uint16_t numTotal, bool forceUpdate = false) : Status()
NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status()
{
this->forceUpdate = forceUpdate;
this->numOnline = numOnline;
@@ -34,11 +34,11 @@ class NodeStatus : public Status
void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }
uint16_t getNumOnline() const { return numOnline; }
uint8_t getNumOnline() const { return numOnline; }
uint16_t getNumTotal() const { return numTotal; }
uint8_t getNumTotal() const { return numTotal; }
uint16_t getLastNumTotal() const { return lastNumTotal; }
uint8_t getLastNumTotal() const { return lastNumTotal; }
bool matches(const NodeStatus *newStatus) const
{
@@ -56,7 +56,7 @@ class NodeStatus : public Status
numTotal = newStatus->getNumTotal();
}
if (isDirty || newStatus->forceUpdate) {
LOG_DEBUG("Node status update: %u online, %u total", numOnline, numTotal);
LOG_DEBUG("Node status update: %d online, %d total", numOnline, numTotal);
onNewStatus.notifyObservers(this);
}
return 0;

View File

@@ -194,7 +194,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se
#ifdef BATTERY_PIN
void battery_adcEnable()
static void adcEnable()
{
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
@@ -214,7 +214,7 @@ void battery_adcEnable()
#endif
}
static void battery_adcDisable()
static void adcDisable()
{
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
@@ -278,11 +278,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
break;
}
}
#if defined(BATTERY_CHARGING_INV)
// bit of trickery to show 99% up until the charge finishes
if (!digitalRead(BATTERY_CHARGING_INV) && battery_SOC > 99)
battery_SOC = 99;
#endif
return clamp((int)(battery_SOC), 0, 100);
}
@@ -325,7 +320,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0;
float scaled = 0;
battery_adcEnable();
adcEnable();
#ifdef ARCH_ESP32 // ADC block for espressif platforms
raw = espAdcRead();
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
@@ -337,7 +332,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
raw = raw / BATTERY_SENSE_SAMPLES;
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
#endif
battery_adcDisable();
adcDisable();
if (!initial_read_done) {
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
@@ -460,8 +455,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
// if it's not HIGH - check the battery
#endif
#elif defined(MUZI_BASE)
return NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk;
#endif
return getBattVoltage() > chargingVolt;
}
@@ -477,8 +470,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
#endif
#ifdef EXT_CHRG_DETECT
return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value;
#elif defined(BATTERY_CHARGING_INV)
return !digitalRead(BATTERY_CHARGING_INV);
#else
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
if (hasINA()) {
@@ -571,7 +562,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
config.power.device_battery_ina_address) {
if (!ina226Sensor.isInitialized())
return ina226Sensor.runOnce() > 0;
return ina226Sensor.isRunning();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
config.power.device_battery_ina_address) {
if (!ina260Sensor.isInitialized())
@@ -701,24 +691,7 @@ bool Power::setup()
#ifdef NRF_APM
found = true;
#endif
#ifdef EXT_PWR_DETECT
attachInterrupt(
EXT_PWR_DETECT,
[]() {
power->setIntervalFromNow(0);
runASAP = true;
},
CHANGE);
#endif
#ifdef BATTERY_CHARGING_INV
attachInterrupt(
BATTERY_CHARGING_INV,
[]() {
power->setIntervalFromNow(0);
runASAP = true;
},
CHANGE);
#endif
enabled = found;
low_voltage_counter = 0;
@@ -775,8 +748,6 @@ void Power::shutdown()
if (screen) {
#ifdef T_DECK_PRO
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
#elif defined(USE_EINK)
screen->showSimpleBanner("Shutting Down...", 2250); // dismiss after 3 seconds to avoid the banner on the sleep screen
#else
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
#endif
@@ -857,11 +828,8 @@ void Power::readPowerStatus()
// Notify any status instances that are observing us
const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isChargingNow, batteryVoltageMv, batteryChargePercent);
if (millis() > lastLogTime + 50 * 1000) {
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
lastLogTime = millis();
}
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(),
powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != memGet.getFreeHeap()) {
@@ -924,8 +892,13 @@ void Power::readPowerStatus()
low_voltage_counter++;
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
// We can't trigger deep sleep on NRF52, it's freezing the board
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
#else
LOG_INFO("Low voltage detected, trigger deep sleep");
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
}
} else {
low_voltage_counter = 0;
@@ -1453,7 +1426,7 @@ class LipoCharger : public HasBatteryLevel
/**
* return true if there is an external power source detected
*/
virtual bool isVbusIn() override { return PPM->isVbusIn(); }
virtual bool isVbusIn() override { return PPM->getVbusVoltage() > 0; }
/**
* return true if the battery is currently charging
@@ -1565,4 +1538,4 @@ bool Power::meshSolarInit()
{
return false;
}
#endif
#endif

View File

@@ -57,21 +57,21 @@ static bool isPowered()
static void sdsEnter()
{
LOG_POWERFSM("State: SDS");
LOG_DEBUG("State: SDS");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false);
}
static void lowBattSDSEnter()
{
LOG_POWERFSM("State: Lower batt SDS");
LOG_DEBUG("State: Lower batt SDS");
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true);
}
extern Power *power;
static void shutdownEnter()
{
LOG_POWERFSM("State: SHUTDOWN");
LOG_DEBUG("State: SHUTDOWN");
shutdownAtMsec = millis();
}
@@ -81,7 +81,7 @@ static uint32_t secsSlept;
static void lsEnter()
{
LOG_POWERFSM("lsEnter begin, ls_secs=%u", config.power.ls_secs);
LOG_INFO("lsEnter begin, ls_secs=%u", config.power.ls_secs);
if (screen)
screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time
@@ -155,12 +155,12 @@ static void lsIdle()
static void lsExit()
{
LOG_POWERFSM("State: lsExit");
LOG_INFO("Exit state: LS");
}
static void nbEnter()
{
LOG_POWERFSM("State: nbEnter");
LOG_DEBUG("State: NB");
if (screen)
screen->setOn(false);
#ifdef ARCH_ESP32
@@ -173,7 +173,6 @@ static void nbEnter()
static void darkEnter()
{
LOG_POWERFSM("State: darkEnter");
setBluetoothEnable(true);
if (screen)
screen->setOn(false);
@@ -181,7 +180,7 @@ static void darkEnter()
static void serialEnter()
{
LOG_POWERFSM("State: serialEnter");
LOG_DEBUG("State: SERIAL");
setBluetoothEnable(false);
if (screen) {
screen->setOn(true);
@@ -190,14 +189,13 @@ static void serialEnter()
static void serialExit()
{
LOG_POWERFSM("State: serialExit");
// Turn bluetooth back on when we leave serial stream API
setBluetoothEnable(true);
}
static void powerEnter()
{
LOG_POWERFSM("State: powerEnter");
// LOG_DEBUG("State: POWER");
if (!isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
LOG_INFO("Loss of power in Powered");
@@ -212,7 +210,6 @@ static void powerEnter()
static void powerIdle()
{
// LOG_POWERFSM("State: powerIdle"); // very chatty
if (!isPowered()) {
// If we got here, we are in the wrong state
LOG_INFO("Loss of power in Powered");
@@ -222,13 +219,14 @@ static void powerIdle()
static void powerExit()
{
LOG_POWERFSM("State: powerExit");
if (screen)
screen->setOn(true);
setBluetoothEnable(true);
}
static void onEnter()
{
LOG_POWERFSM("State: onEnter");
LOG_DEBUG("State: ON");
if (screen)
screen->setOn(true);
setBluetoothEnable(true);
@@ -236,7 +234,6 @@ static void onEnter()
static void onIdle()
{
LOG_POWERFSM("State: onIdle");
if (isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
powerFSM.trigger(EVENT_POWER_CONNECTED);
@@ -245,7 +242,7 @@ static void onIdle()
static void bootEnter()
{
LOG_POWERFSM("State: bootEnter");
LOG_DEBUG("State: BOOT");
}
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
@@ -322,6 +319,11 @@ void PowerFSM_setup()
// if any packet destined for phone arrives, turn on bluetooth at least
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
// Removed 2.7: we don't show the nodes individually for every node on the screen anymore
// powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
// powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
// powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
// Show the received text message
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
@@ -370,7 +372,7 @@ void PowerFSM_setup()
// Don't add power saving transitions if we are a power saving tracker or sensor or have Wifi enabled. Sleep will be initiated
// through the modules
#if HAS_WIFI && !defined(MESHTASTIC_EXCLUDE_WIFI)
#if HAS_WIFI || !defined(MESHTASTIC_EXCLUDE_WIFI)
bool isTrackerOrSensor = 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;

View File

@@ -2,12 +2,6 @@
#include "configuration.h"
#ifdef PowerFSMDebug
#define LOG_POWERFSM(...) LOG_DEBUG(__VA_ARGS__)
#else
#define LOG_POWERFSM(...)
#endif
// See sw-design.md for documentation
#define EVENT_PRESS 1

View File

@@ -4,7 +4,6 @@
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "main.h"
#include "memGet.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
#include <assert.h>
#include <cstring>
@@ -58,7 +57,7 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l
#endif
#ifdef ARCH_PORTDUINO
bool color = !portduino_config.ascii_logs;
bool color = !settingsMap[ascii_logs];
#else
bool color = true;
#endif
@@ -100,7 +99,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
size_t r = 0;
#ifdef ARCH_PORTDUINO
bool color = !portduino_config.ascii_logs;
bool color = !settingsMap[ascii_logs];
#else
bool color = true;
#endif
@@ -167,16 +166,6 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
print(thread->ThreadName);
print("] ");
}
#ifdef DEBUG_HEAP
// Add heap free space bytes prefix before every log message
#ifdef ARCH_PORTDUINO
::printf("[heap %u] ", memGet.getFreeHeap());
#else
printf("[heap %u] ", memGet.getFreeHeap());
#endif
#endif // DEBUG_HEAP
r += vprintf(logLevel, format, arg);
}
@@ -299,7 +288,7 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
#if ARCH_PORTDUINO
// level trace is special, two possible ways to handle it.
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
if (portduino_config.traceFilename != "") {
if (settingsStrings[traceFilename] != "") {
va_list arg;
va_start(arg, format);
try {
@@ -308,18 +297,18 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
}
va_end(arg);
}
if (portduino_config.logoutputlevel < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
delete[] newFormat;
return;
}
}
if (portduino_config.logoutputlevel < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
delete[] newFormat;
return;
} else if (portduino_config.logoutputlevel < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
} else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
delete[] newFormat;
return;
} else if (portduino_config.logoutputlevel < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
} else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
delete[] newFormat;
return;
}

View File

@@ -6,14 +6,6 @@
#include "configuration.h"
#include "time.h"
#if defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT
#define IS_USB_SERIAL
#ifdef SERIAL_HAS_ON_RECEIVE
#undef SERIAL_HAS_ON_RECEIVE
#endif
#include "HWCDC.h"
#endif
#ifdef RP2040_SLOW_CLOCK
#define Port Serial2
#else
@@ -30,12 +22,7 @@ SerialConsole *console;
void consoleInit()
{
auto sc = new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
#if defined(SERIAL_HAS_ON_RECEIVE)
// onReceive does only exist for HardwareSerial not for USB CDC serial
Port.onReceive([sc]() { sc->rxInt(); });
#endif
new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
DEBUG_PORT.rpInit(); // Simply sets up semaphore
}
@@ -50,7 +37,6 @@ void consolePrintf(const char *format, ...)
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
{
api_type = TYPE_SERIAL;
assert(!console);
console = this;
canWrite = false; // We don't send packets to our port until it has talked to us first
@@ -79,21 +65,14 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
int32_t SerialConsole::runOnce()
{
#ifdef HELTEC_MESH_SOLAR
// After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module.
if (moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port &&
moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG) {
//After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module.
if(moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port
&& moduleConfig.serial.mode==meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG)
{
return 250;
}
#endif
int32_t delay = runOncePart();
#if defined(SERIAL_HAS_ON_RECEIVE) || defined(CONFIG_IDF_TARGET_ESP32S2)
return Port.available() ? delay : INT32_MAX;
#elif defined(IS_USB_SERIAL)
return HWCDC::isPlugged() ? delay : (1000 * 20);
#else
return delay;
#endif
return runOncePart();
}
void SerialConsole::flush()
@@ -101,18 +80,6 @@ void SerialConsole::flush()
Port.flush();
}
// trigger tx of serial data
void SerialConsole::onNowHasData(uint32_t fromRadioNum)
{
setIntervalFromNow(0);
}
// trigger rx of serial data
void SerialConsole::rxInt()
{
setIntervalFromNow(0);
}
// 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()
{

View File

@@ -32,14 +32,11 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur
virtual int32_t runOnce() override;
void flush();
void rxInt();
protected:
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
virtual void onNowHasData(uint32_t fromRadioNum) override;
/// Possibly switch to protobufs if we see a valid protobuf message
virtual void log_to_serial(const char *logLevel, const char *format, va_list arg);
};

View File

@@ -5,7 +5,7 @@
BuzzerFeedbackThread *buzzerFeedbackThread;
BuzzerFeedbackThread::BuzzerFeedbackThread()
BuzzerFeedbackThread::BuzzerFeedbackThread() : OSThread("BuzzerFeedback")
{
if (inputBroker)
inputObserver.observe(inputBroker);
@@ -15,24 +15,24 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
{
// Only provide feedback if buzzer is enabled for notifications
if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED ||
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY ||
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY) {
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY) {
return 0; // Let other handlers process the event
}
// Track last event time for potential future use
lastEventTime = millis();
needsUpdate = true;
// Handle different input events with appropriate buzzer feedback
switch (event->inputEvent) {
case INPUT_BROKER_USER_PRESS:
case INPUT_BROKER_ALT_PRESS:
case INPUT_BROKER_SELECT:
case INPUT_BROKER_SELECT_LONG:
playBeep(); // Confirmation feedback
break;
case INPUT_BROKER_UP:
case INPUT_BROKER_UP_LONG:
case INPUT_BROKER_DOWN:
case INPUT_BROKER_DOWN_LONG:
case INPUT_BROKER_LEFT:
case INPUT_BROKER_RIGHT:
playChirp(); // Navigation feedback
@@ -58,4 +58,15 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
}
return 0; // Allow other handlers to process the event
}
}
int32_t BuzzerFeedbackThread::runOnce()
{
// This thread is primarily event-driven, but we can use runOnce
// for any periodic tasks if needed in the future
needsUpdate = false;
// Run every 100ms when active, less frequently when idle
return needsUpdate ? 100 : 1000;
}

View File

@@ -4,7 +4,7 @@
#include "concurrency/OSThread.h"
#include "input/InputBroker.h"
class BuzzerFeedbackThread
class BuzzerFeedbackThread : public concurrency::OSThread
{
CallbackObserver<BuzzerFeedbackThread, const InputEvent *> inputObserver =
CallbackObserver<BuzzerFeedbackThread, const InputEvent *>(this, &BuzzerFeedbackThread::handleInputEvent);
@@ -12,6 +12,13 @@ class BuzzerFeedbackThread
public:
BuzzerFeedbackThread();
int handleInputEvent(const InputEvent *event);
protected:
virtual int32_t runOnce() override;
private:
uint32_t lastEventTime = 0;
bool needsUpdate = false;
};
extern BuzzerFeedbackThread *buzzerFeedbackThread;

View File

@@ -90,9 +90,7 @@ void OSThread::run()
if (heap < newHeap)
LOG_HEAP("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
#endif
#ifdef DEBUG_LOOP_TIMING
LOG_DEBUG("====== Thread next run in: %d", newDelay);
#endif
runned();
if (newDelay >= 0)

View File

@@ -33,32 +33,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "pcf8563.h"
#endif
/* Offer chance for variant-specific defines */
#include "variant.h"
// -----------------------------------------------------------------------------
// Display feature overrides
// -----------------------------------------------------------------------------
// Allow build environments to opt-in explicitly to the E-Ink UI stack while
// keeping headless targets slim by default. Existing variants that already
// define USE_EINK continue to work without additional flags.
#ifndef MESHTASTIC_USE_EINK_UI
#ifdef USE_EINK
#define MESHTASTIC_USE_EINK_UI 1
#else
#define MESHTASTIC_USE_EINK_UI 0
#endif
#endif
#if MESHTASTIC_USE_EINK_UI
#ifndef USE_EINK
#define USE_EINK
#endif
#else
#undef USE_EINK
#endif
// -----------------------------------------------------------------------------
// Version
// -----------------------------------------------------------------------------
@@ -143,17 +117,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SX126X_MAX_POWER 22
#endif
#ifdef USE_GC1109_PA
// Power Amps are often non-linear, so we can use an array of values for the power curve
#define NUM_PA_POINTS 22
#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
#endif
#ifdef RAK13302
#define NUM_PA_POINTS 22
#define TX_GAIN_LORA 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8
#endif
// Default system gain to 0 if not defined
#ifndef TX_GAIN_LORA
#define TX_GAIN_LORA 0
@@ -251,7 +214,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define ICM20948_ADDR_ALT 0x68
#define BHI260AP_ADDR 0x28
#define BMM150_ADDR 0x13
#define DA217_ADDR 0x26
// -----------------------------------------------------------------------------
// LED
@@ -273,9 +235,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Touchscreen
// -----------------------------------------------------------------------------
#define FT6336U_ADDR 0x48
#define CST328_ADDR 0x1A // same address as CST226SE
#define CHSC6X_ADDR 0x2E
#define CST226SE_ADDR_ALT 0x5A
#define CST328_ADDR 0x1A
// -----------------------------------------------------------------------------
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
@@ -294,18 +254,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// convert 24-bit color to 16-bit (56K)
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
/* Step #1: offer chance for variant-specific defines */
#include "variant.h"
#if defined(VEXT_ENABLE) && !defined(VEXT_ON_VALUE)
// Older variant.h files might not be defining this value, so stay with the old default
#define VEXT_ON_VALUE LOW
#endif
// -----------------------------------------------------------------------------
// Rotary encoder
// -----------------------------------------------------------------------------
#ifndef ROTARY_DELAY
#define ROTARY_DELAY 5
#endif
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------
@@ -394,9 +350,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef HAS_BLUETOOTH
#define HAS_BLUETOOTH 0
#endif
#ifndef USE_TFTDISPLAY
#define USE_TFTDISPLAY 0
#endif
#ifndef HW_VENDOR
#error HW_VENDOR must be defined
@@ -423,13 +376,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HAS_RGB_LED
#endif
#ifndef LED_STATE_OFF
#define LED_STATE_OFF 0
#endif
#ifndef LED_STATE_ON
#define LED_STATE_ON 1
#endif
// default mapping of pins
#if defined(PIN_BUTTON2) && !defined(CANCEL_BUTTON_PIN)
#define ALT_BUTTON_PIN PIN_BUTTON2

View File

@@ -25,8 +25,8 @@ ScanI2C::FoundDevice ScanI2C::firstScreen() const
ScanI2C::FoundDevice ScanI2C::firstRTC() const
{
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563, RTC_RX8130CE};
return firstOfOrNONE(3, types);
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const

View File

@@ -14,7 +14,6 @@ class ScanI2C
SCREEN_ST7567,
RTC_RV3028,
RTC_PCF8563,
RTC_RX8130CE,
CARDKB,
TDECKKB,
BBQ10KB,
@@ -82,11 +81,7 @@ class ScanI2C
BHI260AP,
BMM150,
TSL2561,
DRV2605,
BH1750,
DA217,
CHSC6X,
CST226SE
DRV2605
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@@ -1,16 +0,0 @@
#include "ScanI2CConsumer.h"
#include <forward_list>
static std::forward_list<ScanI2CConsumer *> ScanI2CConsumers;
ScanI2CConsumer::ScanI2CConsumer()
{
ScanI2CConsumers.push_front(this);
}
void ScanI2CCompleted(ScanI2C *i2cScanner)
{
for (ScanI2CConsumer *consumer : ScanI2CConsumers) {
consumer->i2cScanFinished(i2cScanner);
}
}

View File

@@ -1,13 +0,0 @@
#pragma once
#include "ScanI2C.h"
#include <stddef.h>
class ScanI2CConsumer
{
public:
ScanI2CConsumer();
virtual void i2cScanFinished(ScanI2C *i2cScanner) = 0;
};
void ScanI2CCompleted(ScanI2C *i2cScanner);

View File

@@ -106,7 +106,6 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
if (i2cBus->available())
i2cBus->read();
}
LOG_DEBUG("Register value: 0x%x", value);
return value;
}
@@ -198,9 +197,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#ifdef PCF8563_RTC
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address)
#endif
#ifdef RX8130CE_RTC
SCAN_SIMPLE_CASE(RX8130CE_RTC, RTC_RX8130CE, "RX8130CE", (uint8_t)addr.address)
#endif
case CARDKB_ADDR:
// Do we have the RAK14006 instead?
@@ -378,13 +374,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2);
if (registerValue == 0x5449) {
type = OPT3001;
logFoundDevice("OPT3001", (uint8_t)addr.address);
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2) != 0) { // unique SHT4x serial number
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c || registerValue == 0xc8d) {
type = SHT4X;
logFoundDevice("SHT4X", (uint8_t)addr.address);
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
type = OPT3001;
logFoundDevice("OPT3001", (uint8_t)addr.address);
} else {
type = SHT31;
logFoundDevice("SHT31", (uint8_t)addr.address);
@@ -465,23 +461,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
case TCA9555_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 1);
if (registerValue == 0x13) {
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
if (registerValue == 0x81) {
type = DA217;
logFoundDevice("DA217", (uint8_t)addr.address);
} else {
type = TCA9555;
logFoundDevice("TCA9555", (uint8_t)addr.address);
}
} else {
type = TCA9555;
logFoundDevice("TCA9555", (uint8_t)addr.address);
}
break;
case TSL25911_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
if (registerValue == 0x50) {
@@ -499,38 +480,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address);
case CST328_ADDR:
// Do we have the CST328 or the CST226SE
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xAB), 1);
if (registerValue == 0xA9) {
type = CST226SE;
logFoundDevice("CST226SE", (uint8_t)addr.address);
} else {
type = CST328;
logFoundDevice("CST328", (uint8_t)addr.address);
}
break;
SCAN_SIMPLE_CASE(CHSC6X_ADDR, CHSC6X, "CHSC6X", (uint8_t)addr.address);
case LTR553ALS_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x86), 1); // Part ID register
if (registerValue == 0x92) { // LTR553ALS Part ID
type = LTR553ALS;
logFoundDevice("LTR553ALS", (uint8_t)addr.address);
} else {
// Test BH1750 - send power on command
i2cBus->beginTransmission(addr.address);
i2cBus->write(0x01); // Power On command
uint8_t bh1750_error = i2cBus->endTransmission();
if (bh1750_error == 0) {
type = BH1750;
logFoundDevice("BH1750", (uint8_t)addr.address);
} else {
LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address);
}
}
break;
SCAN_SIMPLE_CASE(CST328_ADDR, CST328, "CST328", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(LTR553ALS_ADDR, LTR553ALS, "LTR553ALS", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(BHI260AP_ADDR, BHI260AP, "BHI260AP", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(SCD4X_ADDR, SCD4X, "SCD4X", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(BMM150_ADDR, BMM150, "BMM150", (uint8_t)addr.address);
@@ -539,12 +490,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#endif
case MLX90614_ADDR_DEF:
// Do we have the MLX90614 or the MPR121KB or the CST226SE
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x06), 1);
if (registerValue == 0xAB) {
type = CST226SE;
logFoundDevice("CST226SE", (uint8_t)addr.address);
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1) == 0x5a) {
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
if (registerValue == 0x5a) {
type = MLX90614;
logFoundDevice("MLX90614", (uint8_t)addr.address);
} else {
@@ -562,11 +509,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
#ifdef HAS_ICM20948
type = ICM20948;
logFoundDevice("ICM20948", (uint8_t)addr.address);
break;
#endif
if (registerValue == 0xEA) {
type = ICM20948;
logFoundDevice("ICM20948", (uint8_t)addr.address);
@@ -635,7 +577,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
scanPort(port, nullptr, 0);
}
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address)
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
{
if (address.port == ScanI2C::I2CPort::WIRE) {
return &Wire;

View File

@@ -23,12 +23,12 @@ class ScanI2CTwoWire : public ScanI2C
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
static TwoWire *fetchI2CBus(ScanI2C::DeviceAddress);
protected:
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;

View File

@@ -38,16 +38,14 @@ template <typename T, std::size_t N> std::size_t array_count(const T (&)[N])
return N;
}
#ifndef GPS_SERIAL_PORT
#define GPS_SERIAL_PORT Serial1
#endif
#if defined(ARCH_NRF52)
Uart *GPS::_serial_gps = &GPS_SERIAL_PORT;
#elif defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
#if defined(GPS_SERIAL_PORT)
HardwareSerial *GPS::_serial_gps = &GPS_SERIAL_PORT;
#else
HardwareSerial *GPS::_serial_gps = &Serial1;
#endif
#elif defined(ARCH_RP2040)
SerialUART *GPS::_serial_gps = &GPS_SERIAL_PORT;
SerialUART *GPS::_serial_gps = &Serial1;
#else
HardwareSerial *GPS::_serial_gps = nullptr;
#endif
@@ -242,9 +240,6 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
buffer[bytesRead] = b;
bytesRead++;
if ((bytesRead == 767) || (b == '\r')) {
#ifdef GPS_DEBUG
LOG_DEBUG(debugmsg.c_str());
#endif
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
#ifdef GPS_DEBUG
LOG_DEBUG("Found: %s", message); // Log the found message
@@ -252,6 +247,9 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
return GNSS_RESPONSE_OK;
} else {
bytesRead = 0;
#ifdef GPS_DEBUG
LOG_DEBUG(debugmsg.c_str());
#endif
}
}
}
@@ -496,27 +494,38 @@ bool GPS::setup()
if (!didSerialInit) {
int msglen = 0;
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
#ifdef TRACKER_T1000_E
// add power up/down strategy, improve ag3335 detection success
digitalWrite(PIN_GPS_EN, LOW);
delay(500);
digitalWrite(GPS_VRTC_EN, LOW);
delay(1000);
digitalWrite(GPS_VRTC_EN, HIGH);
delay(500);
digitalWrite(PIN_GPS_EN, HIGH);
delay(1000);
#endif
if (probeTries < GPS_PROBETRIES) {
LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (currentStep == 0 && ++speedSelect == array_count(serialSpeeds)) {
if (++speedSelect == array_count(serialSpeeds)) {
speedSelect = 0;
++probeTries;
}
}
}
// Rare Serial Speeds
#ifndef CONFIG_IDF_TARGET_ESP32C6
if (probeTries == GPS_PROBETRIES) {
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
gnssModel = probe(rareSerialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
if (currentStep == 0 && ++speedSelect == array_count(rareSerialSpeeds)) {
if (++speedSelect == array_count(rareSerialSpeeds)) {
LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE);
return true;
}
}
}
#endif
}
if (gnssModel != GNSS_MODEL_UNKNOWN) {
@@ -798,14 +807,6 @@ bool GPS::setup()
} else {
LOG_INFO("GNSS module configuration saved!");
}
} else if (gnssModel == GNSS_MODEL_CM121) {
// only ask for RMC and GGA
// enable GGA
_serial_gps->write("$CFGMSG,0,0,1,1*1B\r\n");
delay(250);
// enable RMC
_serial_gps->write("$CFGMSG,0,4,1,1*1F\r\n");
delay(250);
}
didSerialInit = true;
}
@@ -1022,7 +1023,7 @@ void GPS::down()
LOG_DEBUG("%us until next search", sleepTime / 1000);
// If update interval less than 10 seconds, no attempt to sleep
if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS || sleepTime == 0)
if (updateInterval <= 10 * 1000UL || sleepTime == 0)
setPowerState(GPS_IDLE);
else {
@@ -1083,7 +1084,7 @@ int32_t GPS::runOnce()
return disable();
}
if (!setup())
return currentDelay; // Setup failed, re-run in two seconds
return 2000; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
@@ -1093,29 +1094,11 @@ int32_t GPS::runOnce()
publishUpdate();
}
// ======================== GPS_ACTIVE state ========================
// In GPS_ACTIVE state, GPS is powered on and we're receiving NMEA messages.
// We use the following logic to determine when to update the local position
// or time by running GPS::publishUpdate.
// Note: Local position update is asynchronous to position broadcast. We
// generally run this state every gps_update_interval seconds, and in most cases
// gps_update_interval is faster than the position broadcast interval so there's a
// fresh position ready when the device wants to broadcast one on the mesh.
//
// 1. Got a time for the first time --> set the time, don't publish.
// 2. Got a lock for the first time
// --> If gps_update_interval is <= 10s --> publishUpdate
// --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s)
// 3. Got a lock after turning back on
// --> If gps_update_interval is <= 10s --> publishUpdate
// --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s)
// 4. Hold has expired
// --> If we have a time and a location --> publishUpdate
// --> down()
// 5. Search time has expired
// --> If we have a time and a location --> publishUpdate
// --> If we had a location before but don't now --> publishUpdate
// --> down()
// Repeaters have no need for GPS
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
return disable();
}
if (whileActive()) {
// if we have received valid NMEA claim we are connected
setConnected();
@@ -1125,81 +1108,55 @@ int32_t GPS::runOnce()
if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue())
up();
// quality of the previous fix. We set it to 0 when we go down, so it's a way
// to check if we're getting a lock after being GPS_OFF.
// If we've already set time from the GPS, no need to ask the GPS
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
shouldPublish = true;
}
uint8_t prev_fixQual = fixQual;
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE");
hasValidLocation = true;
shouldPublish = true;
// Hold for 20secs after getting a lock to download ephemeris etc
fixHoldEnds = millis() + 20000;
}
if (powerState == GPS_ACTIVE) {
// if gps_update_interval is <=10s, GPS never goes off, so we treat that differently
uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval);
if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on.
fixHoldEnds = millis() + 20000;
shouldPublish = true; // Publish immediately, since next publish is at end of hold
}
// 1. Got a time for the first time
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
}
bool tooLong = scheduling.searchedTooLong();
if (tooLong)
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time");
// 2. Got a lock for the first time, or 3. Got a lock after turning back on
bool gotLoc = lookForLocation();
if (gotLoc) {
#ifdef GPS_DEBUG
if (!hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE");
}
#endif
if (updateInterval <= GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS) {
hasValidLocation = true;
shouldPublish = true;
} else if (!hasValidLocation || prev_fixQual == 0 || (fixHoldEnds + GPS_THREAD_INTERVAL) < millis()) {
hasValidLocation = true;
// Hold for up to 20secs after getting a lock to download ephemeris etc
uint32_t holdTime = updateInterval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS;
if (holdTime > GPS_FIX_HOLD_MAX_MS)
holdTime = GPS_FIX_HOLD_MAX_MS;
fixHoldEnds = millis() + holdTime;
#ifdef GPS_DEBUG
LOG_DEBUG("Holding for %ums after lock", holdTime);
#endif
}
}
bool tooLong = scheduling.searchedTooLong();
// Once we get a location we no longer desperately want an update
if ((gotLoc && gotTime) || tooLong) {
if (tooLong && !gotLoc) {
LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time");
// we didn't get a location during this ack window, therefore declare loss of lock
if (hasValidLocation) {
p = meshtastic_Position_init_default;
hasValidLocation = false;
shouldPublish = true;
#ifdef GPS_DEBUG
LOG_DEBUG("hasValidLocation FALLING EDGE");
#endif
}
p = meshtastic_Position_init_default;
hasValidLocation = false;
}
// Hold has expired , Search time has expired, we got a time only, or we never needed to hold.
bool holdExpired = (fixHoldEnds != 0 && millis() > fixHoldEnds);
if (shouldPublish || tooLong || holdExpired) {
if (gotTime && hasValidLocation) {
shouldPublish = true;
}
if (shouldPublish) {
fixHoldEnds = 0;
publishUpdate();
}
// There's a chance we just got a time, so keep going to see if we can get a location too
if (tooLong || holdExpired) {
down();
}
if (millis() > fixHoldEnds) {
shouldPublish = true; // publish our update at the end of the lock hold
publishUpdate();
down();
#ifdef GPS_DEBUG
} else if (fixHoldEnds != 0) {
} else {
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
#endif
}
}
// ===================== end GPS_ACTIVE state ========================
// If state has changed do a publish
publishUpdate();
if (config.position.fixed_position == true && hasValidLocation)
return disable(); // This should trigger when we have a fixed position, and get that first position
@@ -1256,215 +1213,157 @@ static const char *DETECTED_MESSAGE = "%s detected";
GnssModel_t GPS::probe(int serialSpeed)
{
uint8_t buffer[768] = {0};
switch (currentStep) {
case 0: {
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
_serial_gps->end();
_serial_gps->begin(serialSpeed);
_serial_gps->end();
_serial_gps->begin(serialSpeed);
#elif defined(ARCH_RP2040)
_serial_gps->end();
_serial_gps->setFIFOSize(256);
_serial_gps->begin(serialSpeed);
_serial_gps->end();
_serial_gps->setFIFOSize(256);
_serial_gps->begin(serialSpeed);
#else
if (_serial_gps->baudRate() != serialSpeed) {
LOG_DEBUG("Set GPS Baud to %i", serialSpeed);
_serial_gps->updateBaudRate(serialSpeed);
}
if (_serial_gps->baudRate() != serialSpeed) {
LOG_DEBUG("Set Baud to %i", serialSpeed);
_serial_gps->updateBaudRate(serialSpeed);
}
#endif
memset(&ublox_info, 0, sizeof(ublox_info));
delay(100);
memset(&ublox_info, 0, sizeof(ublox_info));
uint8_t buffer[768] = {0};
delay(100);
#if defined(PIN_GPS_RESET) && PIN_GPS_RESET != -1
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
delay(10);
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
delay(20);
// Close NMEA sequences on Ublox
_serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n");
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
delay(20);
// attempt to detect the chip based on boot messages
std::vector<ChipInfo> passive_detect = {
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
if (detectedDriver != GNSS_MODEL_UNKNOWN) {
return detectedDriver;
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A
std::vector<ChipInfo> unicore = {{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}};
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
std::vector<ChipInfo> atgm = {
{"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H},
/* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */
{"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}};
PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500);
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
std::vector<ChipInfo> airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}};
PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000);
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
// Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms
_serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
delay(20);
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D},
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B},
{"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B},
{"L80", "_3339_", GNSS_MODEL_MTK_L76B}};
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
UBXChecksum(cfg_rate, sizeof(cfg_rate));
clearBuffer();
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct
GPS_RESPONSE response = getACK(0x06, 0x08, 750);
if (response == GNSS_RESPONSE_NONE) {
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
return GNSS_MODEL_UNKNOWN;
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed);
}
memset(buffer, 0, sizeof(buffer));
uint8_t _message_MONVER[8] = {
0xB5, 0x62, // Sync message for UBX protocol
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
0x00, 0x00 // Checksum
};
// Get Ublox gnss module hardware and software info
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
clearBuffer();
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200);
if (len) {
uint16_t position = 0;
for (int i = 0; i < 30; i++) {
ublox_info.swVersion[i] = buffer[position];
position++;
}
for (int i = 0; i < 10; i++) {
ublox_info.hwVersion[i] = buffer[position];
position++;
}
#endif
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
delay(20);
// Close NMEA sequences on Ublox
_serial_gps->write("$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n");
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
delay(20);
// Close NMEA sequences on CM121
_serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n");
_serial_gps->write("$CFGMSG,0,2,0,1*18\r\n");
_serial_gps->write("$CFGMSG,0,3,0,1*19\r\n");
currentDelay = 20;
currentStep = 1;
return GNSS_MODEL_UNKNOWN;
}
case 1: {
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
std::vector<ChipInfo> unicore = {
{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
currentDelay = 20;
currentStep = 2;
return GNSS_MODEL_UNKNOWN;
}
case 2: {
std::vector<ChipInfo> atgm = {
{"ATGM336H", "$GPTXT,01,01,02,HW=ATGM336H", GNSS_MODEL_ATGM336H},
/* ATGM332D series (-11(GPS), -21(BDS), -31(GPS+BDS), -51(GPS+GLONASS), -71-0(GPS+BDS+GLONASS)) based on AT6558 */
{"ATGM332D", "$GPTXT,01,01,02,HW=ATGM332D", GNSS_MODEL_ATGM336H}};
PROBE_FAMILY("ATGM33xx Family", "$PCAS06,1*1A", atgm, 500);
currentDelay = 20;
currentStep = 3;
return GNSS_MODEL_UNKNOWN;
}
case 3: {
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
std::vector<ChipInfo> airoha = {{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352}};
PROBE_FAMILY("Airoha Family", "$PAIR021*39", airoha, 1000);
currentDelay = 20;
currentStep = 4;
return GNSS_MODEL_UNKNOWN;
}
case 4: {
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
currentDelay = 20;
currentStep = 5;
return GNSS_MODEL_UNKNOWN;
}
case 5: {
while (len >= position + 30) {
for (int i = 0; i < 30; i++) {
ublox_info.extension[ublox_info.extensionNo][i] = buffer[position];
position++;
}
ublox_info.extensionNo++;
if (ublox_info.extensionNo > 9)
break;
}
// Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms
_serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
delay(20);
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B}, {"PA1010D", "1010D", GNSS_MODEL_MTK_PA1010D},
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S}, {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B},
{"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}, {"L80-R", "_3337_", GNSS_MODEL_MTK_L76B},
{"L80", "_3339_", GNSS_MODEL_MTK_L76B}};
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
currentDelay = 20;
currentStep = 6;
return GNSS_MODEL_UNKNOWN;
}
case 6: {
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
UBXChecksum(cfg_rate, sizeof(cfg_rate));
clearBuffer();
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct
GPS_RESPONSE response = getACK(0x06, 0x08, 750);
if (response == GNSS_RESPONSE_NONE) {
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
currentDelay = 2000;
currentStep = 0;
return GNSS_MODEL_UNKNOWN;
} else if (response == GNSS_RESPONSE_FRAME_ERRORS) {
LOG_INFO("UBlox Frame Errors (baudrate %d)", serialSpeed);
LOG_DEBUG("Module Info : ");
LOG_DEBUG("Soft version: %s", ublox_info.swVersion);
LOG_DEBUG("Hard version: %s", ublox_info.hwVersion);
LOG_DEBUG("Extensions:%d", ublox_info.extensionNo);
for (int i = 0; i < ublox_info.extensionNo; i++) {
LOG_DEBUG(" %s", ublox_info.extension[i]);
}
memset(buffer, 0, sizeof(buffer));
uint8_t _message_MONVER[8] = {
0xB5, 0x62, // Sync message for UBX protocol
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
0x00, 0x00 // Checksum
};
// Get Ublox gnss module hardware and software info
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
clearBuffer();
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
uint16_t len = getACK(buffer, sizeof(buffer), 0x0A, 0x04, 1200);
if (len) {
uint16_t position = 0;
for (int i = 0; i < 30; i++) {
ublox_info.swVersion[i] = buffer[position];
position++;
}
for (int i = 0; i < 10; i++) {
ublox_info.hwVersion[i] = buffer[position];
position++;
}
while (len >= position + 30) {
for (int i = 0; i < 30; i++) {
ublox_info.extension[ublox_info.extensionNo][i] = buffer[position];
position++;
// tips: extensionNo field is 0 on some 6M GNSS modules
for (int i = 0; i < ublox_info.extensionNo; ++i) {
if (!strncmp(ublox_info.extension[i], "MOD=", 4)) {
strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer));
} else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) {
char *ptr = nullptr;
memset(buffer, 0, sizeof(buffer));
strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer));
LOG_DEBUG("Protocol Version:%s", (char *)buffer);
if (strlen((char *)buffer)) {
ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10);
LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version);
} else {
ublox_info.protocol_version = 0;
}
ublox_info.extensionNo++;
if (ublox_info.extensionNo > 9)
break;
}
LOG_DEBUG("Module Info : ");
LOG_DEBUG("Soft version: %s", ublox_info.swVersion);
LOG_DEBUG("Hard version: %s", ublox_info.hwVersion);
LOG_DEBUG("Extensions:%d", ublox_info.extensionNo);
for (int i = 0; i < ublox_info.extensionNo; i++) {
LOG_DEBUG(" %s", ublox_info.extension[i]);
}
memset(buffer, 0, sizeof(buffer));
// tips: extensionNo field is 0 on some 6M GNSS modules
for (int i = 0; i < ublox_info.extensionNo; ++i) {
if (!strncmp(ublox_info.extension[i], "MOD=", 4)) {
strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer));
} else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) {
char *ptr = nullptr;
memset(buffer, 0, sizeof(buffer));
strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer));
LOG_DEBUG("Protocol Version:%s", (char *)buffer);
if (strlen((char *)buffer)) {
ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10);
LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version);
} else {
ublox_info.protocol_version = 0;
}
}
}
if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6");
return GNSS_MODEL_UBLOX6;
} else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7");
return GNSS_MODEL_UBLOX7;
} else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8");
return GNSS_MODEL_UBLOX8;
} else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9");
return GNSS_MODEL_UBLOX9;
} else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10");
return GNSS_MODEL_UBLOX10;
}
}
}
if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6");
return GNSS_MODEL_UBLOX6;
} else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7");
return GNSS_MODEL_UBLOX7;
} else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8");
return GNSS_MODEL_UBLOX8;
} else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9");
return GNSS_MODEL_UBLOX9;
} else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) {
LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10");
return GNSS_MODEL_UBLOX10;
}
}
LOG_WARN("No GNSS Module (baudrate %d)", serialSpeed);
currentDelay = 2000;
currentStep = 0;
return GNSS_MODEL_UNKNOWN;
}
@@ -1493,12 +1392,12 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
}
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
#ifdef GPS_DEBUG
LOG_DEBUG(response);
#endif
// check if we can see our chips
for (const auto &chipInfo : responseMap) {
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
#ifdef GPS_DEBUG
LOG_DEBUG(response);
#endif
LOG_INFO("%s detected", chipInfo.chipName.c_str());
delete[] response; // Cleanup before return
return chipInfo.driver;
@@ -1506,9 +1405,6 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
}
}
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
#ifdef GPS_DEBUG
LOG_DEBUG(response);
#endif
// Reset the response buffer for the next potential message
responseLen = 0;
response[0] = '\0';
@@ -1527,7 +1423,10 @@ GPS *GPS::createGps()
int8_t _rx_gpio = config.position.rx_gpio;
int8_t _tx_gpio = config.position.tx_gpio;
int8_t _en_gpio = config.position.gps_en_gpio;
#if HAS_GPS && !defined(ARCH_ESP32)
_rx_gpio = 1; // We only specify GPS serial ports on ESP32. Otherwise, these are just flags.
_tx_gpio = 1;
#endif
#if defined(GPS_RX_PIN)
if (!_rx_gpio)
_rx_gpio = GPS_RX_PIN;
@@ -1541,7 +1440,7 @@ GPS *GPS::createGps()
_en_gpio = PIN_GPS_EN;
#endif
#ifdef ARCH_PORTDUINO
if (!portduino_config.has_gps)
if (!settingsMap[has_gps])
return nullptr;
#endif
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
@@ -1592,6 +1491,8 @@ GPS *GPS::createGps()
#ifdef PIN_GPS_RESET
pinMode(PIN_GPS_RESET, OUTPUT);
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
delay(10);
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
#endif
@@ -1601,28 +1502,16 @@ GPS *GPS::createGps()
_serial_gps->setRxBufferSize(SERIAL_BUFFER_SIZE); // the default is 256
#endif
LOG_DEBUG("Use GPIO%d for GPS RX", new_gps->rx_gpio);
LOG_DEBUG("Use GPIO%d for GPS TX", new_gps->tx_gpio);
// ESP32 has a special set of parameters vs other arduino ports
#if defined(ARCH_ESP32)
LOG_DEBUG("Use GPIO%d for GPS RX", new_gps->rx_gpio);
LOG_DEBUG("Use GPIO%d for GPS TX", new_gps->tx_gpio);
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio);
#elif defined(ARCH_RP2040)
_serial_gps->setPinout(new_gps->tx_gpio, new_gps->rx_gpio);
_serial_gps->setFIFOSize(256);
_serial_gps->begin(GPS_BAUDRATE);
#elif defined(ARCH_NRF52)
_serial_gps->setPins(new_gps->rx_gpio, new_gps->tx_gpio);
_serial_gps->begin(GPS_BAUDRATE);
#elif defined(ARCH_STM32WL)
_serial_gps->setTx(new_gps->tx_gpio);
_serial_gps->setRx(new_gps->rx_gpio);
_serial_gps->begin(GPS_BAUDRATE);
#elif defined(ARCH_PORTDUINO)
// Portduino can't set the GPS pins directly.
_serial_gps->begin(GPS_BAUDRATE);
#else
#error Unsupported architecture!
_serial_gps->begin(GPS_BAUDRATE);
#endif
}
return new_gps;
@@ -1689,12 +1578,8 @@ bool GPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_STATISTICS
if (reader.failedChecksum() > lastChecksumFailCount) {
// In a GPS_DEBUG build we want to log all of these. In production, we only care if there are many of them.
#ifndef GPS_DEBUG
if (reader.failedChecksum() > 4)
#endif
LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount,
reader.failedChecksum());
LOG_WARN("%u new GPS checksum failures, for a total of %u", reader.failedChecksum() - lastChecksumFailCount,
reader.failedChecksum());
lastChecksumFailCount = reader.failedChecksum();
}
#endif

View File

@@ -16,9 +16,6 @@
#define GPS_EN_ACTIVE 1
#endif
static constexpr uint32_t GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS = 10 * 1000UL;
static constexpr uint32_t GPS_FIX_HOLD_MAX_MS = 20000;
typedef enum {
GNSS_MODEL_ATGM336H,
GNSS_MODEL_MTK,
@@ -34,8 +31,7 @@ typedef enum {
GNSS_MODEL_MTK_PA1616S,
GNSS_MODEL_AG3335,
GNSS_MODEL_AG3352,
GNSS_MODEL_LS20031,
GNSS_MODEL_CM121
GNSS_MODEL_LS20031
} GnssModel_t;
typedef enum {
@@ -154,8 +150,6 @@ class GPS : private concurrency::OSThread
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
uint8_t currentStep = 0;
int32_t currentDelay = 2000;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
@@ -178,6 +172,8 @@ class GPS : private concurrency::OSThread
*/
bool hasValidLocation = false; // default to false, until we complete our first read
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to
@@ -194,8 +190,6 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */
#if defined(ARCH_RP2040)
static SerialUART *_serial_gps;
#elif defined(ARCH_NRF52)
static Uart *_serial_gps;
#else
static HardwareSerial *_serial_gps;
#endif

View File

@@ -109,39 +109,6 @@ RTCSetResult readFromRTC()
}
return RTCSetResultSuccess;
}
#elif defined(RX8130CE_RTC)
if (rtc_found.address == RX8130CE_RTC) {
uint32_t now = millis();
#ifdef MUZI_BASE
ArtronShop_RX8130CE rtc(&Wire1);
#else
ArtronShop_RX8130CE rtc(&Wire);
#endif
tm t;
if (rtc.getTime(&t)) {
tv.tv_sec = gm_mktime(&t);
tv.tv_usec = 0;
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time from RX8130CE getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
#ifdef BUILD_EPOCH
if (tv.tv_sec < BUILD_EPOCH) {
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
lastTimeValidationWarning = millis();
}
return RTCSetResultInvalidTime;
}
#endif
if (currentQuality == RTCQualityNone) {
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
currentQuality = RTCQualityDevice;
}
return RTCSetResultSuccess;
}
}
#else
if (!gettimeofday(&tv, NULL)) {
uint32_t now = millis();
@@ -247,21 +214,6 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
}
#elif defined(RX8130CE_RTC)
if (rtc_found.address == RX8130CE_RTC) {
#ifdef MUZI_BASE
ArtronShop_RX8130CE rtc(&Wire1);
#else
ArtronShop_RX8130CE rtc(&Wire);
#endif
tm *t = gmtime(&tv->tv_sec);
if (rtc.setTime(*t)) {
LOG_DEBUG("RX8130CE setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1,
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
} else {
LOG_WARN("Failed to set time for RX8130CE");
}
}
#elif defined(ARCH_ESP32)
settimeofday(tv, NULL);
#endif
@@ -318,7 +270,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
#ifdef BUILD_EPOCH
if (tv.tv_sec < BUILD_EPOCH) {
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
LOG_WARN("Ignore time (%lu) before build epoch (%lu)!", printableEpoch, BUILD_EPOCH);
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
lastTimeValidationWarning = millis();
}
return RTCSetResultInvalidTime;
@@ -327,7 +279,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
// Calculate max allowed time safely to avoid overflow in logging
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
LOG_WARN("Ignore time (%lu) too far in the future (build epoch: %lu, max allowed: %lu)!", printableEpoch,
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
lastTimeValidationWarning = millis();
}

Some files were not shown because too many files have changed in this diff Show More