mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-14 23:02:53 +00:00
Compare commits
13 Commits
arduino-es
...
lora-type
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bbdc10054 | ||
|
|
1e8f0a935e | ||
|
|
f73d6e5674 | ||
|
|
5cb5ad91bc | ||
|
|
e6061b5370 | ||
|
|
35ab9fab98 | ||
|
|
2dafe07a74 | ||
|
|
f41f21c53b | ||
|
|
e46a55c127 | ||
|
|
68c4599743 | ||
|
|
839a0e4dd0 | ||
|
|
6e3b71d5fb | ||
|
|
54240c0d87 |
7
.github/actions/setup-base/action.yml
vendored
7
.github/actions/setup-base/action.yml
vendored
@@ -11,6 +11,11 @@ runs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Uncomment build epoch
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -18,7 +23,7 @@ runs:
|
||||
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev lsb-release
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
cache: pip
|
||||
|
||||
11
.github/workflows/main_matrix.yml
vendored
11
.github/workflows/main_matrix.yml
vendored
@@ -3,7 +3,7 @@ concurrency:
|
||||
group: ci-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
on:
|
||||
# # Triggers the workflow on push but only for the main branches
|
||||
# # Triggers the workflow on push but only for the master branch
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
cache: pip
|
||||
@@ -258,7 +258,6 @@ jobs:
|
||||
push: false
|
||||
|
||||
gather-artifacts:
|
||||
# trunk-ignore(checkov/CKV2_GHA_1)
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -371,7 +370,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
@@ -440,7 +439,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
@@ -495,7 +494,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
|
||||
508
.github/workflows/merge_queue.yml
vendored
508
.github/workflows/merge_queue.yml
vendored
@@ -1,508 +0,0 @@
|
||||
name: Merge Queue
|
||||
# Not sure how concurrency works in merge_queue, removing for now.
|
||||
# concurrency:
|
||||
# group: merge-queue-${{ github.head_ref || github.run_id }}
|
||||
# cancel-in-progress: true
|
||||
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:
|
||||
- esp32
|
||||
- esp32s3
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- nrf52840
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
- check
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
cache: pip
|
||||
- run: pip install -U platformio
|
||||
- name: Generate matrix
|
||||
id: jsonStep
|
||||
run: |
|
||||
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
|
||||
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
|
||||
else
|
||||
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr)
|
||||
fi
|
||||
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:
|
||||
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@v4
|
||||
- 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 }}
|
||||
|
||||
check:
|
||||
needs: setup
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix: ${{ fromJson(needs.setup.outputs.check) }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
- name: Check ${{ matrix.board }}
|
||||
run: bin/check-all.sh ${{ matrix.board }}
|
||||
|
||||
build-esp32:
|
||||
needs: [setup, version]
|
||||
strategy:
|
||||
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.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'
|
||||
uses: ./.github/workflows/build_debian_src.yml
|
||||
with:
|
||||
series: UNRELEASED
|
||||
build_location: local
|
||||
secrets: inherit
|
||||
|
||||
package-pio-deps-native-tft:
|
||||
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/') }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker-deb-amd64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
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)
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch:
|
||||
- esp32
|
||||
- esp32s3
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- nrf52840
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
runs-on: ubuntu-latest
|
||||
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@v4
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
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@v4
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ 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@v4
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ 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-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ 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-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
description: "Download firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
needs:
|
||||
- version
|
||||
- gather-artifacts
|
||||
- build-debian-src
|
||||
- package-pio-deps-native-tft
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
id: create_release
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
|
||||
tag_name: v${{ needs.version.outputs.long }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
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@v4
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./output/pio-deps-native-tft
|
||||
|
||||
- name: Zip Linux sources
|
||||
working-directory: output
|
||||
run: |
|
||||
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
|
||||
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
|
||||
|
||||
# For diagnostics
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -lR
|
||||
|
||||
- name: Add Linux sources to GtiHub Release
|
||||
# Only run when targeting master branch with workflow_dispatch
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
run: |
|
||||
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
|
||||
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-firmware:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch:
|
||||
- esp32
|
||||
- esp32s3
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- nrf52840
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
needs: [release-artifacts, version]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./output
|
||||
|
||||
- name: Display structure of downloaded files
|
||||
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-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
merge-multiple: true
|
||||
path: ./elfs
|
||||
|
||||
- name: Zip debug elfs
|
||||
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./elfs
|
||||
|
||||
# For diagnostics
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -lR
|
||||
|
||||
- name: Add bins and debug elfs to GitHub Release
|
||||
# Only run when targeting master branch with workflow_dispatch
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
run: |
|
||||
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
publish-firmware:
|
||||
runs-on: ubuntu-24.04
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
needs: [release-firmware, version]
|
||||
env:
|
||||
targets: |-
|
||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./publish
|
||||
|
||||
- name: Publish firmware to meshtastic.github.io
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
env:
|
||||
# On event/* branches, use the event name as the destination prefix
|
||||
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
|
||||
with:
|
||||
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
|
||||
external_repository: meshtastic/meshtastic.github.io
|
||||
publish_branch: master
|
||||
publish_dir: ./publish
|
||||
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
|
||||
keep_files: true
|
||||
user_name: github-actions[bot]
|
||||
user_email: github-actions[bot]@users.noreply.github.com
|
||||
commit_message: ${{ needs.version.outputs.long }}
|
||||
enable_jekyll: true
|
||||
2
.github/workflows/package_pio_deps.yml
vendored
2
.github/workflows/package_pio_deps.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
|
||||
2
.github/workflows/pr_enforce_labels.yml
vendored
2
.github/workflows/pr_enforce_labels.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Check for PR labels
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const labels = context.payload.pull_request.labels.map(label => label.name);
|
||||
|
||||
2
.github/workflows/pr_tests.yml
vendored
2
.github/workflows/pr_tests.yml
vendored
@@ -177,7 +177,7 @@ jobs:
|
||||
|
||||
- name: Comment test results on PR
|
||||
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
2
.github/workflows/release_channels.yml
vendored
2
.github/workflows/release_channels.yml
vendored
@@ -63,7 +63,7 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
|
||||
2
.github/workflows/stale_bot.yml
vendored
2
.github/workflows/stale_bot.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Stale PR+Issues
|
||||
uses: actions/stale@v10.0.0
|
||||
uses: actions/stale@v9.1.0
|
||||
with:
|
||||
days-before-stale: 45
|
||||
exempt-issue-labels: pinned,3.0
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
pio upgrade
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v5
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
|
||||
2
.github/workflows/trunk_format_pr.yml
vendored
2
.github/workflows/trunk_format_pr.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
git push
|
||||
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -39,14 +39,5 @@ 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.*
|
||||
|
||||
@@ -8,22 +8,22 @@ plugins:
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.471
|
||||
- renovate@41.115.2
|
||||
- checkov@3.2.467
|
||||
- renovate@41.88.0
|
||||
- prettier@3.6.2
|
||||
- trufflehog@3.90.6
|
||||
- trufflehog@3.90.5
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.8.6
|
||||
- trivy@0.66.0
|
||||
- trivy@0.65.0
|
||||
- taplo@0.10.0
|
||||
- ruff@0.13.0
|
||||
- ruff@0.12.10
|
||||
- isort@6.0.1
|
||||
- markdownlint@0.45.0
|
||||
- oxipng@9.1.5
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.7
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.13.1
|
||||
- hadolint@2.12.1-beta
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.11.0
|
||||
- black@25.1.0
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# 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,
|
||||
|
@@ -52,8 +52,8 @@ 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/mverch67/libpax gitBranch=master
|
||||
https://github.com/mverch67/libpax/archive/6f52ee989301cdabaeef00bcbf93bff55708ce2f.zip
|
||||
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
||||
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
||||
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
|
||||
|
||||
@@ -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/c490bcd019e0658404088a61b96e653c9da22c45.zip
|
||||
https://github.com/meshtastic/platform-native/archive/37d986499ce24511952d7146db72d667c6bdaff7.zip
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
@@ -31,8 +31,6 @@ lib_deps =
|
||||
https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip
|
||||
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
||||
adafruit/Adafruit seesaw Library@1.7.9
|
||||
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
||||
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
|
||||
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
|
||||
@@ -50,7 +50,7 @@ lib_deps =
|
||||
${radiolib_base.lib_deps}
|
||||
|
||||
# renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main
|
||||
https://github.com/caveman99/Crypto/archive/1aa30eb536bd52a576fde6dfa393bf7349cf102d.zip
|
||||
https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip
|
||||
|
||||
lib_ignore =
|
||||
OneButton
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||
|
||||
export PIP_BREAK_SYSTEM_PACKAGES=1
|
||||
|
||||
if (echo $2 | grep -q "esp32"); then
|
||||
|
||||
@@ -7,7 +7,6 @@ SET "DEBUG=0"
|
||||
SET "PYTHON="
|
||||
SET "TFT_BUILD=0"
|
||||
SET "BIGDB8=0"
|
||||
SET "MUIDB8=0"
|
||||
SET "BIGDB16=0"
|
||||
SET "ESPTOOL_BAUD=115200"
|
||||
SET "ESPTOOL_CMD="
|
||||
@@ -15,12 +14,11 @@ 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"
|
||||
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone"
|
||||
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"
|
||||
SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator 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 "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite t-watch-s3"
|
||||
|
||||
GOTO getopts
|
||||
:help
|
||||
@@ -102,6 +100,7 @@ IF NOT "!FILENAME:update=!"=="!FILENAME!" (
|
||||
)
|
||||
|
||||
:skip-filename
|
||||
SET "ESPTOOL_BAUD=1200"
|
||||
|
||||
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
||||
IF NOT "__%PYTHON%__"=="____" (
|
||||
@@ -121,10 +120,11 @@ IF NOT "__%PYTHON%__"=="____" (
|
||||
|
||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||
!ESPTOOL_CMD! >nul 2>&1
|
||||
IF %ERRORLEVEL% EQU 9009 (
|
||||
@REM 9009 = command not found on Windows
|
||||
IF %ERRORLEVEL% GEQ 2 (
|
||||
@REM esptool exits with code 1 if help is displayed.
|
||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||
EXIT /B 1
|
||||
GOTO eof
|
||||
)
|
||||
IF %DEBUG% EQU 1 (
|
||||
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
||||
@@ -142,7 +142,7 @@ CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
||||
|
||||
IF %BPS_RESET% EQU 1 (
|
||||
@REM Attempt to change mode via 1200bps Reset.
|
||||
CALL :RUN_ESPTOOL 1200 --after no_reset read_flash_status
|
||||
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! --after no_reset read_flash_status
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
@@ -164,15 +164,6 @@ FOR %%a IN (%BIGDB_8MB%) DO (
|
||||
)
|
||||
:end_loop_bigdb_8mb
|
||||
|
||||
FOR %%a IN (%MUIDB_8MB%) DO (
|
||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||
@REM We are working with any of %MUIDB_8MB%.
|
||||
SET "MUIDB8=1"
|
||||
GOTO end_loop_muidb_8mb
|
||||
)
|
||||
)
|
||||
:end_loop_muidb_8mb
|
||||
|
||||
FOR %%a IN (%BIGDB_16MB%) DO (
|
||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||
@REM We are working with any of %BIGDB_16MB%.
|
||||
@@ -183,7 +174,6 @@ FOR %%a IN (%BIGDB_16MB%) DO (
|
||||
:end_loop_bigdb_16mb
|
||||
|
||||
IF %BIGDB8% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 8mb partition selected."
|
||||
IF %MUIDB8% EQU 1 CALL :LOG_MESSAGE INFO "MUIDB 8mb partition selected."
|
||||
IF %BIGDB16% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 16mb partition selected."
|
||||
|
||||
@REM Extract BASENAME from %FILENAME% for later use.
|
||||
@@ -228,12 +218,6 @@ IF %BIGDB8% EQU 1 (
|
||||
SET "SPIFFS_OFFSET=0x670000"
|
||||
)
|
||||
|
||||
@REM Offsets for MUIDB 8mb.
|
||||
IF %MUIDB8% EQU 1 (
|
||||
SET "OTA_OFFSET=0x5D0000"
|
||||
SET "SPIFFS_OFFSET=0x670000"
|
||||
)
|
||||
|
||||
@REM Offsets for BigDB 16mb.
|
||||
IF %BIGDB16% EQU 1 (
|
||||
SET "OTA_OFFSET=0x650000"
|
||||
|
||||
@@ -5,43 +5,38 @@ BPS_RESET=false
|
||||
TFT_BUILD=false
|
||||
MCU=""
|
||||
|
||||
# Constants
|
||||
RESET_BAUD=1200
|
||||
FIRMWARE_OFFSET=0x00
|
||||
|
||||
# Variant groups
|
||||
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"
|
||||
)
|
||||
MUIDB_8MB=(
|
||||
"picomputer-s3"
|
||||
"unphone"
|
||||
"seeed-sensecap-indicator"
|
||||
"picomputer-s3"
|
||||
"unphone"
|
||||
"seeed-sensecap-indicator"
|
||||
"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"
|
||||
)
|
||||
BIGDB_16MB=(
|
||||
"t-deck"
|
||||
"mesh-tab"
|
||||
"t-energy-s3"
|
||||
"dreamcatcher"
|
||||
"ESP32-S3-Pico"
|
||||
"m5stack-cores3"
|
||||
"station-g2"
|
||||
"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"
|
||||
"elecrow-adv-35-tft"
|
||||
"elecrow-adv-24-28-tft"
|
||||
"elecrow-adv1-43-50-70-tft"
|
||||
)
|
||||
S3_VARIANTS=(
|
||||
"s3"
|
||||
@@ -52,7 +47,6 @@ S3_VARIANTS=(
|
||||
"station-g2"
|
||||
"unphone"
|
||||
"t-eth-elite"
|
||||
"tlora-pager"
|
||||
"mesh-tab"
|
||||
"dreamcatcher"
|
||||
"ESP32-S3-Pico"
|
||||
@@ -112,8 +106,8 @@ while [ $# -gt 0 ]; do
|
||||
shift
|
||||
;;
|
||||
--1200bps-reset)
|
||||
BPS_RESET=true
|
||||
;;
|
||||
BPS_RESET=true
|
||||
;;
|
||||
--) # Stop parsing options
|
||||
shift
|
||||
break
|
||||
@@ -127,7 +121,7 @@ while [ $# -gt 0 ]; do
|
||||
done
|
||||
|
||||
if [[ $BPS_RESET == true ]]; then
|
||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
||||
$ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -164,13 +158,6 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
||||
fi
|
||||
done
|
||||
|
||||
for variant in "${MUIDB_8MB[@]}"; do
|
||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
||||
OFFSET=0x670000
|
||||
OTA_OFFSET=0x5D0000
|
||||
fi
|
||||
done
|
||||
|
||||
# littlefs* offset for BigDB 16mb and OTA OFFSET.
|
||||
for variant in "${BIGDB_16MB[@]}"; do
|
||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
||||
@@ -214,8 +201,8 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
||||
fi
|
||||
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
$ESPTOOL_CMD erase-flash
|
||||
$ESPTOOL_CMD write-flash $FIRMWARE_OFFSET "${FILENAME}"
|
||||
$ESPTOOL_CMD erase_flash
|
||||
$ESPTOOL_CMD write_flash 0x00 "${FILENAME}"
|
||||
echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}"
|
||||
$ESPTOOL_CMD write_flash $OTA_OFFSET "${OTAFILE}"
|
||||
echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}"
|
||||
|
||||
@@ -6,8 +6,6 @@ SET "SCRIPT_NAME=%~nx0"
|
||||
SET "DEBUG=0"
|
||||
SET "PYTHON="
|
||||
SET "ESPTOOL_BAUD=115200"
|
||||
SET "RESET_BAUD=1200"
|
||||
SET "UPDATE_OFFSET=0x10000"
|
||||
SET "ESPTOOL_CMD="
|
||||
SET "LOGCOUNTER=0"
|
||||
SET "CHANGE_MODE=0"
|
||||
@@ -87,13 +85,14 @@ IF "!FILENAME:update=!"=="!FILENAME!" (
|
||||
)
|
||||
|
||||
:skip-filename
|
||||
SET "ESPTOOL_BAUD=1200"
|
||||
|
||||
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
||||
IF NOT "__%PYTHON%__"=="____" (
|
||||
SET "ESPTOOL_CMD=""!PYTHON!"" -m esptool"
|
||||
SET "ESPTOOL_CMD=!PYTHON! -m esptool"
|
||||
CALL :LOG_MESSAGE DEBUG "Python interpreter supplied."
|
||||
) ELSE (
|
||||
CALL :LOG_MESSAGE DEBUG "Python interpreter NOT supplied. Looking for esptool..."
|
||||
CALL :LOG_MESSAGE DEBUG "Python interpreter NOT supplied. Looking for esptool...
|
||||
WHERE esptool >nul 2>&1
|
||||
IF %ERRORLEVEL% EQU 0 (
|
||||
@REM WHERE exits with code 0 if esptool is found.
|
||||
@@ -106,11 +105,11 @@ IF NOT "__%PYTHON%__"=="____" (
|
||||
|
||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||
!ESPTOOL_CMD! >nul 2>&1
|
||||
CALL :LOG_MESSAGE DEBUG "esptool exit code: %ERRORLEVEL%"
|
||||
IF %ERRORLEVEL% EQU 9009 (
|
||||
@REM 9009 = command not found on Windows
|
||||
IF %ERRORLEVEL% GEQ 2 (
|
||||
@REM esptool exits with code 1 if help is displayed.
|
||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||
EXIT /B 1
|
||||
GOTO eof
|
||||
)
|
||||
IF %DEBUG% EQU 1 (
|
||||
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
||||
@@ -128,13 +127,13 @@ CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
||||
|
||||
IF %CHANGE_MODE% EQU 1 (
|
||||
@REM Attempt to change mode via 1200bps Reset.
|
||||
CALL :RUN_ESPTOOL !RESET_BAUD! --after no_reset read_flash_status
|
||||
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! --after no_reset read_flash_status
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
@REM Flashing operations.
|
||||
CALL :LOG_MESSAGE INFO "Trying to flash update "!FILENAME!" at OFFSET !UPDATE_OFFSET!..."
|
||||
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write-flash !UPDATE_OFFSET! "!FILENAME!" || GOTO eof
|
||||
CALL :LOG_MESSAGE INFO "Trying to flash update "!FILENAME!" at OFFSET 0x10000..."
|
||||
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write_flash 0x10000 "!FILENAME!" || GOTO eof
|
||||
|
||||
CALL :LOG_MESSAGE INFO "Script complete!."
|
||||
|
||||
@@ -146,9 +145,9 @@ EXIT /B %ERRORLEVEL%
|
||||
:RUN_ESPTOOL
|
||||
@REM Subroutine used to run ESPTOOL_CMD with arguments.
|
||||
@REM Also handles %ERRORLEVEL%.
|
||||
@REM CALL :RUN_ESPTOOL [Baud] [erase-flash|write-flash] [OFFSET] [Filename]
|
||||
@REM CALL :RUN_ESPTOOL [Baud] [erase_flash|write_flash] [OFFSET] [Filename]
|
||||
@REM.
|
||||
@REM Example:: CALL :RUN_ESPTOOL 115200 write-flash 0x10000 "firmwarefile.bin"
|
||||
@REM Example:: CALL :RUN_ESPTOOL 115200 write_flash 0x10000 "firmwarefile.bin"
|
||||
IF %DEBUG% EQU 1 CALL :LOG_MESSAGE DEBUG "About to run command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4"
|
||||
CALL :RESET_ERROR
|
||||
!ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
|
||||
CHANGE_MODE=false
|
||||
|
||||
# Constants
|
||||
FLASH_BAUD=115200
|
||||
RESET_BAUD=1200
|
||||
UPDATE_OFFSET=0x10000
|
||||
|
||||
# Determine the correct esptool command to use
|
||||
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
||||
ESPTOOL_CMD="$PYTHON -m esptool"
|
||||
@@ -69,7 +64,7 @@ done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
if [ "$CHANGE_MODE" = true ]; then
|
||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
||||
$ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -80,7 +75,7 @@ fi
|
||||
|
||||
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
|
||||
echo "Trying to flash update ${FILENAME}"
|
||||
$ESPTOOL_CMD --baud $FLASH_BAUD write-flash $UPDATE_OFFSET "${FILENAME}"
|
||||
$ESPTOOL_CMD --baud 115200 write_flash 0x10000 "${FILENAME}"
|
||||
else
|
||||
show_help
|
||||
echo "Invalid file: ${FILENAME}"
|
||||
|
||||
@@ -87,12 +87,6 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<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>
|
||||
<release version="2.7.8" date="2025-08-30">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.8</url>
|
||||
</release>
|
||||
<release version="2.7.7" date="2025-08-28">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.7</url>
|
||||
</release>
|
||||
|
||||
@@ -6,8 +6,6 @@ from os.path import join
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from readprops import readProps
|
||||
|
||||
@@ -127,16 +125,11 @@ for pref in userPrefs:
|
||||
pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "")
|
||||
|
||||
# General options that are passed to the C and C++ compilers
|
||||
# Calculate unix epoch for current day (midnight)
|
||||
current_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
build_epoch = int(current_date.timestamp())
|
||||
|
||||
flags = [
|
||||
"-DAPP_VERSION=" + verObj["long"],
|
||||
"-DAPP_VERSION_SHORT=" + verObj["short"],
|
||||
"-DAPP_ENV=" + env.get("PIOENV"),
|
||||
"-DAPP_REPO=" + repo_owner,
|
||||
"-DBUILD_EPOCH=" + str(build_epoch),
|
||||
] + pref_flags
|
||||
|
||||
print ("Using flags:")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "partition-table-8MB.csv",
|
||||
"partitions": "default_8MB.csv",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
@@ -16,7 +16,6 @@
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"f_boot": "120000000L",
|
||||
"boot_freq": "120000000L",
|
||||
"boot": "qio",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi",
|
||||
"partitions": "partition-table-8MB.csv"
|
||||
"partitions": "default_8MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"core": "stm32",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_RAK3172_MODULE",
|
||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
|
||||
"f_cpu": "48000000L",
|
||||
"mcu": "stm32wle5ccu",
|
||||
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
|
||||
|
||||
10
debian/changelog
vendored
10
debian/changelog
vendored
@@ -1,4 +1,4 @@
|
||||
meshtasticd (2.7.9.0) UNRELEASED; urgency=medium
|
||||
meshtasticd (2.7.7.0) UNRELEASED; urgency=medium
|
||||
|
||||
[ Austin Lane ]
|
||||
* Initial packaging
|
||||
@@ -41,10 +41,4 @@ meshtasticd (2.7.9.0) UNRELEASED; urgency=medium
|
||||
* 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
|
||||
-- Ubuntu <github-actions[bot]@users.noreply.github.com> Thu, 28 Aug 2025 10:33:25 +0000
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a layout for 8MB of flash for MUI devices
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x5C0000,
|
||||
flashApp, app, ota_1, 0x5D0000,0x0A0000,
|
||||
spiffs, data, spiffs, 0x670000,0x180000
|
||||
|
@@ -53,14 +53,14 @@ build_flags = -Wno-missing-field-initializers
|
||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
||||
-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
|
||||
#-DBUILD_EPOCH=$UNIX_TIME
|
||||
#-D OLED_PL=1
|
||||
|
||||
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/0cbc26b1f8f61957af0475f486b362eafe7cc4e2.zip
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/9573abb64dc9c94f3051348f2bf4fc5cedf03c22.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
|
||||
@@ -87,9 +87,8 @@ check_flags =
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=mverch67/library/NonBlockingRTTTL
|
||||
https://github.com/mverch67/NonBlockingRTTTL/archive/ad1c2fb12bc81db546c6a94e963acb3382d3689e.zip ; TODO
|
||||
|
||||
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=end2endzone/library/NonBlockingRTTTL
|
||||
end2endzone/NonBlockingRTTTL@1.3.0
|
||||
build_flags = ${env.build_flags} -Os
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/> -<graphics/niche/>
|
||||
|
||||
@@ -100,6 +99,8 @@ 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]
|
||||
@@ -117,7 +118,7 @@ lib_deps =
|
||||
[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/9ed5355a24059750e9b2eb5d669574d9ea42a37b.zip
|
||||
https://github.com/meshtastic/device-ui/archive/a3e0e1be372d069f47b4c19d718f5267251744d7.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
@@ -156,8 +157,8 @@ lib_deps =
|
||||
emotibit/EmotiBit MLX90632@1.0.8
|
||||
# renovate: datasource=custom.pio depName=Adafruit MLX90614 packageName=adafruit/library/Adafruit MLX90614 Library
|
||||
adafruit/Adafruit MLX90614 Library@2.1.5
|
||||
# renovate: datasource=github-tags depName=INA3221 packageName=sgtwilko/INA3221
|
||||
https://github.com/sgtwilko/INA3221#bb03d7e9bfcc74fc798838a54f4f99738f29fc6a
|
||||
# renovate: datasource=github-tags depName=INA3221 packageName=KodinLanewave/INA3221
|
||||
https://github.com/KodinLanewave/INA3221/archive/1.0.1.zip
|
||||
# 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
|
||||
@@ -176,8 +177,6 @@ lib_deps =
|
||||
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
|
||||
|
||||
; (not included in native / portduino)
|
||||
[environmental_extra]
|
||||
|
||||
Submodule protobufs updated: 945b796a98...4c4427c4a7
@@ -183,9 +183,9 @@ class AmbientLightingThread : public concurrency::OSThread
|
||||
#endif
|
||||
#endif
|
||||
pixels.show();
|
||||
// LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
|
||||
// moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red,
|
||||
// moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
|
||||
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red,
|
||||
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
// Forward declarations
|
||||
#if defined(DEBUG_HEAP)
|
||||
class MemGet;
|
||||
extern MemGet memGet;
|
||||
#endif
|
||||
|
||||
// DEBUG LED
|
||||
#ifndef LED_STATE_ON
|
||||
#define LED_STATE_ON 1
|
||||
@@ -29,7 +23,6 @@ extern MemGet memGet;
|
||||
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
||||
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
||||
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
||||
#define MESHTASTIC_LOG_LEVEL_HEAP "HEAP"
|
||||
|
||||
#include "SerialConsole.h"
|
||||
|
||||
@@ -69,25 +62,6 @@ extern MemGet memGet;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_HEAP)
|
||||
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
|
||||
|
||||
// Macro-based heap debugging
|
||||
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
|
||||
#define DEBUG_HEAP_AFTER(context, ptr) \
|
||||
do { \
|
||||
auto heapAfter = memGet.getFreeHeap(); \
|
||||
if (heapBefore != heapAfter) { \
|
||||
LOG_HEAP("Alloc in %s pointer 0x%x, size: %u, free: %u", context, ptr, heapBefore - heapAfter, heapAfter); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define LOG_HEAP(...)
|
||||
#define DEBUG_HEAP_BEFORE
|
||||
#define DEBUG_HEAP_AFTER(context, ptr)
|
||||
#endif
|
||||
|
||||
/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
|
||||
extern "C" void logLegacy(const char *level, const char *fmt, ...);
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
#include "DisplayFormatters.h"
|
||||
|
||||
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
||||
bool usePreset)
|
||||
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
|
||||
{
|
||||
|
||||
// If use_preset is false, always return "Custom"
|
||||
if (!usePreset) {
|
||||
return "Custom";
|
||||
}
|
||||
|
||||
switch (preset) {
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
|
||||
return useShortName ? "ShortT" : "ShortTurbo";
|
||||
|
||||
@@ -4,6 +4,5 @@
|
||||
class DisplayFormatters
|
||||
{
|
||||
public:
|
||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
||||
bool usePreset);
|
||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
|
||||
};
|
||||
|
||||
@@ -128,7 +128,6 @@ RAK9154Sensor rak9154Sensor;
|
||||
#ifdef HAS_PPM
|
||||
// note: XPOWERS_CHIP_XXX must be defined in variant.h
|
||||
#include <XPowersLib.h>
|
||||
XPowersPPM *PPM = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BQ27220
|
||||
@@ -682,7 +681,7 @@ bool Power::setup()
|
||||
found = true;
|
||||
} else if (lipoChargerInit()) {
|
||||
found = true;
|
||||
} else if (meshSolarInit()) {
|
||||
} else if (meshSolarInit()) {
|
||||
found = true;
|
||||
} else if (analogInit()) {
|
||||
found = true;
|
||||
@@ -746,11 +745,7 @@ void Power::shutdown()
|
||||
|
||||
#if HAS_SCREEN
|
||||
if (screen) {
|
||||
#ifdef T_DECK_PRO
|
||||
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
|
||||
#else
|
||||
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if !defined(ARCH_STM32WL)
|
||||
@@ -768,7 +763,7 @@ void Power::shutdown()
|
||||
#ifdef PIN_LED3
|
||||
ledOff(PIN_LED3);
|
||||
#endif
|
||||
doDeepSleep(DELAY_FOREVER, true, true);
|
||||
doDeepSleep(DELAY_FOREVER, false, true);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
@@ -833,27 +828,18 @@ void Power::readPowerStatus()
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
#ifdef DEBUG_HEAP
|
||||
if (lastheap != memGet.getFreeHeap()) {
|
||||
// Use stack-allocated buffer to avoid heap allocations in monitoring code
|
||||
char threadlist[256] = "Threads running:";
|
||||
int threadlistLen = strlen(threadlist);
|
||||
std::string threadlist = "Threads running:";
|
||||
int running = 0;
|
||||
for (int i = 0; i < MAX_THREADS; i++) {
|
||||
auto thread = concurrency::mainController.get(i);
|
||||
if ((thread != nullptr) && (thread->enabled)) {
|
||||
// Use snprintf to safely append to stack buffer without heap allocation
|
||||
int remaining = sizeof(threadlist) - threadlistLen - 1;
|
||||
if (remaining > 0) {
|
||||
int written = snprintf(threadlist + threadlistLen, remaining, " %s", thread->ThreadName.c_str());
|
||||
if (written > 0 && written < remaining) {
|
||||
threadlistLen += written;
|
||||
}
|
||||
}
|
||||
threadlist += vformat(" %s", thread->ThreadName.c_str());
|
||||
running++;
|
||||
}
|
||||
}
|
||||
LOG_HEAP(threadlist);
|
||||
LOG_HEAP("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||
LOG_DEBUG(threadlist.c_str());
|
||||
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||
lastheap = memGet.getFreeHeap();
|
||||
}
|
||||
#ifdef DEBUG_HEAP_MQTT
|
||||
@@ -865,19 +851,15 @@ void Power::readPowerStatus()
|
||||
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
||||
|
||||
auto newHeap = memGet.getFreeHeap();
|
||||
// Use stack-allocated buffers to avoid heap allocations in monitoring code
|
||||
char heapTopic[128];
|
||||
snprintf(heapTopic, sizeof(heapTopic), "%s/2/heap/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
||||
char heapString[16];
|
||||
snprintf(heapString, sizeof(heapString), "%u", newHeap);
|
||||
mqtt->pubSub.publish(heapTopic, heapString, false);
|
||||
|
||||
std::string heapTopic =
|
||||
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
|
||||
std::string heapString = std::to_string(newHeap);
|
||||
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
|
||||
auto wifiRSSI = WiFi.RSSI();
|
||||
char wifiTopic[128];
|
||||
snprintf(wifiTopic, sizeof(wifiTopic), "%s/2/wifi/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
||||
char wifiString[16];
|
||||
snprintf(wifiString, sizeof(wifiString), "%d", wifiRSSI);
|
||||
mqtt->pubSub.publish(wifiTopic, wifiString, false);
|
||||
std::string wifiTopic =
|
||||
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
|
||||
std::string wifiString = std::to_string(wifiRSSI);
|
||||
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1338,6 +1320,7 @@ bool Power::lipoInit()
|
||||
class LipoCharger : public HasBatteryLevel
|
||||
{
|
||||
private:
|
||||
XPowersPPM *ppm = nullptr;
|
||||
BQ27220 *bq = nullptr;
|
||||
|
||||
public:
|
||||
@@ -1346,41 +1329,41 @@ class LipoCharger : public HasBatteryLevel
|
||||
*/
|
||||
bool runOnce()
|
||||
{
|
||||
if (PPM == nullptr) {
|
||||
PPM = new XPowersPPM;
|
||||
bool result = PPM->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
||||
if (ppm == nullptr) {
|
||||
ppm = new XPowersPPM;
|
||||
bool result = ppm->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
||||
if (result) {
|
||||
LOG_INFO("PPM BQ25896 init succeeded");
|
||||
// Set the minimum operating voltage. Below this voltage, the PPM will protect
|
||||
// PPM->setSysPowerDownVoltage(3100);
|
||||
// ppm->setSysPowerDownVoltage(3100);
|
||||
|
||||
// Set input current limit, default is 500mA
|
||||
// PPM->setInputCurrentLimit(800);
|
||||
// ppm->setInputCurrentLimit(800);
|
||||
|
||||
// Disable current limit pin
|
||||
// PPM->disableCurrentLimitPin();
|
||||
// ppm->disableCurrentLimitPin();
|
||||
|
||||
// Set the charging target voltage, Range:3840 ~ 4608mV ,step:16 mV
|
||||
PPM->setChargeTargetVoltage(4288);
|
||||
ppm->setChargeTargetVoltage(4288);
|
||||
|
||||
// Set the precharge current , Range: 64mA ~ 1024mA ,step:64mA
|
||||
// PPM->setPrechargeCurr(64);
|
||||
// ppm->setPrechargeCurr(64);
|
||||
|
||||
// The premise is that limit pin is disabled, or it will
|
||||
// only follow the maximum charging current set by limit pin.
|
||||
// Set the charging current , Range:0~5056mA ,step:64mA
|
||||
PPM->setChargerConstantCurr(1024);
|
||||
ppm->setChargerConstantCurr(1024);
|
||||
|
||||
// To obtain voltage data, the ADC must be enabled first
|
||||
PPM->enableMeasure();
|
||||
ppm->enableMeasure();
|
||||
|
||||
// Turn on charging function
|
||||
// If there is no battery connected, do not turn on the charging function
|
||||
PPM->enableCharge();
|
||||
ppm->enableCharge();
|
||||
} else {
|
||||
LOG_WARN("PPM BQ25896 init failed");
|
||||
delete PPM;
|
||||
PPM = nullptr;
|
||||
delete ppm;
|
||||
ppm = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1421,23 +1404,23 @@ class LipoCharger : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is a battery installed in this unit
|
||||
*/
|
||||
virtual bool isBatteryConnect() override { return PPM->getBattVoltage() > 0; }
|
||||
virtual bool isBatteryConnect() override { return ppm->getBattVoltage() > 0; }
|
||||
|
||||
/**
|
||||
* return true if there is an external power source detected
|
||||
*/
|
||||
virtual bool isVbusIn() override { return PPM->getVbusVoltage() > 0; }
|
||||
virtual bool isVbusIn() override { return ppm->getVbusVoltage() > 0; }
|
||||
|
||||
/**
|
||||
* return true if the battery is currently charging
|
||||
*/
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
bool isCharging = PPM->isCharging();
|
||||
bool isCharging = ppm->isCharging();
|
||||
if (isCharging) {
|
||||
LOG_DEBUG("BQ27220 time to full charge: %d min", bq->getTimeToFull());
|
||||
} else {
|
||||
if (!PPM->isVbusIn()) {
|
||||
if (!ppm->isVbusIn()) {
|
||||
LOG_DEBUG("BQ27220 time to empty: %d min (%d mAh)", bq->getTimeToEmpty(), bq->getRemainingCapacity());
|
||||
}
|
||||
}
|
||||
@@ -1470,6 +1453,8 @@ bool Power::lipoChargerInit()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef HELTEC_MESH_SOLAR
|
||||
#include "meshSolarApp.h"
|
||||
|
||||
@@ -1507,7 +1492,7 @@ class meshSolarBatteryLevel : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is an external power source detected
|
||||
*/
|
||||
virtual bool isVbusIn() override { return meshSolarIsVbusIn(); }
|
||||
virtual bool isVbusIn() override { return meshSolarIsVbusIn();}
|
||||
|
||||
/**
|
||||
* return true if the battery is currently charging
|
||||
|
||||
@@ -86,9 +86,9 @@ void OSThread::run()
|
||||
#ifdef DEBUG_HEAP
|
||||
auto newHeap = memGet.getFreeHeap();
|
||||
if (newHeap < heap)
|
||||
LOG_HEAP("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
if (heap < newHeap)
|
||||
LOG_HEAP("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||
#endif
|
||||
|
||||
runned();
|
||||
|
||||
@@ -26,10 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if __has_include("Melopero_RV3028.h")
|
||||
#ifdef RV3028_RTC
|
||||
#include "Melopero_RV3028.h"
|
||||
#endif
|
||||
#if __has_include("pcf8563.h")
|
||||
#ifdef PCF8563_RTC
|
||||
#include "pcf8563.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ class ScanI2C
|
||||
LTR553ALS,
|
||||
BHI260AP,
|
||||
BMM150,
|
||||
TSL2561,
|
||||
DRV2605
|
||||
} DeviceType;
|
||||
|
||||
|
||||
@@ -294,7 +294,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
type = AHT10;
|
||||
break;
|
||||
#endif
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
case INA_ADDR:
|
||||
case INA_ADDR_ALTERNATE:
|
||||
case INA_ADDR_WAVESHARE_UPS:
|
||||
@@ -341,7 +340,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
// else: probably a RAK12500/UBLOX GPS on I2C
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case MCP9808_ADDR:
|
||||
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
|
||||
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
|
||||
@@ -463,17 +461,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
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 TSL25911_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
||||
if (registerValue == 0x50) {
|
||||
type = TSL2591;
|
||||
logFoundDevice("TSL25911", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = TSL2561;
|
||||
logFoundDevice("TSL2561", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
||||
|
||||
122
src/gps/GPS.cpp
122
src/gps/GPS.cpp
@@ -1,4 +1,5 @@
|
||||
#include <cstring> // Include for strstr
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "configuration.h"
|
||||
@@ -842,6 +843,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
setPowerPMU(true); // Power (PMU): on
|
||||
writePinStandby(false); // Standby (pin): awake (not standby)
|
||||
setPowerUBLOX(true); // Standby (UBLOX): awake
|
||||
#ifdef GNSS_AIROHA
|
||||
lastFixStartMsec = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GPS_SOFTSLEEP:
|
||||
@@ -859,7 +863,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
writePinStandby(true); // Standby (pin): asleep (not awake)
|
||||
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
|
||||
#ifdef GNSS_AIROHA
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -871,7 +877,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
writePinStandby(true); // Standby (pin): asleep
|
||||
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
|
||||
#ifdef GNSS_AIROHA
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -1054,8 +1062,6 @@ void GPS::down()
|
||||
}
|
||||
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
||||
setPowerState(GPS_HARDSLEEP, sleepTime);
|
||||
// Reset the fix quality to 0, since we're off.
|
||||
fixQual = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1115,19 +1121,11 @@ int32_t GPS::runOnce()
|
||||
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 (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
|
||||
}
|
||||
|
||||
bool tooLong = scheduling.searchedTooLong();
|
||||
@@ -1136,7 +1134,8 @@ int32_t GPS::runOnce()
|
||||
|
||||
// Once we get a location we no longer desperately want an update
|
||||
if ((gotLoc && gotTime) || tooLong) {
|
||||
if (tooLong && !gotLoc) {
|
||||
|
||||
if (tooLong) {
|
||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||
if (hasValidLocation) {
|
||||
LOG_DEBUG("hasValidLocation FALLING EDGE");
|
||||
@@ -1144,15 +1143,9 @@ int32_t GPS::runOnce()
|
||||
p = meshtastic_Position_init_default;
|
||||
hasValidLocation = false;
|
||||
}
|
||||
if (millis() > fixHoldEnds) {
|
||||
shouldPublish = true; // publish our update at the end of the lock hold
|
||||
publishUpdate();
|
||||
down();
|
||||
#ifdef GPS_DEBUG
|
||||
} else {
|
||||
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
|
||||
#endif
|
||||
}
|
||||
|
||||
down();
|
||||
shouldPublish = true; // publish our update for this just finished acquisition window
|
||||
}
|
||||
|
||||
// If state has changed do a publish
|
||||
@@ -1205,7 +1198,7 @@ static const char *DETECTED_MESSAGE = "%s detected";
|
||||
LOG_DEBUG(PROBE_MESSAGE, COMMAND, FAMILY_NAME); \
|
||||
clearBuffer(); \
|
||||
_serial_gps->write(COMMAND "\r\n"); \
|
||||
GnssModel_t detectedDriver = getProbeResponse(TIMEOUT, RESPONSE_MAP, serialSpeed); \
|
||||
GnssModel_t detectedDriver = getProbeResponse(TIMEOUT, RESPONSE_MAP); \
|
||||
if (detectedDriver != GNSS_MODEL_UNKNOWN) { \
|
||||
return detectedDriver; \
|
||||
} \
|
||||
@@ -1367,55 +1360,36 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
return GNSS_MODEL_UNKNOWN;
|
||||
}
|
||||
|
||||
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap, int serialSpeed)
|
||||
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap)
|
||||
{
|
||||
// Calculate buffer size based on baud rate - 256 bytes for 9600 baud as baseline
|
||||
// Higher baud rates get proportionally larger buffers to handle more data
|
||||
int bufferSize = (serialSpeed * 256) / 9600;
|
||||
// Clamp buffer size between reasonable limits
|
||||
if (bufferSize < 128)
|
||||
bufferSize = 128;
|
||||
if (bufferSize > 2048)
|
||||
bufferSize = 2048;
|
||||
|
||||
char *response = new char[bufferSize](); // Dynamically allocate based on baud rate
|
||||
uint16_t responseLen = 0;
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < timeout) {
|
||||
if (_serial_gps->available()) {
|
||||
char c = _serial_gps->read();
|
||||
response += (char)_serial_gps->read();
|
||||
|
||||
// Add char to buffer if there's space
|
||||
if (responseLen < bufferSize - 1) {
|
||||
response[responseLen++] = c;
|
||||
response[responseLen] = '\0';
|
||||
}
|
||||
|
||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||
if (response.endsWith(",") || response.endsWith("\r\n")) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(response);
|
||||
LOG_DEBUG(response.c_str());
|
||||
#endif
|
||||
// check if we can see our chips
|
||||
for (const auto &chipInfo : responseMap) {
|
||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||
if (strstr(response.c_str(), chipInfo.detectionString.c_str()) != nullptr) {
|
||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||
delete[] response; // Cleanup before return
|
||||
return chipInfo.driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||
// Reset the response buffer for the next potential message
|
||||
responseLen = 0;
|
||||
response[0] = '\0';
|
||||
if (response.endsWith("\r\n")) {
|
||||
response.trim();
|
||||
response = ""; // Reset the response string for the next potential message
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(response);
|
||||
LOG_DEBUG(response.c_str());
|
||||
#endif
|
||||
delete[] response; // Cleanup before return
|
||||
return GNSS_MODEL_UNKNOWN; // Return unknown on timeout
|
||||
return GNSS_MODEL_UNKNOWN; // Return empty string on timeout
|
||||
}
|
||||
|
||||
GPS *GPS::createGps()
|
||||
@@ -1534,6 +1508,24 @@ static int32_t toDegInt(RawDegrees d)
|
||||
*/
|
||||
bool GPS::lookForTime()
|
||||
{
|
||||
|
||||
#ifdef GNSS_AIROHA
|
||||
uint8_t fix = reader.fixQuality();
|
||||
if (fix >= 1 && fix <= 5) {
|
||||
if (lastFixStartMsec > 0) {
|
||||
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||
return false;
|
||||
} else {
|
||||
clearBuffer();
|
||||
}
|
||||
} else {
|
||||
lastFixStartMsec = millis();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
auto ti = reader.time;
|
||||
auto d = reader.date;
|
||||
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
||||
@@ -1550,9 +1542,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
if (t.tm_mon > -1) {
|
||||
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
|
||||
t.tm_sec, ti.age());
|
||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultSuccess) {
|
||||
LOG_DEBUG("NMEA GPS time set %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour,
|
||||
t.tm_min, t.tm_sec, ti.age());
|
||||
LOG_DEBUG("Time set.");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -1571,6 +1564,25 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
*/
|
||||
bool GPS::lookForLocation()
|
||||
{
|
||||
#ifdef GNSS_AIROHA
|
||||
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
|
||||
uint8_t fix = reader.fixQuality();
|
||||
if (fix >= 1 && fix <= 5) {
|
||||
if (lastFixStartMsec > 0) {
|
||||
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||
return false;
|
||||
} else {
|
||||
clearBuffer();
|
||||
}
|
||||
} else {
|
||||
lastFixStartMsec = millis();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||
// the 2D/3D fixType (see NMEAGPS.h)
|
||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||
|
||||
@@ -159,7 +159,7 @@ class GPS : private concurrency::OSThread
|
||||
uint8_t fixType = 0; // fix type from GPGSA
|
||||
#endif
|
||||
|
||||
uint32_t fixHoldEnds = 0;
|
||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
|
||||
uint32_t rx_gpio = 0;
|
||||
uint32_t tx_gpio = 0;
|
||||
|
||||
@@ -236,7 +236,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
GnssModel_t getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap, int serialSpeed);
|
||||
GnssModel_t getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap);
|
||||
|
||||
// Get GNSS model
|
||||
GnssModel_t probe(int serialSpeed);
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
static RTCQuality currentQuality = RTCQualityNone;
|
||||
uint32_t lastSetFromPhoneNtpOrGps = 0;
|
||||
|
||||
static uint32_t lastTimeValidationWarning = 0;
|
||||
static const uint32_t TIME_VALIDATION_WARNING_INTERVAL_MS = 15000; // 15 seconds
|
||||
|
||||
RTCQuality getRTCQuality()
|
||||
{
|
||||
return currentQuality;
|
||||
@@ -51,18 +48,16 @@ RTCSetResult readFromRTC()
|
||||
|
||||
#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);
|
||||
}
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_DEBUG("Read RTC time from RV3028 getTime 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);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
return RTCSetResultSuccess;
|
||||
@@ -92,19 +87,16 @@ RTCSetResult readFromRTC()
|
||||
|
||||
#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();
|
||||
}
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_DEBUG("Read RTC time from PCF8563 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);
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
return RTCSetResultSuccess;
|
||||
@@ -138,20 +130,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#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;
|
||||
} else if ((uint64_t)tv->tv_sec > ((uint64_t)BUILD_EPOCH + FORTY_YEARS)) {
|
||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||
// 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 (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||
lastTimeValidationWarning = millis();
|
||||
}
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
@@ -269,20 +248,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#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;
|
||||
} else if ((uint64_t)tv.tv_sec > ((uint64_t)BUILD_EPOCH + FORTY_YEARS)) {
|
||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||
// 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 (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||
lastTimeValidationWarning = millis();
|
||||
}
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
@@ -342,40 +308,14 @@ uint32_t getValidTime(RTCQuality minQuality, bool local)
|
||||
time_t gm_mktime(struct tm *tm)
|
||||
{
|
||||
#if !MESHTASTIC_EXCLUDE_TZ
|
||||
time_t result = 0;
|
||||
|
||||
// First, get us to the start of tm->year, by calcuating the number of days since the Unix epoch.
|
||||
int year = 1900 + tm->tm_year; // tm_year is years since 1900
|
||||
int year_minus_one = year - 1;
|
||||
int days_before_this_year = 0;
|
||||
days_before_this_year += year_minus_one * 365;
|
||||
// leap days: every 4 years, except 100s, but including 400s.
|
||||
days_before_this_year += year_minus_one / 4 - year_minus_one / 100 + year_minus_one / 400;
|
||||
// subtract from 1970-01-01 to get days since epoch
|
||||
days_before_this_year -= 719162; // (1969 * 365 + 1969 / 4 - 1969 / 100 + 1969 / 400);
|
||||
|
||||
// Now, within this tm->year, compute the days *before* this tm->month starts.
|
||||
int days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // non-leap year
|
||||
int days_this_year_before_this_month = days_before_month[tm->tm_mon]; // tm->tm_mon is 0..11
|
||||
|
||||
// If this is a leap year, and we're past February, add a day:
|
||||
if (tm->tm_mon >= 2 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
|
||||
days_this_year_before_this_month += 1;
|
||||
setenv("TZ", "GMT0", 1);
|
||||
time_t res = mktime(tm);
|
||||
if (*config.device.tzdef) {
|
||||
setenv("TZ", config.device.tzdef, 1);
|
||||
} else {
|
||||
setenv("TZ", "UTC0", 1);
|
||||
}
|
||||
|
||||
// And within this month:
|
||||
int days_this_month_before_today = tm->tm_mday - 1; // tm->tm_mday is 1..31
|
||||
|
||||
// Now combine them all together, and convert days to seconds:
|
||||
result += (days_before_this_year + days_this_year_before_this_month + days_this_month_before_today);
|
||||
result *= 86400L;
|
||||
|
||||
// Finally, add in the hours, minutes, and seconds of today:
|
||||
result += tm->tm_hour * 3600;
|
||||
result += tm->tm_min * 60;
|
||||
result += tm->tm_sec;
|
||||
|
||||
return result;
|
||||
return res;
|
||||
#else
|
||||
return mktime(tm);
|
||||
#endif
|
||||
|
||||
@@ -55,6 +55,3 @@ time_t gm_mktime(struct tm *tm);
|
||||
#define SEC_PER_DAY 86400
|
||||
#define SEC_PER_HOUR 3600
|
||||
#define SEC_PER_MIN 60
|
||||
#ifdef BUILD_EPOCH
|
||||
static constexpr uint64_t FORTY_YEARS = (40ULL * 365 * SEC_PER_DAY); // Use 64-bit arithmetic to prevent overflow
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
// Constructor
|
||||
|
||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
{
|
||||
// Set dimensions in OLEDDisplay base class
|
||||
@@ -229,6 +230,12 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->setRotation(0);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
}
|
||||
#elif defined(LORA_TYPE)
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
|
||||
#elif defined(M5_COREINK) || defined(T_DECK_PRO)
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
@@ -317,14 +317,6 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#elif defined(USE_SSD1306)
|
||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_SPISSD1306)
|
||||
dispdev = new SSD1306Spi(SSD1306_RESET, SSD1306_RS, SSD1306_NSS, GEOMETRY_64_48);
|
||||
if (!dispdev->init()) {
|
||||
LOG_DEBUG("Error: SSD1306 not detected!");
|
||||
} else {
|
||||
static_cast<SSD1306Spi *>(dispdev)->setHorizontalOffset(32);
|
||||
LOG_INFO("SSD1306 init success");
|
||||
}
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
@@ -515,7 +507,7 @@ void Screen::setup()
|
||||
// === Apply loaded brightness ===
|
||||
#if defined(ST7789_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SPISSD1306)
|
||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
dispdev->setBrightness(brightness);
|
||||
#endif
|
||||
LOG_INFO("Applied screen brightness: %d", brightness);
|
||||
@@ -562,7 +554,7 @@ void Screen::setup()
|
||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||
#elif defined(USE_ST7789)
|
||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||
#elif !defined(M5STACK_UNITC6L)
|
||||
#else
|
||||
dispdev->flipScreenVertically();
|
||||
#endif
|
||||
}
|
||||
@@ -700,11 +692,7 @@ int32_t Screen::runOnce()
|
||||
|
||||
#ifndef DISABLE_WELCOME_UNSET
|
||||
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
menuHandler::LoraRegionPicker();
|
||||
#else
|
||||
menuHandler::OnboardMessage();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
|
||||
@@ -902,12 +890,8 @@ void Screen::setFrames(FrameFocus focus)
|
||||
|
||||
#if defined(DISPLAY_CLOCK_FRAME)
|
||||
fsi.positions.clock = numframes;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
normalFrames[numframes++] = graphics::ClockRenderer::drawAnalogClockFrame;
|
||||
#else
|
||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||
#endif
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
#endif
|
||||
|
||||
@@ -1242,10 +1226,6 @@ void Screen::handleShowNextFrame()
|
||||
|
||||
void Screen::setFastFramerate()
|
||||
{
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
dispdev->clear();
|
||||
dispdev->display();
|
||||
#endif
|
||||
// We are about to start a transition so speed up fps
|
||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
|
||||
@@ -1317,23 +1297,13 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
}
|
||||
} else {
|
||||
if (longName && longName[0]) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
strcpy(banner, "New Message");
|
||||
#else
|
||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
strcpy(banner, "New Message");
|
||||
}
|
||||
}
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
screen->setOn(true);
|
||||
screen->showSimpleBanner(banner, 1500);
|
||||
playLongBeep();
|
||||
#else
|
||||
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1416,11 +1386,7 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
if (devicestate.rx_text_message.from) {
|
||||
menuHandler::messageResponseMenu();
|
||||
} else {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
menuHandler::textMessageMenu();
|
||||
#else
|
||||
menuHandler::textMessageBaseMenu();
|
||||
#endif
|
||||
}
|
||||
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
||||
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
||||
|
||||
@@ -81,8 +81,6 @@ class Screen
|
||||
#include <SSD1306Wire.h>
|
||||
#elif defined(USE_ST7789)
|
||||
#include <ST7789Spi.h>
|
||||
#elif defined(USE_SPISSD1306)
|
||||
#include <SSD1306Spi.h>
|
||||
#else
|
||||
// the SH1106/SSD1306 variant is auto-detected
|
||||
#include <AutoOLEDWire.h>
|
||||
|
||||
@@ -79,10 +79,6 @@
|
||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
||||
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
||||
#elif defined(M5STACK_UNITC6L)
|
||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
||||
#define FONT_MEDIUM FONT_SMALL_LOCAL // Height: 13
|
||||
#define FONT_LARGE FONT_SMALL_LOCAL // Height: 13
|
||||
#else
|
||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
||||
#define FONT_MEDIUM FONT_MEDIUM_LOCAL // Height: 19
|
||||
|
||||
@@ -124,7 +124,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
|
||||
int batteryX = 1;
|
||||
int batteryY = HEADER_OFFSET_Y + 1;
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
|
||||
// === Battery Icons ===
|
||||
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
||||
batteryX += 1;
|
||||
@@ -337,7 +337,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
display->setColor(WHITE); // Reset for other UI
|
||||
}
|
||||
|
||||
|
||||
@@ -1128,15 +1128,6 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
||||
#endif
|
||||
}
|
||||
|
||||
TFTDisplay::~TFTDisplay()
|
||||
{
|
||||
// Clean up allocated line pixel buffer to prevent memory leak
|
||||
if (linePixelBuffer != nullptr) {
|
||||
free(linePixelBuffer);
|
||||
linePixelBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void TFTDisplay::display(bool fromBlank)
|
||||
{
|
||||
|
||||
@@ -20,9 +20,6 @@ class TFTDisplay : public OLEDDisplay
|
||||
*/
|
||||
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||
|
||||
// Destructor to clean up allocated memory
|
||||
~TFTDisplay();
|
||||
|
||||
// Write the buffer to the display memory
|
||||
virtual void display() override { display(false); };
|
||||
virtual void display(bool fromBlank);
|
||||
|
||||
@@ -263,6 +263,12 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
display->drawString(x + 1, y, "USB");
|
||||
}
|
||||
|
||||
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||||
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
// if (config.display.heading_bold)
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||
|
||||
uint32_t currentMillis = millis();
|
||||
uint32_t seconds = currentMillis / 1000;
|
||||
uint32_t minutes = seconds / 60;
|
||||
@@ -277,13 +283,12 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
std::string uptime = UIRenderer::drawTimeDelta(days, hours, minutes, seconds);
|
||||
|
||||
// Line 1 (Still)
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||
if (config.display.heading_bold)
|
||||
display->drawString(x - 1 + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||
|
||||
display->setColor(WHITE);
|
||||
#endif
|
||||
|
||||
// Setup string to assemble analogClock string
|
||||
std::string analogClock = "";
|
||||
|
||||
@@ -387,24 +392,17 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
char shortnameble[35];
|
||||
getMacAddr(dmac);
|
||||
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(shortnameble, sizeof(shortnameble), "%s", screen->ourId);
|
||||
#else
|
||||
snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId);
|
||||
#endif
|
||||
int textWidth = display->getStringWidth(shortnameble);
|
||||
int nameX = (SCREEN_WIDTH - textWidth);
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
|
||||
// === Second Row: Radio Preset ===
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
char regionradiopreset[25];
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
if (region != nullptr) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s", region);
|
||||
#else
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
|
||||
#endif
|
||||
}
|
||||
textWidth = display->getStringWidth(regionradiopreset);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
@@ -416,17 +414,9 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
float freq = RadioLibInterface::instance->getFreq();
|
||||
snprintf(freqStr, sizeof(freqStr), "%.3f", freq);
|
||||
if (config.lora.channel_num == 0) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz", freqStr);
|
||||
#else
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz", freqStr);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num);
|
||||
#else
|
||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
||||
#endif
|
||||
}
|
||||
size_t len = strlen(frequencyslot);
|
||||
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
||||
@@ -436,7 +426,6 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// === Fourth Row: Channel Utilization ===
|
||||
const char *chUtil = "ChUtil:";
|
||||
char chUtilPercentage[10];
|
||||
@@ -493,7 +482,6 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[4],
|
||||
chUtilPercentage);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -519,11 +507,8 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
#ifdef USE_EINK
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int barX = x + 45 + barsOffset;
|
||||
#else
|
||||
const int barX = x + 40 + barsOffset;
|
||||
#endif
|
||||
|
||||
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
||||
if (total == 0)
|
||||
return;
|
||||
@@ -548,7 +533,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
// Label
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawString(labelX, getTextPositions(display)[line], label);
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
|
||||
// Bar
|
||||
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||
display->setColor(WHITE);
|
||||
@@ -556,7 +541,7 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
display->fillRect(barX, barY, fillWidth, barHeight);
|
||||
display->setColor(WHITE);
|
||||
#endif
|
||||
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||
@@ -609,16 +594,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
line += 1;
|
||||
}
|
||||
line += 1;
|
||||
|
||||
char appversionstr[35];
|
||||
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
||||
char appversionstr_formatted[40];
|
||||
char *lastDot = strrchr(appversionstr, '.');
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (lastDot != nullptr) {
|
||||
*lastDot = '\0'; // truncate string
|
||||
}
|
||||
#else
|
||||
if (lastDot) {
|
||||
size_t prefixLen = lastDot - appversionstr;
|
||||
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
||||
@@ -629,12 +608,10 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
||||
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
int textWidth = display->getStringWidth(appversionstr);
|
||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
|
||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
|
||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it
|
||||
line += 1;
|
||||
char uptimeStr[32] = "";
|
||||
@@ -653,7 +630,6 @@ void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line], uptimeStr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // namespace DebugRenderer
|
||||
} // namespace graphics
|
||||
|
||||
@@ -79,11 +79,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
"NP_865",
|
||||
"BR_902"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "LoRa Region";
|
||||
#else
|
||||
bannerOptions.message = "Set the LoRa region";
|
||||
#endif
|
||||
bannerOptions.durationMs = duration;
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 27;
|
||||
@@ -264,11 +260,7 @@ void menuHandler::TZPicker()
|
||||
|
||||
void menuHandler::clockMenu()
|
||||
{
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[] = {"Back", "Time Format", "Timezone"};
|
||||
#else
|
||||
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
||||
#endif
|
||||
enum optionsNumbers { Back = 0, Clock = 1, Time = 2, Timezone = 3 };
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Clock Action";
|
||||
@@ -292,11 +284,8 @@ void menuHandler::clockMenu()
|
||||
void menuHandler::messageResponseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 };
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply Preset"};
|
||||
#else
|
||||
|
||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"};
|
||||
#endif
|
||||
static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset};
|
||||
int options = 3;
|
||||
|
||||
@@ -310,11 +299,7 @@ void menuHandler::messageResponseMenu()
|
||||
optionsEnumArray[options++] = Aloud;
|
||||
#endif
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Message";
|
||||
#else
|
||||
bannerOptions.message = "Message Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -364,11 +349,7 @@ void menuHandler::homeBaseMenu()
|
||||
|
||||
optionsArray[options] = "Send Position";
|
||||
optionsEnumArray[options++] = Position;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "New Preset";
|
||||
#else
|
||||
optionsArray[options] = "New Preset Msg";
|
||||
#endif
|
||||
optionsEnumArray[options++] = Preset;
|
||||
if (kb_found) {
|
||||
optionsArray[options] = "New Freetext Msg";
|
||||
@@ -376,11 +357,7 @@ void menuHandler::homeBaseMenu()
|
||||
}
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Home";
|
||||
#else
|
||||
bannerOptions.message = "Home Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -419,11 +396,6 @@ void menuHandler::homeBaseMenu()
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::textMessageMenu()
|
||||
{
|
||||
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST);
|
||||
}
|
||||
|
||||
void menuHandler::textMessageBaseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Preset, Freetext, enumEnd };
|
||||
@@ -467,17 +439,11 @@ void menuHandler::systemBaseMenu()
|
||||
optionsArray[options] = "Screen Options";
|
||||
optionsEnumArray[options++] = ScreenOptions;
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Bluetooth";
|
||||
#else
|
||||
|
||||
optionsArray[options] = "Bluetooth Toggle";
|
||||
#endif
|
||||
optionsEnumArray[options++] = Bluetooth;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Power";
|
||||
#else
|
||||
|
||||
optionsArray[options] = "Reboot/Shutdown";
|
||||
#endif
|
||||
optionsEnumArray[options++] = PowerMenu;
|
||||
|
||||
if (test_enabled) {
|
||||
@@ -486,11 +452,7 @@ void menuHandler::systemBaseMenu()
|
||||
}
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "System";
|
||||
#else
|
||||
bannerOptions.message = "System Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
@@ -523,11 +485,7 @@ void menuHandler::systemBaseMenu()
|
||||
void menuHandler::favoriteBaseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Preset, Freetext, Remove, TraceRoute, enumEnd };
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset"};
|
||||
#else
|
||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"};
|
||||
#endif
|
||||
static int optionsEnumArray[enumEnd] = {Back, Preset};
|
||||
int options = 2;
|
||||
|
||||
@@ -535,19 +493,13 @@ void menuHandler::favoriteBaseMenu()
|
||||
optionsArray[options] = "New Freetext Msg";
|
||||
optionsEnumArray[options++] = Freetext;
|
||||
}
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Trace Route";
|
||||
optionsEnumArray[options++] = TraceRoute;
|
||||
#endif
|
||||
optionsArray[options] = "Remove Favorite";
|
||||
optionsEnumArray[options++] = Remove;
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Favorites";
|
||||
#else
|
||||
bannerOptions.message = "Favorites Action";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
@@ -576,12 +528,10 @@ void menuHandler::positionBaseMenu()
|
||||
static int optionsEnumArray[enumEnd] = {Back, GPSToggle, CompassMenu};
|
||||
int options = 3;
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
if (accelerometerThread) {
|
||||
optionsArray[options] = "Compass Calibrate";
|
||||
optionsEnumArray[options++] = CompassCalibrate;
|
||||
}
|
||||
#endif
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Position Action";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
@@ -594,10 +544,8 @@ void menuHandler::positionBaseMenu()
|
||||
} else if (selected == CompassMenu) {
|
||||
menuQueue = compass_point_north_menu;
|
||||
screen->runNow();
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
} else if (selected == CompassCalibrate) {
|
||||
accelerometerThread->calibrate(30);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
@@ -606,19 +554,11 @@ void menuHandler::positionBaseMenu()
|
||||
void menuHandler::nodeListMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Favorite, TraceRoute, Verify, Reset, enumEnd };
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Reset Node"};
|
||||
#else
|
||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Trace Route", "Key Verification", "Reset NodeDB"};
|
||||
#endif
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Node Action";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.optionsCount = 3;
|
||||
#else
|
||||
bannerOptions.optionsCount = 5;
|
||||
#endif
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Favorite) {
|
||||
menuQueue = add_favorite;
|
||||
@@ -725,11 +665,7 @@ void menuHandler::BluetoothToggleMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Bluetooth";
|
||||
#else
|
||||
bannerOptions.message = "Toggle Bluetooth";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 3;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -921,11 +857,7 @@ void menuHandler::rebootMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Reboot";
|
||||
#else
|
||||
bannerOptions.message = "Reboot Device?";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -945,11 +877,7 @@ void menuHandler::shutdownMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Shutdown";
|
||||
#else
|
||||
bannerOptions.message = "Shutdown Device?";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
@@ -966,12 +894,7 @@ void menuHandler::shutdownMenu()
|
||||
|
||||
void menuHandler::addFavoriteMenu()
|
||||
{
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
screen->showNodePicker("Node Favorite", 30000, [](uint32_t nodenum) -> void {
|
||||
#else
|
||||
screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void {
|
||||
|
||||
#endif
|
||||
LOG_WARN("Nodenum: %u", nodenum);
|
||||
nodeDB->set_favorite(true, nodenum);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
@@ -1167,11 +1090,7 @@ void menuHandler::powerMenu()
|
||||
#endif
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "Power";
|
||||
#else
|
||||
bannerOptions.message = "Reboot / Shutdown";
|
||||
#endif
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
|
||||
@@ -76,7 +76,6 @@ class menuHandler
|
||||
static void notificationsMenu();
|
||||
static void screenOptionsMenu();
|
||||
static void powerMenu();
|
||||
static void textMessageMenu();
|
||||
|
||||
private:
|
||||
static void saveUIConfig();
|
||||
|
||||
@@ -181,19 +181,12 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int fixedTopHeight = 24;
|
||||
const int windowX = 0;
|
||||
const int windowY = fixedTopHeight;
|
||||
const int windowWidth = 64;
|
||||
const int windowHeight = SCREEN_HEIGHT - fixedTopHeight;
|
||||
#else
|
||||
|
||||
const int navHeight = FONT_HEIGHT_SMALL;
|
||||
const int scrollBottom = SCREEN_HEIGHT - navHeight;
|
||||
const int usableHeight = scrollBottom;
|
||||
const int textWidth = SCREEN_WIDTH;
|
||||
|
||||
#endif
|
||||
bool isInverted = (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED);
|
||||
bool isBold = config.display.heading_bold;
|
||||
|
||||
@@ -208,11 +201,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
const char *messageString = "No messages";
|
||||
int center_text = (SCREEN_WIDTH / 2) - (display->getStringWidth(messageString) / 2);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->drawString(center_text, windowY + (windowHeight / 2) - (FONT_HEIGHT_SMALL / 2) - 5, messageString);
|
||||
#else
|
||||
display->drawString(center_text, getTextPositions(display)[2], messageString);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,10 +209,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||
char headerStr[80];
|
||||
const char *sender = "???";
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (node && node->has_user)
|
||||
sender = node->user.short_name;
|
||||
#else
|
||||
if (node && node->has_user) {
|
||||
if (SCREEN_WIDTH >= 200 && strlen(node->user.long_name) > 0) {
|
||||
sender = node->user.long_name;
|
||||
@@ -231,7 +216,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
sender = node->user.short_name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
uint32_t seconds = sinceReceived(&mp), minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
||||
uint8_t timestampHours, timestampMinutes;
|
||||
int32_t daysAgo;
|
||||
@@ -251,61 +235,10 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
sender);
|
||||
}
|
||||
} else {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(headerStr, sizeof(headerStr), "%s from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
sender);
|
||||
#else
|
||||
snprintf(headerStr, sizeof(headerStr), "%s ago from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||
sender);
|
||||
#endif
|
||||
}
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
int headerY = getTextPositions(display)[1];
|
||||
display->drawString(x, headerY, headerStr);
|
||||
for (int separatorX = 0; separatorX < SCREEN_WIDTH; separatorX += 2) {
|
||||
display->setPixel(separatorX, fixedTopHeight - 1);
|
||||
}
|
||||
cachedLines.clear();
|
||||
std::string fullMsg(messageBuf);
|
||||
std::string currentLine;
|
||||
for (size_t i = 0; i < fullMsg.size();) {
|
||||
unsigned char c = fullMsg[i];
|
||||
size_t charLen = 1;
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
charLen = 2;
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
charLen = 3;
|
||||
else if ((c & 0xF8) == 0xF0)
|
||||
charLen = 4;
|
||||
std::string nextChar = fullMsg.substr(i, charLen);
|
||||
std::string testLine = currentLine + nextChar;
|
||||
if (display->getStringWidth(testLine.c_str()) > windowWidth) {
|
||||
cachedLines.push_back(currentLine);
|
||||
currentLine = nextChar;
|
||||
} else {
|
||||
currentLine = testLine;
|
||||
}
|
||||
|
||||
i += charLen;
|
||||
}
|
||||
if (!currentLine.empty())
|
||||
cachedLines.push_back(currentLine);
|
||||
cachedHeights = calculateLineHeights(cachedLines, emotes);
|
||||
int yOffset = windowY;
|
||||
int linesDrawn = 0;
|
||||
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
||||
if (linesDrawn >= 2)
|
||||
break;
|
||||
int lineHeight = cachedHeights[i];
|
||||
if (yOffset + lineHeight > windowY + windowHeight)
|
||||
break;
|
||||
drawStringWithEmotes(display, windowX, yOffset, cachedLines[i], emotes, numEmotes);
|
||||
yOffset += lineHeight;
|
||||
linesDrawn++;
|
||||
}
|
||||
screen->forceDisplay();
|
||||
#else
|
||||
uint32_t now = millis();
|
||||
#ifndef EXCLUDE_EMOJI
|
||||
// === Bounce animation setup ===
|
||||
@@ -422,7 +355,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
|
||||
// Draw header at the end to sort out overlapping elements
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::string> generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth)
|
||||
|
||||
@@ -21,10 +21,6 @@ extern bool haveGlyphs(const char *str);
|
||||
// Global screen instance
|
||||
extern graphics::Screen *screen;
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
static uint32_t lastSwitchTime = 0;
|
||||
#else
|
||||
#endif
|
||||
namespace graphics
|
||||
{
|
||||
namespace NodeListRenderer
|
||||
@@ -397,11 +393,9 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
{
|
||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
int columnWidth = display->getWidth();
|
||||
#else
|
||||
|
||||
int columnWidth = display->getWidth() / 2;
|
||||
#endif
|
||||
|
||||
display->clear();
|
||||
|
||||
// Draw the battery/time header
|
||||
@@ -414,11 +408,8 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
||||
|
||||
int visibleNodeRows = totalRowsAvailable;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
int totalColumns = 1;
|
||||
#else
|
||||
int totalColumns = 2;
|
||||
#endif
|
||||
|
||||
int startIndex = scrollIndex * visibleNodeRows * totalColumns;
|
||||
if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) {
|
||||
startIndex++; // skip own node
|
||||
@@ -454,14 +445,12 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
// Draw column separator
|
||||
if (shownCount > 0) {
|
||||
const int firstNodeY = y + 3;
|
||||
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
||||
}
|
||||
|
||||
#endif
|
||||
const int scrollStartY = y + 3;
|
||||
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
||||
}
|
||||
@@ -479,13 +468,6 @@ void drawDynamicNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->clear();
|
||||
if (now - lastSwitchTime >= 3000) {
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
// On very first call (on boot or state enter)
|
||||
if (lastRenderedMode == MODE_COUNT) {
|
||||
currentMode = MODE_LAST_HEARD;
|
||||
@@ -540,14 +522,6 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
double lat = DegD(ourNode->position.latitude_i);
|
||||
double lon = DegD(ourNode->position.longitude_i);
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->clear();
|
||||
uint32_t now = millis();
|
||||
if (now - lastSwitchTime >= 2000) {
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||
#if HAS_GPS
|
||||
if (screen->hasHeading()) {
|
||||
|
||||
@@ -459,135 +459,6 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
||||
// count lines
|
||||
|
||||
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
boxWidth += 26;
|
||||
if (!isHighResolution && boxWidth <= 100)
|
||||
boxWidth += 20;
|
||||
}
|
||||
|
||||
uint16_t screenHeight = display->height();
|
||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
||||
uint8_t visibleTotalLines = std::min<uint8_t>(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
||||
uint16_t contentHeight = visibleTotalLines * effectiveLineHeight;
|
||||
uint16_t boxHeight = contentHeight + vPadding * 2;
|
||||
if (visibleTotalLines == 1)
|
||||
boxHeight += (isHighResolution ? 4 : 3);
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
if (totalLines > visibleTotalLines)
|
||||
boxWidth += (isHighResolution ? 4 : 2);
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
if (visibleTotalLines == 1) {
|
||||
boxTop += 25;
|
||||
}
|
||||
if (alertBannerOptions < 3) {
|
||||
int missingLines = 3 - alertBannerOptions;
|
||||
int moveUp = missingLines * (effectiveLineHeight / 2);
|
||||
boxTop -= moveUp;
|
||||
if (boxTop < 0)
|
||||
boxTop = 0;
|
||||
}
|
||||
|
||||
// === Draw Box ===
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, boxHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight);
|
||||
display->fillRect(boxLeft, boxTop - 2, boxWidth, 1);
|
||||
display->fillRect(boxLeft - 2, boxTop, 1, boxHeight);
|
||||
display->fillRect(boxLeft + boxWidth + 1, boxTop, 1, boxHeight);
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, 1, 1);
|
||||
display->fillRect(boxLeft + boxWidth - 1, boxTop, 1, 1);
|
||||
display->fillRect(boxLeft, boxTop + boxHeight - 1, 1, 1);
|
||||
display->fillRect(boxLeft + boxWidth - 1, boxTop + boxHeight - 1, 1, 1);
|
||||
display->setColor(WHITE);
|
||||
int16_t lineY = boxTop + vPadding;
|
||||
int swingRange = 8;
|
||||
static int swingOffset = 0;
|
||||
static bool swingRight = true;
|
||||
static unsigned long lastSwingTime = 0;
|
||||
unsigned long now = millis();
|
||||
int swingSpeedMs = 10 / (swingRange * 2);
|
||||
if (now - lastSwingTime >= (unsigned long)swingSpeedMs) {
|
||||
lastSwingTime = now;
|
||||
if (swingRight) {
|
||||
swingOffset++;
|
||||
if (swingOffset >= swingRange)
|
||||
swingRight = false;
|
||||
} else {
|
||||
swingOffset--;
|
||||
if (swingOffset <= 0)
|
||||
swingRight = true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
bool isTitle = (i == 0);
|
||||
int globalOptionIndex = (i - 1) + firstOptionToShow;
|
||||
bool isSelectedOption = (!isTitle && globalOptionIndex >= 0 && globalOptionIndex == curSelected);
|
||||
|
||||
uint16_t visibleWidth = 64 - hPadding * 2;
|
||||
if (totalLines > visibleTotalLines)
|
||||
visibleWidth -= 6;
|
||||
char lineBuffer[lineLengths[i] + 1];
|
||||
strncpy(lineBuffer, lines[i], lineLengths[i]);
|
||||
lineBuffer[lineLengths[i]] = '\0';
|
||||
|
||||
if (isTitle) {
|
||||
if (visibleTotalLines == 1) {
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
||||
} else {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
||||
display->setColor(WHITE);
|
||||
if (needs_bell) {
|
||||
int bellY = boxTop + (FONT_HEIGHT_SMALL - 8) / 2;
|
||||
display->drawXbm(boxLeft + (boxWidth - lineWidths[i]) / 2 - 10, bellY, 8, 8, bell_alert);
|
||||
display->drawXbm(boxLeft + (boxWidth + lineWidths[i]) / 2 + 2, bellY, 8, 8, bell_alert);
|
||||
}
|
||||
}
|
||||
lineY = boxTop + effectiveLineHeight + 1;
|
||||
} else if (isSelectedOption) {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
||||
display->setColor(BLACK);
|
||||
if (lineLengths[i] > 15 && lineWidths[i] > visibleWidth) {
|
||||
int textX = boxLeft + hPadding + swingOffset;
|
||||
display->drawString(textX, lineY - 1, lineBuffer);
|
||||
} else {
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY - 1, lineBuffer);
|
||||
}
|
||||
display->setColor(WHITE);
|
||||
lineY += effectiveLineHeight;
|
||||
} else {
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
||||
display->setColor(WHITE);
|
||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY, lineBuffer);
|
||||
lineY += effectiveLineHeight;
|
||||
}
|
||||
}
|
||||
if (totalLines > visibleTotalLines) {
|
||||
const uint8_t scrollBarWidth = 5;
|
||||
int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2;
|
||||
int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight;
|
||||
uint16_t scrollBarHeight = boxHeight - vPadding * 2 - effectiveLineHeight;
|
||||
float ratio = (float)visibleTotalLines / totalLines;
|
||||
uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4);
|
||||
float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines);
|
||||
uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight);
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
||||
}
|
||||
#else
|
||||
if (needs_bell) {
|
||||
if (isHighResolution && boxWidth <= 150)
|
||||
boxWidth += 26;
|
||||
@@ -676,7 +547,6 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
// External variables
|
||||
extern graphics::Screen *screen;
|
||||
static uint32_t lastSwitchTime = 0;
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||
@@ -218,6 +218,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
||||
// **********************
|
||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
|
||||
if (favoritedNodes.empty())
|
||||
return;
|
||||
|
||||
@@ -229,15 +230,8 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
meshtastic_NodeInfoLite *node = favoritedNodes[nodeIndex];
|
||||
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
||||
return;
|
||||
uint32_t now = millis();
|
||||
|
||||
display->clear();
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
if (now - lastSwitchTime >= 10000) // 10000 ms = 10 秒
|
||||
{
|
||||
display->display();
|
||||
lastSwitchTime = now;
|
||||
}
|
||||
#endif
|
||||
currentFavoriteNodeNum = node->num;
|
||||
// === Create the shortName and title string ===
|
||||
const char *shortName = (node->has_user && haveGlyphs(node->user.short_name)) ? node->user.short_name : "Node";
|
||||
@@ -256,13 +250,9 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
// List of available macro Y positions in order, from top to bottom.
|
||||
int line = 1; // which slot to use next
|
||||
std::string usernameStr;
|
||||
// === 1. Long Name (always try to show first) ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.short_name : nullptr;
|
||||
#else
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
#endif
|
||||
|
||||
// === 1. Long Name (always try to show first) ===
|
||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||
if (username) {
|
||||
usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case
|
||||
// Print node's long name (e.g. "Backpack Node")
|
||||
@@ -317,7 +307,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
if (seenStr[0] && line < 5) {
|
||||
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
||||
}
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
char uptimeStr[32] = "";
|
||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||
@@ -489,7 +479,6 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
}
|
||||
// else show nothing
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -503,11 +492,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
int line = 1;
|
||||
|
||||
// === Header ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
graphics::drawCommonHeader(display, x, y, "Home");
|
||||
#else
|
||||
graphics::drawCommonHeader(display, x, y, "");
|
||||
#endif
|
||||
|
||||
// === Content below header ===
|
||||
|
||||
@@ -522,25 +507,20 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
config.display.heading_bold = false;
|
||||
|
||||
// Display Region and Channel Utilization
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
drawNodes(display, x, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
#else
|
||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||
#endif
|
||||
|
||||
char uptimeStr[32] = "";
|
||||
uint32_t uptime = millis() / 1000;
|
||||
uint32_t days = uptime / 86400;
|
||||
uint32_t hours = (uptime % 86400) / 3600;
|
||||
uint32_t mins = (uptime % 3600) / 60;
|
||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
if (days)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
||||
else if (hours)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
||||
#endif
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||
|
||||
// === Second Row: Satellites and Voltage ===
|
||||
@@ -569,21 +549,6 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
line += 1;
|
||||
|
||||
// === Node Identity ===
|
||||
int textWidth = 0;
|
||||
int nameX = 0;
|
||||
char shortnameble[35];
|
||||
snprintf(shortnameble, sizeof(shortnameble), "%s",
|
||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
||||
|
||||
// === ShortName Centered ===
|
||||
textWidth = display->getStringWidth(shortnameble);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
#else
|
||||
if (powerStatus->getHasBattery()) {
|
||||
char batStr[20];
|
||||
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||||
@@ -709,7 +674,6 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Start Functions to write date/time to the screen
|
||||
@@ -868,28 +832,6 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
// needs to be drawn relative to x and y
|
||||
|
||||
// draw centered icon left to right and centered above the one line of app text
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
display->drawXbm(x + (SCREEN_WIDTH - 50) / 2, y + (SCREEN_HEIGHT - 28) / 2, icon_width, icon_height, icon_bits);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
// Draw region in upper left
|
||||
if (upperMsg) {
|
||||
int msgWidth = display->getStringWidth(upperMsg);
|
||||
int msgX = x + (SCREEN_WIDTH - msgWidth) / 2;
|
||||
int msgY = y;
|
||||
display->drawString(msgX, msgY, upperMsg);
|
||||
}
|
||||
// Draw version and short name in bottom middle
|
||||
char buf[25];
|
||||
snprintf(buf, sizeof(buf), "%s %s", xstr(APP_VERSION_SHORT),
|
||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
||||
|
||||
display->drawString(x + getStringCenteredX(buf), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
#else
|
||||
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
|
||||
icon_width, icon_height, icon_bits);
|
||||
|
||||
@@ -898,6 +840,7 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
const char *title = "meshtastic.org";
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
if (upperMsg)
|
||||
display->drawString(x + 0, y + 0, upperMsg);
|
||||
@@ -912,7 +855,6 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
||||
screen->forceDisplay();
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
#endif
|
||||
}
|
||||
|
||||
// ****************************
|
||||
@@ -988,26 +930,15 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||
char fullLine[40];
|
||||
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
display->drawString(0, getTextPositions(display)[line++], fullLine);
|
||||
#endif
|
||||
|
||||
// === Third Row: Latitude ===
|
||||
char latStr[32];
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(latStr, sizeof(latStr), "Lat:%.5f", geoCoord.getLatitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++] + 2, latStr);
|
||||
#else
|
||||
snprintf(latStr, sizeof(latStr), " Lat: %.5f", geoCoord.getLatitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++], latStr);
|
||||
#endif
|
||||
|
||||
// === Fourth Row: Longitude ===
|
||||
char lonStr[32];
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(lonStr, sizeof(lonStr), "Lon:%.3f", geoCoord.getLongitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++] + 4, lonStr);
|
||||
#else
|
||||
snprintf(lonStr, sizeof(lonStr), " Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++], lonStr);
|
||||
|
||||
@@ -1019,9 +950,8 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0im", geoCoord.getAltitude());
|
||||
}
|
||||
display->drawString(x, getTextPositions(display)[line++], DisplayLineTwo);
|
||||
#endif
|
||||
}
|
||||
#if !defined(M5STACK_UNITC6L)
|
||||
|
||||
// === Draw Compass if heading is valid ===
|
||||
if (validHeading) {
|
||||
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
||||
@@ -1104,7 +1034,6 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
@@ -1261,6 +1190,7 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->setColor(WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Knock the corners off the square
|
||||
display->setColor(BLACK);
|
||||
display->drawRect(rectX, y - 2, 1, 1);
|
||||
|
||||
@@ -287,9 +287,6 @@ const uint8_t digital_icon_clock[] PROGMEM = {0b00111100, 0b01000010, 0b10000101
|
||||
#define analog_icon_clock_height 8
|
||||
const uint8_t analog_icon_clock[] PROGMEM = {0b11111111, 0b01000010, 0b00100100, 0b00011000,
|
||||
0b00100100, 0b01000010, 0b01000010, 0b11111111};
|
||||
#ifdef M5STACK_UNITC6L
|
||||
#include "img/icon_small.xbm"
|
||||
#else
|
||||
|
||||
#include "img/icon.xbm"
|
||||
#endif
|
||||
static_assert(sizeof(icon_bits) >= 0, "Silence unused variable warning");
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef USERPREFS_HAS_SPLASH
|
||||
#define icon_width 50
|
||||
#define icon_height 20
|
||||
static uint8_t icon_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80,
|
||||
0x07, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xc0, 0x0f,
|
||||
0xc0, 0x0f, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xe0,
|
||||
0x0f, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x1f,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x03, 0xf0, 0x3f, 0x00,
|
||||
0x00, 0x00, 0xf8, 0x03, 0xf8, 0x7f, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x01, 0xfc, 0x7e, 0x00, 0x00, 0x00,
|
||||
0xfc, 0x00, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0xfe,
|
||||
0x00, 0x7e, 0xf8, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
||||
0x3f, 0xf8, 0x01, 0x00, 0x00, 0x3f, 0x00, 0x1f,
|
||||
0xf0, 0x01, 0x00, 0x00, 0x1f, 0x80, 0x1f, 0xe0,
|
||||
0x03, 0x00, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x03,
|
||||
0x00, 0x80, 0x0f, 0xc0, 0x07, 0xc0, 0x07, 0x00,
|
||||
0xc0, 0x0f, 0xe0, 0x07, 0x80, 0x0f, 0x00, 0xe0,
|
||||
0x07, 0xf0, 0x03, 0x80, 0x1f, 0x00, 0xe0, 0x03,
|
||||
0xf8, 0x03, 0x00, 0x1f, 0x00, 0xf0, 0x03, 0xf8,
|
||||
0x01, 0x00, 0x3f, 0x00, 0xf8, 0x01, 0xfc, 0x00,
|
||||
0x00, 0x7e, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x00,
|
||||
0x7e, 0x00, 0xfc, 0x00, 0x7e, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x7e, 0x00, 0x3f, 0x00, 0x00, 0xf8, 0x00,
|
||||
0x7e, 0x00, 0x3e, 0x00, 0x00, 0xf8, 0x00, 0x38,
|
||||
0x00, 0x1c, 0x00, 0x00, 0x70, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00 };
|
||||
#endif
|
||||
@@ -40,7 +40,10 @@ bool RotaryEncoderImpl::init()
|
||||
|
||||
int32_t RotaryEncoderImpl::runOnce()
|
||||
{
|
||||
InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0};
|
||||
InputEvent e;
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
e.source = this->originName;
|
||||
|
||||
static uint32_t lastPressed = millis();
|
||||
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
||||
if (lastPressed + 200 < millis()) {
|
||||
@@ -67,7 +70,7 @@ int32_t RotaryEncoderImpl::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
return 10;
|
||||
return 20;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,11 +13,7 @@ void CardKbI2cImpl::init()
|
||||
if (cardkb_found.address == 0x00) {
|
||||
LOG_DEBUG("Rescan for I2C keyboard");
|
||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, TCA8418_KB_ADDR};
|
||||
#if defined(T_LORA_PAGER)
|
||||
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
|
||||
#else
|
||||
uint8_t i2caddr_asize = 5;
|
||||
#endif
|
||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||
|
||||
#if WIRE_INTERFACES_COUNT == 2
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "i2cButton.h"
|
||||
#include "meshUtils.h"
|
||||
|
||||
#include "configuration.h"
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
|
||||
#include "MeshService.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "buzz.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "main.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
i2cButtonThread *i2cButton;
|
||||
|
||||
using namespace concurrency;
|
||||
|
||||
extern void i2c_read_byte(uint8_t addr, uint8_t reg, uint8_t *value);
|
||||
|
||||
extern void i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t value);
|
||||
|
||||
#define PI4IO_M_ADDR 0x43
|
||||
#define getbit(x, y) ((x) >> (y)&0x01)
|
||||
#define PI4IO_REG_IRQ_STA 0x13
|
||||
#define PI4IO_REG_IN_STA 0x0F
|
||||
#define PI4IO_REG_CHIP_RESET 0x01
|
||||
|
||||
i2cButtonThread::i2cButtonThread(const char *name) : OSThread(name)
|
||||
{
|
||||
_originName = name;
|
||||
if (inputBroker)
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
int32_t i2cButtonThread::runOnce()
|
||||
{
|
||||
static bool btn1_pressed = false;
|
||||
static uint32_t press_start_time = 0;
|
||||
const uint32_t LONG_PRESS_TIME = 1000;
|
||||
static bool long_press_triggered = false;
|
||||
|
||||
uint8_t in_data;
|
||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, &in_data);
|
||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, in_data);
|
||||
if (getbit(in_data, 0)) {
|
||||
uint8_t input_state;
|
||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IN_STA, &input_state);
|
||||
|
||||
if (!getbit(input_state, 0)) {
|
||||
if (!btn1_pressed) {
|
||||
btn1_pressed = true;
|
||||
press_start_time = millis();
|
||||
long_press_triggered = false;
|
||||
}
|
||||
} else {
|
||||
if (btn1_pressed) {
|
||||
btn1_pressed = false;
|
||||
uint32_t press_duration = millis() - press_start_time;
|
||||
if (long_press_triggered) {
|
||||
long_press_triggered = false;
|
||||
return 50;
|
||||
}
|
||||
|
||||
if (press_duration < LONG_PRESS_TIME) {
|
||||
InputEvent evt;
|
||||
evt.source = "UserButton";
|
||||
evt.inputEvent = INPUT_BROKER_USER_PRESS;
|
||||
evt.kbchar = 0;
|
||||
evt.touchX = 0;
|
||||
evt.touchY = 0;
|
||||
this->notifyObservers(&evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (btn1_pressed && !long_press_triggered && (millis() - press_start_time >= LONG_PRESS_TIME)) {
|
||||
long_press_triggered = true;
|
||||
InputEvent evt;
|
||||
evt.source = "UserButton";
|
||||
evt.inputEvent = INPUT_BROKER_SELECT;
|
||||
evt.kbchar = 0;
|
||||
evt.touchX = 0;
|
||||
evt.touchY = 0;
|
||||
this->notifyObservers(&evt);
|
||||
}
|
||||
return 50;
|
||||
}
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "OneButton.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
|
||||
class i2cButtonThread : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
const char *_originName;
|
||||
explicit i2cButtonThread(const char *name);
|
||||
int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern i2cButtonThread *i2cButton;
|
||||
#endif
|
||||
30
src/main.cpp
30
src/main.cpp
@@ -385,6 +385,7 @@ void setup()
|
||||
io.digitalWrite(EXPANDS_GPIO_EN, HIGH);
|
||||
io.pinMode(EXPANDS_SD_PULLEN, INPUT);
|
||||
#endif
|
||||
|
||||
concurrency::hasBeenSetup = true;
|
||||
#if ARCH_PORTDUINO
|
||||
SPISettings spiSettings(settingsMap[spiSpeed], MSBFIRST, SPI_MODE0);
|
||||
@@ -418,7 +419,7 @@ void setup()
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time(NULL);
|
||||
tv.tv_usec = 0;
|
||||
perhapsSetRTC(RTCQualityDevice, &tv);
|
||||
perhapsSetRTC(RTCQualityNTP, &tv);
|
||||
#endif
|
||||
|
||||
powerMonInit();
|
||||
@@ -543,12 +544,6 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
pinMode(LORA_CS, OUTPUT);
|
||||
digitalWrite(LORA_CS, 1);
|
||||
c6l_init();
|
||||
#endif
|
||||
|
||||
#ifdef PIN_LCD_RESET
|
||||
// FIXME - move this someplace better, LCD is at address 0x3F
|
||||
pinMode(PIN_LCD_RESET, OUTPUT);
|
||||
@@ -746,7 +741,6 @@ void setup()
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2561, meshtastic_TelemetrySensorType_TSL2561);
|
||||
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
@@ -865,14 +859,18 @@ void setup()
|
||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||
SPI.begin();
|
||||
#else
|
||||
// ESP32
|
||||
#if defined(HW_SPI1_DEVICE)
|
||||
// ESP32
|
||||
#ifdef LORA_TYPE
|
||||
SPI.begin(PIN_EINK_SCLK, 15, PIN_EINK_MOSI, PIN_EINK_CS);
|
||||
LOG_WARN("SPI.begin(SCK=%d, MISO=15, MOSI=%d, NSS=%d)\n", PIN_EINK_SCLK, PIN_EINK_MOSI, PIN_EINK_CS);
|
||||
#elif defined(HW_SPI1_DEVICE)
|
||||
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
SPI1.setFrequency(4000000);
|
||||
#else
|
||||
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_DEBUG("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
#endif
|
||||
SPI.setFrequency(4000000);
|
||||
#endif
|
||||
#endif
|
||||
@@ -882,8 +880,7 @@ void setup()
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||
defined(USE_SPISSD1306)
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||
@@ -1146,8 +1143,7 @@ void setup()
|
||||
// Don't call screen setup until after nodedb is setup (because we need
|
||||
// the current region name)
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||
defined(USE_SPISSD1306)
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
if (screen)
|
||||
screen->setup();
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
@@ -1219,6 +1215,10 @@ void setup()
|
||||
}
|
||||
#elif defined(HW_SPI1_DEVICE)
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
||||
#elif LORA_TYPE
|
||||
SPIClass radioSPI(VSPI);
|
||||
radioSPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(radioSPI, spiSettings);
|
||||
#else // HW_SPI1_DEVICE
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
#endif
|
||||
@@ -1533,7 +1533,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
||||
#if ((!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
||||
#endif
|
||||
#if NO_EXT_GPIO || MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
#if NO_EXT_GPIO
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
|
||||
#endif
|
||||
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
||||
|
||||
@@ -88,16 +88,4 @@ uint32_t MemGet::getPsramSize()
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void displayPercentHeapFree()
|
||||
{
|
||||
uint32_t freeHeap = memGet.getFreeHeap();
|
||||
uint32_t totalHeap = memGet.getHeapSize();
|
||||
if (totalHeap == 0 || totalHeap == UINT32_MAX) {
|
||||
LOG_INFO("Heap size unavailable");
|
||||
return;
|
||||
}
|
||||
int percent = (int)((freeHeap * 100) / totalHeap);
|
||||
LOG_INFO("Heap free: %d%% (%u/%u bytes)", percent, freeHeap, totalHeap);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ const char *Channels::getName(size_t chIndex)
|
||||
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
|
||||
// the app effed up and forgot to set channelSettings.name
|
||||
if (config.lora.use_preset) {
|
||||
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
} else {
|
||||
channelName = "Custom";
|
||||
}
|
||||
@@ -382,8 +382,7 @@ bool Channels::isDefaultChannel(ChannelIndex chIndex)
|
||||
const auto &ch = getByIndex(chIndex);
|
||||
if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) {
|
||||
const char *name = getName(chIndex);
|
||||
const char *presetName =
|
||||
DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||
// Check if the name is the default derived from the modem preset
|
||||
if (strcmp(name, presetName) == 0)
|
||||
return true;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include "PointerQueue.h"
|
||||
#include "configuration.h" // For LOG_WARN, LOG_DEBUG, LOG_HEAP
|
||||
|
||||
template <class T> class Allocator
|
||||
{
|
||||
@@ -15,14 +14,13 @@ template <class T> class Allocator
|
||||
Allocator() : deleter([this](T *p) { this->release(p); }) {}
|
||||
virtual ~Allocator() {}
|
||||
|
||||
/// Return a queable object which has been prefilled with zeros. Return nullptr if no buffer is available
|
||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||
/// Note: this method is safe to call from regular OR ISR code
|
||||
T *allocZeroed()
|
||||
{
|
||||
T *p = allocZeroed(0);
|
||||
if (!p) {
|
||||
LOG_WARN("Failed to allocate zeroed memory");
|
||||
}
|
||||
|
||||
assert(p); // FIXME panic instead
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -41,12 +39,10 @@ template <class T> class Allocator
|
||||
T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p = alloc(maxWait);
|
||||
if (!p) {
|
||||
LOG_WARN("Failed to allocate memory for copy");
|
||||
return nullptr;
|
||||
}
|
||||
assert(p);
|
||||
|
||||
*p = src;
|
||||
if (p)
|
||||
*p = src;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -87,11 +83,7 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p) override
|
||||
{
|
||||
if (p == nullptr)
|
||||
return;
|
||||
|
||||
LOG_HEAP("Freeing 0x%x", p);
|
||||
|
||||
assert(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
@@ -104,58 +96,3 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A static memory pool that uses a fixed buffer instead of heap allocation
|
||||
*/
|
||||
template <class T, int MaxSize> class MemoryPool : public Allocator<T>
|
||||
{
|
||||
private:
|
||||
T pool[MaxSize];
|
||||
bool used[MaxSize];
|
||||
|
||||
public:
|
||||
MemoryPool() : pool{}, used{}
|
||||
{
|
||||
// Arrays are now zero-initialized by member initializer list
|
||||
// pool array: all elements are default-constructed (zero for POD types)
|
||||
// used array: all elements are false (zero-initialized)
|
||||
}
|
||||
|
||||
/// Return a buffer for use by others
|
||||
virtual void release(T *p) override
|
||||
{
|
||||
if (!p) {
|
||||
LOG_DEBUG("Failed to release memory, pointer is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the index of this pointer in our pool
|
||||
int index = p - pool;
|
||||
if (index >= 0 && index < MaxSize) {
|
||||
assert(used[index]); // Should be marked as used
|
||||
used[index] = false;
|
||||
LOG_HEAP("Released static pool item %d at 0x%x", index, p);
|
||||
} else {
|
||||
LOG_WARN("Pointer 0x%x not from our pool!", p);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Alloc some storage from our static pool
|
||||
virtual T *alloc(TickType_t maxWait) override
|
||||
{
|
||||
// Find first free slot
|
||||
for (int i = 0; i < MaxSize; i++) {
|
||||
if (!used[i]) {
|
||||
used[i] = true;
|
||||
LOG_HEAP("Allocated static pool item %d at 0x%x", i, &pool[i]);
|
||||
return &pool[i];
|
||||
}
|
||||
}
|
||||
|
||||
// No free slots available - return nullptr instead of asserting
|
||||
LOG_WARN("No free slots available in static memory pool!");
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -100,6 +100,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
|
||||
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
||||
auto ourNodeNum = nodeDB->getNodeNum();
|
||||
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
|
||||
bool fromUs = mp.from == ourNodeNum;
|
||||
|
||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||
auto &pi = **i;
|
||||
|
||||
@@ -46,14 +46,11 @@ the new node can build its node db)
|
||||
|
||||
MeshService *service;
|
||||
|
||||
#define MAX_MQTT_PROXY_MESSAGES 16
|
||||
static MemoryPool<meshtastic_MqttClientProxyMessage, MAX_MQTT_PROXY_MESSAGES> staticMqttClientProxyMessagePool;
|
||||
static MemoryDynamic<meshtastic_MqttClientProxyMessage> staticMqttClientProxyMessagePool;
|
||||
|
||||
#define MAX_QUEUE_STATUS 4
|
||||
static MemoryPool<meshtastic_QueueStatus, MAX_QUEUE_STATUS> staticQueueStatusPool;
|
||||
static MemoryDynamic<meshtastic_QueueStatus> staticQueueStatusPool;
|
||||
|
||||
#define MAX_CLIENT_NOTIFICATIONS 4
|
||||
static MemoryPool<meshtastic_ClientNotification, MAX_CLIENT_NOTIFICATIONS> staticClientNotificationPool;
|
||||
static MemoryDynamic<meshtastic_ClientNotification> staticClientNotificationPool;
|
||||
|
||||
Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool = staticMqttClientProxyMessagePool;
|
||||
|
||||
@@ -64,10 +61,8 @@ Allocator<meshtastic_QueueStatus> &queueStatusPool = staticQueueStatusPool;
|
||||
#include "Router.h"
|
||||
|
||||
MeshService::MeshService()
|
||||
#ifdef ARCH_PORTDUINO
|
||||
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_QUEUESTATUS_TOPHONE),
|
||||
toPhoneMqttProxyQueue(MAX_RX_MQTTPROXY_TOPHONE), toPhoneClientNotificationQueue(MAX_RX_NOTIFICATION_TOPHONE)
|
||||
#endif
|
||||
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE), toPhoneMqttProxyQueue(MAX_RX_TOPHONE),
|
||||
toPhoneClientNotificationQueue(MAX_RX_TOPHONE / 2)
|
||||
{
|
||||
lastQueueStatus = {0, 0, 16, 0};
|
||||
}
|
||||
@@ -196,10 +191,8 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
||||
// (so we update our nodedb for the local node)
|
||||
|
||||
// Send the packet into the mesh
|
||||
DEBUG_HEAP_BEFORE;
|
||||
auto a = packetPool.allocCopy(p);
|
||||
DEBUG_HEAP_AFTER("MeshService::handleToRadio", a);
|
||||
sendToMesh(a, RX_SRC_USER);
|
||||
|
||||
sendToMesh(packetPool.allocCopy(p), RX_SRC_USER);
|
||||
|
||||
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
||||
if (loopback) {
|
||||
@@ -255,11 +248,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
|
||||
}
|
||||
|
||||
if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent
|
||||
DEBUG_HEAP_BEFORE;
|
||||
auto a = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("MeshService::sendToMesh", a);
|
||||
|
||||
sendToPhone(a);
|
||||
sendToPhone(packetPool.allocCopy(*p));
|
||||
}
|
||||
|
||||
// Router may ask us to release the packet if it wasn't sent
|
||||
|
||||
@@ -9,12 +9,7 @@
|
||||
#include "MeshRadio.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "Observer.h"
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "PointerQueue.h"
|
||||
#else
|
||||
#include "StaticPointerQueue.h"
|
||||
#endif
|
||||
#include "mesh-pb-constants.h"
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
#include "../platform/portduino/SimRadio.h"
|
||||
#endif
|
||||
@@ -42,32 +37,16 @@ class MeshService
|
||||
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
|
||||
/// we never hang because android hasn't been there in a while
|
||||
/// FIXME - save this to flash on deep sleep
|
||||
#ifdef ARCH_PORTDUINO
|
||||
PointerQueue<meshtastic_MeshPacket> toPhoneQueue;
|
||||
#else
|
||||
StaticPointerQueue<meshtastic_MeshPacket, MAX_RX_TOPHONE> toPhoneQueue;
|
||||
#endif
|
||||
|
||||
// keep list of QueueStatus packets to be send to the phone
|
||||
#ifdef ARCH_PORTDUINO
|
||||
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
|
||||
#else
|
||||
StaticPointerQueue<meshtastic_QueueStatus, MAX_RX_QUEUESTATUS_TOPHONE> toPhoneQueueStatusQueue;
|
||||
#endif
|
||||
|
||||
// keep list of MqttClientProxyMessages to be send to the client for delivery
|
||||
#ifdef ARCH_PORTDUINO
|
||||
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
|
||||
#else
|
||||
StaticPointerQueue<meshtastic_MqttClientProxyMessage, MAX_RX_MQTTPROXY_TOPHONE> toPhoneMqttProxyQueue;
|
||||
#endif
|
||||
|
||||
// keep list of ClientNotifications to be send to the client (phone)
|
||||
#ifdef ARCH_PORTDUINO
|
||||
PointerQueue<meshtastic_ClientNotification> toPhoneClientNotificationQueue;
|
||||
#else
|
||||
StaticPointerQueue<meshtastic_ClientNotification, MAX_RX_NOTIFICATION_TOPHONE> toPhoneClientNotificationQueue;
|
||||
#endif
|
||||
|
||||
// This holds the last QueueStatus send
|
||||
meshtastic_QueueStatus lastQueueStatus;
|
||||
|
||||
@@ -34,11 +34,8 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
bool weWereNextHop = false;
|
||||
if (wasSeenRecently(p, true, &wasFallback, &weWereNextHop)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignore dupe incoming msg", p);
|
||||
|
||||
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
rxDupe++;
|
||||
stopRetransmission(p->from, p->id);
|
||||
}
|
||||
rxDupe++;
|
||||
stopRetransmission(p->from, p->id);
|
||||
|
||||
// If it was a fallback to flooding, try to relay again
|
||||
if (wasFallback) {
|
||||
@@ -74,11 +71,10 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast
|
||||
if (p->from != 0) {
|
||||
meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from);
|
||||
if (origTx) {
|
||||
// Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came directly
|
||||
// from the destination
|
||||
// Either relayer of ACK was also a relayer of the packet, or we were the relayer and the ACK came directly from
|
||||
// the destination
|
||||
if (wasRelayer(p->relay_node, p->decoded.request_id, p->to) ||
|
||||
(p->hop_start != 0 && p->hop_start == p->hop_limit &&
|
||||
wasSoleRelayer(ourRelayID, p->decoded.request_id, p->to))) {
|
||||
(wasRelayer(ourRelayID, p->decoded.request_id, p->to) && p->hop_start != 0 && p->hop_start == p->hop_limit)) {
|
||||
if (origTx->next_hop != p->relay_node) { // Not already set
|
||||
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node);
|
||||
origTx->next_hop = p->relay_node;
|
||||
@@ -175,18 +171,12 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key)
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) {
|
||||
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
|
||||
cancelSending(getFrom(p), p->id);
|
||||
// now free the pooled copy for retransmission too
|
||||
packetPool.release(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it doesn't
|
||||
// get scheduled again. (This is the core of stopRetransmission.)
|
||||
auto numErased = pending.erase(key);
|
||||
assert(numErased == 1);
|
||||
|
||||
// When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the call
|
||||
// to startRetransmission.
|
||||
packetPool.release(p);
|
||||
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
|
||||
@@ -663,7 +663,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_SPISSD1306)
|
||||
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
bool hasScreen = true;
|
||||
#ifdef HELTEC_MESH_NODE_T114
|
||||
uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET);
|
||||
|
||||
@@ -294,7 +294,7 @@ void PacketHistory::insert(const PacketRecord &r)
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
{
|
||||
if (!initOk()) {
|
||||
LOG_ERROR("PacketHistory - wasRelayer: NOT INITIALIZED!");
|
||||
@@ -322,42 +322,27 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
|
||||
found->sender, found->id, found->next_hop, millis() - found->rxTimeMsec, found->relayed_by[0], found->relayed_by[1],
|
||||
found->relayed_by[2], relayer);
|
||||
#endif
|
||||
return wasRelayer(relayer, *found, wasSole);
|
||||
return wasRelayer(relayer, *found);
|
||||
}
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r, bool *wasSole)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r)
|
||||
{
|
||||
bool found = false;
|
||||
bool other_present = false;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; ++i) {
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
|
||||
if (r.relayed_by[i] == relayer) {
|
||||
found = true;
|
||||
} else if (r.relayed_by[i] != 0) {
|
||||
other_present = true;
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? YES", r.sender, r.id,
|
||||
r.relayed_by[0], r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wasSole) {
|
||||
*wasSole = (found && !other_present);
|
||||
}
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? NO", r.sender, r.id, r.relayed_by[0],
|
||||
r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Check if a certain node was the *only* relayer of a packet in the history given an ID and sender
|
||||
bool PacketHistory::wasSoleRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
{
|
||||
bool wasSole = false;
|
||||
wasRelayer(relayer, id, sender, &wasSole);
|
||||
return wasSole;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
|
||||
@@ -34,9 +34,8 @@ class PacketHistory
|
||||
void insert(const PacketRecord &r); // Insert or replace a packet record in the history
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const PacketRecord &r, bool *wasSole = nullptr);
|
||||
bool wasRelayer(const uint8_t relayer, const PacketRecord &r);
|
||||
|
||||
PacketHistory(const PacketHistory &); // non construction-copyable
|
||||
PacketHistory &operator=(const PacketHistory &); // non copyable
|
||||
@@ -55,12 +54,8 @@ class PacketHistory
|
||||
bool *weWereNextHop = nullptr);
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
|
||||
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole = nullptr);
|
||||
|
||||
// Check if a certain node was the *only* relayer of a packet in the history given an ID and sender
|
||||
bool wasSoleRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
@@ -100,7 +100,6 @@ void PhoneAPI::close()
|
||||
config_nonce = 0;
|
||||
config_state = 0;
|
||||
pauseBluetoothLogging = false;
|
||||
heartbeatReceived = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -586,8 +586,7 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
// Check if we use the default frequency slot
|
||||
RadioInterface::uses_default_frequency_slot =
|
||||
channel_num ==
|
||||
hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset)) % numChannels;
|
||||
channel_num == hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false)) % numChannels;
|
||||
|
||||
// Old frequency selection formula
|
||||
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Default.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "configuration.h"
|
||||
#include "memGet.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "modules/NodeInfoModule.h"
|
||||
#include "modules/RoutingModule.h"
|
||||
@@ -22,10 +21,8 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
|
||||
if (p->hop_limit == 0) {
|
||||
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
}
|
||||
DEBUG_HEAP_BEFORE;
|
||||
auto copy = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("ReliableRouter::send", copy);
|
||||
|
||||
auto copy = packetPool.allocCopy(*p);
|
||||
startRetransmission(copy, NUM_RELIABLE_RETX);
|
||||
}
|
||||
|
||||
@@ -61,10 +58,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
// marked as wantAck
|
||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
||||
|
||||
// Only stop retransmissions if the rebroadcast came via LoRa
|
||||
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
stopRetransmission(key);
|
||||
}
|
||||
stopRetransmission(key);
|
||||
} else {
|
||||
LOG_DEBUG("Didn't find pending packet");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
|
||||
#include "configuration.h"
|
||||
#include "detect/LoRaRadioType.h"
|
||||
#include "main.h"
|
||||
@@ -28,24 +27,14 @@
|
||||
|
||||
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
|
||||
// And every TX packet might have a retransmission packet or an ack alive at any moment
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
// Portduino (native) targets can use dynamic memory pools with runtime-configurable sizes
|
||||
#define MAX_PACKETS \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
|
||||
static MemoryDynamic<meshtastic_MeshPacket> dynamicPool;
|
||||
Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
||||
#else
|
||||
// Embedded targets use static memory pools with compile-time constants
|
||||
#define MAX_PACKETS_STATIC \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
// static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
|
||||
static MemoryDynamic<meshtastic_MeshPacket> staticPool;
|
||||
|
||||
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
||||
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
||||
#endif
|
||||
|
||||
static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__));
|
||||
|
||||
@@ -286,10 +275,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
// If the packet is not yet encrypted, do so now
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
|
||||
|
||||
DEBUG_HEAP_BEFORE;
|
||||
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("Router::send", p_decoded);
|
||||
|
||||
auto encodeResult = perhapsEncode(p);
|
||||
if (encodeResult != meshtastic_Routing_Error_NONE) {
|
||||
@@ -621,11 +607,8 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
bool skipHandle = false;
|
||||
// Also, we should set the time from the ISR and it should have msec level resolution
|
||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||
|
||||
// Store a copy of encrypted packet for MQTT
|
||||
DEBUG_HEAP_BEFORE;
|
||||
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
auto decodedState = perhapsDecode(p);
|
||||
@@ -673,7 +656,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
|
||||
// call modules here
|
||||
// If this could be a spoofed packet, don't let the modules see it.
|
||||
if (!skipHandle) {
|
||||
if (!skipHandle && p->from != nodeDB->getNodeNum()) {
|
||||
MeshModule::callModules(*p, src);
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
@@ -687,6 +670,8 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
!isFromUs(p) && mqtt)
|
||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||
#endif
|
||||
} else if (p->from == nodeDB->getNodeNum() && !skipHandle) {
|
||||
MeshModule::callModules(*p, src);
|
||||
}
|
||||
|
||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
#include "STM32WLE5JCInterface.h"
|
||||
#include "configuration.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifndef STM32WLx_MAX_POWER
|
||||
#define STM32WLx_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
|
||||
STM32WLE5JCInterface::STM32WLE5JCInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy)
|
||||
: SX126xInterface(hal, cs, irq, rst, busy)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
#include "SX126xInterface.h"
|
||||
#include "rfswitch.h"
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
|
||||
/**
|
||||
* Our adapter for STM32WLE5JC radios
|
||||
@@ -16,4 +16,13 @@ class STM32WLE5JCInterface : public SX126xInterface<STM32WLx>
|
||||
virtual bool init() override;
|
||||
};
|
||||
|
||||
/* https://wiki.seeedstudio.com/LoRa-E5_STM32WLE5JC_Module/
|
||||
* Wio-E5 module ONLY transmits through RFO_HP
|
||||
* Receive: PA4=1, PA5=0
|
||||
* Transmit(high output power, SMPS mode): PA4=0, PA5=1 */
|
||||
static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PA4, PA5, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
|
||||
static const Module::RfSwitchMode_t rfswitch_table[4] = {
|
||||
{STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE};
|
||||
|
||||
#endif // ARCH_STM32WL
|
||||
@@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "freertosinc.h"
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* A static circular buffer queue for pointers.
|
||||
* This provides the same interface as PointerQueue but uses a statically allocated
|
||||
* buffer instead of dynamic allocation.
|
||||
*/
|
||||
template <class T, int MaxElements> class StaticPointerQueue
|
||||
{
|
||||
static_assert(MaxElements > 0, "MaxElements must be greater than 0");
|
||||
|
||||
T *buffer[MaxElements];
|
||||
int head = 0;
|
||||
int tail = 0;
|
||||
int count = 0;
|
||||
concurrency::OSThread *reader = nullptr;
|
||||
|
||||
public:
|
||||
StaticPointerQueue()
|
||||
{
|
||||
// Initialize all buffer elements to nullptr to silence warnings and ensure clean state
|
||||
for (int i = 0; i < MaxElements; i++) {
|
||||
buffer[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int numFree() const { return MaxElements - count; }
|
||||
|
||||
bool isEmpty() const { return count == 0; }
|
||||
|
||||
int numUsed() const { return count; }
|
||||
|
||||
bool enqueue(T *x, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
if (count >= MaxElements) {
|
||||
return false; // Queue is full
|
||||
}
|
||||
|
||||
if (reader) {
|
||||
reader->setInterval(0);
|
||||
concurrency::mainDelay.interrupt();
|
||||
}
|
||||
|
||||
buffer[tail] = x;
|
||||
tail = (tail + 1) % MaxElements;
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dequeue(T **p, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
if (count == 0) {
|
||||
return false; // Queue is empty
|
||||
}
|
||||
|
||||
*p = buffer[head];
|
||||
head = (head + 1) % MaxElements;
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns a ptr or null if the queue was empty
|
||||
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
T *p;
|
||||
return dequeue(&p, maxWait) ? p : nullptr;
|
||||
}
|
||||
|
||||
void setReader(concurrency::OSThread *t) { reader = t; }
|
||||
|
||||
// For compatibility with PointerQueue interface
|
||||
int getMaxLen() const { return MaxElements; }
|
||||
};
|
||||
@@ -64,12 +64,7 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
|
||||
in areas not already covered by other routers, or to bridge around problematic terrain,
|
||||
but should not be given priority over other routers in order to avoid unnecessaraily
|
||||
consuming hops. */
|
||||
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11,
|
||||
/* Description: Treats packets from or to favorited nodes as ROUTER, and all other packets as CLIENT.
|
||||
Technical Details: Used for stronger attic/roof nodes to distribute messages more widely
|
||||
from weaker, indoor, or less-well-positioned nodes. Recommended for users with multiple nodes
|
||||
where one CLIENT_BASE acts as a more powerful base station, such as an attic/roof node. */
|
||||
meshtastic_Config_DeviceConfig_Role_CLIENT_BASE = 12
|
||||
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11
|
||||
} meshtastic_Config_DeviceConfig_Role;
|
||||
|
||||
/* Defines the device's behavior for how messages are rebroadcast */
|
||||
@@ -651,8 +646,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_CLIENT_BASE
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_CLIENT_BASE+1))
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_ROUTER_LATE
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_ROUTER_LATE+1))
|
||||
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY
|
||||
|
||||
@@ -66,8 +66,6 @@ typedef enum _meshtastic_Language {
|
||||
meshtastic_Language_UKRAINIAN = 16,
|
||||
/* Bulgarian */
|
||||
meshtastic_Language_BULGARIAN = 17,
|
||||
/* Czech */
|
||||
meshtastic_Language_CZECH = 18,
|
||||
/* Simplified Chinese (experimental) */
|
||||
meshtastic_Language_SIMPLIFIED_CHINESE = 30,
|
||||
/* Traditional Chinese (experimental) */
|
||||
|
||||
@@ -360,7 +360,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* meshtastic_NodeDatabase_size depends on runtime parameters */
|
||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
|
||||
#define meshtastic_BackupPreferences_size 2273
|
||||
#define meshtastic_BackupPreferences_size 2271
|
||||
#define meshtastic_ChannelFile_size 718
|
||||
#define meshtastic_DeviceState_size 1737
|
||||
#define meshtastic_NodeInfoLite_size 196
|
||||
|
||||
@@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
|
||||
#define meshtastic_LocalConfig_size 747
|
||||
#define meshtastic_LocalModuleConfig_size 671
|
||||
#define meshtastic_LocalModuleConfig_size 669
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -259,8 +259,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_T_DECK_PRO = 102,
|
||||
/* Lilygo TLora Pager */
|
||||
meshtastic_HardwareModel_T_LORA_PAGER = 103,
|
||||
/* M5Stack Reserved */
|
||||
meshtastic_HardwareModel_M5STACK_RESERVED = 104, /* 0x68 */
|
||||
/* GAT562 Mesh Trial Tracker */
|
||||
meshtastic_HardwareModel_GAT562_MESH_TRIAL_TRACKER = 104,
|
||||
/* RAKwireless WisMesh Tag */
|
||||
meshtastic_HardwareModel_WISMESH_TAG = 105,
|
||||
/* RAKwireless WisBlock Core RAK3312 https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/overview/ */
|
||||
@@ -272,10 +272,6 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_HELTEC_MESH_SOLAR = 108,
|
||||
/* Lilygo T-Echo Lite */
|
||||
meshtastic_HardwareModel_T_ECHO_LITE = 109,
|
||||
/* New Heltec LoRA32 with ESP32-S3 CPU */
|
||||
meshtastic_HardwareModel_HELTEC_V4 = 110,
|
||||
/* M5Stack C6L */
|
||||
meshtastic_HardwareModel_M5STACK_C6L = 111,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
@@ -317,9 +317,6 @@ typedef struct _meshtastic_ModuleConfig_RangeTestConfig {
|
||||
/* Bool value indicating that this node should save a RangeTest.csv file.
|
||||
ESP32 Only */
|
||||
bool save;
|
||||
/* Bool indicating that the node should cleanup / destroy it's RangeTest.csv file.
|
||||
ESP32 Only */
|
||||
bool clear_on_reboot;
|
||||
} meshtastic_ModuleConfig_RangeTestConfig;
|
||||
|
||||
/* Configuration for both device and environment metrics */
|
||||
@@ -522,7 +519,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
|
||||
@@ -538,7 +535,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
|
||||
@@ -613,7 +610,6 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_clear_on_reboot_tag 4
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_device_update_interval_tag 1
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_environment_update_interval_tag 2
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_environment_measurement_enabled_tag 3
|
||||
@@ -807,8 +803,7 @@ X(a, STATIC, SINGULAR, BOOL, is_server, 6)
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, sender, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, save, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, clear_on_reboot, 4)
|
||||
X(a, STATIC, SINGULAR, BOOL, save, 3)
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_DEFAULT NULL
|
||||
|
||||
@@ -906,7 +901,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_MapReportSettings_size 14
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 10
|
||||
#define meshtastic_ModuleConfig_PaxcounterConfig_size 30
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_size 12
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
|
||||
#define meshtastic_ModuleConfig_SerialConfig_size 28
|
||||
#define meshtastic_ModuleConfig_StoreForwardConfig_size 24
|
||||
|
||||
@@ -292,14 +292,11 @@ JSONArray htmlListDir(const char *dirname, uint8_t levels)
|
||||
JSONObject thisFileMap;
|
||||
thisFileMap["size"] = new JSONValue((int)file.size());
|
||||
#ifdef ARCH_ESP32
|
||||
String fileName = String(file.path()).substring(1);
|
||||
thisFileMap["name"] = new JSONValue(fileName.c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.path()).substring(1).c_str());
|
||||
#else
|
||||
String fileName = String(file.name()).substring(1);
|
||||
thisFileMap["name"] = new JSONValue(fileName.c_str());
|
||||
thisFileMap["name"] = new JSONValue(String(file.name()).substring(1).c_str());
|
||||
#endif
|
||||
String tempName = String(file.name()).substring(1);
|
||||
if (tempName.endsWith(".gz")) {
|
||||
if (String(file.name()).substring(1).endsWith(".gz")) {
|
||||
#ifdef ARCH_ESP32
|
||||
String modifiedFile = String(file.path()).substring(1);
|
||||
#else
|
||||
@@ -342,15 +339,9 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
|
||||
delete value;
|
||||
|
||||
// Clean up the fileList to prevent memory leak
|
||||
for (auto *val : fileList) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
|
||||
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
@@ -371,8 +362,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
} else {
|
||||
@@ -381,8 +371,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("Error");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
return;
|
||||
}
|
||||
@@ -621,35 +610,33 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->println("<pre>");
|
||||
}
|
||||
|
||||
// Helper lambda to create JSON array and clean up memory properly
|
||||
auto createJSONArrayFromLog = [](uint32_t *logArray, int count) -> JSONValue * {
|
||||
JSONArray tempArray;
|
||||
for (int i = 0; i < count; i++) {
|
||||
tempArray.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
JSONValue *result = new JSONValue(tempArray);
|
||||
// Note: Don't delete tempArray elements here - JSONValue now owns them
|
||||
return result;
|
||||
};
|
||||
|
||||
// data->airtime->tx_log
|
||||
JSONArray txLogValues;
|
||||
uint32_t *logArray;
|
||||
logArray = airTime->airtimeReport(TX_LOG);
|
||||
JSONValue *txLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
txLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_log
|
||||
JSONArray rxLogValues;
|
||||
logArray = airTime->airtimeReport(RX_LOG);
|
||||
JSONValue *rxLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
rxLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime->rx_all_log
|
||||
JSONArray rxAllLogValues;
|
||||
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
||||
JSONValue *rxAllLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
rxAllLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
|
||||
// data->airtime
|
||||
JSONObject jsonObjAirtime;
|
||||
jsonObjAirtime["tx_log"] = txLogJsonValue;
|
||||
jsonObjAirtime["rx_log"] = rxLogJsonValue;
|
||||
jsonObjAirtime["rx_all_log"] = rxAllLogJsonValue;
|
||||
jsonObjAirtime["tx_log"] = new JSONValue(txLogValues);
|
||||
jsonObjAirtime["rx_log"] = new JSONValue(rxLogValues);
|
||||
jsonObjAirtime["rx_all_log"] = new JSONValue(rxAllLogValues);
|
||||
jsonObjAirtime["channel_utilization"] = new JSONValue(airTime->channelUtilizationPercent());
|
||||
jsonObjAirtime["utilization_tx"] = new JSONValue(airTime->utilizationTXPercent());
|
||||
jsonObjAirtime["seconds_since_boot"] = new JSONValue(int(airTime->getSecondsSinceBoot()));
|
||||
@@ -659,9 +646,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
// data->wifi
|
||||
JSONObject jsonObjWifi;
|
||||
jsonObjWifi["rssi"] = new JSONValue(WiFi.RSSI());
|
||||
String wifiIPString = WiFi.localIP().toString();
|
||||
std::string wifiIP = wifiIPString.c_str();
|
||||
jsonObjWifi["ip"] = new JSONValue(wifiIP.c_str());
|
||||
jsonObjWifi["ip"] = new JSONValue(WiFi.localIP().toString().c_str());
|
||||
|
||||
// data->memory
|
||||
JSONObject jsonObjMemory;
|
||||
@@ -707,8 +692,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
@@ -779,14 +763,8 @@ void handleNodes(HTTPRequest *req, HTTPResponse *res)
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
|
||||
// Clean up the nodesArray to prevent memory leak
|
||||
for (auto *val : nodesArray) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -933,8 +911,7 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONObject jsonObjOuter;
|
||||
jsonObjOuter["status"] = new JSONValue("ok");
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
}
|
||||
|
||||
@@ -976,13 +953,7 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
// serialize and write it to the stream
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
std::string jsonString = value->Stringify();
|
||||
res->print(jsonString.c_str());
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
|
||||
// Clean up the networkObjs to prevent memory leak
|
||||
for (auto *val : networkObjs) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -15,27 +15,8 @@
|
||||
// FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in
|
||||
// RAM #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
|
||||
#ifndef MAX_RX_TOPHONE
|
||||
#if defined(ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3))
|
||||
#define MAX_RX_TOPHONE 8
|
||||
#else
|
||||
#define MAX_RX_TOPHONE 32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// max number of QueueStatus packets which can be waiting for delivery to phone
|
||||
#ifndef MAX_RX_QUEUESTATUS_TOPHONE
|
||||
#define MAX_RX_QUEUESTATUS_TOPHONE 2
|
||||
#endif
|
||||
|
||||
/// max number of MqttClientProxyMessage packets which can be waiting for delivery to phone
|
||||
#ifndef MAX_RX_MQTTPROXY_TOPHONE
|
||||
#define MAX_RX_MQTTPROXY_TOPHONE 8
|
||||
#endif
|
||||
|
||||
/// max number of ClientNotification packets which can be waiting for delivery to phone
|
||||
#ifndef MAX_RX_NOTIFICATION_TOPHONE
|
||||
#define MAX_RX_NOTIFICATION_TOPHONE 2
|
||||
#endif
|
||||
|
||||
/// Verify baseline assumption of node size. If it increases, we need to reevaluate
|
||||
/// the impact of its memory footprint, notably on MAX_NUM_NODES.
|
||||
|
||||
@@ -1432,17 +1432,10 @@ void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, O
|
||||
meshtastic_NodeInfoLite *node = this->filteredNodes[nodeIndex].node;
|
||||
if (node) {
|
||||
if (node->is_favorite) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(entryText, sizeof(entryText), "* %s", node->user.short_name);
|
||||
} else {
|
||||
snprintf(entryText, sizeof(entryText), "%s", node->user.short_name);
|
||||
}
|
||||
#else
|
||||
snprintf(entryText, sizeof(entryText), "* %s", node->user.long_name);
|
||||
} else {
|
||||
snprintf(entryText, sizeof(entryText), "%s", node->user.long_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1613,11 +1606,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
int yOffset = y + 10;
|
||||
#else
|
||||
display->setFont(FONT_MEDIUM);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
int yOffset = y;
|
||||
#else
|
||||
int yOffset = y + 10;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// --- Delivery Status Message ---
|
||||
@@ -1642,20 +1631,13 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
|
||||
display->drawString(display->getWidth() / 2 + x, yOffset, buffer);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
yOffset += lineCount * FONT_HEIGHT_MEDIUM - 5; // only 1 line gap, no extra padding
|
||||
#else
|
||||
yOffset += lineCount * FONT_HEIGHT_MEDIUM; // only 1 line gap, no extra padding
|
||||
#endif
|
||||
|
||||
#ifndef USE_EINK
|
||||
// --- SNR + RSSI Compact Line ---
|
||||
if (this->ack) {
|
||||
display->setFont(FONT_SMALL);
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
snprintf(buffer, sizeof(buffer), "SNR: %.1f dB \nRSSI: %d", this->lastRxSnr, this->lastRxRssi);
|
||||
#else
|
||||
snprintf(buffer, sizeof(buffer), "SNR: %.1f dB RSSI: %d", this->lastRxSnr, this->lastRxRssi);
|
||||
#endif
|
||||
display->drawString(display->getWidth() / 2 + x, yOffset, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -364,10 +364,9 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
#if !defined(MESHTASTIC_EXCLUDE_INPUTBROKER)
|
||||
if (inputBroker) // put our callback in the inputObserver list
|
||||
inputObserver.observe(inputBroker);
|
||||
#endif
|
||||
|
||||
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
|
||||
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
|
||||
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
|
||||
|
||||
@@ -6,13 +6,9 @@
|
||||
#include "input/RotaryEncoderImpl.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/SerialKeyboardImpl.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/i2cButton.h"
|
||||
#include "modules/SystemCommandsModule.h"
|
||||
#if HAS_TRACKBALL
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#endif
|
||||
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "modules/SystemCommandsModule.h"
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#endif
|
||||
@@ -92,7 +88,7 @@
|
||||
#include "modules/StoreForwardModule.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
|
||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#endif
|
||||
@@ -102,6 +98,7 @@
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_SERIAL
|
||||
#include "modules/SerialModule.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||
#include "modules/DropzoneModule.h"
|
||||
@@ -139,20 +136,13 @@ void setupModules()
|
||||
traceRouteModule = new TraceRouteModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
||||
if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) {
|
||||
neighborInfoModule = new NeighborInfoModule();
|
||||
}
|
||||
neighborInfoModule = new NeighborInfoModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
||||
if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) {
|
||||
detectionSensorModule = new DetectionSensorModule();
|
||||
}
|
||||
detectionSensorModule = new DetectionSensorModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_ATAK
|
||||
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK,
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) {
|
||||
atakPluginModule = new AtakPluginModule();
|
||||
}
|
||||
atakPluginModule = new AtakPluginModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PKI
|
||||
keyVerificationModule = new KeyVerificationModule();
|
||||
@@ -174,7 +164,7 @@ void setupModules()
|
||||
#endif
|
||||
// Example: Put your module here
|
||||
// new ReplyModule();
|
||||
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER && !MESHTASTIC_EXCLUDE_I2C
|
||||
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||
@@ -197,9 +187,6 @@ void setupModules()
|
||||
#endif
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
i2cButton = new i2cButtonThread("i2cButtonThread");
|
||||
#endif
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
kbMatrixImpl = new KbMatrixImpl();
|
||||
kbMatrixImpl->init();
|
||||
@@ -221,7 +208,7 @@ void setupModules()
|
||||
aLinuxInputImpl->init();
|
||||
}
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
|
||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
||||
@@ -241,14 +228,11 @@ void setupModules()
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
#endif
|
||||
// TODO: How to improve this?
|
||||
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (moduleConfig.has_telemetry &&
|
||||
(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
|
||||
new EnvironmentTelemetryModule();
|
||||
}
|
||||
new EnvironmentTelemetryModule();
|
||||
#if __has_include("Adafruit_PM25AQI.h")
|
||||
if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled &&
|
||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
||||
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
||||
new AirQualityTelemetryModule();
|
||||
}
|
||||
#endif
|
||||
@@ -260,16 +244,12 @@ void setupModules()
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (moduleConfig.has_telemetry &&
|
||||
(moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) {
|
||||
new PowerTelemetryModule();
|
||||
}
|
||||
new PowerTelemetryModule();
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if !MESHTASTIC_EXCLUDE_SERIAL
|
||||
if (moduleConfig.has_serial && moduleConfig.serial.enabled &&
|
||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
new SerialModule();
|
||||
}
|
||||
#endif
|
||||
@@ -280,26 +260,21 @@ void setupModules()
|
||||
audioModule = new AudioModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) {
|
||||
paxcounterModule = new PaxcounterModule();
|
||||
}
|
||||
paxcounterModule = new PaxcounterModule();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) {
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
}
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
|
||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
if (moduleConfig.has_external_notification && moduleConfig.external_notification.enabled) {
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
}
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
||||
if (moduleConfig.has_range_test && moduleConfig.range_test.enabled)
|
||||
new RangeTestModule();
|
||||
new RangeTestModule();
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||
|
||||
@@ -12,12 +12,12 @@ NodeInfoModule *nodeInfoModule;
|
||||
|
||||
bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr)
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
if (mp.from == nodeDB->getNodeNum()) {
|
||||
LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto p = *pptr;
|
||||
if (p.is_licensed != owner.is_licensed) {
|
||||
LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!");
|
||||
return true;
|
||||
@@ -44,10 +44,7 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
|
||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||
service->cancelSending(prevPacketId);
|
||||
shorterTimeout = _shorterTimeout;
|
||||
DEBUG_HEAP_BEFORE;
|
||||
meshtastic_MeshPacket *p = allocReply();
|
||||
DEBUG_HEAP_AFTER("NodeInfoModule::sendOurNodeInfo", p);
|
||||
|
||||
if (p) { // Check whether we didn't ignore it
|
||||
p->to = dest;
|
||||
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
|
||||
|
||||
@@ -31,7 +31,7 @@ uint32_t packetSequence = 0;
|
||||
|
||||
int32_t RangeTestModule::runOnce()
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
@@ -130,7 +130,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
|
||||
ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
|
||||
if (moduleConfig.range_test.enabled) {
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
#include "meshSolarApp.h"
|
||||
#endif
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#define RX_BUFFER 256
|
||||
#define TIMEOUT 250
|
||||
@@ -67,7 +67,7 @@ SerialModuleRadio *serialModuleRadio;
|
||||
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
|
||||
static Print *serialPrint = &Serial;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {}
|
||||
static Print *serialPrint = &Serial1;
|
||||
#else
|
||||
@@ -173,18 +173,7 @@ int32_t SerialModule::runOnce()
|
||||
Serial.begin(baud);
|
||||
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
}
|
||||
#elif defined(ARCH_STM32WL)
|
||||
#ifndef RAK3172
|
||||
HardwareSerial *serialInstance = &Serial2;
|
||||
#else
|
||||
HardwareSerial *serialInstance = &Serial1;
|
||||
#endif
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
serialInstance->setTx(moduleConfig.serial.txd);
|
||||
serialInstance->setRx(moduleConfig.serial.rxd);
|
||||
}
|
||||
serialInstance->begin(baud);
|
||||
serialInstance->setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
|
||||
#elif defined(ARCH_ESP32)
|
||||
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
@@ -271,13 +260,8 @@ int32_t SerialModule::runOnce()
|
||||
while (Serial1.available()) {
|
||||
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#else
|
||||
#ifndef RAK3172
|
||||
HardwareSerial *serialInstance = &Serial2;
|
||||
#else
|
||||
HardwareSerial *serialInstance = &Serial1;
|
||||
#endif
|
||||
while (serialInstance->available()) {
|
||||
serialPayloadSize = serialInstance->readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
while (Serial2.available()) {
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#endif
|
||||
serialModuleRadio->sendPayload();
|
||||
}
|
||||
@@ -527,7 +511,7 @@ ParsedLine parseLine(const char *line)
|
||||
void SerialModule::processWXSerial()
|
||||
{
|
||||
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL)
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
|
||||
static unsigned int lastAveraged = 0;
|
||||
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
|
||||
static double dir_sum_sin = 0;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
class SerialModule : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
|
||||
@@ -172,10 +172,7 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage,
|
||||
telemetry.variant.device_metrics.uptime_seconds);
|
||||
|
||||
DEBUG_HEAP_BEFORE;
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
||||
DEBUG_HEAP_AFTER("DeviceTelemetryModule::sendTelemetry", p);
|
||||
|
||||
p->to = dest;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
|
||||
@@ -198,13 +198,6 @@ T1000xSensor t1000xSensor;
|
||||
IndicatorSensor indicatorSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_TSL2561_U.h>)
|
||||
#include "Sensor/TSL2561Sensor.h"
|
||||
TSL2561Sensor tsl2561Sensor;
|
||||
#else
|
||||
NullSensor tsl2561Sensor;
|
||||
#endif
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
@@ -303,8 +296,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = max17048Sensor.runOnce();
|
||||
if (cgRadSens.hasSensor())
|
||||
result = cgRadSens.runOnce();
|
||||
if (tsl2561Sensor.hasSensor())
|
||||
result = tsl2561Sensor.runOnce();
|
||||
if (pct2075Sensor.hasSensor())
|
||||
result = pct2075Sensor.runOnce();
|
||||
// this only works on the wismesh hub with the solar option. This is not an I2C sensor, so we don't need the
|
||||
@@ -651,10 +642,6 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && nau7802Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (tsl2561Sensor.hasSensor()) {
|
||||
valid = valid && tsl2561Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (aht10Sensor.hasSensor()) {
|
||||
if (!bmp280Sensor.hasSensor() && !bmp3xxSensor.hasSensor()) {
|
||||
valid = valid && aht10Sensor.getMetrics(m);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_TSL2561_U.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TSL2561Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_TSL2561_U.h>
|
||||
|
||||
TSL2561Sensor::TSL2561Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_TSL2561, "TSL2561") {}
|
||||
|
||||
int32_t TSL2561Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
status = tsl.begin(nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void TSL2561Sensor::setup()
|
||||
{
|
||||
tsl.setGain(TSL2561_GAIN_1X);
|
||||
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);
|
||||
}
|
||||
|
||||
bool TSL2561Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_lux = true;
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
measurement->variant.environment_metrics.lux = event.light;
|
||||
LOG_INFO("Lux: %f", measurement->variant.environment_metrics.lux);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_TSL2561_U.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_TSL2561_U.h>
|
||||
|
||||
class TSL2561Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
// The magic number is a sensor id, the actual value doesn't matter
|
||||
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_LOW, 12345);
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
TSL2561Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user