mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-21 10:12:50 +00:00
Compare commits
214 Commits
v2.7.15.56
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fdba1f1e2 | ||
|
|
db64a5b51e | ||
|
|
3371d3372c | ||
|
|
d97e38bafc | ||
|
|
cadf151826 | ||
|
|
4fe1c87e54 | ||
|
|
1021d967da | ||
|
|
4f94354f60 | ||
|
|
6a93cb7b69 | ||
|
|
b11f292cc4 | ||
|
|
217abc4c10 | ||
|
|
e6af68bd14 | ||
|
|
530f0135ee | ||
|
|
208a873c4c | ||
|
|
f57eb6f27d | ||
|
|
155cdf9f9d | ||
|
|
661f49ad7a | ||
|
|
31e55d0b66 | ||
|
|
ee6449746b | ||
|
|
85aba3a4f7 | ||
|
|
5262233b2d | ||
|
|
e9db03d185 | ||
|
|
176d8def48 | ||
|
|
5b299f3ede | ||
|
|
96c42229b0 | ||
|
|
40f1f91c0d | ||
|
|
269dee7a2d | ||
|
|
f1aefc4eef | ||
|
|
203826374c | ||
|
|
8e0547e76d | ||
|
|
8a48321555 | ||
|
|
917794ebab | ||
|
|
ed77ba5612 | ||
|
|
eafa8c7b47 | ||
|
|
aa8bb6c6f1 | ||
|
|
1952982896 | ||
|
|
024ac74f5c | ||
|
|
de2b9632bb | ||
|
|
c2b7dc2641 | ||
|
|
d0d375f1ff | ||
|
|
e8ebfc0513 | ||
|
|
bf32f17f28 | ||
|
|
b74238194b | ||
|
|
5d5819b876 | ||
|
|
f127702bef | ||
|
|
cce8cbfe34 | ||
|
|
a4a6c3509a | ||
|
|
68250dc937 | ||
|
|
c8628b3422 | ||
|
|
2ac74d6677 | ||
|
|
9d487ddc0d | ||
|
|
bcfe069997 | ||
|
|
4fc96bdf83 | ||
|
|
4ef943f204 | ||
|
|
a8fa5f25cb | ||
|
|
3b2a1547de | ||
|
|
6f725a1996 | ||
|
|
467c042bf7 | ||
|
|
cc4c41167c | ||
|
|
fff2bbf4a0 | ||
|
|
fba92229a6 | ||
|
|
ff0a4ea320 | ||
|
|
83b603827c | ||
|
|
2032ff1c32 | ||
|
|
5910cc2e26 | ||
|
|
ee80ec7b68 | ||
|
|
aa72e397f2 | ||
|
|
ec0dfb7337 | ||
|
|
c55bea8460 | ||
|
|
aa605fc4a2 | ||
|
|
d75680a2dd | ||
|
|
817f3b9ec8 | ||
|
|
decd58cd5c | ||
|
|
e691bd9732 | ||
|
|
6bad81f8dd | ||
|
|
69b9977fc1 | ||
|
|
0726bb4b56 | ||
|
|
6b11991be0 | ||
|
|
8e63dcf59a | ||
|
|
042543eb25 | ||
|
|
ae8d3fbb3d | ||
|
|
928739e0fb | ||
|
|
8be7915fc7 | ||
|
|
c052963395 | ||
|
|
65c418d4e1 | ||
|
|
c3a69a2742 | ||
|
|
66ff1536f3 | ||
|
|
5671e9d96f | ||
|
|
bd4bcb94f0 | ||
|
|
4b2f241478 | ||
|
|
eb087849c0 | ||
|
|
94aedff6ae | ||
|
|
2ae391197f | ||
|
|
2a17c3b5d4 | ||
|
|
8060134224 | ||
|
|
eeaafda62a | ||
|
|
6e9fd189b4 | ||
|
|
2f4eb25b2f | ||
|
|
aa85fbbcc4 | ||
|
|
3f40916223 | ||
|
|
1b4925bd07 | ||
|
|
0828c445fb | ||
|
|
61e41a8beb | ||
|
|
90584359e4 | ||
|
|
8a43741589 | ||
|
|
525c048354 | ||
|
|
41cbd77db3 | ||
|
|
f3e38a425f | ||
|
|
a11152e545 | ||
|
|
859ae4d3d2 | ||
|
|
03600b1252 | ||
|
|
a3d3e1c912 | ||
|
|
0e653056e7 | ||
|
|
eba6e4ed75 | ||
|
|
80e8745714 | ||
|
|
ee6c9101c7 | ||
|
|
34f8300288 | ||
|
|
09bbfce625 | ||
|
|
5b1b420cad | ||
|
|
8899487c2f | ||
|
|
430d55e5e8 | ||
|
|
5ef3ff7116 | ||
|
|
1abf8ddb30 | ||
|
|
5a595a3ae7 | ||
|
|
bcd4a1176a | ||
|
|
0081cec207 | ||
|
|
94db3506bd | ||
|
|
2f0fe4e5da | ||
|
|
a59723030a | ||
|
|
de26dfe468 | ||
|
|
a6cdf2c50b | ||
|
|
1c43d71067 | ||
|
|
1523368c53 | ||
|
|
bc3ed4a7f3 | ||
|
|
7cb7a6cd3e | ||
|
|
d0c6ec28db | ||
|
|
a6d1ce2048 | ||
|
|
f7ae7aa2c1 | ||
|
|
9bfef80e30 | ||
|
|
c3a7ad2865 | ||
|
|
f10aa3daa2 | ||
|
|
06dac12a73 | ||
|
|
d60b263a00 | ||
|
|
654abe5b2c | ||
|
|
79e8fc94bc | ||
|
|
486fa74549 | ||
|
|
66193e1776 | ||
|
|
bacff5c1f0 | ||
|
|
faa6af74af | ||
|
|
81439f16d0 | ||
|
|
592a8f23db | ||
|
|
2baa9ccbe0 | ||
|
|
0336331411 | ||
|
|
ed4a798c60 | ||
|
|
5d7da6868e | ||
|
|
1bfa9ed4c4 | ||
|
|
b18794e98d | ||
|
|
f4e260e0f1 | ||
|
|
14463043bd | ||
|
|
376dc7ef3a | ||
|
|
c051c56544 | ||
|
|
d3976e7461 | ||
|
|
a4c92d9fd5 | ||
|
|
186cbe61bb | ||
|
|
0e3e8b7607 | ||
|
|
451e52b541 | ||
|
|
d743ba8e75 | ||
|
|
626dce8323 | ||
|
|
0100eeea67 | ||
|
|
5640179ce2 | ||
|
|
066da492d5 | ||
|
|
2b8806486d | ||
|
|
9ae545918c | ||
|
|
5374291c3c | ||
|
|
38b0c1588a | ||
|
|
f329de04c4 | ||
|
|
b09fa31492 | ||
|
|
a2a0150ee8 | ||
|
|
9ae92724a9 | ||
|
|
9cf369c5d0 | ||
|
|
441a7c5b20 | ||
|
|
2ca03fbf4b | ||
|
|
ef298814f2 | ||
|
|
8d31fc5ec6 | ||
|
|
f9433a31d1 | ||
|
|
7232dddd69 | ||
|
|
10de230dba | ||
|
|
567b8ea1c2 | ||
|
|
d39d1917ad | ||
|
|
b202559d37 | ||
|
|
85ea22ac38 | ||
|
|
15257b017c | ||
|
|
59864dd09d | ||
|
|
edcdb2dcb2 | ||
|
|
ef4cb2abfb | ||
|
|
c34f94abda | ||
|
|
a8d1a90e16 | ||
|
|
501c296e75 | ||
|
|
ec5e79585b | ||
|
|
438e170b03 | ||
|
|
43e0c35466 | ||
|
|
6e3be132f2 | ||
|
|
0aa11d810c | ||
|
|
4df6627ab1 | ||
|
|
e9590003f4 | ||
|
|
1c0c6b2736 | ||
|
|
602945f66b | ||
|
|
b86827967e | ||
|
|
b707001873 | ||
|
|
85afd706fd | ||
|
|
e76013fb60 | ||
|
|
b25797e1b3 | ||
|
|
bdb3fb1477 | ||
|
|
7eca061f01 |
@@ -51,7 +51,7 @@ for f in .clusterfuzzlite/*_fuzzer.cpp; do
|
||||
fuzzer=$(basename "$f" .cpp)
|
||||
cp -f "$f" src/fuzzer.cpp
|
||||
pio run -vvv --environment "$PIO_ENV"
|
||||
program="$PLATFORMIO_WORKSPACE_DIR/build/$PIO_ENV/program"
|
||||
program="$PLATFORMIO_WORKSPACE_DIR/build/$PIO_ENV/meshtasticd"
|
||||
cp "$program" "$OUT/$fuzzer"
|
||||
|
||||
# Copy shared libraries used by the fuzzer.
|
||||
|
||||
1
.github/actionlint.yaml
vendored
1
.github/actionlint.yaml
vendored
@@ -2,4 +2,5 @@
|
||||
self-hosted-runner:
|
||||
# Labels of self-hosted runner in array of strings.
|
||||
labels:
|
||||
- arctastic
|
||||
- test-runner
|
||||
|
||||
6
.github/actions/build-variant/action.yml
vendored
6
.github/actions/build-variant/action.yml
vendored
@@ -76,7 +76,7 @@ runs:
|
||||
done
|
||||
|
||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.platformio/.cache
|
||||
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
|
||||
@@ -100,9 +100,9 @@ runs:
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: |
|
||||
${{ inputs.artifact-paths }}
|
||||
|
||||
2
.github/actions/setup-base/action.yml
vendored
2
.github/actions/setup-base/action.yml
vendored
@@ -5,7 +5,7 @@ runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
|
||||
4
.github/workflows/build_debian_src.yml
vendored
4
.github/workflows/build_debian_src.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
PKG_VERSION: ${{ steps.version.outputs.deb }}
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
overwrite: true
|
||||
|
||||
40
.github/workflows/build_firmware.yml
vendored
40
.github/workflows/build_firmware.yml
vendored
@@ -18,11 +18,12 @@ permissions: read-all
|
||||
jobs:
|
||||
pio-build:
|
||||
name: build-${{ inputs.platform }}
|
||||
runs-on: ubuntu-24.04
|
||||
# Use 'arctastic' self-hosted runner pool when building in the main repo
|
||||
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||
outputs:
|
||||
artifact-id: ${{ steps.upload.outputs.artifact-id }}
|
||||
artifact-id: ${{ steps.upload-firmware.outputs.artifact-id }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
@@ -55,15 +56,40 @@ jobs:
|
||||
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
|
||||
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
|
||||
|
||||
- name: Job summary
|
||||
env:
|
||||
PIO_ENV: ${{ inputs.pio_env }}
|
||||
run: |
|
||||
echo "## $PIO_ENV" >> $GITHUB_STEP_SUMMARY
|
||||
echo "<details><summary><strong>Manifest</strong></summary>" >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```json' >> $GITHUB_STEP_SUMMARY
|
||||
cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "</details>" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
id: upload
|
||||
uses: actions/upload-artifact@v6
|
||||
id: upload-firmware
|
||||
with:
|
||||
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}.zip
|
||||
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
|
||||
overwrite: true
|
||||
path: |
|
||||
release/*.mt.json
|
||||
release/*.bin
|
||||
release/*.elf
|
||||
release/*.uf2
|
||||
release/*.hex
|
||||
release/*-ota.zip
|
||||
release/*.zip
|
||||
release/device-*.sh
|
||||
release/device-*.bat
|
||||
|
||||
- name: Store manifests as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
id: upload-manifest
|
||||
with:
|
||||
name: manifest-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
|
||||
overwrite: true
|
||||
path: |
|
||||
release/*.mt.json
|
||||
|
||||
176
.github/workflows/build_one_arch.yml
vendored
176
.github/workflows/build_one_arch.yml
vendored
@@ -1,176 +0,0 @@
|
||||
name: Build One Arch
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
# trunk-ignore(checkov/CKV_GHA_7)
|
||||
arch:
|
||||
type: choice
|
||||
options:
|
||||
- esp32
|
||||
- esp32s3
|
||||
- esp32c3
|
||||
- esp32c6
|
||||
- nrf52840
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
- native
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
INPUT_ARCH: ${{ github.event.inputs.arch }}
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
cache: pip
|
||||
- run: pip install -U platformio
|
||||
- name: Generate matrix
|
||||
id: jsonStep
|
||||
run: |
|
||||
TARGETS=$(./bin/generate_ci_matrix.py $INPUT_ARCH --level extra)
|
||||
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
|
||||
echo "selected_arch=$TARGETS" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
selected_arch: ${{ steps.jsonStep.outputs.selected_arch }}
|
||||
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
env:
|
||||
BUILD_LOCATION: local
|
||||
outputs:
|
||||
long: ${{ steps.version.outputs.long }}
|
||||
deb: ${{ steps.version.outputs.deb }}
|
||||
|
||||
build:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
needs: [setup, version]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build: ${{ fromJson(needs.setup.outputs.selected_arch) }}
|
||||
uses: ./.github/workflows/build_firmware.yml
|
||||
with:
|
||||
version: ${{ needs.version.outputs.long }}
|
||||
pio_env: ${{ matrix.build.board }}
|
||||
platform: ${{ matrix.build.arch }}
|
||||
|
||||
build-debian-src:
|
||||
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/build_debian_src.yml
|
||||
with:
|
||||
series: UNRELEASED
|
||||
build_location: local
|
||||
secrets: inherit
|
||||
|
||||
package-pio-deps-native-tft:
|
||||
if: ${{ inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/package_pio_deps.yml
|
||||
with:
|
||||
pio_env: native-tft
|
||||
secrets: inherit
|
||||
|
||||
test-native:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
gather-artifacts:
|
||||
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]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{inputs.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@v5
|
||||
with:
|
||||
name: firmware-${{inputs.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@v6
|
||||
with:
|
||||
name: firmware-${{inputs.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-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: debug-elfs-${{inputs.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-${{inputs.arch}}-${{ needs.version.outputs.long }}
|
||||
description: "Download firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
43
.github/workflows/build_one_target.yml
vendored
43
.github/workflows/build_one_target.yml
vendored
@@ -15,7 +15,6 @@ on:
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
- native
|
||||
target:
|
||||
type: string
|
||||
required: false
|
||||
@@ -42,10 +41,9 @@ jobs:
|
||||
- rp2040
|
||||
- rp2350
|
||||
- stm32
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
@@ -60,13 +58,13 @@ jobs:
|
||||
echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Targets:" >> $GITHUB_STEP_SUMMARY
|
||||
echo $TARGETS >> $GITHUB_STEP_SUMMARY
|
||||
echo $TARGETS | jq -r 'sort_by(.board) |.[] | "- " + .board' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
version:
|
||||
if: ${{ inputs.target != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
@@ -87,25 +85,6 @@ jobs:
|
||||
pio_env: ${{ inputs.target }}
|
||||
platform: ${{ inputs.arch }}
|
||||
|
||||
build-debian-src:
|
||||
if: ${{ github.repository == 'meshtastic/firmware' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/build_debian_src.yml
|
||||
with:
|
||||
series: UNRELEASED
|
||||
build_location: local
|
||||
secrets: inherit
|
||||
|
||||
package-pio-deps-native-tft:
|
||||
if: ${{ inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/package_pio_deps.yml
|
||||
with:
|
||||
pio_env: native-tft
|
||||
secrets: inherit
|
||||
|
||||
test-native:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' && inputs.target != '' }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
gather-artifacts:
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -114,12 +93,12 @@ jobs:
|
||||
needs: [version, build]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-*-*
|
||||
@@ -132,7 +111,7 @@ jobs:
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -140,7 +119,7 @@ jobs:
|
||||
./firmware-*.bin
|
||||
./firmware-*.uf2
|
||||
./firmware-*.hex
|
||||
./firmware-*-ota.zip
|
||||
./firmware-*.zip
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
./littlefs-*.bin
|
||||
@@ -148,7 +127,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-*-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -160,14 +139,14 @@ jobs:
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
chmod +x ./output/device-install.sh || true
|
||||
chmod +x ./output/device-update.sh || true
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
|
||||
2
.github/workflows/docker_build.yml
vendored
2
.github/workflows/docker_build.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
|
||||
2
.github/workflows/docker_manifest.yml
vendored
2
.github/workflows/docker_manifest.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
|
||||
2
.github/workflows/hook_copr.yml
vendored
2
.github/workflows/hook_copr.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
131
.github/workflows/main_matrix.yml
vendored
131
.github/workflows/main_matrix.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
- check
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
@@ -77,16 +77,21 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
check: ${{ fromJson(needs.setup.outputs.check) }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
# Use 'arctastic' self-hosted runner pool when checking in the main repo
|
||||
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
- name: Check ${{ matrix.check.board }}
|
||||
run: bin/check-all.sh ${{ matrix.check.board }}
|
||||
uses: meshtastic/gh-action-firmware@main
|
||||
with:
|
||||
pio_platform: ${{ matrix.check.platform }}
|
||||
pio_env: ${{ matrix.check.board }}
|
||||
pio_target: check
|
||||
|
||||
build:
|
||||
needs: [setup, version]
|
||||
@@ -163,12 +168,12 @@ jobs:
|
||||
needs: [version, build]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
@@ -177,19 +182,17 @@ jobs:
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
|
||||
- name: Move files up
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: |
|
||||
./firmware-*.mt.json
|
||||
./firmware-*.bin
|
||||
./firmware-*.uf2
|
||||
./firmware-*.hex
|
||||
./firmware-*-ota.zip
|
||||
./firmware-*.zip
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
./littlefs-*.bin
|
||||
@@ -197,7 +200,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -209,16 +212,16 @@ jobs:
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
chmod +x ./output/device-install.sh || true
|
||||
chmod +x ./output/device-update.sh || true
|
||||
|
||||
- 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@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: ./*.elf
|
||||
retention-days: 30
|
||||
@@ -230,24 +233,54 @@ jobs:
|
||||
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 }}
|
||||
|
||||
shame:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head)
|
||||
fetch-depth: 0
|
||||
- name: Download the current manifests
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: ./manifests-new/
|
||||
pattern: manifest-*
|
||||
merge-multiple: true
|
||||
- name: Upload combined manifests for later commit and global stats crunching.
|
||||
uses: actions/upload-artifact@v6
|
||||
id: upload-manifest
|
||||
with:
|
||||
name: manifests-all
|
||||
overwrite: true
|
||||
path: |
|
||||
manifests-new/*.mt.json
|
||||
- name: Find the merge base
|
||||
run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV
|
||||
env:
|
||||
base: ${{ github.base_ref }}
|
||||
head: ${{ github.head_ref }}
|
||||
- name: Download the old manifests
|
||||
run: gh run download -R ${{ github.repository }} --commit ${{ env.MERGE_BASE }} --name manifests-all --dir manifest-old/
|
||||
- name: Do scan and post comment
|
||||
run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
|
||||
|
||||
release-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
needs:
|
||||
- setup
|
||||
- version
|
||||
- gather-artifacts
|
||||
- build-debian-src
|
||||
- package-pio-deps-native-tft
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -261,14 +294,14 @@ jobs:
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
||||
merge-multiple: true
|
||||
path: ./output/debian-src
|
||||
|
||||
- name: Download `native-tft` pio deps
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -284,10 +317,25 @@ jobs:
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -lR
|
||||
|
||||
- name: Add Linux sources to GtiHub Release
|
||||
- name: Generate Release manifest
|
||||
run: |
|
||||
jq -n --arg ver "${{ needs.version.outputs.long }}" --argjson targets ${{ toJson(needs.setup.outputs.all) }} '{
|
||||
"version": $ver,
|
||||
"targets": $targets
|
||||
}' > firmware-${{ needs.version.outputs.long }}.json
|
||||
|
||||
- name: Save Release manifest artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: manifest-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: firmware-${{ needs.version.outputs.long }}.json
|
||||
|
||||
- name: Add sources 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-${{ needs.version.outputs.long }}.json
|
||||
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:
|
||||
@@ -311,14 +359,14 @@ jobs:
|
||||
needs: [release-artifacts, version]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -329,15 +377,15 @@ jobs:
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
chmod +x ./output/device-install.sh || true
|
||||
chmod +x ./output/device-update.sh || true
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./elfs
|
||||
|
||||
@@ -366,19 +414,26 @@ jobs:
|
||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- name: Get firmware artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./publish
|
||||
|
||||
- name: Get manifest artifact
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: manifest-${{ needs.version.outputs.long }}
|
||||
path: ./publish
|
||||
|
||||
- name: Publish firmware to meshtastic.github.io
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
env:
|
||||
|
||||
51
.github/workflows/merge_queue.yml
vendored
51
.github/workflows/merge_queue.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
- check
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
@@ -142,12 +142,12 @@ jobs:
|
||||
needs: [version, build]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -168,7 +168,7 @@ jobs:
|
||||
./firmware-*.bin
|
||||
./firmware-*.uf2
|
||||
./firmware-*.hex
|
||||
./firmware-*-ota.zip
|
||||
./firmware-*.zip
|
||||
./device-*.sh
|
||||
./device-*.bat
|
||||
./littlefs-*.bin
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -188,16 +188,16 @@ jobs:
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
chmod +x ./output/device-install.sh || true
|
||||
chmod +x ./output/device-update.sh || true
|
||||
|
||||
- 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@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: ./*.elf
|
||||
retention-days: 30
|
||||
@@ -221,12 +221,7 @@ jobs:
|
||||
- package-pio-deps-native-tft
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -240,14 +235,14 @@ jobs:
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
||||
merge-multiple: true
|
||||
path: ./output/debian-src
|
||||
|
||||
- name: Download `native-tft` pio deps
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -290,14 +285,14 @@ jobs:
|
||||
needs: [release-artifacts, version]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -308,15 +303,15 @@ jobs:
|
||||
|
||||
- name: Device scripts permissions
|
||||
run: |
|
||||
chmod +x ./output/device-install.sh
|
||||
chmod +x ./output/device-update.sh
|
||||
chmod +x ./output/device-install.sh || true
|
||||
chmod +x ./output/device-update.sh || true
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./elfs
|
||||
|
||||
@@ -345,14 +340,14 @@ jobs:
|
||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
4
.github/workflows/nightly.yml
vendored
4
.github/workflows/nightly.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
pull-requests: write # For trunk to create PRs
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Upgrade
|
||||
uses: trunk-io/trunk-action/upgrade@v1
|
||||
|
||||
4
.github/workflows/package_obs.yml
vendored
4
.github/workflows/package_obs.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
needs: build-debian-src
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
4
.github/workflows/package_pio_deps.yml
vendored
4
.github/workflows/package_pio_deps.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
PLATFORMIO_CORE_DIR: pio/core
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
|
||||
4
.github/workflows/package_ppa.yml
vendored
4
.github/workflows/package_ppa.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
needs: build-debian-src
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: meshtasticd
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
2
.github/workflows/pr_enforce_labels.yml
vendored
2
.github/workflows/pr_enforce_labels.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
with:
|
||||
script: |
|
||||
const labels = context.payload.pull_request.labels.map(label => label.name);
|
||||
const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk'];
|
||||
const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk', 'cleanup'];
|
||||
const hasRequiredLabel = labels.some(label => requiredLabels.includes(label));
|
||||
if (!hasRequiredLabel) {
|
||||
core.setFailed(`PR must have at least one of the following labels before it can be merged: ${requiredLabels.join(', ')}.`);
|
||||
|
||||
6
.github/workflows/pr_tests.yml
vendored
6
.github/workflows/pr_tests.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -50,9 +50,9 @@ jobs:
|
||||
|
||||
- name: Download test artifacts
|
||||
if: needs.native-tests.result != 'skipped'
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
- name: Parse test results and create detailed summary
|
||||
|
||||
7
.github/workflows/release_channels.yml
vendored
7
.github/workflows/release_channels.yml
vendored
@@ -60,7 +60,10 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Always use master branch for version bumps
|
||||
ref: master
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
@@ -99,7 +102,7 @@ jobs:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||
|
||||
- name: Create Bumps pull request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
branch: create-pull-request/bump-version
|
||||
|
||||
4
.github/workflows/sec_sast_semgrep_cron.yml
vendored
4
.github/workflows/sec_sast_semgrep_cron.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# step 2
|
||||
- name: full scan
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
# step 3
|
||||
- name: save report as pipeline artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: report.sarif
|
||||
overwrite: true
|
||||
|
||||
2
.github/workflows/sec_sast_semgrep_pull.yml
vendored
2
.github/workflows/sec_sast_semgrep_pull.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
# step 1
|
||||
- name: clone application source code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
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.1.0
|
||||
uses: actions/stale@v10.1.1
|
||||
with:
|
||||
days-before-stale: 45
|
||||
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
|
||||
|
||||
34
.github/workflows/test_native.yml
vendored
34
.github/workflows/test_native.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
name: Native Simulator Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/coverage/program -s &
|
||||
.pio/build/coverage/meshtasticd -s &
|
||||
PID=$!
|
||||
timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
|
||||
echo "Simulator started, launching python test..."
|
||||
@@ -59,10 +59,10 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}.zip
|
||||
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: ./coverage_*.info
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
name: Native PlatformIO Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
@@ -94,9 +94,9 @@ jobs:
|
||||
|
||||
- name: Save test results
|
||||
if: always() # run this step even if previous step failed
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: ./testreport.xml
|
||||
|
||||
@@ -108,10 +108,10 @@ jobs:
|
||||
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}.zip
|
||||
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: ./coverage_*.info
|
||||
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
- platformio-tests
|
||||
if: always()
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
@@ -137,22 +137,22 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download test artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
- name: Test Report
|
||||
uses: dorny/test-reporter@v2.1.1
|
||||
uses: dorny/test-reporter@v2.3.0
|
||||
with:
|
||||
name: PlatformIO Tests
|
||||
path: testreport.xml
|
||||
reporter: java-junit
|
||||
|
||||
- name: Download coverage artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}.zip
|
||||
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
merge-multiple: true
|
||||
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
|
||||
|
||||
- name: Save Code Coverage Report
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: code-coverage-report-${{ steps.version.outputs.long }}.zip
|
||||
name: code-coverage-report-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
|
||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -20,9 +20,9 @@ jobs:
|
||||
runs-on: test-runner
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# - uses: actions/setup-python@v5
|
||||
# - uses: actions/setup-python@v6
|
||||
# with:
|
||||
# python-version: '3.10'
|
||||
|
||||
|
||||
2
.github/workflows/trunk_annotate_pr.yml
vendored
2
.github/workflows/trunk_annotate_pr.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
|
||||
2
.github/workflows/trunk_check.yml
vendored
2
.github/workflows/trunk_check.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
|
||||
2
.github/workflows/trunk_format_pr.yml
vendored
2
.github/workflows/trunk_format_pr.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
6
.github/workflows/update_protobufs.yml
vendored
6
.github/workflows/update_protobufs.yml
vendored
@@ -11,12 +11,12 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update submodule
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' }}
|
||||
run: |
|
||||
git submodule update --remote protobufs
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
./bin/regen-protos.sh
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
branch: create-pull-request/update-protobufs
|
||||
labels: submodules
|
||||
|
||||
@@ -4,31 +4,31 @@ cli:
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.7.3
|
||||
ref: v1.7.4
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.489
|
||||
- renovate@41.169.1
|
||||
- prettier@3.6.2
|
||||
- trufflehog@3.90.12
|
||||
- checkov@3.2.495
|
||||
- renovate@42.64.1
|
||||
- prettier@3.7.4
|
||||
- trufflehog@3.92.3
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.8.6
|
||||
- trivy@0.67.2
|
||||
- bandit@1.9.2
|
||||
- trivy@0.68.2
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.3
|
||||
- ruff@0.14.10
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.45.0
|
||||
- oxipng@9.1.5
|
||||
- markdownlint@0.47.0
|
||||
- oxipng@10.0.0
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.8
|
||||
- actionlint@1.7.9
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.11.0
|
||||
- black@25.9.0
|
||||
- black@25.12.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.28.0
|
||||
- gitleaks@8.30.0
|
||||
- clang-format@16.0.3
|
||||
ignore:
|
||||
- linters: [ALL]
|
||||
|
||||
@@ -37,4 +37,3 @@ Join our community and help improve Meshtastic! 🚀
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ RUN bash ./bin/build-native.sh "$PIO_ENV" && \
|
||||
|
||||
# ##### PRODUCTION BUILD #############
|
||||
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.23
|
||||
LABEL org.opencontainers.image.title="Meshtastic" \
|
||||
org.opencontainers.image.description="Alpine Meshtastic daemon" \
|
||||
org.opencontainers.image.url="https://meshtastic.org" \
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[esp32s3_base]
|
||||
extends = esp32_base
|
||||
custom_esp32_kind = esp32s3
|
||||
|
||||
monitor_speed = 115200
|
||||
@@ -1,7 +0,0 @@
|
||||
[nrf52832_base]
|
||||
extends = nrf52_base
|
||||
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
|
||||
lib_deps =
|
||||
${nrf52_base.lib_deps}
|
||||
165
bin/analyze_map.py
Normal file
165
bin/analyze_map.py
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Summarise linker map output to highlight heavy object files and libraries.
|
||||
|
||||
Usage:
|
||||
python bin/analyze_map.py --map .pio/build/rak4631/output.map --top 20
|
||||
|
||||
The script parses GNU ld map files and aggregates section sizes per object file
|
||||
and per archive/library, then prints sortable tables that make it easy to spot
|
||||
modules worth trimming or hiding behind feature flags.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from typing import DefaultDict, Dict, Tuple
|
||||
|
||||
|
||||
SECTION_LINE_RE = re.compile(r"^\s+(?P<section>\S+)\s+0x[0-9A-Fa-f]+\s+0x(?P<size>[0-9A-Fa-f]+)\s+(?P<object>.+)$")
|
||||
ARCHIVE_MEMBER_RE = re.compile(r"^(?P<archive>.+)\((?P<object>[^)]+)\)$")
|
||||
|
||||
|
||||
def human_size(num_bytes: int) -> str:
|
||||
"""Return a friendly size string with one decimal place."""
|
||||
if num_bytes < 1024:
|
||||
return f"{num_bytes:,} B"
|
||||
num = float(num_bytes)
|
||||
for unit in ("KB", "MB", "GB"):
|
||||
num /= 1024.0
|
||||
if num < 1024.0:
|
||||
return f"{num:.1f} {unit}"
|
||||
return f"{num:.1f} TB"
|
||||
|
||||
|
||||
def shorten_path(path: str, root: str) -> str:
|
||||
"""Prefer repository-relative paths for readability."""
|
||||
path = path.strip()
|
||||
if not path:
|
||||
return path
|
||||
|
||||
# Normalise Windows archives (backslashes) to POSIX style for consistency.
|
||||
path = path.replace("\\", "/")
|
||||
|
||||
# Attempt to strip the root when an absolute path lives inside the repo.
|
||||
if os.path.isabs(path):
|
||||
try:
|
||||
rel = os.path.relpath(path, root)
|
||||
if not rel.startswith(".."):
|
||||
return rel
|
||||
except ValueError:
|
||||
# relpath can fail on mixed drives on Windows; fall back to basename.
|
||||
pass
|
||||
return path
|
||||
|
||||
|
||||
def describe_object(raw_object: str, root: str) -> Tuple[str, str]:
|
||||
"""Return a human friendly object label and the library it belongs to."""
|
||||
raw_object = raw_object.strip()
|
||||
lib_label = "[app]"
|
||||
match = ARCHIVE_MEMBER_RE.match(raw_object)
|
||||
if match:
|
||||
archive = shorten_path(match.group("archive"), root)
|
||||
obj = match.group("object")
|
||||
lib_label = os.path.basename(archive) or archive
|
||||
label = f"{archive}:{obj}"
|
||||
else:
|
||||
label = shorten_path(raw_object, root)
|
||||
# If the object lives under libs, hint at the containing directory.
|
||||
parent = os.path.basename(os.path.dirname(label))
|
||||
if parent:
|
||||
lib_label = parent
|
||||
return label, lib_label
|
||||
|
||||
|
||||
def parse_map(map_path: str, repo_root: str) -> Tuple[Dict[str, int], Dict[str, int], Dict[str, Dict[str, int]]]:
|
||||
per_object: DefaultDict[str, int] = collections.defaultdict(int)
|
||||
per_library: DefaultDict[str, int] = collections.defaultdict(int)
|
||||
per_object_sections: DefaultDict[str, DefaultDict[str, int]] = collections.defaultdict(lambda: collections.defaultdict(int))
|
||||
|
||||
try:
|
||||
with open(map_path, "r", encoding="utf-8", errors="ignore") as handle:
|
||||
for line in handle:
|
||||
match = SECTION_LINE_RE.match(line)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
section = match.group("section")
|
||||
if section.startswith("*") or section in {"LOAD", "ORIGIN"}:
|
||||
continue
|
||||
|
||||
size = int(match.group("size"), 16)
|
||||
if size == 0:
|
||||
continue
|
||||
|
||||
obj_token = match.group("object").strip()
|
||||
if not obj_token or obj_token.startswith("*") or "load address" in obj_token:
|
||||
continue
|
||||
|
||||
label, lib_label = describe_object(obj_token, repo_root)
|
||||
per_object[label] += size
|
||||
per_library[lib_label] += size
|
||||
per_object_sections[label][section] += size
|
||||
except FileNotFoundError:
|
||||
raise SystemExit(f"error: map file '{map_path}' not found. Run a build first.")
|
||||
|
||||
return per_object, per_library, per_object_sections
|
||||
|
||||
|
||||
def format_section_breakdown(section_sizes: Dict[str, int], total: int, limit: int = 3) -> str:
|
||||
items = sorted(section_sizes.items(), key=lambda kv: kv[1], reverse=True)
|
||||
parts = []
|
||||
for section, size in items[:limit]:
|
||||
pct = (size / total) * 100 if total else 0
|
||||
parts.append(f"{section} {pct:.1f}%")
|
||||
if len(items) > limit:
|
||||
remainder = total - sum(size for _, size in items[:limit])
|
||||
pct = (remainder / total) * 100 if total else 0
|
||||
parts.append(f"other {pct:.1f}%")
|
||||
return ", ".join(parts)
|
||||
|
||||
|
||||
def print_report(map_path: str, top_n: int, per_object: Dict[str, int], per_library: Dict[str, int], per_object_sections: Dict[str, Dict[str, int]]):
|
||||
total_bytes = sum(per_object.values())
|
||||
if total_bytes == 0:
|
||||
print("No section data found in map file.")
|
||||
return
|
||||
|
||||
print(f"Map file: {map_path}")
|
||||
print(f"Accounted size: {human_size(total_bytes)} across {len(per_object)} object files\n")
|
||||
|
||||
sorted_objects = sorted(per_object.items(), key=lambda kv: kv[1], reverse=True)
|
||||
print(f"Top {min(top_n, len(sorted_objects))} object files by linked size:")
|
||||
for idx, (obj, size) in enumerate(sorted_objects[:top_n], 1):
|
||||
pct = (size / total_bytes) * 100
|
||||
breakdown = format_section_breakdown(per_object_sections[obj], size)
|
||||
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size)")
|
||||
print(f" {obj}")
|
||||
if breakdown:
|
||||
print(f" sections: {breakdown}")
|
||||
print()
|
||||
|
||||
sorted_libs = sorted(per_library.items(), key=lambda kv: kv[1], reverse=True)
|
||||
print(f"Top {min(top_n, len(sorted_libs))} libraries or source roots:")
|
||||
for idx, (lib, size) in enumerate(sorted_libs[:top_n], 1):
|
||||
pct = (size / total_bytes) * 100
|
||||
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size) {lib}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Highlight heavy object files from a GNU ld map file.")
|
||||
parser.add_argument("--map", default=".pio/build/rak4631/output.map", help="Path to the map file (default: %(default)s)")
|
||||
parser.add_argument("--top", type=int, default=20, help="Number of entries to display per table (default: %(default)s)")
|
||||
args = parser.parse_args()
|
||||
|
||||
map_path = os.path.abspath(args.map)
|
||||
repo_root = os.path.abspath(os.getcwd())
|
||||
|
||||
per_object, per_library, per_object_sections = parse_map(map_path, repo_root)
|
||||
print_report(os.path.relpath(map_path, repo_root), args.top, per_object, per_library, per_object_sections)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -5,7 +5,8 @@ set -e
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
BUILDDIR=.pio/build/$1
|
||||
OUTDIR=release
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
@@ -14,33 +15,27 @@ rm -r $OUTDIR/* || true
|
||||
platformio pkg install -e $1
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
rm -f $BUILDDIR/firmware*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying ESP32 bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.factory.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin
|
||||
|
||||
echo "Copying ESP32 update bin file"
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
cp $SRCBIN $OUTDIR/$basename-update.bin
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
# If you want to build the webui, uncomment the following lines
|
||||
# pio run --environment $1 -t buildfs
|
||||
# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin
|
||||
# # Remove webserver files from the filesystem and rebuild
|
||||
# ls -l data/static # Diagnostic list of files
|
||||
# rm -rf data/static
|
||||
pio run --environment $1 -t buildfs
|
||||
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
echo "Copying Filesystem for ESP32 targets"
|
||||
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR/
|
||||
cp bin/device-update.* $OUTDIR/
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -17,15 +17,19 @@ VERSION=$(bin/buildinfo.py long)
|
||||
SHORT_VERSION=$(bin/buildinfo.py short)
|
||||
PIO_ENV=${1:-native}
|
||||
|
||||
OUTDIR=release/
|
||||
BUILDDIR=.pio/build/$PIO_ENV
|
||||
OUTDIR=release
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -f $OUTDIR/meshtasticd*
|
||||
|
||||
mkdir -p $OUTDIR/
|
||||
rm -r $OUTDIR/* || true
|
||||
|
||||
basename=meshtasticd-$1-$VERSION
|
||||
|
||||
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
|
||||
pio pkg install --environment "$PIO_ENV" || platformioFailed
|
||||
pio run --environment "$PIO_ENV" || platformioFailed
|
||||
cp ".pio/build/$PIO_ENV/program" "$OUTDIR/meshtasticd_linux_$(uname -m)"
|
||||
cp bin/native-install.* $OUTDIR
|
||||
|
||||
cp "$BUILDDIR/meshtasticd" "$OUTDIR/meshtasticd_linux_$(uname -m)"
|
||||
cp bin/native-install.* $OUTDIR/
|
||||
|
||||
@@ -5,7 +5,8 @@ set -e
|
||||
VERSION=$(bin/buildinfo.py long)
|
||||
SHORT_VERSION=$(bin/buildinfo.py short)
|
||||
|
||||
OUTDIR=release/
|
||||
BUILDDIR=.pio/build/$1
|
||||
OUTDIR=release
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
@@ -14,40 +15,37 @@ rm -r $OUTDIR/* || true
|
||||
platformio pkg install -e $1
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
rm -f $BUILDDIR/firmware*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
echo "Generating NRF52 dfu file"
|
||||
DFUPKG=.pio/build/$1/firmware.zip
|
||||
cp $DFUPKG $OUTDIR/$basename-ota.zip
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Generating NRF52 uf2 file"
|
||||
SRCHEX=.pio/build/$1/firmware.hex
|
||||
echo "Copying NRF52 dfu (OTA) file"
|
||||
cp $BUILDDIR/$basename.zip $OUTDIR/$basename.zip
|
||||
|
||||
# if WM1110 target, merge hex with softdevice 7.3.0
|
||||
echo "Copying NRF52 UF2 file"
|
||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||
cp bin/*.uf2 $OUTDIR/
|
||||
|
||||
SRCHEX=$BUILDDIR/$basename.hex
|
||||
|
||||
# if WM1110 target, copy the merged.hex
|
||||
if (echo $1 | grep -q "wio-sdk-wm1110"); then
|
||||
echo "Merging with softdevice"
|
||||
bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/$basename.hex
|
||||
SRCHEX=.pio/build/$1/$basename.hex
|
||||
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
|
||||
cp $SRCHEX $OUTDIR
|
||||
cp bin/*.uf2 $OUTDIR
|
||||
else
|
||||
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
cp bin/*.uf2 $OUTDIR
|
||||
echo "Copying .merged.hex file"
|
||||
SRCHEX=$BUILDDIR/$basename.merged.hex
|
||||
cp $SRCHEX $OUTDIR/
|
||||
fi
|
||||
|
||||
if (echo $1 | grep -q "rak4631"); then
|
||||
echo "Copying hex file"
|
||||
cp .pio/build/$1/firmware.hex $OUTDIR/$basename.hex
|
||||
fi
|
||||
echo "Copying .hex file"
|
||||
cp $SRCHEX $OUTDIR/
|
||||
fi
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -5,7 +5,8 @@ set -e
|
||||
VERSION=`bin/buildinfo.py long`
|
||||
SHORT_VERSION=`bin/buildinfo.py short`
|
||||
|
||||
OUTDIR=release/
|
||||
BUILDDIR=.pio/build/$1
|
||||
OUTDIR=release
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
@@ -14,20 +15,19 @@ rm -r $OUTDIR/* || true
|
||||
platformio pkg install -e $1
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
rm -f $BUILDDIR/firmware*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying uf2 file"
|
||||
SRCBIN=.pio/build/$1/firmware.uf2
|
||||
cp $SRCBIN $OUTDIR/$basename.uf2
|
||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||
|
||||
cp bin/device-install.* $OUTDIR
|
||||
cp bin/device-update.* $OUTDIR
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -5,7 +5,8 @@ set -e
|
||||
VERSION=$(bin/buildinfo.py long)
|
||||
SHORT_VERSION=$(bin/buildinfo.py short)
|
||||
|
||||
OUTDIR=release/
|
||||
BUILDDIR=.pio/build/$1
|
||||
OUTDIR=release
|
||||
|
||||
rm -f $OUTDIR/firmware*
|
||||
rm -r $OUTDIR/* || true
|
||||
@@ -14,16 +15,19 @@ rm -r $OUTDIR/* || true
|
||||
platformio pkg install -e $1
|
||||
|
||||
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
|
||||
rm -f .pio/build/$1/firmware.*
|
||||
rm -f $BUILDDIR/firmware*
|
||||
|
||||
# The shell vars the build tool expects to find
|
||||
export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
SRCELF=.pio/build/$1/firmware.elf
|
||||
cp $SRCELF $OUTDIR/$basename.elf
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
SRCBIN=.pio/build/$1/firmware.bin
|
||||
cp $SRCBIN $OUTDIR/$basename.bin
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying STM32 bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -184,6 +184,8 @@ Input:
|
||||
Logging:
|
||||
LogLevel: info # debug, info, warn, error
|
||||
# TraceFile: /var/log/meshtasticd.json
|
||||
# JSONFile: /packets.json # File location for JSON output of decoded packets
|
||||
# JSONFilter: position # filter for packets to save to JSON file
|
||||
# AsciiLogs: true # default if not specified is !isatty() on stdout
|
||||
|
||||
Webserver:
|
||||
|
||||
@@ -5,22 +5,14 @@ TITLE Meshtastic device-install
|
||||
SET "SCRIPT_NAME=%~nx0"
|
||||
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="
|
||||
SET "LOGCOUNTER=0"
|
||||
SET "BPS_RESET=0"
|
||||
|
||||
@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable.
|
||||
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone t-eth-elite tlora-pager mesh-tab dreamcatcher ESP32-S3-Pico seeed-sensecap-indicator heltec_capsule_sensor_v3 vision-master icarus tracksenger elecrow-adv heltec-v4"
|
||||
SET "C3=esp32c3"
|
||||
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
|
||||
SET "BIGDB_8MB=crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
|
||||
SET "MUIDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator"
|
||||
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite tlora-pager t-watch-s3 elecrow-adv heltec-v4"
|
||||
@REM Default offsets.
|
||||
@REM https://github.com/meshtastic/web-flasher/blob/main/stores/firmwareStore.ts#L202
|
||||
SET "OTA_OFFSET=0x260000"
|
||||
SET "SPIFFS_OFFSET=0x300000"
|
||||
|
||||
GOTO getopts
|
||||
:help
|
||||
@@ -29,7 +21,7 @@ ECHO.
|
||||
ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] [--1200bps-reset]
|
||||
ECHO.
|
||||
ECHO Options:
|
||||
ECHO -f filename The firmware .bin file to flash. Custom to your device type and region. (required)
|
||||
ECHO -f filename The firmware .factory.bin file to flash. Custom to your device type and region. (required)
|
||||
ECHO The file must be located in this current directory.
|
||||
ECHO -p PORT Set the environment variable for ESPTOOL_PORT.
|
||||
ECHO If not set, ESPTOOL iterates all ports (Dangerous).
|
||||
@@ -40,12 +32,12 @@ ECHO --1200bps-reset Attempt to place the device in correct mode. (1200bps
|
||||
ECHO Some hardware requires this twice.
|
||||
ECHO.
|
||||
ECHO Example: %SCRIPT_NAME% -p COM17 --1200bps-reset
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.bin -p COM11
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.factory.bin -p COM11
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.factory.bin -p COM11
|
||||
GOTO eof
|
||||
|
||||
:version
|
||||
ECHO %SCRIPT_NAME% [Version 2.6.2]
|
||||
ECHO %SCRIPT_NAME% [Version 2.7.0]
|
||||
ECHO Meshtastic
|
||||
GOTO eof
|
||||
|
||||
@@ -78,8 +70,8 @@ IF "__!FILENAME!__"=="____" (
|
||||
CALL :LOG_MESSAGE ERROR "Filename containing spaces are not supported."
|
||||
GOTO help
|
||||
)
|
||||
IF "__!FILENAME:firmware-=!__"=="__!FILENAME!__" (
|
||||
CALL :LOG_MESSAGE ERROR "Filename must be a firmware-* file."
|
||||
IF NOT "__!FILENAME:.factory.bin=!__"=="__!FILENAME!__" (
|
||||
CALL :LOG_MESSAGE ERROR "Filename must be a firmware-*.factory.bin file."
|
||||
GOTO help
|
||||
)
|
||||
@REM Remove ".\" or "./" file prefix if present.
|
||||
@@ -93,12 +85,26 @@ IF NOT EXIST !FILENAME! (
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
IF NOT "!FILENAME:update=!"=="!FILENAME!" (
|
||||
CALL :LOG_MESSAGE DEBUG "We are working with a *update* file. !FILENAME!"
|
||||
CALL :LOG_MESSAGE INFO "Use script device-update.bat to flash update !FILENAME!."
|
||||
GOTO eof
|
||||
CALL :LOG_MESSAGE DEBUG "Checking for metadata..."
|
||||
@REM Derive metadata filename from firmware filename.
|
||||
SET "METAFILE=!FILENAME:.factory.bin=!.mt.json"
|
||||
IF EXIST !METAFILE! (
|
||||
@REM Print parsed json with powershell
|
||||
CALL :LOG_MESSAGE INFO "Firmware metadata: !METAFILE!"
|
||||
powershell -NoProfile -Command "(Get-Content '!METAFILE!' | ConvertFrom-Json | Out-String).Trim()"
|
||||
|
||||
@REM Save metadata values to variables for later use.
|
||||
FOR /f "usebackq" %%A IN (`powershell -NoProfile -Command ^
|
||||
"(Get-Content '!METAFILE!' | ConvertFrom-Json).mcu"`) DO SET "MCU=%%A"
|
||||
FOR /f "usebackq" %%A IN (`powershell -NoProfile -Command ^
|
||||
"(Get-Content '!METAFILE!' | ConvertFrom-Json).part | Where-Object { $_.subtype -eq 'ota_1' } | Select-Object -ExpandProperty offset"`
|
||||
) DO SET "OTA_OFFSET=%%A"
|
||||
FOR /f "usebackq" %%A IN (`powershell -NoProfile -Command ^
|
||||
"(Get-Content '!METAFILE!' | ConvertFrom-Json).part | Where-Object { $_.subtype -eq 'spiffs' } | Select-Object -ExpandProperty offset"`
|
||||
) DO SET "SPIFFS_OFFSET=%%A"
|
||||
) ELSE (
|
||||
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!"
|
||||
CALL :LOG_MESSAGE ERROR "No metadata file found: !METAFILE!"
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
:skip-filename
|
||||
@@ -108,7 +114,7 @@ IF NOT "__%PYTHON%__"=="____" (
|
||||
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.
|
||||
@@ -146,100 +152,26 @@ IF %BPS_RESET% EQU 1 (
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
@REM Check if FILENAME contains "-tft-" and set target partitionScheme accordingly.
|
||||
@REM https://github.com/meshtastic/web-flasher/blob/main/types/resources.ts#L3
|
||||
IF NOT "!FILENAME:-tft-=!"=="!FILENAME!" (
|
||||
CALL :LOG_MESSAGE DEBUG "We are working with a *-tft-* file. !FILENAME!"
|
||||
SET "TFT_BUILD=1"
|
||||
@REM Extract PROGNAME from %FILENAME% for later use.
|
||||
SET "PROGNAME=!FILENAME:.factory.bin=!"
|
||||
CALL :LOG_MESSAGE DEBUG "Computed PROGNAME: !PROGNAME!"
|
||||
|
||||
IF "__!MCU!__" == "__esp32s3__" (
|
||||
@REM We are working with ESP32-S3
|
||||
SET "OTA_FILENAME=bleota-s3.bin"
|
||||
) ELSE IF "__!MCU!__" == "__esp32c3__" (
|
||||
@REM We are working with ESP32-C3
|
||||
SET "OTA_FILENAME=bleota-c3.bin"
|
||||
) ELSE (
|
||||
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *-tft-* file. !FILENAME!"
|
||||
@REM Everything else
|
||||
SET "OTA_FILENAME=bleota.bin"
|
||||
)
|
||||
|
||||
FOR %%a IN (%BIGDB_8MB%) DO (
|
||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||
@REM We are working with any of %BIGDB_8MB%.
|
||||
SET "BIGDB8=1"
|
||||
GOTO end_loop_bigdb_8mb
|
||||
)
|
||||
)
|
||||
: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%.
|
||||
SET "BIGDB16=1"
|
||||
GOTO end_loop_bigdb_16mb
|
||||
)
|
||||
)
|
||||
: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.
|
||||
SET "BASENAME=!FILENAME:firmware-=!"
|
||||
CALL :LOG_MESSAGE DEBUG "Computed firmware basename: !BASENAME!"
|
||||
|
||||
@REM Account for S3 and C3 board's different OTA partition.
|
||||
FOR %%a IN (%S3%) DO (
|
||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||
@REM We are working with any of %S3%.
|
||||
SET "OTA_FILENAME=bleota-s3.bin"
|
||||
GOTO :end_loop_s3
|
||||
)
|
||||
)
|
||||
|
||||
FOR %%a IN (%C3%) DO (
|
||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||
@REM We are working with any of %C3%.
|
||||
SET "OTA_FILENAME=bleota-c3.bin"
|
||||
GOTO :end_loop_c3
|
||||
)
|
||||
)
|
||||
|
||||
@REM Everything else
|
||||
SET "OTA_FILENAME=bleota.bin"
|
||||
:end_loop_s3
|
||||
:end_loop_c3
|
||||
CALL :LOG_MESSAGE DEBUG "Set OTA_FILENAME to: !OTA_FILENAME!"
|
||||
|
||||
@REM Set SPIFFS filename with "littlefs-" prefix.
|
||||
SET "SPIFFS_FILENAME=littlefs-%BASENAME%"
|
||||
SET "SPIFFS_FILENAME=littlefs-!PROGNAME:firmware-=!.bin"
|
||||
CALL :LOG_MESSAGE DEBUG "Set SPIFFS_FILENAME to: !SPIFFS_FILENAME!"
|
||||
|
||||
@REM Default offsets.
|
||||
@REM https://github.com/meshtastic/web-flasher/blob/main/stores/firmwareStore.ts#L202
|
||||
SET "OTA_OFFSET=0x260000"
|
||||
SET "SPIFFS_OFFSET=0x300000"
|
||||
|
||||
@REM Offsets for BigDB 8mb.
|
||||
IF %BIGDB8% EQU 1 (
|
||||
SET "OTA_OFFSET=0x340000"
|
||||
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"
|
||||
SET "SPIFFS_OFFSET=0xc90000"
|
||||
)
|
||||
|
||||
CALL :LOG_MESSAGE DEBUG "Set OTA_OFFSET to: !OTA_OFFSET!"
|
||||
CALL :LOG_MESSAGE DEBUG "Set SPIFFS_OFFSET to: !SPIFFS_OFFSET!"
|
||||
|
||||
|
||||
@@ -2,69 +2,15 @@
|
||||
|
||||
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
||||
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"
|
||||
)
|
||||
BIGDB_16MB=(
|
||||
"dreamcatcher"
|
||||
"elecrow-adv"
|
||||
"ESP32-S3-Pico"
|
||||
"heltec-v4"
|
||||
"m5stack-cores3"
|
||||
"mesh-tab"
|
||||
"station-g2"
|
||||
"t-deck"
|
||||
"t-energy-s3"
|
||||
"t-eth-elite"
|
||||
"t-watch-s3"
|
||||
"tlora-pager"
|
||||
)
|
||||
S3_VARIANTS=(
|
||||
"s3"
|
||||
"-v3"
|
||||
"-v4"
|
||||
"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"
|
||||
)
|
||||
# Default littlefs* offset.
|
||||
OFFSET=0x300000
|
||||
# Default OTA Offset
|
||||
OTA_OFFSET=0x260000
|
||||
|
||||
# Determine the correct esptool command to use
|
||||
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
||||
@@ -78,6 +24,14 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for jq
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "Error: jq not found" >&2
|
||||
echo "Install jq with your package manager." >&2
|
||||
echo "e.g. 'apt install jq', 'dnf install jq', 'brew install jq', etc." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Usage info
|
||||
@@ -89,7 +43,7 @@ Flash image file to device, but first erasing and writing system information.
|
||||
-h Display this help and exit.
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The firmware .bin file to flash. Custom to your device type and region.
|
||||
-f FILENAME The firmware *.factory.bin file to flash. Custom to your device type and region.
|
||||
--1200bps-reset Attempt to place the device in correct mode. Some hardware requires this twice. (1200bps Reset)
|
||||
|
||||
EOF
|
||||
@@ -138,69 +92,43 @@ fi
|
||||
shift
|
||||
}
|
||||
|
||||
if [[ "$FILENAME" != firmware-* ]]; then
|
||||
echo "Filename must be a firmware-* file."
|
||||
if [[ $(basename "$FILENAME") != firmware-*.factory.bin ]]; then
|
||||
echo "Filename must be a firmware-*.factory.bin file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if FILENAME contains "-tft-" and set target partitionScheme accordingly.
|
||||
if [[ "${FILENAME//-tft-/}" != "$FILENAME" ]]; then
|
||||
TFT_BUILD=true
|
||||
fi
|
||||
# Extract PROGNAME from %FILENAME% for later use.
|
||||
PROGNAME="${FILENAME/.factory.bin/}"
|
||||
# Derive metadata filename from %PROGNAME%.
|
||||
METAFILE="${PROGNAME}.mt.json"
|
||||
|
||||
# Extract BASENAME from %FILENAME% for later use.
|
||||
BASENAME="${FILENAME/firmware-/}"
|
||||
|
||||
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
||||
# Default littlefs* offset.
|
||||
OFFSET=0x300000
|
||||
|
||||
# Default OTA Offset
|
||||
OTA_OFFSET=0x260000
|
||||
|
||||
# littlefs* offset for BigDB 8mb and OTA OFFSET.
|
||||
for variant in "${BIGDB_8MB[@]}"; do
|
||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
||||
OFFSET=0x670000
|
||||
OTA_OFFSET=0x340000
|
||||
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
|
||||
OFFSET=0xc90000
|
||||
OTA_OFFSET=0x650000
|
||||
fi
|
||||
done
|
||||
|
||||
# Account for S3 board's different OTA partition
|
||||
# FIXME: Use PlatformIO info to determine MCU type, this is unmaintainable
|
||||
for variant in "${S3_VARIANTS[@]}"; do
|
||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
||||
MCU="esp32s3"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$MCU" != "esp32s3" ]; then
|
||||
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
|
||||
OTAFILE=bleota.bin
|
||||
else
|
||||
OTAFILE=bleota-c3.bin
|
||||
if [[ -f "$FILENAME" && "$FILENAME" == *.factory.bin ]]; then
|
||||
# Display metadata if it exists
|
||||
if [[ -f "$METAFILE" ]]; then
|
||||
echo "Firmware metadata: ${METAFILE}"
|
||||
jq . "$METAFILE"
|
||||
# Extract relevant fields from metadata
|
||||
if [[ $(jq -r '.part' "$METAFILE") != "null" ]]; then
|
||||
OTA_OFFSET=$(jq -r '.part[] | select(.subtype == "ota_1") | .offset' "$METAFILE")
|
||||
SPIFFS_OFFSET=$(jq -r '.part[] | select(.subtype == "spiffs") | .offset' "$METAFILE")
|
||||
fi
|
||||
MCU=$(jq -r '.mcu' "$METAFILE")
|
||||
else
|
||||
echo "ERROR: No metadata file found at ${METAFILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine OTA filename based on MCU type
|
||||
if [ "$MCU" == "esp32s3" ]; then
|
||||
OTAFILE=bleota-s3.bin
|
||||
elif [ "$MCU" == "esp32c3" ]; then
|
||||
OTAFILE=bleota-c3.bin
|
||||
else
|
||||
OTAFILE=bleota.bin
|
||||
fi
|
||||
|
||||
# Set SPIFFS filename with "littlefs-" prefix.
|
||||
SPIFFSFILE=littlefs-${BASENAME}
|
||||
SPIFFSFILE="littlefs-${PROGNAME/firmware-/}.bin"
|
||||
|
||||
if [[ ! -f "$FILENAME" ]]; then
|
||||
echo "Error: file ${FILENAME} wasn't found. Terminating."
|
||||
|
||||
@@ -30,11 +30,11 @@ ECHO --change-mode Attempt to place the device in correct mode. (1200bps
|
||||
ECHO Some hardware requires this twice.
|
||||
ECHO.
|
||||
ECHO Example: %SCRIPT_NAME% -p COM17 --change-mode
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4-update.bin -p COM11
|
||||
ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.bin -p COM11
|
||||
GOTO eof
|
||||
|
||||
:version
|
||||
ECHO %SCRIPT_NAME% [Version 2.6.2]
|
||||
ECHO %SCRIPT_NAME% [Version 2.7.0]
|
||||
ECHO Meshtastic
|
||||
GOTO eof
|
||||
|
||||
@@ -78,12 +78,12 @@ IF NOT EXIST !FILENAME! (
|
||||
GOTO eof
|
||||
)
|
||||
|
||||
IF "!FILENAME:update=!"=="!FILENAME!" (
|
||||
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!"
|
||||
IF NOT "__!FILENAME:.factory.bin=!__"=="__!FILENAME!__" (
|
||||
CALL :LOG_MESSAGE DEBUG "We are working with a *.factory.bin* file. !FILENAME!"
|
||||
CALL :LOG_MESSAGE INFO "Use script device-install.bat to flash !FILENAME!."
|
||||
GOTO eof
|
||||
) ELSE (
|
||||
CALL :LOG_MESSAGE DEBUG "We are working with a *update* file. !FILENAME!"
|
||||
CALL :LOG_MESSAGE DEBUG "We are not working with a *.factory.bin* file. !FILENAME!"
|
||||
)
|
||||
|
||||
:skip-filename
|
||||
|
||||
@@ -29,7 +29,7 @@ Flash image file to device, leave existing system intact."
|
||||
-h Display this help and exit
|
||||
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
|
||||
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
|
||||
-f FILENAME The *update.bin file to flash. Custom to your device type.
|
||||
-f FILENAME The *.bin file to flash. Custom to your device type.
|
||||
--change-mode Attempt to place the device in correct mode. Some hardware requires this twice. (1200bps Reset)
|
||||
|
||||
EOF
|
||||
@@ -78,7 +78,7 @@ fi
|
||||
shift
|
||||
}
|
||||
|
||||
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
|
||||
if [[ -f "$FILENAME" && "$FILENAME" != *.factory.bin ]]; then
|
||||
echo "Trying to flash update ${FILENAME}"
|
||||
$ESPTOOL_CMD --baud $FLASH_BAUD write-flash $UPDATE_OFFSET "${FILENAME}"
|
||||
else
|
||||
|
||||
@@ -75,7 +75,7 @@ TOOLS = {
|
||||
}
|
||||
|
||||
BACKTRACE_REGEX = re.compile(
|
||||
r"(?:\s+(0x40[0-2](?:\d|[a-f]|[A-F]){5}):0x(?:\d|[a-f]|[A-F]){8})\b"
|
||||
r"\b(0x4[0-9a-fA-F]{7,8}):0x[0-9a-fA-F]{8}\b"
|
||||
)
|
||||
EXCEPTION_REGEX = re.compile("^Exception \\((?P<exc>[0-9]*)\\):$")
|
||||
COUNTER_REGEX = re.compile(
|
||||
@@ -89,7 +89,7 @@ POINTER_REGEX = re.compile(
|
||||
STACK_BEGIN = ">>>stack>>>"
|
||||
STACK_END = "<<<stack<<<"
|
||||
STACK_REGEX = re.compile(
|
||||
"^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$"
|
||||
r"^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$"
|
||||
)
|
||||
|
||||
StackLine = namedtuple("StackLine", ["offset", "content"])
|
||||
@@ -223,7 +223,7 @@ class AddressResolver(object):
|
||||
if match is None:
|
||||
if last is not None and line.startswith("(inlined by)"):
|
||||
line = line[12:].strip()
|
||||
self._address_map[last] += "\n \-> inlined by: " + line
|
||||
self._address_map[last] += "\n \\-> inlined by: " + line
|
||||
continue
|
||||
|
||||
if match.group("result") == "?? ??:0":
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
set -e
|
||||
pio run --environment native
|
||||
gdbserver --once localhost:2345 .pio/build/native/program "$@"
|
||||
gdbserver --once localhost:2345 .pio/build/native/meshtasticd "$@"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
set -e
|
||||
pio run --environment native
|
||||
.pio/build/native/program "$@"
|
||||
.pio/build/native/meshtasticd "$@"
|
||||
|
||||
@@ -87,6 +87,15 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="2.7.18" date="2025-12-20">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.18</url>
|
||||
</release>
|
||||
<release version="2.7.17" date="2025-11-28">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.17</url>
|
||||
</release>
|
||||
<release version="2.7.16" date="2025-11-19">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.16</url>
|
||||
</release>
|
||||
<release version="2.7.15" date="2025-11-13">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.15</url>
|
||||
</release>
|
||||
|
||||
@@ -2,98 +2,77 @@
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
import sys
|
||||
from os.path import join
|
||||
from os.path import join, basename, isfile
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from readprops import readProps
|
||||
|
||||
Import("env")
|
||||
platform = env.PioPlatform()
|
||||
progname = env.get("PROGNAME")
|
||||
lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin"
|
||||
|
||||
|
||||
def esp32_create_combined_bin(source, target, env):
|
||||
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
|
||||
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
|
||||
print("Generating combined binary for serial flashing")
|
||||
|
||||
app_offset = 0x10000
|
||||
|
||||
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||
chip = env.get("BOARD_MCU")
|
||||
flash_size = env.BoardConfig().get("upload.flash_size")
|
||||
flash_freq = env.BoardConfig().get("build.f_flash", "40m")
|
||||
flash_freq = flash_freq.replace("000000L", "m")
|
||||
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
|
||||
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
|
||||
if flash_mode == "qio" or flash_mode == "qout":
|
||||
flash_mode = "dio"
|
||||
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||
flash_mode = "dout"
|
||||
cmd = [
|
||||
"--chip",
|
||||
chip,
|
||||
"merge_bin",
|
||||
"-o",
|
||||
new_file_name,
|
||||
"--flash_mode",
|
||||
flash_mode,
|
||||
"--flash_freq",
|
||||
flash_freq,
|
||||
"--flash_size",
|
||||
flash_size,
|
||||
def manifest_gather(source, target, env):
|
||||
out = []
|
||||
check_paths = [
|
||||
progname,
|
||||
f"{progname}.elf",
|
||||
f"{progname}.bin",
|
||||
f"{progname}.factory.bin",
|
||||
f"{progname}.hex",
|
||||
f"{progname}.merged.hex",
|
||||
f"{progname}.uf2",
|
||||
f"{progname}.factory.uf2",
|
||||
f"{progname}.zip",
|
||||
lfsbin
|
||||
]
|
||||
for p in check_paths:
|
||||
f = env.File(env.subst(f"$BUILD_DIR/{p}"))
|
||||
if f.exists():
|
||||
d = {
|
||||
"name": p,
|
||||
"md5": f.get_content_hash(), # Returns MD5 hash
|
||||
"bytes": f.get_size() # Returns file size in bytes
|
||||
}
|
||||
out.append(d)
|
||||
print(d)
|
||||
manifest_write(out, env)
|
||||
|
||||
print(" Offset | File")
|
||||
for section in sections:
|
||||
sect_adr, sect_file = section.split(" ", 1)
|
||||
print(f" - {sect_adr} | {sect_file}")
|
||||
cmd += [sect_adr, sect_file]
|
||||
def manifest_write(files, env):
|
||||
manifest = {
|
||||
"version": verObj["long"],
|
||||
"build_epoch": build_epoch,
|
||||
"board": env.get("PIOENV"),
|
||||
"mcu": env.get("BOARD_MCU"),
|
||||
"repo": repo_owner,
|
||||
"files": files,
|
||||
"part": None,
|
||||
"has_mui": False,
|
||||
"has_inkhud": False,
|
||||
}
|
||||
# Get partition table (generated in esp32_pre.py) if it exists
|
||||
if env.get("custom_mtjson_part"):
|
||||
# custom_mtjson_part is a JSON string, convert it back to a dict
|
||||
pj = json.loads(env.get("custom_mtjson_part"))
|
||||
manifest["part"] = pj
|
||||
# Enable has_mui for TFT builds
|
||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
||||
manifest["has_mui"] = True
|
||||
if "MESHTASTIC_INCLUDE_INKHUD" in env.get("CPPDEFINES", []):
|
||||
manifest["has_inkhud"] = True
|
||||
|
||||
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||
cmd += [hex(app_offset), firmware_name]
|
||||
|
||||
print("Using esptool.py arguments: %s" % " ".join(cmd))
|
||||
|
||||
esptool.main(cmd)
|
||||
|
||||
|
||||
if platform.name == "espressif32":
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
import esptool
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||
|
||||
esp32_kind = env.GetProjectOption("custom_esp32_kind")
|
||||
if esp32_kind == "esp32":
|
||||
# Free up some IRAM by removing auxiliary SPI flash chip drivers.
|
||||
# Wrapped stub symbols are defined in src/platform/esp32/iram-quirk.c.
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"-Wl,--wrap=esp_flash_chip_gd",
|
||||
"-Wl,--wrap=esp_flash_chip_issi",
|
||||
"-Wl,--wrap=esp_flash_chip_winbond",
|
||||
]
|
||||
)
|
||||
else:
|
||||
# For newer ESP32 targets, using newlib nano works better.
|
||||
env.Append(LINKFLAGS=["--specs=nano.specs", "-u", "_printf_float"])
|
||||
|
||||
if platform.name == "nordicnrf52":
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex",
|
||||
env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py \"$BUILD_DIR/firmware.hex\" -c -f 0xADA52840 -o \"$BUILD_DIR/firmware.uf2\"",
|
||||
"Generating UF2 file"))
|
||||
# Write the manifest to the build directory
|
||||
with open(env.subst("$BUILD_DIR/${PROGNAME}.mt.json"), "w") as f:
|
||||
json.dump(manifest, f, indent=2)
|
||||
|
||||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"] + " on " + env.get("PIOENV"))
|
||||
print(f"Using meshtastic platformio-custom.py, firmware version {verObj['long']} on {env.get('PIOENV')}")
|
||||
|
||||
# get repository owner if git is installed
|
||||
try:
|
||||
@@ -139,10 +118,10 @@ flags = [
|
||||
"-DBUILD_EPOCH=" + str(build_epoch),
|
||||
] + pref_flags
|
||||
|
||||
print ("Using flags:")
|
||||
print("Using flags:")
|
||||
for flag in flags:
|
||||
print(flag)
|
||||
|
||||
|
||||
projenv.Append(
|
||||
CCFLAGS=flags,
|
||||
)
|
||||
@@ -180,4 +159,22 @@ def load_boot_logo(source, target, env):
|
||||
|
||||
# Load the boot logo on TFT builds
|
||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
||||
env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo)
|
||||
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo)
|
||||
|
||||
mtjson_deps = ["buildprog"]
|
||||
if platform.name == "espressif32":
|
||||
# Build littlefs image as part of mtjson target
|
||||
# Equivalent to `pio run -t buildfs`
|
||||
target_lfs = env.DataToBin(
|
||||
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
|
||||
)
|
||||
mtjson_deps.append(target_lfs)
|
||||
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=mtjson_deps,
|
||||
actions=[manifest_gather],
|
||||
title="Meshtastic Manifest",
|
||||
description="Generating Meshtastic manifest JSON + Checksums",
|
||||
always_build=False,
|
||||
)
|
||||
|
||||
19
bin/platformio-pre.py
Normal file
19
bin/platformio-pre.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
Import("env")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
if platform.name == "native":
|
||||
env.Replace(PROGNAME="meshtasticd")
|
||||
else:
|
||||
from readprops import readProps
|
||||
prefsLoc = env["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}")
|
||||
env.Replace(ESP32_FS_IMAGE_NAME=f"littlefs-{env.get('PIOENV')}-{verObj['long']}")
|
||||
|
||||
# Print the new program name for verification
|
||||
print(f"PROGNAME: {env.get('PROGNAME')}")
|
||||
if platform.name == "espressif32":
|
||||
print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}")
|
||||
101
bin/shame.py
Normal file
101
bin/shame.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from github import Github
|
||||
|
||||
def parseFile(path):
|
||||
with open(path, "r") as f:
|
||||
data = json.loads(f)
|
||||
for file in data["files"]:
|
||||
if file["name"].endswith(".bin"):
|
||||
return file["name"], file["bytes"]
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print(f"expected usage: {sys.argv[0]} <PR number> <path to old-manifests> <path to new-manifests>")
|
||||
sys.exit(1)
|
||||
|
||||
pr_number = int(sys.argv[1])
|
||||
|
||||
token = os.getenv("GITHUB_TOKEN")
|
||||
if not token:
|
||||
raise EnvironmentError("GITHUB_TOKEN not found in environment.")
|
||||
|
||||
repo_name = os.getenv("GITHUB_REPOSITORY") # "owner/repo"
|
||||
if not repo_name:
|
||||
raise EnvironmentError("GITHUB_REPOSITORY not found in environment.")
|
||||
|
||||
oldFiles = sys.argv[2]
|
||||
old = set(os.path.join(oldFiles, f) for f in os.listdir(oldFiles) if os.path.isfile(f))
|
||||
newFiles = sys.argv[3]
|
||||
new = set(os.path.join(newFiles, f) for f in os.listdir(newFiles) if os.path.isfile(f))
|
||||
|
||||
startMarkdown = "# Target Size Changes\n\n"
|
||||
markdown = ""
|
||||
|
||||
newlyIntroduced = new - old
|
||||
if len(newlyIntroduced) > 0:
|
||||
markdown += "## Newly Introduced Targets\n\n"
|
||||
# create a table
|
||||
markdown += "| File | Size |\n"
|
||||
markdown += "| ---- | ---- |\n"
|
||||
for f in newlyIntroduced:
|
||||
name, size = parseFile(f)
|
||||
markdown += f"| `{name}` | {size}b |\n"
|
||||
|
||||
removed = old - new
|
||||
if len(removed) > 0:
|
||||
markdown += "\n## Removed Targets\n\n"
|
||||
# create a table
|
||||
markdown += "| File | Size |\n"
|
||||
markdown += "| ---- | ---- |\n"
|
||||
for f in removed:
|
||||
name, size = parseFile(f)
|
||||
markdown += f"| `{name}` | {size}b |\n"
|
||||
|
||||
both = old & new
|
||||
degradations = []
|
||||
improvements = []
|
||||
for f in both:
|
||||
oldName, oldSize = parseFile(f)
|
||||
_, newSize = parseFile(f)
|
||||
if oldSize != newSize:
|
||||
if newSize < oldSize:
|
||||
improvements.append((oldName, oldSize, newSize))
|
||||
else:
|
||||
degradations.append((oldName, oldSize, newSize))
|
||||
|
||||
if len(degradations) > 0:
|
||||
markdown += "\n## Degradation\n\n"
|
||||
# create a table
|
||||
markdown += "| File | Difference | Old Size | New Size |\n"
|
||||
markdown += "| ---- | ---------- | -------- | -------- |\n"
|
||||
for oldName, oldSize, newSize in degradations:
|
||||
markdown += f"| `{oldName}` | **{oldSize - newSize}b** | {oldSize}b | {newSize}b |\n"
|
||||
|
||||
if len(improvements) > 0:
|
||||
markdown += "\n## Improvement\n\n"
|
||||
# create a table
|
||||
markdown += "| File | Difference | Old Size | New Size |\n"
|
||||
markdown += "| ---- | ---------- | -------- | -------- |\n"
|
||||
for oldName, oldSize, newSize in improvements:
|
||||
markdown += f"| `{oldName}` | **{oldSize - newSize}b** | {oldSize}b | {newSize}b |\n"
|
||||
|
||||
if len(markdown) == 0:
|
||||
markdown = "No changes in target sizes detected."
|
||||
|
||||
g = Github(token)
|
||||
repo = g.get_repo(repo_name)
|
||||
pr = repo.get_pull(pr_number)
|
||||
|
||||
existing_comment = None
|
||||
for comment in pr.get_issue_comments():
|
||||
if comment.body.startswith(startMarkdown):
|
||||
existing_comment = comment
|
||||
break
|
||||
|
||||
final_markdown = startMarkdown + markdown
|
||||
|
||||
if existing_comment:
|
||||
existing_comment.edit(body=final_markdown)
|
||||
else:
|
||||
pr.create_issue_comment(body=final_markdown)
|
||||
@@ -3,7 +3,7 @@
|
||||
set -e
|
||||
|
||||
echo "Starting simulator"
|
||||
.pio/build/native/program &
|
||||
.pio/build/native/meshtasticd -s &
|
||||
sleep 20 # 5 seconds was not enough
|
||||
|
||||
echo "Simulator started, launching python test..."
|
||||
|
||||
53
boards/ThinkNode-M3.json
Normal file
53
boards/ThinkNode-M3.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x4405"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"]
|
||||
],
|
||||
"usb_product": "elecrow_eink",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "ELECROW-ThinkNode-M3",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": ["jlink"],
|
||||
"svd_path": "nrf52840.svd",
|
||||
"openocd_target": "nrf52840-mdk-rs"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "elecrow nrf",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "",
|
||||
"vendor": "ELECROW"
|
||||
}
|
||||
53
boards/ThinkNode-M6.json
Normal file
53
boards/ThinkNode-M6.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_ELECROW_M6 -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x4405"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"]
|
||||
],
|
||||
"usb_product": "elecrow_thinknode_m6",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "ELECROW-ThinkNode-M6",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": ["jlink"],
|
||||
"svd_path": "nrf52840.svd",
|
||||
"openocd_target": "nrf52840-mdk-rs"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "ELECROW ThinkNode M6",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://www.elecrow.com/thinknode-m6-outdoor-solar-power-for-lora-powered-by-nrf52840-supports-gps.html",
|
||||
"vendor": "ELECROW"
|
||||
}
|
||||
41
boards/hackaday-communicator.json
Normal file
41
boards/hackaday-communicator.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "hackaday-communicator"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "hackaday-communicator (16 MB FLASH, 8 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 1500000
|
||||
},
|
||||
"url": "hackaday.com",
|
||||
"vendor": "hackaday"
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
|
||||
56
boards/muzi-base.json
Normal file
56
boards/muzi-base.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_MUZI_BASE -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [["0x239A", "0xcafe"]],
|
||||
"mcu": "nrf52840",
|
||||
"variant": "muzi-base",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": ["jlink"],
|
||||
"svd_path": "nrf52840.svd",
|
||||
"openocd_target": "nrf52840-mdk-rs"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "Muzi Base",
|
||||
"url": "https://muzi.works/",
|
||||
"vendor": "MuziWorks",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"blackmagic",
|
||||
"cmsis-dap",
|
||||
"mbed",
|
||||
"stlink"
|
||||
],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
}
|
||||
}
|
||||
19
debian/changelog
vendored
19
debian/changelog
vendored
@@ -1,3 +1,22 @@
|
||||
meshtasticd (2.7.18.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.18
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 20 Dec 2025 15:47:25 +0000
|
||||
|
||||
meshtasticd (2.7.17.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.17
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Fri, 28 Nov 2025 15:11:34 +0000
|
||||
|
||||
meshtasticd (2.7.16.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.16
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Wed, 19 Nov 2025 16:12:32 +0000
|
||||
|
||||
|
||||
meshtasticd (2.7.15.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.15
|
||||
|
||||
1
debian/rules
vendored
1
debian/rules
vendored
@@ -28,5 +28,4 @@ override_dh_auto_build:
|
||||
# Build with platformio
|
||||
$(PIO_ENV) platformio run -e native-tft
|
||||
# Move the binary and default config to the correct name
|
||||
mv .pio/build/native-tft/program .pio/build/native-tft/meshtasticd
|
||||
cp bin/config-dist.yaml bin/config.yaml
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(flake8/F821)
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
|
||||
Import("env")
|
||||
|
||||
# NOTE: This is not currently used, but can serve as an example on how to write extra_scripts
|
||||
|
||||
# print("Current CLI targets", COMMAND_LINE_TARGETS)
|
||||
# print("Current Build targets", BUILD_TARGETS)
|
||||
# print("CPP defs", env.get("CPPDEFINES"))
|
||||
|
||||
86
extra_scripts/esp32_extra.py
Executable file
86
extra_scripts/esp32_extra.py
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
# trunk-ignore-all(ruff/E402): Hacky esptool import
|
||||
# trunk-ignore-all(flake8/E402): Hacky esptool import
|
||||
import sys
|
||||
from os.path import join
|
||||
|
||||
Import("env")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
# IntelHex workaround, remove after fixed upstream
|
||||
# https://github.com/platformio/platform-espressif32/issues/1632
|
||||
try:
|
||||
import intelhex
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install intelhex")
|
||||
import esptool
|
||||
|
||||
|
||||
def esp32_create_combined_bin(source, target, env):
|
||||
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
|
||||
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
|
||||
print("Generating combined binary for serial flashing")
|
||||
|
||||
app_offset = 0x10000
|
||||
|
||||
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||
chip = env.get("BOARD_MCU")
|
||||
board = env.BoardConfig()
|
||||
flash_size = board.get("upload.flash_size")
|
||||
flash_freq = board.get("build.f_flash", "40m")
|
||||
flash_freq = flash_freq.replace("000000L", "m")
|
||||
flash_mode = board.get("build.flash_mode", "dio")
|
||||
memory_type = board.get("build.arduino.memory_type", "qio_qspi")
|
||||
if flash_mode == "qio" or flash_mode == "qout":
|
||||
flash_mode = "dio"
|
||||
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||
flash_mode = "dout"
|
||||
cmd = [
|
||||
"--chip",
|
||||
chip,
|
||||
"merge_bin",
|
||||
"-o",
|
||||
new_file_name,
|
||||
"--flash_mode",
|
||||
flash_mode,
|
||||
"--flash_freq",
|
||||
flash_freq,
|
||||
"--flash_size",
|
||||
flash_size,
|
||||
]
|
||||
|
||||
print(" Offset | File")
|
||||
for section in sections:
|
||||
sect_adr, sect_file = section.split(" ", 1)
|
||||
print(f" - {sect_adr} | {sect_file}")
|
||||
cmd += [sect_adr, sect_file]
|
||||
|
||||
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||
cmd += [hex(app_offset), firmware_name]
|
||||
|
||||
print("Using esptool.py arguments: %s" % " ".join(cmd))
|
||||
|
||||
esptool.main(cmd)
|
||||
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||
|
||||
esp32_kind = env.GetProjectOption("custom_esp32_kind")
|
||||
if esp32_kind == "esp32":
|
||||
# Free up some IRAM by removing auxiliary SPI flash chip drivers.
|
||||
# Wrapped stub symbols are defined in src/platform/esp32/iram-quirk.c.
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"-Wl,--wrap=esp_flash_chip_gd",
|
||||
"-Wl,--wrap=esp_flash_chip_issi",
|
||||
"-Wl,--wrap=esp_flash_chip_winbond",
|
||||
]
|
||||
)
|
||||
else:
|
||||
# For newer ESP32 targets, using newlib nano works better.
|
||||
env.Append(LINKFLAGS=["--specs=nano.specs", "-u", "_printf_float"])
|
||||
73
extra_scripts/esp32_pre.py
Executable file
73
extra_scripts/esp32_pre.py
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
import json
|
||||
import sys
|
||||
from os.path import isfile
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
# From https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py
|
||||
def _parse_size(value):
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
elif value.isdigit():
|
||||
return int(value)
|
||||
elif value.startswith("0x"):
|
||||
return int(value, 16)
|
||||
elif value[-1].upper() in ("K", "M"):
|
||||
base = 1024 if value[-1].upper() == "K" else 1024 * 1024
|
||||
return int(value[:-1]) * base
|
||||
return value
|
||||
|
||||
|
||||
def _parse_partitions(env):
|
||||
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
|
||||
if not isfile(partitions_csv):
|
||||
sys.stderr.write(
|
||||
"Could not find the file %s with partitions " "table.\n" % partitions_csv
|
||||
)
|
||||
env.Exit(1)
|
||||
return
|
||||
|
||||
result = []
|
||||
# The first offset is 0x9000 because partition table is flashed to 0x8000 and
|
||||
# occupies an entire flash sector, which size is 0x1000
|
||||
next_offset = 0x9000
|
||||
with open(partitions_csv) as fp:
|
||||
for line in fp.readlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
tokens = [t.strip() for t in line.split(",")]
|
||||
if len(tokens) < 5:
|
||||
continue
|
||||
|
||||
bound = 0x10000 if tokens[1] in ("0", "app") else 4
|
||||
calculated_offset = (next_offset + bound - 1) & ~(bound - 1)
|
||||
partition = {
|
||||
"name": tokens[0],
|
||||
"type": tokens[1],
|
||||
"subtype": tokens[2],
|
||||
"offset": tokens[3] or calculated_offset,
|
||||
"size": tokens[4],
|
||||
"flags": tokens[5] if len(tokens) > 5 else None,
|
||||
}
|
||||
result.append(partition)
|
||||
next_offset = _parse_size(partition["offset"]) + _parse_size(
|
||||
partition["size"]
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def mtjson_esp32_part(target, source, env):
|
||||
part = _parse_partitions(env)
|
||||
pj = json.dumps(part)
|
||||
# print(f"JSON_PARTITIONS: {pj}")
|
||||
# Dump json string to 'custom_mtjson_part' variable to use later when writing the manifest
|
||||
env.Replace(custom_mtjson_part=pj)
|
||||
|
||||
|
||||
env.AddPreAction("mtjson", mtjson_esp32_part)
|
||||
50
extra_scripts/nrf52_extra.py
Executable file
50
extra_scripts/nrf52_extra.py
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
|
||||
import sys
|
||||
from os.path import basename
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
# Custom HEX from ELF
|
||||
# Convert hex to uf2 for nrf52
|
||||
def nrf52_hex_to_uf2(source, target, env):
|
||||
hex_path = target[0].get_abspath()
|
||||
# When using merged hex, drop 'merged' from uf2 filename
|
||||
uf2_path = hex_path.replace(".merged.", ".")
|
||||
uf2_path = uf2_path.replace(".hex", ".uf2")
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
f'"{sys.executable}" ./bin/uf2conv.py "{hex_path}" -c -f 0xADA52840 -o "{uf2_path}"',
|
||||
f"Generating UF2 file from {basename(hex_path)}",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def nrf52_mergehex(source, target, env):
|
||||
hex_path = target[0].get_abspath()
|
||||
merged_hex_path = hex_path.replace(".hex", ".merged.hex")
|
||||
merge_with = None
|
||||
if "wio-sdk-wm1110" == str(env.get("PIOENV")):
|
||||
merge_with = env.subst("$PROJECT_DIR/bin/s140_nrf52_7.3.0_softdevice.hex")
|
||||
else:
|
||||
print("merge_with not defined for this target")
|
||||
|
||||
if merge_with is not None:
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
f'"$PROJECT_DIR/bin/mergehex" -m "{hex_path}" "{merge_with}" -o "{merged_hex_path}"',
|
||||
"Merging HEX with SoftDevice",
|
||||
)
|
||||
)
|
||||
print(f'Merged file saved at "{basename(merged_hex_path)}"')
|
||||
nrf52_hex_to_uf2([hex_path, merge_with], [env.File(merged_hex_path)], env)
|
||||
|
||||
|
||||
# if WM1110 target, merge hex with softdevice 7.3.0
|
||||
if "wio-sdk-wm1110" == env.get("PIOENV"):
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", nrf52_mergehex)
|
||||
else:
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", nrf52_hex_to_uf2)
|
||||
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
|
||||
Import("env")
|
||||
|
||||
# Custom HEX from ELF
|
||||
env.AddPostAction(
|
||||
"$BUILD_DIR/${PROGNAME}.elf",
|
||||
@@ -33,7 +33,6 @@ BuildRequires: python3dist(grpcio[protobuf])
|
||||
BuildRequires: python3dist(grpcio-tools)
|
||||
BuildRequires: git-core
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: (glibc-devel >= 2.38) or pkgconfig(libbsd-overlay)
|
||||
BuildRequires: pkgconfig(yaml-cpp)
|
||||
BuildRequires: pkgconfig(libgpiod)
|
||||
BuildRequires: pkgconfig(bluez)
|
||||
@@ -50,6 +49,13 @@ BuildRequires: pkgconfig(x11)
|
||||
BuildRequires: pkgconfig(libinput)
|
||||
BuildRequires: pkgconfig(xkbcommon-x11)
|
||||
|
||||
# libbsd is needed on older Fedora/RHEL to provide 'strlcpy'
|
||||
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
|
||||
BuildRequires: glibc-devel >= 2.38
|
||||
%else
|
||||
BuildRequires: pkgconfig(libbsd-overlay)
|
||||
%endif
|
||||
|
||||
Requires: systemd-udev
|
||||
|
||||
%description
|
||||
@@ -70,7 +76,7 @@ platformio run -e native-tft
|
||||
%install
|
||||
# Install meshtasticd binary
|
||||
mkdir -p %{buildroot}%{_bindir}
|
||||
install -m 0755 .pio/build/native-tft/program %{buildroot}%{_bindir}/meshtasticd
|
||||
install -m 0755 .pio/build/native-tft/meshtasticd %{buildroot}%{_bindir}/meshtasticd
|
||||
|
||||
# Install portduino VFS dir
|
||||
install -p -d -m 0770 %{buildroot}%{_localstatedir}/lib/meshtasticd
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
default_envs = tbeam
|
||||
|
||||
extra_configs =
|
||||
arch/*/*.ini
|
||||
variants/*/*.ini
|
||||
variants/*/*/platformio.ini
|
||||
variants/*/diy/*/platformio.ini
|
||||
src/graphics/niche/InkHUD/PlatformioConfig.ini
|
||||
@@ -14,7 +14,9 @@ description = Meshtastic
|
||||
|
||||
[env]
|
||||
test_build_src = true
|
||||
extra_scripts = bin/platformio-custom.py
|
||||
extra_scripts =
|
||||
pre:bin/platformio-pre.py
|
||||
bin/platformio-custom.py
|
||||
; note: we add src to our include search path so that lmic_project_config can override
|
||||
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
|
||||
; of code is a heap corruption bug!
|
||||
@@ -62,7 +64,7 @@ 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/2887bf4a19f64d92c984dcc8fd5ca7429e425e4a.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
|
||||
@@ -90,7 +92,7 @@ framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=end2endzone/library/NonBlockingRTTTL
|
||||
end2endzone/NonBlockingRTTTL@1.3.0
|
||||
end2endzone/NonBlockingRTTTL@1.4.0
|
||||
build_flags = ${env.build_flags} -Os
|
||||
build_src_filter = ${env.build_src_filter} -<platform/portduino/> -<graphics/niche/>
|
||||
|
||||
@@ -101,17 +103,13 @@ lib_deps =
|
||||
thingsboard/TBPubSubClient@2.12.1
|
||||
# renovate: datasource=custom.pio depName=NTPClient packageName=arduino-libraries/library/NTPClient
|
||||
arduino-libraries/NTPClient@3.2.1
|
||||
|
||||
; Extra TCP/IP networking libs for supported devices
|
||||
[networking_extra]
|
||||
lib_deps =
|
||||
# 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]
|
||||
lib_deps =
|
||||
# renovate: datasource=custom.pio depName=TBPubSubClient packageName=thingsboard/library/TBPubSubClient
|
||||
thingsboard/TBPubSubClient@2.12.1
|
||||
# renovate: datasource=custom.pio depName=NTPClient packageName=arduino-libraries/library/NTPClient
|
||||
arduino-libraries/NTPClient@3.2.1
|
||||
|
||||
[radiolib_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
|
||||
@@ -121,7 +119,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/19b7855e9a1d9deff37391659ca7194e4ef57c43.zip
|
||||
https://github.com/meshtastic/device-ui/archive/862ed040c4ab44f0dfbbe492691f144886102588.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
@@ -160,8 +158,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=git-refs depName=INA3221 packageName=https://github.com/sgtwilko/INA3221 gitBranch=FixOverflow
|
||||
https://github.com/sgtwilko/INA3221/archive/bb03d7e9bfcc74fc798838a54f4f99738f29fc6a.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
|
||||
@@ -169,7 +167,7 @@ lib_deps =
|
||||
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
|
||||
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
|
||||
# renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226
|
||||
robtillaart/INA226@0.6.4
|
||||
robtillaart/INA226@0.6.5
|
||||
# renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library
|
||||
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
|
||||
# renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library
|
||||
@@ -182,8 +180,8 @@ lib_deps =
|
||||
dfrobot/DFRobot_BMM150@1.0.0
|
||||
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
||||
adafruit/Adafruit TSL2561@1.1.2
|
||||
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/BH1750_WE@^1.1.10
|
||||
wollewald/BH1750_WE@^1.1.10
|
||||
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE
|
||||
wollewald/BH1750_WE@1.1.10
|
||||
|
||||
; (not included in native / portduino)
|
||||
[environmental_extra]
|
||||
@@ -205,7 +203,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/library/SparkFun Qwiic Scale NAU7802 Arduino Library
|
||||
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
|
||||
# renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001
|
||||
ClosedCube OPT3001@1.1.2
|
||||
closedcube/ClosedCube OPT3001@1.1.2
|
||||
# renovate: datasource=custom.pio depName=Bosch BSEC2 packageName=boschsensortec/library/bsec2
|
||||
boschsensortec/bsec2@1.10.2610
|
||||
# renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library
|
||||
@@ -213,6 +211,6 @@ lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
|
||||
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
|
||||
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
|
||||
sensirion/Sensirion Core@0.7.1
|
||||
sensirion/Sensirion Core@0.7.2
|
||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
||||
sensirion/Sensirion I2C SCD4x@1.1.0
|
||||
|
||||
Submodule protobufs updated: 7654db2e2d...c474fd3f49
@@ -50,8 +50,11 @@ class AudioThread : public concurrency::OSThread
|
||||
delete i2sRtttl;
|
||||
i2sRtttl = nullptr;
|
||||
}
|
||||
delete rtttlFile;
|
||||
rtttlFile = nullptr;
|
||||
|
||||
if (rtttlFile != nullptr) {
|
||||
delete rtttlFile;
|
||||
rtttlFile = nullptr;
|
||||
}
|
||||
|
||||
setCPUFast(false);
|
||||
#ifdef T_LORA_PAGER
|
||||
@@ -99,9 +102,9 @@ class AudioThread : public concurrency::OSThread
|
||||
};
|
||||
|
||||
AudioGeneratorRTTTL *i2sRtttl = nullptr;
|
||||
AudioOutputI2S *audioOut;
|
||||
AudioOutputI2S *audioOut = nullptr;
|
||||
|
||||
AudioFileSourcePROGMEM *rtttlFile;
|
||||
AudioFileSourcePROGMEM *rtttlFile = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,9 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
|
||||
return useShortName ? "LongF" : "LongFast";
|
||||
break;
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
|
||||
return useShortName ? "LongT" : "LongTurbo";
|
||||
break;
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
|
||||
return useShortName ? "LongM" : "LongMod";
|
||||
break;
|
||||
|
||||
@@ -278,6 +278,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(BATTERY_CHARGING_INV)
|
||||
// bit of trickery to show 99% up until the charge finishes
|
||||
if (!digitalRead(BATTERY_CHARGING_INV) && battery_SOC > 99)
|
||||
battery_SOC = 99;
|
||||
#endif
|
||||
return clamp((int)(battery_SOC), 0, 100);
|
||||
}
|
||||
|
||||
@@ -455,6 +460,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
}
|
||||
// if it's not HIGH - check the battery
|
||||
#endif
|
||||
#elif defined(MUZI_BASE)
|
||||
return NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk;
|
||||
#endif
|
||||
return getBattVoltage() > chargingVolt;
|
||||
}
|
||||
@@ -470,6 +477,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
#endif
|
||||
#ifdef EXT_CHRG_DETECT
|
||||
return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value;
|
||||
#elif defined(BATTERY_CHARGING_INV)
|
||||
return !digitalRead(BATTERY_CHARGING_INV);
|
||||
#else
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
|
||||
if (hasINA()) {
|
||||
@@ -698,11 +707,18 @@ bool Power::setup()
|
||||
[]() {
|
||||
power->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
},
|
||||
CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_CHARGING_INV
|
||||
attachInterrupt(
|
||||
BATTERY_CHARGING_INV,
|
||||
[]() {
|
||||
power->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
},
|
||||
CHANGE);
|
||||
#endif
|
||||
enabled = found;
|
||||
low_voltage_counter = 0;
|
||||
|
||||
@@ -759,6 +775,8 @@ void Power::shutdown()
|
||||
if (screen) {
|
||||
#ifdef T_DECK_PRO
|
||||
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
|
||||
#elif defined(USE_EINK)
|
||||
screen->showSimpleBanner("Shutting Down...", 2250); // dismiss after 3 seconds to avoid the banner on the sleep screen
|
||||
#else
|
||||
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
||||
#endif
|
||||
@@ -1435,7 +1453,7 @@ class LipoCharger : public HasBatteryLevel
|
||||
/**
|
||||
* return true if there is an external power source detected
|
||||
*/
|
||||
virtual bool isVbusIn() override { return PPM->getVbusVoltage() > 0; }
|
||||
virtual bool isVbusIn() override { return PPM->isVbusIn(); }
|
||||
|
||||
/**
|
||||
* return true if the battery is currently charging
|
||||
|
||||
@@ -57,21 +57,21 @@ static bool isPowered()
|
||||
|
||||
static void sdsEnter()
|
||||
{
|
||||
LOG_DEBUG("State: SDS");
|
||||
LOG_POWERFSM("State: SDS");
|
||||
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
|
||||
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false);
|
||||
}
|
||||
|
||||
static void lowBattSDSEnter()
|
||||
{
|
||||
LOG_DEBUG("State: Lower batt SDS");
|
||||
LOG_POWERFSM("State: Lower batt SDS");
|
||||
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true);
|
||||
}
|
||||
extern Power *power;
|
||||
|
||||
static void shutdownEnter()
|
||||
{
|
||||
LOG_DEBUG("State: SHUTDOWN");
|
||||
LOG_POWERFSM("State: SHUTDOWN");
|
||||
shutdownAtMsec = millis();
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ static uint32_t secsSlept;
|
||||
|
||||
static void lsEnter()
|
||||
{
|
||||
LOG_INFO("lsEnter begin, ls_secs=%u", config.power.ls_secs);
|
||||
LOG_POWERFSM("lsEnter begin, ls_secs=%u", config.power.ls_secs);
|
||||
if (screen)
|
||||
screen->setOn(false);
|
||||
secsSlept = 0; // How long have we been sleeping this time
|
||||
@@ -155,12 +155,12 @@ static void lsIdle()
|
||||
|
||||
static void lsExit()
|
||||
{
|
||||
LOG_INFO("Exit state: LS");
|
||||
LOG_POWERFSM("State: lsExit");
|
||||
}
|
||||
|
||||
static void nbEnter()
|
||||
{
|
||||
LOG_DEBUG("State: NB");
|
||||
LOG_POWERFSM("State: nbEnter");
|
||||
if (screen)
|
||||
screen->setOn(false);
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -173,6 +173,7 @@ static void nbEnter()
|
||||
|
||||
static void darkEnter()
|
||||
{
|
||||
LOG_POWERFSM("State: darkEnter");
|
||||
setBluetoothEnable(true);
|
||||
if (screen)
|
||||
screen->setOn(false);
|
||||
@@ -180,7 +181,7 @@ static void darkEnter()
|
||||
|
||||
static void serialEnter()
|
||||
{
|
||||
LOG_DEBUG("State: SERIAL");
|
||||
LOG_POWERFSM("State: serialEnter");
|
||||
setBluetoothEnable(false);
|
||||
if (screen) {
|
||||
screen->setOn(true);
|
||||
@@ -189,13 +190,14 @@ static void serialEnter()
|
||||
|
||||
static void serialExit()
|
||||
{
|
||||
LOG_POWERFSM("State: serialExit");
|
||||
// Turn bluetooth back on when we leave serial stream API
|
||||
setBluetoothEnable(true);
|
||||
}
|
||||
|
||||
static void powerEnter()
|
||||
{
|
||||
// LOG_DEBUG("State: POWER");
|
||||
LOG_POWERFSM("State: powerEnter");
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
|
||||
LOG_INFO("Loss of power in Powered");
|
||||
@@ -210,6 +212,7 @@ static void powerEnter()
|
||||
|
||||
static void powerIdle()
|
||||
{
|
||||
// LOG_POWERFSM("State: powerIdle"); // very chatty
|
||||
if (!isPowered()) {
|
||||
// If we got here, we are in the wrong state
|
||||
LOG_INFO("Loss of power in Powered");
|
||||
@@ -219,14 +222,13 @@ static void powerIdle()
|
||||
|
||||
static void powerExit()
|
||||
{
|
||||
if (screen)
|
||||
screen->setOn(true);
|
||||
LOG_POWERFSM("State: powerExit");
|
||||
setBluetoothEnable(true);
|
||||
}
|
||||
|
||||
static void onEnter()
|
||||
{
|
||||
LOG_DEBUG("State: ON");
|
||||
LOG_POWERFSM("State: onEnter");
|
||||
if (screen)
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
@@ -234,6 +236,7 @@ static void onEnter()
|
||||
|
||||
static void onIdle()
|
||||
{
|
||||
LOG_POWERFSM("State: onIdle");
|
||||
if (isPowered()) {
|
||||
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
|
||||
powerFSM.trigger(EVENT_POWER_CONNECTED);
|
||||
@@ -242,7 +245,7 @@ static void onIdle()
|
||||
|
||||
static void bootEnter()
|
||||
{
|
||||
LOG_DEBUG("State: BOOT");
|
||||
LOG_POWERFSM("State: bootEnter");
|
||||
}
|
||||
|
||||
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
|
||||
@@ -319,11 +322,6 @@ void PowerFSM_setup()
|
||||
// if any packet destined for phone arrives, turn on bluetooth at least
|
||||
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
|
||||
|
||||
// Removed 2.7: we don't show the nodes individually for every node on the screen anymore
|
||||
// powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||
// powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||
// powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
|
||||
|
||||
// Show the received text message
|
||||
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
|
||||
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_MSG, NULL, "Received text");
|
||||
@@ -372,7 +370,7 @@ void PowerFSM_setup()
|
||||
// Don't add power saving transitions if we are a power saving tracker or sensor or have Wifi enabled. Sleep will be initiated
|
||||
// through the modules
|
||||
|
||||
#if HAS_WIFI || !defined(MESHTASTIC_EXCLUDE_WIFI)
|
||||
#if HAS_WIFI && !defined(MESHTASTIC_EXCLUDE_WIFI)
|
||||
bool isTrackerOrSensor = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR;
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef PowerFSMDebug
|
||||
#define LOG_POWERFSM(...) LOG_DEBUG(__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_POWERFSM(...)
|
||||
#endif
|
||||
|
||||
// See sw-design.md for documentation
|
||||
|
||||
#define EVENT_PRESS 1
|
||||
|
||||
@@ -16,6 +16,7 @@ struct ToneDuration {
|
||||
};
|
||||
|
||||
// Some common frequencies.
|
||||
#define NOTE_SILENT 1
|
||||
#define NOTE_C3 131
|
||||
#define NOTE_CS3 139
|
||||
#define NOTE_D3 147
|
||||
@@ -29,11 +30,16 @@ struct ToneDuration {
|
||||
#define NOTE_AS3 233
|
||||
#define NOTE_B3 247
|
||||
#define NOTE_CS4 277
|
||||
#define NOTE_B4 494
|
||||
#define NOTE_F5 698
|
||||
#define NOTE_G6 1568
|
||||
#define NOTE_E7 2637
|
||||
|
||||
const int DURATION_1_16 = 62; // 1/16 note
|
||||
const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
const int DURATION_1_2 = 500; // 1/2 note
|
||||
const int DURATION_3_4 = 750; // 1/4 note
|
||||
const int DURATION_3_4 = 750; // 3/4 note
|
||||
const int DURATION_1_1 = 1000; // 1/1 note
|
||||
|
||||
void playTones(const ToneDuration *tone_durations, int size)
|
||||
@@ -71,13 +77,24 @@ void playLongBeep()
|
||||
|
||||
void playGPSEnableBeep()
|
||||
{
|
||||
#if defined(R1_NEO) || defined(MUZI_BASE)
|
||||
ToneDuration melody[] = {
|
||||
{NOTE_F5, DURATION_1_2}, {NOTE_G6, DURATION_1_8}, {NOTE_E7, DURATION_1_4}, {NOTE_SILENT, DURATION_1_2}};
|
||||
#else
|
||||
ToneDuration melody[] = {{NOTE_C3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_CS4, DURATION_1_4}};
|
||||
#endif
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
void playGPSDisableBeep()
|
||||
{
|
||||
#if defined(R1_NEO) || defined(MUZI_BASE)
|
||||
ToneDuration melody[] = {{NOTE_B4, DURATION_1_16}, {NOTE_B4, DURATION_1_16}, {NOTE_SILENT, DURATION_1_8},
|
||||
{NOTE_F3, DURATION_1_16}, {NOTE_F3, DURATION_1_16}, {NOTE_SILENT, DURATION_1_8},
|
||||
{NOTE_C3, DURATION_1_1}, {NOTE_SILENT, DURATION_1_1}};
|
||||
#else
|
||||
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_C3, DURATION_1_4}};
|
||||
#endif
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,36 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#if __has_include("Melopero_RV3028.h")
|
||||
#include "Melopero_RV3028.h"
|
||||
#endif
|
||||
#if __has_include("pcf8563.h")
|
||||
#include "pcf8563.h"
|
||||
#if __has_include("SensorRtcHelper.hpp")
|
||||
#include "SensorRtcHelper.hpp"
|
||||
#endif
|
||||
|
||||
/* Offer chance for variant-specific defines */
|
||||
#include "variant.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Display feature overrides
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Allow build environments to opt-in explicitly to the E-Ink UI stack while
|
||||
// keeping headless targets slim by default. Existing variants that already
|
||||
// define USE_EINK continue to work without additional flags.
|
||||
#ifndef MESHTASTIC_USE_EINK_UI
|
||||
#ifdef USE_EINK
|
||||
#define MESHTASTIC_USE_EINK_UI 1
|
||||
#else
|
||||
#define MESHTASTIC_USE_EINK_UI 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MESHTASTIC_USE_EINK_UI
|
||||
#ifndef USE_EINK
|
||||
#define USE_EINK
|
||||
#endif
|
||||
#else
|
||||
#undef USE_EINK
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Version
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -250,8 +273,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Touchscreen
|
||||
// -----------------------------------------------------------------------------
|
||||
#define FT6336U_ADDR 0x48
|
||||
#define CST328_ADDR 0x1A
|
||||
#define CST328_ADDR 0x1A // same address as CST226SE
|
||||
#define CHSC6X_ADDR 0x2E
|
||||
#define CST226SE_ADDR_ALT 0x5A
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
|
||||
@@ -370,6 +394,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef HAS_BLUETOOTH
|
||||
#define HAS_BLUETOOTH 0
|
||||
#endif
|
||||
#ifndef USE_TFTDISPLAY
|
||||
#define USE_TFTDISPLAY 0
|
||||
#endif
|
||||
|
||||
#ifndef HW_VENDOR
|
||||
#error HW_VENDOR must be defined
|
||||
@@ -396,6 +423,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define HAS_RGB_LED
|
||||
#endif
|
||||
|
||||
#ifndef LED_STATE_OFF
|
||||
#define LED_STATE_OFF 0
|
||||
#endif
|
||||
#ifndef LED_STATE_ON
|
||||
#define LED_STATE_ON 1
|
||||
#endif
|
||||
|
||||
// default mapping of pins
|
||||
#if defined(PIN_BUTTON2) && !defined(CANCEL_BUTTON_PIN)
|
||||
#define ALT_BUTTON_PIN PIN_BUTTON2
|
||||
|
||||
@@ -25,8 +25,8 @@ ScanI2C::FoundDevice ScanI2C::firstScreen() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563, RTC_RX8130CE};
|
||||
return firstOfOrNONE(3, types);
|
||||
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563, RTC_PCF85063, RTC_RX8130CE};
|
||||
return firstOfOrNONE(4, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
|
||||
@@ -14,6 +14,7 @@ class ScanI2C
|
||||
SCREEN_ST7567,
|
||||
RTC_RV3028,
|
||||
RTC_PCF8563,
|
||||
RTC_PCF85063,
|
||||
RTC_RX8130CE,
|
||||
CARDKB,
|
||||
TDECKKB,
|
||||
@@ -85,7 +86,8 @@ class ScanI2C
|
||||
DRV2605,
|
||||
BH1750,
|
||||
DA217,
|
||||
CHSC6X
|
||||
CHSC6X,
|
||||
CST226SE
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -202,6 +202,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(RX8130CE_RTC, RTC_RX8130CE, "RX8130CE", (uint8_t)addr.address)
|
||||
#endif
|
||||
|
||||
#ifdef PCF85063_RTC
|
||||
SCAN_SIMPLE_CASE(PCF85063_RTC, RTC_PCF85063, "PCF85063", (uint8_t)addr.address)
|
||||
#endif
|
||||
|
||||
case CARDKB_ADDR:
|
||||
// Do we have the RAK14006 instead?
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
|
||||
@@ -499,7 +503,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(CST328_ADDR, CST328, "CST328", (uint8_t)addr.address);
|
||||
case CST328_ADDR:
|
||||
// Do we have the CST328 or the CST226SE
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xAB), 1);
|
||||
if (registerValue == 0xA9) {
|
||||
type = CST226SE;
|
||||
logFoundDevice("CST226SE", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = CST328;
|
||||
logFoundDevice("CST328", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(CHSC6X_ADDR, CHSC6X, "CHSC6X", (uint8_t)addr.address);
|
||||
case LTR553ALS_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x86), 1); // Part ID register
|
||||
@@ -528,8 +543,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
#endif
|
||||
|
||||
case MLX90614_ADDR_DEF:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
|
||||
if (registerValue == 0x5a) {
|
||||
// Do we have the MLX90614 or the MPR121KB or the CST226SE
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x06), 1);
|
||||
if (registerValue == 0xAB) {
|
||||
type = CST226SE;
|
||||
logFoundDevice("CST226SE", (uint8_t)addr.address);
|
||||
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1) == 0x5a) {
|
||||
type = MLX90614;
|
||||
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
||||
} else {
|
||||
@@ -547,6 +566,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
case ICM20948_ADDR: // same as BMX160_ADDR
|
||||
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
||||
#ifdef HAS_ICM20948
|
||||
type = ICM20948;
|
||||
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
||||
break;
|
||||
#endif
|
||||
if (registerValue == 0xEA) {
|
||||
type = ICM20948;
|
||||
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
||||
|
||||
@@ -38,14 +38,16 @@ template <typename T, std::size_t N> std::size_t array_count(const T (&)[N])
|
||||
return N;
|
||||
}
|
||||
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
|
||||
#if defined(GPS_SERIAL_PORT)
|
||||
HardwareSerial *GPS::_serial_gps = &GPS_SERIAL_PORT;
|
||||
#else
|
||||
HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
#ifndef GPS_SERIAL_PORT
|
||||
#define GPS_SERIAL_PORT Serial1
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_NRF52)
|
||||
Uart *GPS::_serial_gps = &GPS_SERIAL_PORT;
|
||||
#elif defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL)
|
||||
HardwareSerial *GPS::_serial_gps = &GPS_SERIAL_PORT;
|
||||
#elif defined(ARCH_RP2040)
|
||||
SerialUART *GPS::_serial_gps = &Serial1;
|
||||
SerialUART *GPS::_serial_gps = &GPS_SERIAL_PORT;
|
||||
#else
|
||||
HardwareSerial *GPS::_serial_gps = nullptr;
|
||||
#endif
|
||||
@@ -1525,10 +1527,7 @@ GPS *GPS::createGps()
|
||||
int8_t _rx_gpio = config.position.rx_gpio;
|
||||
int8_t _tx_gpio = config.position.tx_gpio;
|
||||
int8_t _en_gpio = config.position.gps_en_gpio;
|
||||
#if HAS_GPS && !defined(ARCH_ESP32)
|
||||
_rx_gpio = 1; // We only specify GPS serial ports on ESP32. Otherwise, these are just flags.
|
||||
_tx_gpio = 1;
|
||||
#endif
|
||||
|
||||
#if defined(GPS_RX_PIN)
|
||||
if (!_rx_gpio)
|
||||
_rx_gpio = GPS_RX_PIN;
|
||||
@@ -1602,16 +1601,28 @@ GPS *GPS::createGps()
|
||||
_serial_gps->setRxBufferSize(SERIAL_BUFFER_SIZE); // the default is 256
|
||||
#endif
|
||||
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(ARCH_ESP32)
|
||||
LOG_DEBUG("Use GPIO%d for GPS RX", new_gps->rx_gpio);
|
||||
LOG_DEBUG("Use GPIO%d for GPS TX", new_gps->tx_gpio);
|
||||
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(ARCH_ESP32)
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, new_gps->rx_gpio, new_gps->tx_gpio);
|
||||
#elif defined(ARCH_RP2040)
|
||||
_serial_gps->setPinout(new_gps->tx_gpio, new_gps->rx_gpio);
|
||||
_serial_gps->setFIFOSize(256);
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#else
|
||||
#elif defined(ARCH_NRF52)
|
||||
_serial_gps->setPins(new_gps->rx_gpio, new_gps->tx_gpio);
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#elif defined(ARCH_STM32WL)
|
||||
_serial_gps->setTx(new_gps->tx_gpio);
|
||||
_serial_gps->setRx(new_gps->rx_gpio);
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
// Portduino can't set the GPS pins directly.
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
}
|
||||
return new_gps;
|
||||
|
||||
@@ -194,6 +194,8 @@ class GPS : private concurrency::OSThread
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
#if defined(ARCH_RP2040)
|
||||
static SerialUART *_serial_gps;
|
||||
#elif defined(ARCH_NRF52)
|
||||
static Uart *_serial_gps;
|
||||
#else
|
||||
static HardwareSerial *_serial_gps;
|
||||
#endif
|
||||
|
||||
@@ -66,26 +66,26 @@ RTCSetResult readFromRTC()
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
return RTCSetResultSuccess;
|
||||
} else {
|
||||
LOG_WARN("RTC not found (found address 0x%02X)", rtc_found.address);
|
||||
}
|
||||
#elif defined(PCF8563_RTC)
|
||||
#elif defined(PCF8563_RTC) || defined(PCF85063_RTC)
|
||||
#if defined(PCF8563_RTC)
|
||||
if (rtc_found.address == PCF8563_RTC) {
|
||||
#elif defined(PCF85063_RTC)
|
||||
if (rtc_found.address == PCF85063_RTC) {
|
||||
#endif
|
||||
uint32_t now = millis();
|
||||
PCF8563_Class rtc;
|
||||
SensorRtcHelper rtc;
|
||||
|
||||
#if WIRE_INTERFACES_COUNT == 2
|
||||
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||
#else
|
||||
rtc.begin();
|
||||
rtc.begin(Wire);
|
||||
#endif
|
||||
|
||||
auto tc = rtc.getDateTime();
|
||||
tm t;
|
||||
t.tm_year = tc.year - 1900;
|
||||
t.tm_mon = tc.month - 1;
|
||||
t.tm_mday = tc.day;
|
||||
t.tm_hour = tc.hour;
|
||||
t.tm_min = tc.minute;
|
||||
t.tm_sec = tc.second;
|
||||
RTC_DateTime datetime = rtc.getDateTime();
|
||||
tm t = datetime.toUnixTime();
|
||||
tv.tv_sec = gm_mktime(&t);
|
||||
tv.tv_usec = 0;
|
||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
@@ -100,19 +100,25 @@ RTCSetResult readFromRTC()
|
||||
}
|
||||
#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);
|
||||
LOG_DEBUG("Read RTC time from %s getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", rtc.getChipName(), t.tm_year + 1900,
|
||||
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
||||
if (currentQuality == RTCQualityNone) {
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv.tv_sec;
|
||||
currentQuality = RTCQualityDevice;
|
||||
}
|
||||
return RTCSetResultSuccess;
|
||||
} else {
|
||||
LOG_WARN("RTC not found (found address 0x%02X)", rtc_found.address);
|
||||
}
|
||||
#elif defined(RX8130CE_RTC)
|
||||
if (rtc_found.address == RX8130CE_RTC) {
|
||||
uint32_t now = millis();
|
||||
#ifdef MUZI_BASE
|
||||
ArtronShop_RX8130CE rtc(&Wire1);
|
||||
#else
|
||||
ArtronShop_RX8130CE rtc(&Wire);
|
||||
#endif
|
||||
tm t;
|
||||
if (rtc.getTime(&t)) {
|
||||
tv.tv_sec = gm_mktime(&t);
|
||||
@@ -228,24 +234,36 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
||||
} else {
|
||||
LOG_WARN("RTC not found (found address 0x%02X)", rtc_found.address);
|
||||
}
|
||||
#elif defined(PCF8563_RTC)
|
||||
#elif defined(PCF8563_RTC) || defined(PCF85063_RTC)
|
||||
#if defined(PCF8563_RTC)
|
||||
if (rtc_found.address == PCF8563_RTC) {
|
||||
PCF8563_Class rtc;
|
||||
#elif defined(PCF85063_RTC)
|
||||
if (rtc_found.address == PCF85063_RTC) {
|
||||
#endif
|
||||
SensorRtcHelper rtc;
|
||||
|
||||
#if WIRE_INTERFACES_COUNT == 2
|
||||
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
|
||||
#else
|
||||
rtc.begin();
|
||||
rtc.begin(Wire);
|
||||
#endif
|
||||
tm *t = gmtime(&tv->tv_sec);
|
||||
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
|
||||
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
||||
rtc.setDateTime(*t);
|
||||
LOG_DEBUG("%s setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", rtc.getChipName(), t->tm_year + 1900, t->tm_mon + 1,
|
||||
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
|
||||
} else {
|
||||
LOG_WARN("RTC not found (found address 0x%02X)", rtc_found.address);
|
||||
}
|
||||
#elif defined(RX8130CE_RTC)
|
||||
if (rtc_found.address == RX8130CE_RTC) {
|
||||
#ifdef MUZI_BASE
|
||||
ArtronShop_RX8130CE rtc(&Wire1);
|
||||
#else
|
||||
ArtronShop_RX8130CE rtc(&Wire);
|
||||
#endif
|
||||
tm *t = gmtime(&tv->tv_sec);
|
||||
if (rtc.setTime(*t)) {
|
||||
LOG_DEBUG("RX8130CE setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1,
|
||||
|
||||
@@ -69,7 +69,11 @@ using graphics::Emote;
|
||||
using graphics::emotes;
|
||||
using graphics::numEmotes;
|
||||
|
||||
#if USE_TFTDISPLAY
|
||||
extern uint16_t TFT_MESH;
|
||||
#else
|
||||
uint16_t TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
@@ -226,24 +230,9 @@ void Screen::showTextInput(const char *header, const char *initialText, uint32_t
|
||||
{
|
||||
LOG_INFO("showTextInput called with header='%s', durationMs=%d", header ? header : "NULL", durationMs);
|
||||
|
||||
if (NotificationRenderer::virtualKeyboard) {
|
||||
delete NotificationRenderer::virtualKeyboard;
|
||||
NotificationRenderer::virtualKeyboard = nullptr;
|
||||
}
|
||||
|
||||
NotificationRenderer::textInputCallback = nullptr;
|
||||
|
||||
NotificationRenderer::virtualKeyboard = new VirtualKeyboard();
|
||||
if (header) {
|
||||
NotificationRenderer::virtualKeyboard->setHeader(header);
|
||||
}
|
||||
if (initialText) {
|
||||
NotificationRenderer::virtualKeyboard->setInputText(initialText);
|
||||
}
|
||||
|
||||
// Set up callback with safer cleanup mechanism
|
||||
// Start OnScreenKeyboardModule session (non-touch variant)
|
||||
OnScreenKeyboardModule::instance().start(header, initialText, durationMs, textCallback);
|
||||
NotificationRenderer::textInputCallback = textCallback;
|
||||
NotificationRenderer::virtualKeyboard->setCallback([textCallback](const std::string &text) { textCallback(text); });
|
||||
|
||||
// Store the message and set the expiration timestamp (use same pattern as other notifications)
|
||||
strncpy(NotificationRenderer::alertBannerMessage, header ? header : "Text Input", 255);
|
||||
@@ -324,7 +313,7 @@ static int8_t prevFrame = -1;
|
||||
// Combined dynamic node list frame cycling through LastHeard, HopSignal, and Distance modes
|
||||
// Uses a single frame and changes data every few seconds (E-Ink variant is separate)
|
||||
|
||||
#if defined(ESP_PLATFORM) && defined(USE_ST7789)
|
||||
#if defined(ESP_PLATFORM) && (defined(USE_ST7789) || defined(USE_ST7796))
|
||||
SPIClass SPI1(HSPI);
|
||||
#endif
|
||||
|
||||
@@ -356,7 +345,13 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#else
|
||||
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
#endif
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#elif defined(USE_ST7796)
|
||||
#ifdef ESP_PLATFORM
|
||||
dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7796_SDA,
|
||||
ST7796_MISO, ST7796_SCK, TFT_SPI_FREQUENCY);
|
||||
#else
|
||||
dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||
#endif
|
||||
#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);
|
||||
@@ -369,7 +364,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
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)
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(HACKADAY_COMMUNICATOR)
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
||||
@@ -399,6 +394,12 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
isAUTOOled = true;
|
||||
#endif
|
||||
|
||||
#if defined(USE_ST7789)
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#elif defined(USE_ST7796)
|
||||
static_cast<ST7796Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#endif
|
||||
|
||||
ui = new OLEDDisplayUi(dispdev);
|
||||
cmdQueue.setReader(this);
|
||||
}
|
||||
@@ -435,6 +436,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
|
||||
#if defined(MUZI_BASE)
|
||||
dispdev->init();
|
||||
dispdev->setBrightness(brightness);
|
||||
dispdev->flipScreenVertically();
|
||||
dispdev->resetDisplay();
|
||||
digitalWrite(SCREEN_12V_ENABLE, HIGH);
|
||||
delay(100);
|
||||
#endif
|
||||
#if !ARCH_PORTDUINO
|
||||
dispdev->displayOn();
|
||||
#endif
|
||||
@@ -466,6 +475,15 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
pinMode(VTFT_LEDA, OUTPUT);
|
||||
digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_ST7796
|
||||
ui->init();
|
||||
#ifdef ESP_PLATFORM
|
||||
analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT);
|
||||
#else
|
||||
pinMode(VTFT_LEDA, OUTPUT);
|
||||
digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#endif
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
@@ -484,6 +502,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
#endif
|
||||
|
||||
dispdev->displayOff();
|
||||
|
||||
#ifdef SCREEN_12V_ENABLE
|
||||
digitalWrite(SCREEN_12V_ENABLE, LOW);
|
||||
#endif
|
||||
#ifdef USE_ST7789
|
||||
SPI1.end();
|
||||
#if defined(ARCH_ESP32)
|
||||
@@ -500,6 +522,21 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
nrf_gpio_cfg_default(ST7789_NSS);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_ST7796
|
||||
SPI1.end();
|
||||
#if defined(ARCH_ESP32)
|
||||
pinMode(VTFT_LEDA, OUTPUT);
|
||||
digitalWrite(VTFT_LEDA, LOW);
|
||||
pinMode(ST7796_RESET, ANALOG);
|
||||
pinMode(ST7796_RS, ANALOG);
|
||||
pinMode(ST7796_NSS, ANALOG);
|
||||
#else
|
||||
nrf_gpio_cfg_default(VTFT_LEDA);
|
||||
nrf_gpio_cfg_default(ST7796_RESET);
|
||||
nrf_gpio_cfg_default(ST7796_RS);
|
||||
nrf_gpio_cfg_default(ST7796_NSS);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
||||
@@ -534,7 +571,7 @@ void Screen::setup()
|
||||
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SH1107_128_64
|
||||
#if defined(USE_SH1107_128_64) || defined(USE_SH1107)
|
||||
static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
|
||||
#endif
|
||||
|
||||
@@ -542,6 +579,13 @@ void Screen::setup()
|
||||
// Apply custom RGB color (e.g. Heltec T114/T190)
|
||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#endif
|
||||
#if defined(MUZI_BASE)
|
||||
dispdev->delayPoweron = true;
|
||||
#endif
|
||||
#if defined(USE_ST7796) && defined(TFT_MESH)
|
||||
// Custom text color, if defined in variant.h
|
||||
static_cast<ST7796Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||
#endif
|
||||
|
||||
// === Initialize display and UI system ===
|
||||
ui->init();
|
||||
@@ -601,10 +645,12 @@ void Screen::setup()
|
||||
#else
|
||||
if (!config.display.flip_screen) {
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(HACKADAY_COMMUNICATOR)
|
||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||
#elif defined(USE_ST7789)
|
||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||
#elif defined(USE_ST7796)
|
||||
static_cast<ST7796Spi *>(dispdev)->mirrorScreen();
|
||||
#elif !defined(M5STACK_UNITC6L)
|
||||
dispdev->flipScreenVertically();
|
||||
#endif
|
||||
@@ -637,7 +683,7 @@ void Screen::setup()
|
||||
touchScreenImpl1->init();
|
||||
}
|
||||
}
|
||||
#elif HAS_TOUCHSCREEN && !defined(USE_EINK)
|
||||
#elif HAS_TOUCHSCREEN && !defined(USE_EINK) && !HAS_CST226SE
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
@@ -1452,14 +1498,14 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
// Incoming message
|
||||
devicestate.has_rx_text_message = true; // Needed to include the message frame
|
||||
hasUnreadMessage = true; // Enables mail icon in the header
|
||||
setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view
|
||||
setFrames(FOCUS_PRESERVE); // Refresh frame list without switching view (no-op during text_input)
|
||||
|
||||
// Only wake/force display if the configuration allows it
|
||||
if (shouldWakeOnReceivedMessage()) {
|
||||
setOn(true); // Wake up the screen first
|
||||
forceDisplay(); // Forces screen redraw
|
||||
}
|
||||
// === Prepare banner content ===
|
||||
// === Prepare banner/popup content ===
|
||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
||||
const meshtastic_Channel channel =
|
||||
channels.getByIndex(packet->channel ? packet->channel : channels.getPrimaryIndex());
|
||||
@@ -1483,38 +1529,84 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
|
||||
// Unlike generic messages, alerts (when enabled via the ext notif module) ignore any
|
||||
// 'mute' preferences set to any specific node or channel.
|
||||
if (isAlert) {
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||
} else {
|
||||
strcpy(banner, "Alert Received");
|
||||
// If on-screen keyboard is active, show a transient popup over keyboard instead of interrupting it
|
||||
if (NotificationRenderer::current_notification_type == notificationTypeEnum::text_input) {
|
||||
// Wake and force redraw so popup is visible immediately
|
||||
if (shouldWakeOnReceivedMessage()) {
|
||||
setOn(true);
|
||||
forceDisplay();
|
||||
}
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
} else if (!channel.settings.has_module_settings || !channel.settings.module_settings.is_muted) {
|
||||
if (longName && longName[0]) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
strcpy(banner, "New Message");
|
||||
#else
|
||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||
#endif
|
||||
|
||||
// Build popup: title = message source name, content = message text (sanitized)
|
||||
// Title
|
||||
char titleBuf[64] = {0};
|
||||
if (longName && longName[0]) {
|
||||
// Sanitize sender name
|
||||
std::string t = sanitizeString(longName);
|
||||
strncpy(titleBuf, t.c_str(), sizeof(titleBuf) - 1);
|
||||
} else {
|
||||
strcpy(banner, "New Message");
|
||||
strncpy(titleBuf, "Message", sizeof(titleBuf) - 1);
|
||||
}
|
||||
|
||||
// Content: payload bytes may not be null-terminated, remove ASCII_BELL and sanitize
|
||||
char content[256] = {0};
|
||||
{
|
||||
std::string raw;
|
||||
raw.reserve(packet->decoded.payload.size);
|
||||
for (size_t i = 0; i < packet->decoded.payload.size; ++i) {
|
||||
char c = msgRaw[i];
|
||||
if (c == ASCII_BELL)
|
||||
continue; // strip bell
|
||||
raw.push_back(c);
|
||||
}
|
||||
std::string sanitized = sanitizeString(raw);
|
||||
strncpy(content, sanitized.c_str(), sizeof(content) - 1);
|
||||
}
|
||||
|
||||
NotificationRenderer::showKeyboardMessagePopupWithTitle(titleBuf, content, 3000);
|
||||
|
||||
// Maintain existing buzzer behavior on M5 if applicable
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
screen->setOn(true);
|
||||
screen->showSimpleBanner(banner, 1500);
|
||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||
(isAlert && moduleConfig.external_notification.alert_bell_buzzer) ||
|
||||
(!isBroadcast(packet->to) && isToUs(packet))) {
|
||||
// Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either
|
||||
// - packet contains an alert and alert bell buzzer is enabled
|
||||
// - packet is a non-broadcast that is addressed to this node
|
||||
playLongBeep();
|
||||
}
|
||||
#else
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
#endif
|
||||
} else {
|
||||
// No keyboard active: use regular banner flow, respecting mute settings
|
||||
if (isAlert) {
|
||||
if (longName && longName[0]) {
|
||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||
} else {
|
||||
strcpy(banner, "Alert Received");
|
||||
}
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
} else if (!channel.settings.has_module_settings || !channel.settings.module_settings.is_muted) {
|
||||
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);
|
||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||
(isAlert && moduleConfig.external_notification.alert_bell_buzzer) ||
|
||||
(!isBroadcast(packet->to) && isToUs(packet))) {
|
||||
// Beep if not in DIRECT_MSG_ONLY mode or if in DIRECT_MSG_ONLY mode and either
|
||||
// - packet contains an alert and alert bell buzzer is enabled
|
||||
// - packet is a non-broadcast that is addressed to this node
|
||||
playLongBeep();
|
||||
}
|
||||
#else
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1549,6 +1641,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
|
||||
int Screen::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
LOG_INPUT("Screen Input event %u! kb %u", event->inputEvent, event->kbchar);
|
||||
if (!screenOn)
|
||||
return 0;
|
||||
|
||||
@@ -1596,6 +1689,12 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == INPUT_BROKER_RIGHT || event->inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
showNextFrame();
|
||||
} else if (event->inputEvent == INPUT_BROKER_UP_LONG) {
|
||||
// Long press up button for fast frame switching
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||
// Long press down button for fast frame switching
|
||||
showNextFrame();
|
||||
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
||||
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
||||
menuHandler::homeBaseMenu();
|
||||
|
||||
@@ -83,6 +83,8 @@ class Screen
|
||||
#include <ST7789Spi.h>
|
||||
#elif defined(USE_SPISSD1306)
|
||||
#include <SSD1306Spi.h>
|
||||
#elif defined(USE_ST7796)
|
||||
#include <ST7796Spi.h>
|
||||
#else
|
||||
// the SH1106/SSD1306 variant is auto-detected
|
||||
#include <AutoOLEDWire.h>
|
||||
@@ -249,6 +251,8 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
bool isOverlayBannerShowing();
|
||||
|
||||
bool isScreenOn() { return screenOn; }
|
||||
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
// FIXME: Needs refactoring and getMacAddr needs to be moved to a utility class
|
||||
char ourId[5];
|
||||
|
||||
@@ -73,7 +73,8 @@
|
||||
#endif
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||
defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||
|
||||
@@ -17,6 +17,12 @@ namespace graphics
|
||||
|
||||
void determineResolution(int16_t screenheight, int16_t screenwidth)
|
||||
{
|
||||
|
||||
#ifdef FORCE_LOW_RES
|
||||
isHighResolution = false;
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (screenwidth > 128) {
|
||||
isHighResolution = true;
|
||||
}
|
||||
@@ -24,11 +30,6 @@ void determineResolution(int16_t screenheight, int16_t screenwidth)
|
||||
if (screenwidth > 128 && screenheight <= 64) {
|
||||
isHighResolution = false;
|
||||
}
|
||||
|
||||
// Special case for Heltec Wireless Tracker v1.1
|
||||
if (screenwidth == 160 && screenheight == 80) {
|
||||
isHighResolution = false;
|
||||
}
|
||||
}
|
||||
|
||||
// === Shared External State ===
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#if USE_TFTDISPLAY
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
@@ -123,6 +124,11 @@ static void rak14014_tpIntHandle(void)
|
||||
_rak14014_touch_int = true;
|
||||
}
|
||||
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
#include <Arduino_GFX_Library.h>
|
||||
Arduino_DataBus *bus = nullptr;
|
||||
Arduino_GFX *tft = nullptr;
|
||||
|
||||
#elif defined(ST72xx_DE)
|
||||
#include <LovyanGFX.hpp>
|
||||
#include <TCA9534.h>
|
||||
@@ -427,33 +433,35 @@ static LGFX *tft = nullptr;
|
||||
#include "lgfx/v1/Touch.hpp"
|
||||
namespace lgfx
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
class TOUCH_CHSC6X : public ITouch
|
||||
{
|
||||
public:
|
||||
public:
|
||||
TOUCH_CHSC6X(void)
|
||||
{
|
||||
_cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||
_cfg.x_min = 0;
|
||||
_cfg.x_max = 240;
|
||||
_cfg.y_min = 0;
|
||||
_cfg.y_max = 320;
|
||||
_cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||
_cfg.x_min = 0;
|
||||
_cfg.x_max = 240;
|
||||
_cfg.y_min = 0;
|
||||
_cfg.y_max = 320;
|
||||
};
|
||||
|
||||
bool init(void) override {
|
||||
if(chsc6xTouch==nullptr) {
|
||||
chsc6xTouch=new chsc6x(&Wire1,TOUCH_SDA_PIN,TOUCH_SCL_PIN,TOUCH_INT_PIN,TOUCH_RST_PIN);
|
||||
bool init(void) override
|
||||
{
|
||||
if (chsc6xTouch == nullptr) {
|
||||
chsc6xTouch = new chsc6x(&Wire1, TOUCH_SDA_PIN, TOUCH_SCL_PIN, TOUCH_INT_PIN, TOUCH_RST_PIN);
|
||||
}
|
||||
chsc6xTouch->chsc6x_init();
|
||||
return true;
|
||||
};
|
||||
|
||||
uint_fast8_t getTouchRaw(touch_point_t* tp, uint_fast8_t count) override {
|
||||
uint16_t raw_x,raw_y;
|
||||
if (chsc6xTouch->chsc6x_read_touch_info(&raw_x, &raw_y)==0) {
|
||||
tp[0].x = 320-1-raw_y;
|
||||
tp[0].y = 240-1-raw_x ;
|
||||
uint_fast8_t getTouchRaw(touch_point_t *tp, uint_fast8_t count) override
|
||||
{
|
||||
uint16_t raw_x, raw_y;
|
||||
if (chsc6xTouch->chsc6x_read_touch_info(&raw_x, &raw_y) == 0) {
|
||||
tp[0].x = 320 - 1 - raw_y;
|
||||
tp[0].y = 240 - 1 - raw_x;
|
||||
tp[0].size = 1;
|
||||
tp[0].id = 1;
|
||||
return 1;
|
||||
@@ -462,13 +470,14 @@ public:
|
||||
return 0;
|
||||
};
|
||||
|
||||
void wakeup(void) override {};
|
||||
void sleep(void) override {};
|
||||
void wakeup(void) override{};
|
||||
void sleep(void) override{};
|
||||
|
||||
private:
|
||||
chsc6x *chsc6xTouch=nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
chsc6x *chsc6xTouch = nullptr;
|
||||
};
|
||||
} // namespace v1
|
||||
} // namespace lgfx
|
||||
#endif
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
@@ -513,9 +522,9 @@ class LGFX : public lgfx::LGFX_Device
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = ST7789_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = ST7789_RESET; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = ST7789_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
cfg.pin_cs = ST7789_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = ST7789_RESET; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = ST7789_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
@@ -1130,9 +1139,6 @@ static LGFX *tft = nullptr;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ST7796_CS) || defined(ILI9341_DRIVER) || \
|
||||
defined(ILI9342_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || \
|
||||
(ARCH_PORTDUINO && HAS_SCREEN != 0)
|
||||
#include "SPILock.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
@@ -1268,12 +1274,15 @@ void TFTDisplay::display(bool fromBlank)
|
||||
x_LastPixelUpdate = x;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HACKADAY_COMMUNICATOR)
|
||||
tft->draw16bitBeRGBBitmap(x_FirstPixelUpdate, y, &linePixelBuffer[x_FirstPixelUpdate],
|
||||
(x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1);
|
||||
#else
|
||||
// Step 4: Send the changed pixels on this line to the screen as a single block transfer.
|
||||
// This function accepts pixel data MSB first so it can dump the memory straight out the SPI port.
|
||||
tft->pushRect(x_FirstPixelUpdate, y, (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1,
|
||||
&linePixelBuffer[x_FirstPixelUpdate]);
|
||||
|
||||
#endif
|
||||
somethingChanged = true;
|
||||
}
|
||||
y++;
|
||||
@@ -1337,6 +1346,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
display(true);
|
||||
if (portduino_config.displayBacklight.pin > 0)
|
||||
digitalWrite(portduino_config.displayBacklight.pin, TFT_BACKLIGHT_ON);
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
tft->displayOn();
|
||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||
tft->wakeup();
|
||||
tft->powerSaveOff();
|
||||
@@ -1349,7 +1360,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
unphone.backlight(true); // using unPhone library
|
||||
#endif
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK) && !defined(ST7789_CS) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function
|
||||
#elif !defined(M5STACK) && !defined(ST7789_CS) && \
|
||||
!defined(HACKADAY_COMMUNICATOR) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function
|
||||
tft->setBrightness(172);
|
||||
#endif
|
||||
break;
|
||||
@@ -1361,6 +1373,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
tft->clear();
|
||||
if (portduino_config.displayBacklight.pin > 0)
|
||||
digitalWrite(portduino_config.displayBacklight.pin, !TFT_BACKLIGHT_ON);
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
tft->displayOff();
|
||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||
tft->sleep();
|
||||
tft->powerSaveOn();
|
||||
@@ -1373,7 +1387,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
unphone.backlight(false); // using unPhone library
|
||||
#endif
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR)
|
||||
tft->setBrightness(0);
|
||||
#endif
|
||||
break;
|
||||
@@ -1389,7 +1403,7 @@ void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
|
||||
{
|
||||
#ifdef RAK14014
|
||||
// todo
|
||||
#else
|
||||
#elif !defined(HACKADAY_COMMUNICATOR)
|
||||
tft->setBrightness(_brightness);
|
||||
LOG_DEBUG("Brightness is set to value: %i ", _brightness);
|
||||
#endif
|
||||
@@ -1407,7 +1421,7 @@ bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifdef RAK14014
|
||||
return true;
|
||||
#elif !defined(M5STACK)
|
||||
#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR)
|
||||
return tft->touch() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
@@ -1426,7 +1440,7 @@ bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#elif !defined(M5STACK)
|
||||
#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR)
|
||||
return tft->getTouch(x, y);
|
||||
#else
|
||||
return false;
|
||||
@@ -1445,6 +1459,12 @@ bool TFTDisplay::connect()
|
||||
LOG_INFO("Do TFT init");
|
||||
#ifdef RAK14014
|
||||
tft = new TFT_eSPI;
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, 38 /* SCK */, 21 /* MOSI */, GFX_NOT_DEFINED /* MISO */, HSPI /* spi_num */);
|
||||
tft = new Arduino_NV3007(bus, 40, 0 /* rotation */, false /* IPS */, 142 /* width */, 428 /* height */, 12 /* col offset 1 */,
|
||||
0 /* row offset 1 */, 14 /* col offset 2 */, 0 /* row offset 2 */, nv3007_279_init_operations,
|
||||
sizeof(nv3007_279_init_operations));
|
||||
|
||||
#else
|
||||
tft = new LGFX;
|
||||
#endif
|
||||
@@ -1455,8 +1475,15 @@ bool TFTDisplay::connect()
|
||||
#ifdef UNPHONE
|
||||
unphone.backlight(true); // using unPhone library
|
||||
#endif
|
||||
|
||||
#ifdef HACKADAY_COMMUNICATOR
|
||||
bool beginStatus = tft->begin();
|
||||
if (beginStatus)
|
||||
LOG_DEBUG("TFT Success!");
|
||||
else
|
||||
LOG_ERROR("TFT Fail!");
|
||||
#else
|
||||
tft->init();
|
||||
#endif
|
||||
|
||||
#if defined(M5STACK)
|
||||
tft->setRotation(0);
|
||||
@@ -1489,4 +1516,4 @@ bool TFTDisplay::connect()
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // USE_TFTDISPLAY
|
||||
|
||||
@@ -101,3 +101,23 @@ void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength)
|
||||
else
|
||||
snprintf(timeStr, maxLength, "unknown age");
|
||||
}
|
||||
|
||||
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs)
|
||||
{
|
||||
uint32_t days = uptimeMillis / 86400000;
|
||||
uint32_t hours = (uptimeMillis % 86400000) / 3600000;
|
||||
uint32_t mins = (uptimeMillis % 3600000) / 60000;
|
||||
uint32_t secs = (uptimeMillis % 60000) / 1000;
|
||||
|
||||
if (days) {
|
||||
snprintf(uptimeStr, maxLength, "%s: %ud %uh", prefix, days, hours);
|
||||
} else if (hours) {
|
||||
snprintf(uptimeStr, maxLength, "%s: %uh %um", prefix, hours, mins);
|
||||
} else if (!includeSecs) {
|
||||
snprintf(uptimeStr, maxLength, "%s: %um", prefix, mins);
|
||||
} else if (mins) {
|
||||
snprintf(uptimeStr, maxLength, "%s: %um %us", prefix, mins, secs);
|
||||
} else {
|
||||
snprintf(uptimeStr, maxLength, "%s: %us", prefix, secs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,10 @@ bool deltaToTimestamp(uint32_t secondsAgo, uint8_t *hours, uint8_t *minutes, int
|
||||
* @param maxLength Maximum length of the resulting string buffer
|
||||
*/
|
||||
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
||||
|
||||
/**
|
||||
* Get a compact human-readable string that only shows the largest non-zero time components.
|
||||
* For example, 0 days 1 hour 2 minutes will display as "1h 2m" but 1 day 2 hours 3 minutes
|
||||
* will display as "1d 2h".
|
||||
*/
|
||||
void getUptimeStr(uint32_t uptimeMillis, const char *prefix, char *uptimeStr, uint8_t maxLength, bool includeSecs = false);
|
||||
|
||||
@@ -506,6 +506,9 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
|
||||
centeredTextY -= 1;
|
||||
}
|
||||
}
|
||||
#ifdef MUZI_BASE // Correct issue with character vertical position on MUZI_BASE
|
||||
centeredTextY -= 2;
|
||||
#endif
|
||||
display->drawString(textX, centeredTextY, keyText.c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/TimeFormatters.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "mesh/Channels.h"
|
||||
@@ -96,7 +97,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
||||
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796) || ARCH_PORTDUINO) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
||||
8, imgQuestionL1);
|
||||
@@ -108,7 +109,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
||||
#endif
|
||||
} else {
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
||||
8, imgSFL1);
|
||||
@@ -124,7 +126,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
||||
// TODO: Raspberry Pi supports more than just the one screen size
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796) || ARCH_PORTDUINO) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
@@ -530,8 +532,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
const int labelX = x;
|
||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
#ifdef USE_EINK
|
||||
#ifndef T_DECK_PRO
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int barX = x + 45 + barsOffset;
|
||||
#else
|
||||
@@ -572,7 +576,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
#endif
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||
display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr);
|
||||
};
|
||||
|
||||
// === Memory values ===
|
||||
@@ -650,17 +654,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
|
||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it
|
||||
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 (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), " Uptime: %um", mins);
|
||||
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||
textWidth = display->getStringWidth(uptimeStr);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], uptimeStr);
|
||||
@@ -729,4 +723,4 @@ void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int1
|
||||
|
||||
} // namespace DebugRenderer
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -13,18 +13,48 @@
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "main.h"
|
||||
#include "mesh/Default.h"
|
||||
#include "mesh/MeshTypes.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "modules/KeyVerificationModule.h"
|
||||
|
||||
#include "modules/TraceRouteModule.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
extern uint16_t TFT_MESH;
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Caller must ensure the provided options array outlives the banner callback.
|
||||
template <typename T, size_t N, typename Callback>
|
||||
BannerOverlayOptions createStaticBannerOptions(const char *message, const MenuOption<T> (&options)[N],
|
||||
std::array<const char *, N> &labels, Callback &&onSelection)
|
||||
{
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
labels[i] = options[i].label;
|
||||
}
|
||||
|
||||
const MenuOption<T> *optionsPtr = options;
|
||||
auto callback = std::function<void(const MenuOption<T> &, int)>(std::forward<Callback>(onSelection));
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = message;
|
||||
bannerOptions.optionsArrayPtr = labels.data();
|
||||
bannerOptions.optionsCount = static_cast<uint8_t>(N);
|
||||
bannerOptions.bannerCallback = [optionsPtr, callback](int selected) -> void { callback(optionsPtr[selected], selected); };
|
||||
return bannerOptions;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
menuHandler::screenMenus menuHandler::menuQueue = menu_none;
|
||||
bool test_enabled = false;
|
||||
uint8_t test_count = 0;
|
||||
@@ -119,6 +149,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
auto changes = SEGMENT_CONFIG;
|
||||
|
||||
// This is needed as we wait til picking the LoRa region to generate keys for the first time.
|
||||
#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
|
||||
if (!owner.is_licensed) {
|
||||
bool keygenSuccess = false;
|
||||
if (config.security.private_key.size == 32) {
|
||||
@@ -139,6 +170,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
config.lora.tx_enabled = true;
|
||||
initRegion();
|
||||
if (myRegion->dutyCycle < 100) {
|
||||
@@ -194,48 +226,38 @@ void menuHandler::DeviceRolePicker()
|
||||
|
||||
void menuHandler::RadioPresetPicker()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "LongSlow", "LongModerate", "LongFast", "MediumSlow",
|
||||
"MediumFast", "ShortSlow", "ShortFast", "ShortTurbo"};
|
||||
enum optionsNumbers {
|
||||
Back = 0,
|
||||
radiopreset_LongSlow = 1,
|
||||
radiopreset_LongModerate = 2,
|
||||
radiopreset_LongFast = 3,
|
||||
radiopreset_MediumSlow = 4,
|
||||
radiopreset_MediumFast = 5,
|
||||
radiopreset_ShortSlow = 6,
|
||||
radiopreset_ShortFast = 7,
|
||||
radiopreset_ShortTurbo = 8
|
||||
};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Radio Preset";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 9;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Back) {
|
||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
||||
screen->runNow();
|
||||
return;
|
||||
} else if (selected == radiopreset_LongSlow) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW;
|
||||
} else if (selected == radiopreset_LongModerate) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE;
|
||||
} else if (selected == radiopreset_LongFast) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
} else if (selected == radiopreset_MediumSlow) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW;
|
||||
} else if (selected == radiopreset_MediumFast) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST;
|
||||
} else if (selected == radiopreset_ShortSlow) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW;
|
||||
} else if (selected == radiopreset_ShortFast) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST;
|
||||
} else if (selected == radiopreset_ShortTurbo) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO;
|
||||
}
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
static const RadioPresetOption presetOptions[] = {
|
||||
{"Back", OptionsAction::Back},
|
||||
{"LongTurbo", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO},
|
||||
{"LongModerate", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE},
|
||||
{"LongFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST},
|
||||
{"MediumSlow", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW},
|
||||
{"MediumFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST},
|
||||
{"ShortSlow", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW},
|
||||
{"ShortFast", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST},
|
||||
{"ShortTurbo", OptionsAction::Select, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO},
|
||||
};
|
||||
|
||||
constexpr size_t presetCount = sizeof(presetOptions) / sizeof(presetOptions[0]);
|
||||
static std::array<const char *, presetCount> presetLabels{};
|
||||
|
||||
auto bannerOptions =
|
||||
createStaticBannerOptions("Radio Preset", presetOptions, presetLabels, [](const RadioPresetOption &option, int) -> void {
|
||||
if (option.action == OptionsAction::Back) {
|
||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
||||
screen->runNow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!option.hasValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
config.lora.modem_preset = option.value;
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
});
|
||||
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
@@ -574,7 +596,7 @@ void menuHandler::textMessageBaseMenu()
|
||||
|
||||
void menuHandler::systemBaseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, PowerMenu, Test, enumEnd };
|
||||
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, WiFiToggle, PowerMenu, Test, enumEnd };
|
||||
static const char *optionsArray[enumEnd] = {"Back"};
|
||||
static int optionsEnumArray[enumEnd] = {Back};
|
||||
int options = 1;
|
||||
@@ -590,6 +612,10 @@ void menuHandler::systemBaseMenu()
|
||||
optionsArray[options] = "Bluetooth Toggle";
|
||||
#endif
|
||||
optionsEnumArray[options++] = Bluetooth;
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
optionsArray[options] = "WiFi Toggle";
|
||||
optionsEnumArray[options++] = WiFiToggle;
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
optionsArray[options] = "Power";
|
||||
#else
|
||||
@@ -627,6 +653,11 @@ void menuHandler::systemBaseMenu()
|
||||
} else if (selected == Bluetooth) {
|
||||
menuQueue = bluetooth_toggle_menu;
|
||||
screen->runNow();
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
} else if (selected == WiFiToggle) {
|
||||
menuQueue = wifi_toggle_menu;
|
||||
screen->runNow();
|
||||
#endif
|
||||
} else if (selected == Back && !test_enabled) {
|
||||
test_count++;
|
||||
if (test_count > 4) {
|
||||
@@ -935,7 +966,9 @@ void menuHandler::BluetoothToggleMenu()
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 3;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == 1 || selected == 2) {
|
||||
if (selected == 0)
|
||||
return;
|
||||
else if (selected != (config.bluetooth.enabled ? 1 : 2)) {
|
||||
InputEvent event = {.inputEvent = (input_broker_event)170, .kbchar = 170, .touchX = 0, .touchY = 0};
|
||||
inputBroker->injectInputEvent(&event);
|
||||
}
|
||||
@@ -1027,14 +1060,16 @@ void menuHandler::switchToMUIMenu()
|
||||
|
||||
void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Teal",
|
||||
"Pink", "White"};
|
||||
static const char *optionsArray[] = {
|
||||
"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Blue", "Teal", "Cyan", "Ice", "Pink",
|
||||
"White", "Gray"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Select Screen Color";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 10;
|
||||
bannerOptions.optionsCount = 14;
|
||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || \
|
||||
HAS_TFT || defined(HACKADAY_COMMUNICATOR)
|
||||
uint8_t TFT_MESH_r = 0;
|
||||
uint8_t TFT_MESH_g = 0;
|
||||
uint8_t TFT_MESH_b = 0;
|
||||
@@ -1067,20 +1102,40 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
TFT_MESH_g = 153;
|
||||
TFT_MESH_b = 255;
|
||||
} else if (selected == 7) {
|
||||
LOG_INFO("Setting color to Teal");
|
||||
TFT_MESH_r = 64;
|
||||
TFT_MESH_g = 224;
|
||||
TFT_MESH_b = 208;
|
||||
LOG_INFO("Setting color to Blue");
|
||||
TFT_MESH_r = 0;
|
||||
TFT_MESH_g = 0;
|
||||
TFT_MESH_b = 255;
|
||||
} else if (selected == 8) {
|
||||
LOG_INFO("Setting color to Teal");
|
||||
TFT_MESH_r = 16;
|
||||
TFT_MESH_g = 102;
|
||||
TFT_MESH_b = 102;
|
||||
} else if (selected == 9) {
|
||||
LOG_INFO("Setting color to Cyan");
|
||||
TFT_MESH_r = 0;
|
||||
TFT_MESH_g = 255;
|
||||
TFT_MESH_b = 255;
|
||||
} else if (selected == 10) {
|
||||
LOG_INFO("Setting color to Ice");
|
||||
TFT_MESH_r = 173;
|
||||
TFT_MESH_g = 216;
|
||||
TFT_MESH_b = 230;
|
||||
} else if (selected == 11) {
|
||||
LOG_INFO("Setting color to Pink");
|
||||
TFT_MESH_r = 255;
|
||||
TFT_MESH_g = 105;
|
||||
TFT_MESH_b = 180;
|
||||
} else if (selected == 9) {
|
||||
} else if (selected == 12) {
|
||||
LOG_INFO("Setting color to White");
|
||||
TFT_MESH_r = 255;
|
||||
TFT_MESH_g = 255;
|
||||
TFT_MESH_b = 255;
|
||||
} else if (selected == 13) {
|
||||
LOG_INFO("Setting color to Gray");
|
||||
TFT_MESH_r = 128;
|
||||
TFT_MESH_g = 128;
|
||||
TFT_MESH_b = 128;
|
||||
} else {
|
||||
menuQueue = system_base_menu;
|
||||
screen->runNow();
|
||||
@@ -1274,19 +1329,28 @@ void menuHandler::wifiBaseMenu()
|
||||
|
||||
void menuHandler::wifiToggleMenu()
|
||||
{
|
||||
enum optionsNumbers { Back, Wifi_toggle };
|
||||
enum optionsNumbers { Back, Wifi_disable, Wifi_enable };
|
||||
|
||||
static const char *optionsArray[] = {"Back", "Disable"};
|
||||
static const char *optionsArray[] = {"Back", "WiFi Disabled", "WiFi Enabled"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Disable Wifi and\nEnable Bluetooth?";
|
||||
bannerOptions.message = "WiFi Actions";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.optionsCount = 3;
|
||||
if (config.network.wifi_enabled == true)
|
||||
bannerOptions.InitialSelected = 2;
|
||||
else
|
||||
bannerOptions.InitialSelected = 1;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Wifi_toggle) {
|
||||
if (selected == Wifi_disable) {
|
||||
config.network.wifi_enabled = false;
|
||||
config.bluetooth.enabled = true;
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
} else if (selected == Wifi_enable) {
|
||||
config.network.wifi_enabled = true;
|
||||
config.bluetooth.enabled = false;
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
@@ -1334,7 +1398,7 @@ void menuHandler::screenOptionsMenu()
|
||||
static int optionsEnumArray[5] = {Back};
|
||||
int options = 1;
|
||||
|
||||
#if defined(T_DECK) || defined(T_LORA_PAGER)
|
||||
#if defined(T_DECK) || defined(T_LORA_PAGER) || defined(HACKADAY_COMMUNICATOR)
|
||||
optionsArray[options] = "Show Long/Short Name";
|
||||
optionsEnumArray[options++] = NodeNameLength;
|
||||
#endif
|
||||
@@ -1346,12 +1410,13 @@ void menuHandler::screenOptionsMenu()
|
||||
}
|
||||
|
||||
// Only show screen color for TFT displays
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || \
|
||||
HAS_TFT || defined(HACKADAY_COMMUNICATOR)
|
||||
optionsArray[options] = "Screen Color";
|
||||
optionsEnumArray[options++] = ScreenColor;
|
||||
#endif
|
||||
|
||||
optionsArray[options] = "Frame Visiblity Toggle";
|
||||
optionsArray[options] = "Frame Visibility Toggle";
|
||||
optionsEnumArray[options++] = FrameToggles;
|
||||
|
||||
optionsArray[options] = "Display Units";
|
||||
@@ -1748,4 +1813,4 @@ void menuHandler::saveUIConfig()
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -99,5 +99,24 @@ class menuHandler
|
||||
static void BluetoothToggleMenu();
|
||||
};
|
||||
|
||||
/* Generic Menu Options designations */
|
||||
enum class OptionsAction { Back, Select };
|
||||
|
||||
template <typename T> struct MenuOption {
|
||||
const char *label;
|
||||
OptionsAction action;
|
||||
bool hasValue;
|
||||
T value;
|
||||
|
||||
MenuOption(const char *labelIn, OptionsAction actionIn, T valueIn)
|
||||
: label(labelIn), action(actionIn), hasValue(true), value(valueIn)
|
||||
{
|
||||
}
|
||||
|
||||
MenuOption(const char *labelIn, OptionsAction actionIn) : label(labelIn), action(actionIn), hasValue(false), value() {}
|
||||
};
|
||||
|
||||
using RadioPresetOption = MenuOption<meshtastic_Config_LoRaConfig_ModemPreset>;
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -85,9 +85,13 @@ void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
|
||||
void NotificationRenderer::resetBanner()
|
||||
{
|
||||
notificationTypeEnum previousType = current_notification_type;
|
||||
|
||||
alertBannerMessage[0] = '\0';
|
||||
current_notification_type = notificationTypeEnum::none;
|
||||
|
||||
OnScreenKeyboardModule::instance().clearPopup();
|
||||
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
inEvent.kbchar = 0;
|
||||
curSelected = 0;
|
||||
@@ -100,6 +104,13 @@ void NotificationRenderer::resetBanner()
|
||||
currentNumber = 0;
|
||||
|
||||
nodeDB->pause_sort(false);
|
||||
|
||||
// If we're exiting from text_input (virtual keyboard), stop module and trigger frame update
|
||||
// to ensure any messages received during keyboard use are now displayed
|
||||
if (previousType == notificationTypeEnum::text_input && screen) {
|
||||
OnScreenKeyboardModule::instance().stop(false);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
@@ -163,13 +174,15 @@ void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiS
|
||||
// modulo to extract
|
||||
uint8_t this_digit = (currentNumber % (pow_of_10(numDigits - curSelected))) / (pow_of_10(numDigits - curSelected - 1));
|
||||
// Handle input
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS ||
|
||||
inEvent.inputEvent == INPUT_BROKER_UP_LONG) {
|
||||
if (this_digit == 9) {
|
||||
currentNumber -= 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
currentNumber += (pow_of_10(numDigits - curSelected - 1));
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS ||
|
||||
inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||
if (this_digit == 0) {
|
||||
currentNumber += 9 * (pow_of_10(numDigits - curSelected - 1));
|
||||
} else {
|
||||
@@ -251,10 +264,10 @@ void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiSta
|
||||
|
||||
// Handle input
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_LEFT ||
|
||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS || inEvent.inputEvent == INPUT_BROKER_UP_LONG) {
|
||||
curSelected--;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_RIGHT ||
|
||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS || inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||
curSelected++;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||
alertBannerCallback(selectedNodenum);
|
||||
@@ -368,10 +381,10 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
||||
// Handle input
|
||||
if (alertBannerOptions > 0) {
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_LEFT ||
|
||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS || inEvent.inputEvent == INPUT_BROKER_UP_LONG) {
|
||||
curSelected--;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_RIGHT ||
|
||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS || inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||
curSelected++;
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||
if (optionsEnumPtr != nullptr) {
|
||||
@@ -769,40 +782,8 @@ void NotificationRenderer::drawTextInput(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
}
|
||||
|
||||
if (inEvent.inputEvent != INPUT_BROKER_NONE) {
|
||||
if (inEvent.inputEvent == INPUT_BROKER_UP) {
|
||||
// high frequency for move cursor left/right than up/down with encoders
|
||||
extern ::RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
extern ::UpDownInterruptImpl1 *upDownInterruptImpl1;
|
||||
if (::rotaryEncoderInterruptImpl1 || ::upDownInterruptImpl1) {
|
||||
virtualKeyboard->moveCursorLeft();
|
||||
} else {
|
||||
virtualKeyboard->moveCursorUp();
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN) {
|
||||
extern ::RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
extern ::UpDownInterruptImpl1 *upDownInterruptImpl1;
|
||||
if (::rotaryEncoderInterruptImpl1 || ::upDownInterruptImpl1) {
|
||||
virtualKeyboard->moveCursorRight();
|
||||
} else {
|
||||
virtualKeyboard->moveCursorDown();
|
||||
}
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_LEFT) {
|
||||
virtualKeyboard->moveCursorLeft();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_RIGHT) {
|
||||
virtualKeyboard->moveCursorRight();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_UP_LONG) {
|
||||
virtualKeyboard->moveCursorUp();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||
virtualKeyboard->moveCursorDown();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||
virtualKeyboard->moveCursorLeft();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||
virtualKeyboard->moveCursorRight();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||
virtualKeyboard->handlePress();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT_LONG) {
|
||||
virtualKeyboard->handleLongPress();
|
||||
} else if (inEvent.inputEvent == INPUT_BROKER_CANCEL) {
|
||||
bool handled = OnScreenKeyboardModule::processVirtualKeyboardInput(inEvent, virtualKeyboard);
|
||||
if (!handled && inEvent.inputEvent == INPUT_BROKER_CANCEL) {
|
||||
auto callback = textInputCallback;
|
||||
delete virtualKeyboard;
|
||||
virtualKeyboard = nullptr;
|
||||
@@ -821,12 +802,28 @@ void NotificationRenderer::drawTextInput(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
}
|
||||
|
||||
// Re-check pointer before drawing to avoid use-after-free and crashes
|
||||
if (!virtualKeyboard) {
|
||||
// Ensure we exit text_input state and restore frames
|
||||
if (current_notification_type == notificationTypeEnum::text_input) {
|
||||
resetBanner();
|
||||
}
|
||||
if (screen) {
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
}
|
||||
// If screen is null, do nothing (safe fallback)
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the screen to avoid overlapping with underlying frames or overlays
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(0, 0, display->getWidth(), display->getHeight());
|
||||
display->setColor(WHITE);
|
||||
// Draw the virtual keyboard
|
||||
virtualKeyboard->draw(display, 0, 0);
|
||||
|
||||
// Draw transient popup overlay (if any) managed by OnScreenKeyboardModule
|
||||
OnScreenKeyboardModule::instance().drawPopupOverlay(display);
|
||||
} else {
|
||||
// If virtualKeyboard is null, reset the banner to avoid getting stuck
|
||||
LOG_INFO("Virtual keyboard is null - resetting banner");
|
||||
@@ -839,5 +836,12 @@ bool NotificationRenderer::isOverlayBannerShowing()
|
||||
return strlen(alertBannerMessage) > 0 && (alertBannerUntil == 0 || millis() <= alertBannerUntil);
|
||||
}
|
||||
|
||||
void NotificationRenderer::showKeyboardMessagePopupWithTitle(const char *title, const char *content, uint32_t durationMs)
|
||||
{
|
||||
if (!title || !content || current_notification_type != notificationTypeEnum::text_input)
|
||||
return;
|
||||
OnScreenKeyboardModule::instance().showPopup(title, content, durationMs);
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "OLEDDisplayUi.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/VirtualKeyboard.h"
|
||||
#include "modules/OnScreenKeyboardModule.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#define MAX_LINES 5
|
||||
@@ -31,6 +32,7 @@ class NotificationRenderer
|
||||
static bool pauseBanner;
|
||||
|
||||
static void resetBanner();
|
||||
static void showKeyboardMessagePopupWithTitle(const char *title, const char *content, uint32_t durationMs);
|
||||
static void drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/TimeFormatters.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "target_specific.h"
|
||||
@@ -256,7 +257,8 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
||||
}
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
defined(HACKADAY_COMMUNICATOR) || defined(USE_ST7796)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
|
||||
if (isHighResolution) {
|
||||
@@ -383,17 +385,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
||||
// === 4. Uptime (only show if metric is present) ===
|
||||
char uptimeStr[32] = "";
|
||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||
uint32_t uptime = node->device_metrics.uptime_seconds;
|
||||
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 (days)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %ud %uh", days, hours);
|
||||
else if (hours)
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %uh %um", hours, mins);
|
||||
else
|
||||
snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins);
|
||||
getUptimeStr(node->device_metrics.uptime_seconds * 1000, " Up", uptimeStr, sizeof(uptimeStr));
|
||||
}
|
||||
if (uptimeStr[0] && line < 5) {
|
||||
display->drawString(x, getTextPositions(display)[line++], uptimeStr);
|
||||
@@ -592,18 +584,8 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
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);
|
||||
getUptimeStr(millis(), "Up", uptimeStr, sizeof(uptimeStr));
|
||||
#endif
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||
|
||||
@@ -1048,36 +1030,17 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||
// === Second Row: Last GPS Fix ===
|
||||
if (gpsStatus->getLastFixMillis() > 0) {
|
||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
||||
uint32_t days = delta / 86400;
|
||||
uint32_t hours = (delta % 86400) / 3600;
|
||||
uint32_t mins = (delta % 3600) / 60;
|
||||
uint32_t secs = delta % 60;
|
||||
|
||||
char buf[32];
|
||||
uint32_t delta = millis() - gpsStatus->getLastFixMillis();
|
||||
char uptimeStr[32];
|
||||
#if defined(USE_EINK)
|
||||
// E-Ink: skip seconds, show only days/hours/mins
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Last: %um", mins);
|
||||
}
|
||||
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), false);
|
||||
#else
|
||||
// Non E-Ink: include seconds where useful
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
||||
} else if (mins > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
||||
}
|
||||
getUptimeStr(delta, "Last", uptimeStr, sizeof(uptimeStr), true);
|
||||
#endif
|
||||
|
||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
||||
display->drawString(0, getTextPositions(display)[line++], uptimeStr);
|
||||
} else {
|
||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
||||
}
|
||||
@@ -1422,4 +1385,4 @@ std::string UIRenderer::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t mi
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
|
||||
@@ -13,41 +13,81 @@ const Emote emotes[] = {
|
||||
{"\U0001F44E", thumbdown, thumbs_width, thumbs_height}, // 👎 Thumbs Down
|
||||
|
||||
// --- Smileys (Multiple Unicode Aliases) ---
|
||||
{"\U0001F60A", Smiling_Eyes, Smiling_Eyes_width, Smiling_Eyes_height}, // 😊 Smiling Eyes
|
||||
{"\U0001F600", Grinning, Grinning_width, Grinning_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face
|
||||
{"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes
|
||||
{"\U0001F60D", Heart_eyes, Heart_eyes_width, Heart_eyes_height}, // 😍 Heart Eyes
|
||||
{"\U0001F60A", smiling_eyes, smiling_eyes_width, smiling_eyes_height}, // 😊 Smiling Eyes
|
||||
{"\U0001F600", grinning, grinning_width, grinning_height}, // 😀 Grinning Face
|
||||
{"\U0001F642", slightly_smiling, slightly_smiling_width, slightly_smiling_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", winking_face, winking_face_width, winking_face_height}, // 😉 Winking Face
|
||||
{"\U0001F601", grinning_smiling_eyes, grinning_smiling_eyes_width, grinning_smiling_eyes_height}, // 😁 Grinning Smiling Eyes
|
||||
{"\U0001F60D", heart_eyes, heart_eyes_width, heart_eyes_height}, // 😍 Heart Eyes
|
||||
{"\U0001F970", heart_smile, heart_smile_width, heart_smile_height}, // 🥰 Smiling Face with Hearts
|
||||
|
||||
// --- Question/Alert ---
|
||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||
{"\u203C\uFE0F", bang, bang_width, bang_height}, // ‼️ Double Exclamation Mark
|
||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||
{"\u203C\uFE0F", bang, bang_width, bang_height}, // ‼️ Double Exclamation Mark
|
||||
{"\u26A0\uFE0F", caution, caution_width, caution_height}, // ⚠️ Warning Sign
|
||||
|
||||
// --- Laughing Faces ---
|
||||
{"\U0001F602", haha, haha_width, haha_height}, // 😂 Face with Tears of Joy
|
||||
{"\U0001F923", ROFL, ROFL_width, ROFL_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", Smiling_Closed_Eyes, Smiling_Closed_Eyes_width, Smiling_Closed_Eyes_height}, // 😆 Smiling Closed Eyes
|
||||
{"\U0001F923", rofl, rofl_width, rofl_height}, // 🤣 Rolling on the Floor Laughing
|
||||
{"\U0001F606", smiling_closed_eyes, smiling_closed_eyes_width, smiling_closed_eyes_height}, // 😆 Smiling Closed Eyes
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
||||
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
{"\U0001F62D", Loudly_Crying_Face, Loudly_Crying_Face_width, Loudly_Crying_Face_height}, // 😭 Loudly Crying Face
|
||||
{"\U0001F604", grinning_smiling_eyes_2, grinning_smiling_eyes_2_width,
|
||||
grinning_smiling_eyes_2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
{"\U0001F62D", loudly_crying_face, loudly_crying_face_width, loudly_crying_face_height}, // 😭 Loudly Crying Face
|
||||
{"\U0001F92E", vomiting, vomiting_width, vomiting_height}, // 🤮 Face Vomiting
|
||||
{"\U0001F60E", cool, cool_width, cool_height}, // 😎 Smiling Face with Sunglasses
|
||||
{"\U0001F440", eyes, eyes_width, eyes_height}, // 👀 Eyes
|
||||
{"\U0001F441\uFE0F", eye, eye_width, eye_height}, // 👁️ Eye
|
||||
|
||||
// --- Gestures and People ---
|
||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||
{"\u270C\uFE0F", peace_sign, peace_sign_width, peace_sign_height}, // ✌️ Victory Hand
|
||||
{"\U0001F596", vulcan_salute, vulcan_salute_width, vulcan_salute_height}, // 🖖 Vulcan Salute
|
||||
{"\U0001F64F", Praying, Praying_width, Praying_height}, // 🙏 Praying Hands
|
||||
{"\U0001F64F", praying, praying_width, praying_height}, // 🙏 Praying Hands
|
||||
{"\U0001F4AA", strong, strong_width, strong_height}, // 💪 Flexed Biceps
|
||||
{"\U0001F937", shrug, shrug_width, shrug_height}, // 🤷 Person Shrugging
|
||||
{"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face
|
||||
{"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones
|
||||
|
||||
// --- Symbols ---
|
||||
{"\u2714\uFE0F", check_mark, check_mark_width, check_mark_height}, // ✔️ Check Mark
|
||||
{"\u2705", check_mark, check_mark_width, check_mark_height}, // ✅ Check Mark Button
|
||||
{"\u2611\uFE0F", check_mark, check_mark_width, check_mark_height}, // ☑️ Check Box with Check
|
||||
{"\U0001F3E0", house, house_width, house_height}, // 🏠 House
|
||||
|
||||
// --- Weather ---
|
||||
{"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector)
|
||||
{"\u2600\uFE0F", sun, sun_width, sun_height}, // ☀️ Sun (with variation selector)
|
||||
{"\U0001F327\uFE0F", rain, rain_width, rain_height}, // 🌧️ Cloud with Rain
|
||||
{"\u2601\uFE0F", cloud, cloud_width, cloud_height}, // ☁️ Cloud
|
||||
{"\U0001F32B\uFE0F", fog, fog_width, fog_height}, // 🌫️ Fog
|
||||
{"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector)
|
||||
{"\u2600\uFE0F", sun, sun_width, sun_height}, // ☀️ Sun (with variation selector)
|
||||
{"\U0001F327\uFE0F", rain, rain_width, rain_height}, // 🌧️ Cloud with Rain
|
||||
{"\u2601\uFE0F", cloud, cloud_width, cloud_height}, // ☁️ Cloud
|
||||
{"\U0001F32B\uFE0F", fog, fog_width, fog_height}, // 🌫️ Fog
|
||||
{"\u2744\uFE0F", snowflake, snowflake_width, snowflake_height}, // ❄️ Snowflake
|
||||
{"\U0001F4A7", drop, drop_width, drop_height}, // 💧 Droplet
|
||||
{"\U0001F321\uFE0F", thermometer, thermometer_width, thermometer_height}, // 🌡️ Thermometer
|
||||
{"\U0001F326\uFE0F", sun_behind_raincloud, sun_behind_raincloud_width,
|
||||
sun_behind_raincloud_height}, // 🌦️ Sun Behind Rain Cloud
|
||||
{"\u26C5", sun_behind_cloud, sun_behind_cloud_width, sun_behind_cloud_height}, // ⛅ Sun Behind Cloud
|
||||
{"\u26C5\uFE0F", sun_behind_cloud, sun_behind_cloud_width, sun_behind_cloud_height}, // ⛅️ Sun Behind Cloud
|
||||
{"\U0001F328\uFE0F", cloud_with_snow, cloud_with_snow_width, cloud_with_snow_height}, // 🌨️ Cloud with Snow
|
||||
{"\U0001F329\uFE0F", cloud_with_lightning, cloud_with_lightning_width,
|
||||
cloud_with_lightning_height}, // 🌩️ Cloud with Lightning
|
||||
{"\u26C8", cloud_with_lightning_rain, cloud_with_lightning_rain_width,
|
||||
cloud_with_lightning_rain_height}, // ⛈ Cloud with Lightning and Rain
|
||||
{"\u26C8\uFE0F", cloud_with_lightning_rain, cloud_with_lightning_rain_width,
|
||||
cloud_with_lightning_rain_height}, // ⛈️ Cloud with Lightning and Rain
|
||||
{"\U0001F32C\uFE0F", wind_face, wind_face_width, wind_face_height}, // 🌬️ Wind Face
|
||||
|
||||
// --- Moon Phases ---
|
||||
{"\U0001F311", new_moon, new_moon_width, new_moon_height}, // 🌑 New Moon
|
||||
{"\U0001F312", waxing_crescent_moon, waxing_crescent_moon_width, waxing_crescent_moon_height}, // 🌒 Waxing Crescent Moon
|
||||
{"\U0001F313", first_quarter_moon, first_quarter_moon_width, first_quarter_moon_height}, // 🌓 First Quarter Moon
|
||||
{"\U0001F314", waxing_gibbous_moon, waxing_gibbous_moon_width, waxing_gibbous_moon_height}, // 🌔 Waxing Gibbous Moon
|
||||
{"\U0001F315", full_moon, full_moon_width, full_moon_height}, // 🌕 Full Moon
|
||||
{"\U0001F316", waning_gibbous_moon, waning_gibbous_moon_width, waning_gibbous_moon_height}, // 🌖 Waning Gibbous Moon
|
||||
{"\U0001F317", last_quarter_moon, last_quarter_moon_width, last_quarter_moon_height}, // 🌗 Last Quarter Moon
|
||||
{"\U0001F318", waning_crescent_moon, waning_crescent_moon_width, waning_crescent_moon_height}, // 🌘 Waning Crescent Moon
|
||||
{"\U0001F31B", first_quarter_moon_face, first_quarter_moon_face_width,
|
||||
first_quarter_moon_face_height}, // 🌛 First Quarter Moon Face
|
||||
|
||||
// --- Misc Faces ---
|
||||
{"\U0001F608", devil, devil_width, devil_height}, // 😈 Smiling Face with Horns
|
||||
@@ -67,13 +107,49 @@ const Emote emotes[] = {
|
||||
{"\U0001F498", heart, heart_width, heart_height}, // 💘 Heart with Arrow
|
||||
|
||||
// --- Objects ---
|
||||
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
||||
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height}, // 🔔 Bell
|
||||
{"\U0001F36A", cookie, cookie_width, cookie_height}, // 🍪 Cookie
|
||||
{"\U0001F525", Fire, Fire_width, Fire_height}, // 🔥 Fire
|
||||
{"\u2728", Sparkles, Sparkles_width, Sparkles_height}, // ✨ Sparkles
|
||||
{"\U0001F573\uFE0F", hole, hole_width, hole_height}, // 🕳️ Hole
|
||||
{"\U0001F3B3", bowling, bowling_width, bowling_height} // 🎳 Bowling
|
||||
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
||||
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height}, // 🔔 Bell
|
||||
{"\U0001F4CB", clipboard, clipboard_width, clipboard_height}, // 📋 Clipboard
|
||||
{"\U0001F36A", cookie, cookie_width, cookie_height}, // 🍪 Cookie
|
||||
{"\U0001F370", shortcake, shortcake_width, shortcake_height}, // 🍰 Shortcake
|
||||
{"\U0001F351", peach, peach_width, peach_height}, // 🍑 Peach
|
||||
{"\U0001F983", turkey, turkey_width, turkey_height}, // 🦃 Turkey
|
||||
{"\U0001F357", turkey_leg, turkey_leg_width, turkey_leg_height}, // 🍗 Poultry Leg
|
||||
{"\U0001F525", fire, fire_width, fire_height}, // 🔥 Fire
|
||||
{"\u2728", sparkles, sparkles_width, sparkles_height}, // ✨ Sparkles
|
||||
{"\U0001F573\uFE0F", hole, hole_width, hole_height}, // 🕳️ Hole
|
||||
{"\U0001F3B3", bowling, bowling_width, bowling_height}, // 🎳 Bowling
|
||||
|
||||
// --- Arrows ---
|
||||
{"\u2193", downwards_arrow, downwards_arrow_width, downwards_arrow_height}, // ↓ Downwards Arrow
|
||||
{"\u2193\uFE0E", downwards_arrow, downwards_arrow_width, downwards_arrow_height}, // ↓︎ Downwards Arrow (text)
|
||||
{"\u2193\uFE0F", downwards_arrow, downwards_arrow_width, downwards_arrow_height}, // ↓️ Downwards Arrow (emoji)
|
||||
{"\u2199", south_west_arrow, south_west_arrow_width, south_west_arrow_height}, // ↙ South West Arrow
|
||||
{"\u2199\uFE0E", south_west_arrow, south_west_arrow_width, south_west_arrow_height}, // ↙︎ South West Arrow (text)
|
||||
{"\u2199\uFE0F", south_west_arrow, south_west_arrow_width, south_west_arrow_height}, // ↙️ South West Arrow (emoji)
|
||||
{"\u2190", leftwards_arrow, leftwards_arrow_width, leftwards_arrow_height}, // ← Leftwards Arrow
|
||||
{"\u2190\uFE0E", leftwards_arrow, leftwards_arrow_width, leftwards_arrow_height}, // ←︎ Leftwards Arrow (text)
|
||||
{"\u2190\uFE0F", leftwards_arrow, leftwards_arrow_width, leftwards_arrow_height}, // ←️ Leftwards Arrow (emoji)
|
||||
{"\u2196", north_west_arrow, north_west_arrow_width, north_west_arrow_height}, // ↖ North West Arrow
|
||||
{"\u2196\uFE0E", north_west_arrow, north_west_arrow_width, north_west_arrow_height}, // ↖︎ North West Arrow (text)
|
||||
{"\u2196\uFE0F", north_west_arrow, north_west_arrow_width, north_west_arrow_height}, // ↖️ North West Arrow (emoji)
|
||||
{"\u2191", upwards_arrow, upwards_arrow_width, upwards_arrow_height}, // ↑ Upwards Arrow
|
||||
{"\u2191\uFE0E", upwards_arrow, upwards_arrow_width, upwards_arrow_height}, // ↑︎ Upwards Arrow (text)
|
||||
{"\u2191\uFE0F", upwards_arrow, upwards_arrow_width, upwards_arrow_height}, // ↑️ Upwards Arrow (emoji)
|
||||
{"\u2197", north_east_arrow, north_east_arrow_width, north_east_arrow_height}, // ↗ North East Arrow
|
||||
{"\u2197\uFE0E", north_east_arrow, north_east_arrow_width, north_east_arrow_height}, // ↗︎ North East Arrow (text)
|
||||
{"\u2197\uFE0F", north_east_arrow, north_east_arrow_width, north_east_arrow_height}, // ↗️ North East Arrow (emoji)
|
||||
{"\u2192", rightwards_arrow, rightwards_arrow_width, rightwards_arrow_height}, // → Rightwards Arrow
|
||||
{"\u2192\uFE0E", rightwards_arrow, rightwards_arrow_width, rightwards_arrow_height}, // →︎ Rightwards Arrow (text)
|
||||
{"\u2192\uFE0F", rightwards_arrow, rightwards_arrow_width, rightwards_arrow_height}, // →️ Rightwards Arrow (emoji)
|
||||
{"\u2198", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘ South East Arrow
|
||||
{"\u2198\uFE0E", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘︎ South East Arrow (text)
|
||||
{"\u2198\uFE0F", south_east_arrow, south_east_arrow_width, south_east_arrow_height}, // ↘️ South East Arrow (emoji)
|
||||
|
||||
// --- Halloween ---
|
||||
{"\U0001F383", jack_o_lantern, jack_o_lantern_width, jack_o_lantern_height}, // 🎃 Jack-O-Lantern
|
||||
{"\U0001F47B", ghost, ghost_width, ghost_height}, // 👻 Ghost
|
||||
{"\U0001F480", skull, skull_width, skull_height} // 💀 Skull
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -88,23 +164,23 @@ const unsigned char thumbdown[] PROGMEM = {0xF0, 0x1F, 0x08, 0x20, 0x06, 0x30, 0
|
||||
0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x3F, 0x18, 0x02, 0x20, 0x02,
|
||||
0x40, 0x04, 0x80, 0x04, 0x80, 0x04, 0x00, 0x03, 0x00, 0x00};
|
||||
|
||||
const unsigned char Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
const unsigned char smiling_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0x02, 0x40, 0x22, 0x44, 0x22, 0x44, 0xC2, 0x43,
|
||||
0x04, 0x20, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Grinning[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
const unsigned char grinning[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
0x42, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Slightly_Smiling[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
const unsigned char slightly_smiling[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
0x42, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Winking_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x20, 0x42,
|
||||
const unsigned char winking_face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x20, 0x42,
|
||||
0x46, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
const unsigned char grinning_smiling_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0xFA, 0x5F, 0x0A, 0x50, 0x0A, 0x50, 0x12, 0x48,
|
||||
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
@@ -112,7 +188,7 @@ const unsigned char heart_smile[] PROGMEM = {0x00, 0x00, 0x6C, 0x07, 0x7C, 0x18,
|
||||
0x0A, 0x02, 0xD8, 0x02, 0xF8, 0x22, 0xFC, 0x20, 0x74, 0xDB, 0x23,
|
||||
0x1F, 0x00, 0x1F, 0x20, 0x0E, 0x18, 0xE4, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Heart_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x54, 0x2A, 0xFA,
|
||||
const unsigned char heart_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x54, 0x2A, 0xFA,
|
||||
0x5F, 0x72, 0x4E, 0x22, 0x44, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48,
|
||||
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
@@ -128,19 +204,19 @@ const unsigned char haha[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04,
|
||||
0x4A, 0x0A, 0x50, 0x0E, 0x70, 0xF2, 0x4F, 0x12, 0x48, 0x32, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char ROFL[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x84, 0x21, 0x84, 0x20, 0x02,
|
||||
const unsigned char rofl[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x84, 0x21, 0x84, 0x20, 0x02,
|
||||
0x4C, 0x02, 0x4A, 0x1A, 0x49, 0x8A, 0x48, 0x42, 0x48, 0x22, 0x44,
|
||||
0xE4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x42,
|
||||
const unsigned char smiling_closed_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x42,
|
||||
0x42, 0x22, 0x44, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char grinning_smiling_eyes_2[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Loudly_Crying_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x2C, 0x4A,
|
||||
const unsigned char loudly_crying_face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x2C, 0x4A,
|
||||
0x52, 0x12, 0x48, 0x12, 0x48, 0x92, 0x49, 0x52, 0x4A, 0x52, 0x4A,
|
||||
0x54, 0x2A, 0x94, 0x29, 0x18, 0x18, 0xF0, 0x0F, 0x00, 0x00};
|
||||
|
||||
@@ -192,7 +268,7 @@ const unsigned char cookie[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04
|
||||
0x40, 0x02, 0x58, 0x82, 0x5B, 0x92, 0x43, 0x82, 0x43, 0x02, 0x40,
|
||||
0x64, 0x28, 0x64, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Fire[] PROGMEM = {0x30, 0x00, 0xF0, 0x00, 0xF8, 0x03, 0xF8, 0x07, 0xFC, 0x1F, 0xFC,
|
||||
const unsigned char fire[] PROGMEM = {0x30, 0x00, 0xF0, 0x00, 0xF8, 0x03, 0xF8, 0x07, 0xFC, 0x1F, 0xFC,
|
||||
0x1F, 0xFE, 0x3E, 0x7E, 0x3E, 0x3E, 0x7C, 0x1E, 0x78, 0x1E, 0x70,
|
||||
0x1C, 0x70, 0x1C, 0x70, 0x38, 0x38, 0x30, 0x38, 0x60, 0x0C};
|
||||
|
||||
@@ -200,11 +276,11 @@ const unsigned char peace_sign[] PROGMEM = {0xC0, 0x30, 0x40, 0x29, 0x40, 0x25,
|
||||
0x0A, 0x54, 0x68, 0x54, 0x58, 0x54, 0x44, 0x3C, 0x22, 0x04, 0x22,
|
||||
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Praying[] PROGMEM = {0x00, 0x00, 0x40, 0x02, 0xA0, 0x05, 0x90, 0x09, 0x90, 0x09, 0x90,
|
||||
const unsigned char praying[] PROGMEM = {0x00, 0x00, 0x40, 0x02, 0xA0, 0x05, 0x90, 0x09, 0x90, 0x09, 0x90,
|
||||
0x09, 0x98, 0x19, 0x94, 0x29, 0xA4, 0x25, 0xA4, 0x25, 0x84, 0x21,
|
||||
0x84, 0x21, 0x86, 0x61, 0x4E, 0x72, 0x7F, 0x7E, 0x3F, 0xFC};
|
||||
|
||||
const unsigned char Sparkles[] PROGMEM = {0x00, 0x00, 0x10, 0x00, 0x38, 0x04, 0x10, 0x04, 0x00, 0x0E, 0x00,
|
||||
const unsigned char sparkles[] PROGMEM = {0x00, 0x00, 0x10, 0x00, 0x38, 0x04, 0x10, 0x04, 0x00, 0x0E, 0x00,
|
||||
0x1F, 0x80, 0x3F, 0xE0, 0xFF, 0x80, 0x3F, 0x10, 0x1F, 0x10, 0x0E,
|
||||
0x38, 0x04, 0xFE, 0x04, 0x38, 0x00, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
@@ -227,7 +303,179 @@ const unsigned char bowling[] PROGMEM = {0x00, 0x38, 0x00, 0x44, 0x00, 0x44, 0x0
|
||||
const unsigned char vulcan_salute[] PROGMEM = {0x08, 0x02, 0x16, 0x0D, 0x15, 0x15, 0x15, 0x15, 0xA9, 0x12, 0x4A,
|
||||
0x0A, 0x02, 0x38, 0x04, 0x48, 0x04, 0x44, 0x04, 0x22, 0x04, 0x22,
|
||||
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char jack_o_lantern[] PROGMEM = {0xC0, 0x00, 0x80, 0x01, 0xB8, 0x1D, 0xC4, 0x23, 0x22, 0x44, 0x05,
|
||||
0xA0, 0x31, 0x8C, 0x51, 0x8A, 0x61, 0x86, 0x09, 0x90, 0xB9, 0x9D,
|
||||
0x49, 0x92, 0xB2, 0x4D, 0x42, 0x42, 0x04, 0x20, 0xF8, 0x1F};
|
||||
|
||||
const unsigned char ghost[] PROGMEM = {0xC0, 0x03, 0xF0, 0x0F, 0xF8, 0x1F, 0xDC, 0x3B, 0xBC, 0x3D, 0xDF,
|
||||
0xFB, 0xFF, 0xFF, 0x1F, 0xF8, 0x1E, 0x78, 0x1C, 0x38, 0x3C, 0x3C,
|
||||
0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0x8C, 0x31};
|
||||
|
||||
const unsigned char skull[] PROGMEM = {0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xC7,
|
||||
0xE3, 0x87, 0xE1, 0x87, 0xE1, 0x8F, 0xF1, 0xFE, 0x7F, 0x7C, 0x3E,
|
||||
0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xF8, 0x1F, 0xB0, 0x0D};
|
||||
|
||||
const unsigned char vomiting[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x04, 0x20, 0x22,
|
||||
0x44, 0x42, 0x42, 0x22, 0x44, 0x02, 0x40, 0x02, 0x40, 0xC2, 0x43,
|
||||
0x64, 0x26, 0x64, 0x26, 0x68, 0x16, 0x50, 0x0A, 0xF8, 0x1F};
|
||||
|
||||
const unsigned char cool[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0xFC, 0x3F, 0xFA,
|
||||
0x5F, 0x72, 0x4E, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char shortcake[] PROGMEM = {0x00, 0x00, 0x00, 0x0F, 0x80, 0x3F, 0xE0, 0xFC, 0xE0, 0xE1, 0xF0,
|
||||
0xB8, 0x10, 0x87, 0xC8, 0x80, 0x3C, 0xE0, 0x06, 0x98, 0x02, 0xC7,
|
||||
0xE2, 0x30, 0x1A, 0x0E, 0xC6, 0x01, 0x32, 0x00, 0x0E, 0x00};
|
||||
|
||||
const unsigned char caution[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x06, 0x60,
|
||||
0x06, 0x70, 0x0E, 0x70, 0x0E, 0x78, 0x1E, 0x78, 0x1E, 0x7C, 0x3E,
|
||||
0xFC, 0x3F, 0x7E, 0x7E, 0x7E, 0x7E, 0xFC, 0x3F, 0x00, 0x00};
|
||||
|
||||
const unsigned char clipboard[] PROGMEM = {0xC0, 0x03, 0x7E, 0x7E, 0xC2, 0x43, 0xFA, 0x5F, 0x0A, 0x5B, 0xFA,
|
||||
0x5F, 0x8A, 0x54, 0xFA, 0x5F, 0x4A, 0x58, 0xFA, 0x5F, 0x2A, 0x51,
|
||||
0xFA, 0x5F, 0x0A, 0x59, 0xFA, 0x5F, 0x02, 0x40, 0xFE, 0x7F};
|
||||
|
||||
const unsigned char snowflake[] PROGMEM = {0x00, 0x00, 0x40, 0x01, 0x88, 0x08, 0x8C, 0x18, 0xD0, 0x05, 0x60,
|
||||
0x03, 0x32, 0x26, 0x1C, 0x1C, 0x32, 0x26, 0x60, 0x03, 0xD0, 0x05,
|
||||
0x8C, 0x18, 0x88, 0x08, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char drop[] PROGMEM = {0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x0F, 0xE0,
|
||||
0x0F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF8, 0x3F, 0xF8, 0x3F, 0xF8, 0x3F,
|
||||
0xF8, 0x3F, 0xF0, 0x1F, 0xE0, 0x0F, 0x80, 0x03, 0x00, 0x00};
|
||||
|
||||
const unsigned char thermometer[] PROGMEM = {0x00, 0x00, 0x0C, 0x00, 0x16, 0x00, 0x2E, 0x00, 0x5C, 0x00, 0xB8,
|
||||
0x00, 0x70, 0x01, 0xE0, 0x02, 0xC0, 0x05, 0x80, 0x3B, 0x00, 0x47,
|
||||
0x00, 0xBE, 0x00, 0x9E, 0x00, 0xBE, 0x00, 0x7C, 0x00, 0x38};
|
||||
|
||||
const unsigned char sun_behind_raincloud[] PROGMEM = {0xC0, 0x03, 0x20, 0x04, 0x10, 0x0E, 0x38, 0x1F, 0xFC, 0x37, 0xEE,
|
||||
0x77, 0xDE, 0x7B, 0x3E, 0x7C, 0xFC, 0x3F, 0x00, 0x00, 0x48, 0x12,
|
||||
0x48, 0x12, 0x24, 0x09, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char sun_behind_cloud[] PROGMEM = {0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x04, 0x0E, 0x3C, 0x1B, 0xFC,
|
||||
0x3B, 0xFE, 0x7B, 0xFA, 0x7B, 0xF6, 0x7D, 0x0C, 0x3E, 0xF8, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char cloud_with_snow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC, 0x3F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0x00, 0x00, 0x08, 0x02,
|
||||
0x40, 0x10, 0x00, 0x00, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char cloud_with_lightning[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC, 0x3F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0x00, 0x01, 0x80, 0x01,
|
||||
0x80, 0x01, 0xC0, 0x07, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01};
|
||||
|
||||
const unsigned char cloud_with_lightning_rain[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC, 0x3F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0x00, 0x01, 0x90, 0x21,
|
||||
0x90, 0x21, 0xC8, 0x17, 0x08, 0x13, 0x00, 0x03, 0x00, 0x01};
|
||||
|
||||
const unsigned char wind_face[] PROGMEM = {0xFF, 0x00, 0x01, 0x01, 0x01, 0x01, 0xF9, 0x00, 0xF9, 0x01, 0xD9,
|
||||
0x01, 0x99, 0x01, 0xF9, 0x01, 0xF9, 0x33, 0xFD, 0x4B, 0xFD, 0x85,
|
||||
0xFD, 0x9A, 0xFD, 0x75, 0xFD, 0x09, 0xFD, 0x01, 0xFF, 0x00};
|
||||
|
||||
const unsigned char new_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x04, 0x20, 0x02,
|
||||
0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
|
||||
0x04, 0x20, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char waxing_crescent_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x1F, 0x04, 0x3E, 0x04, 0x3C, 0x02,
|
||||
0x78, 0x02, 0x78, 0x02, 0x78, 0x02, 0x78, 0x02, 0x78, 0x02, 0x78,
|
||||
0x04, 0x3C, 0x04, 0x3E, 0x18, 0x1F, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char first_quarter_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x1F, 0x04, 0x3F, 0x04, 0x3F, 0x02,
|
||||
0x7F, 0x02, 0x7F, 0x02, 0x7F, 0x02, 0x7F, 0x02, 0x7F, 0x02, 0x7F,
|
||||
0x04, 0x3F, 0x04, 0x3F, 0x18, 0x1F, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char waxing_gibbous_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x1F, 0x84, 0x3F, 0xC4, 0x3F, 0xC2,
|
||||
0x7F, 0xC2, 0x7F, 0xC2, 0x7F, 0xC2, 0x7F, 0xC2, 0x7F, 0xC2, 0x7F,
|
||||
0xC4, 0x3F, 0x84, 0x3F, 0x18, 0x1F, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char full_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F,
|
||||
0xFC, 0x3F, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char waning_gibbous_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0xF8, 0x18, 0xFC, 0x21, 0xFC, 0x23, 0xFE,
|
||||
0x43, 0xFE, 0x43, 0xFE, 0x43, 0xFE, 0x43, 0xFE, 0x43, 0xFE, 0x43,
|
||||
0xFC, 0x23, 0xFC, 0x21, 0xF8, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char last_quarter_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0xF8, 0x18, 0xFC, 0x20, 0xFC, 0x20, 0xFE,
|
||||
0x40, 0xFE, 0x40, 0xFE, 0x40, 0xFE, 0x40, 0xFE, 0x40, 0xFE, 0x40,
|
||||
0xFC, 0x20, 0xFC, 0x20, 0xF8, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char waning_crescent_moon[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0xF8, 0x18, 0x7C, 0x20, 0x3C, 0x20, 0x1E,
|
||||
0x40, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x40,
|
||||
0x3C, 0x20, 0x7C, 0x20, 0xF8, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char first_quarter_moon_face[] PROGMEM = {0x00, 0x0F, 0x00, 0x12, 0x00, 0x24, 0x00, 0x44, 0x00, 0x48, 0x00,
|
||||
0x88, 0x00, 0x84, 0x80, 0x93, 0x80, 0x80, 0x03, 0x81, 0x8D, 0x80,
|
||||
0x71, 0x40, 0x82, 0x41, 0x02, 0x20, 0x0C, 0x18, 0xF0, 0x07};
|
||||
|
||||
const unsigned char peach[] PROGMEM = {0x70, 0x0F, 0x88, 0x10, 0x78, 0x1F, 0x88, 0x11, 0x04, 0x22, 0x02,
|
||||
0x44, 0x02, 0x44, 0x02, 0x44, 0x02, 0x44, 0x02, 0x42, 0x02, 0x40,
|
||||
0x04, 0x20, 0x04, 0x20, 0x08, 0x10, 0x30, 0x0C, 0xC0, 0x03};
|
||||
|
||||
const unsigned char turkey[] PROGMEM = {0x00, 0x00, 0x38, 0x00, 0x44, 0x38, 0x56, 0x54, 0x45, 0x52, 0xE2,
|
||||
0x21, 0x2C, 0x56, 0x14, 0x58, 0x0A, 0x37, 0x86, 0x68, 0x82, 0x50,
|
||||
0x82, 0x20, 0x04, 0x41, 0xF8, 0x7F, 0x40, 0x02, 0xF0, 0x07};
|
||||
|
||||
const unsigned char turkey_leg[] PROGMEM = {0x0C, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x2F, 0x00, 0x46, 0x00, 0x88,
|
||||
0x01, 0x10, 0x0E, 0x20, 0x30, 0x20, 0x40, 0x40, 0x40, 0x40, 0x80,
|
||||
0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x43, 0x00, 0x3C};
|
||||
|
||||
const unsigned char south_west_arrow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1C, 0x00, 0x3E, 0x00,
|
||||
0x1F, 0x80, 0x0F, 0xC2, 0x07, 0xE6, 0x03, 0xFE, 0x01, 0xFE, 0x00,
|
||||
0x7E, 0x00, 0x7E, 0x00, 0xFE, 0x00, 0xFE, 0x01, 0x00, 0x00};
|
||||
|
||||
const unsigned char south_east_arrow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x38, 0x00, 0x7C, 0x00, 0xF8,
|
||||
0x00, 0xF0, 0x01, 0xE0, 0x43, 0xC0, 0x67, 0x80, 0x7F, 0x00, 0x7F,
|
||||
0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7F, 0x80, 0x7F, 0x00, 0x00};
|
||||
|
||||
const unsigned char north_west_arrow[] PROGMEM = {0x00, 0x00, 0xFE, 0x01, 0xFE, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0xFE,
|
||||
0x00, 0xFE, 0x01, 0xE6, 0x03, 0xC2, 0x07, 0x80, 0x0F, 0x00, 0x1F,
|
||||
0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char north_east_arrow[] PROGMEM = {0x00, 0x00, 0x80, 0x7F, 0x00, 0x7F, 0x00, 0x7E, 0x00, 0x7E, 0x00,
|
||||
0x7F, 0x80, 0x7F, 0xC0, 0x67, 0xE0, 0x43, 0xF0, 0x01, 0xF8, 0x00,
|
||||
0x7C, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char downwards_arrow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
|
||||
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xFC, 0x3F,
|
||||
0xF8, 0x1F, 0xF0, 0x0F, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01};
|
||||
|
||||
const unsigned char leftwards_arrow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3C,
|
||||
0x00, 0xFE, 0x3F, 0xFF, 0x3F, 0xFF, 0x3F, 0xFE, 0x3F, 0x3C, 0x00,
|
||||
0x38, 0x00, 0x30, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char upwards_arrow[] PROGMEM = {0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xF0, 0x0F, 0xF8, 0x1F, 0xFC,
|
||||
0x3F, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03,
|
||||
0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char rightwards_arrow[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x1C, 0x00,
|
||||
0x3C, 0xFC, 0x7F, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0x7F, 0x00, 0x3C,
|
||||
0x00, 0x1C, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char strong[] PROGMEM = {0x38, 0x00, 0x44, 0x00, 0x62, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3A,
|
||||
0x00, 0x11, 0x3C, 0x11, 0x42, 0xD1, 0x81, 0x31, 0x82, 0x11, 0x82,
|
||||
0x21, 0x80, 0x01, 0x80, 0x01, 0x80, 0x02, 0x40, 0xFC, 0x3F};
|
||||
|
||||
const unsigned char check_mark[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00,
|
||||
0x1E, 0x00, 0x0F, 0x80, 0x07, 0xC3, 0x03, 0xEE, 0x03, 0xFC, 0x01,
|
||||
0xF8, 0x00, 0xF0, 0x00, 0x70, 0x00, 0x60, 0x00, 0x20, 0x00};
|
||||
|
||||
const unsigned char house[] PROGMEM = {0x80, 0x01, 0x5C, 0x02, 0x34, 0x04, 0x14, 0x08, 0x0C, 0x10, 0x04,
|
||||
0x20, 0x02, 0x40, 0xFF, 0xFF, 0x02, 0x40, 0x7A, 0x5F, 0x4A, 0x55,
|
||||
0x4A, 0x5F, 0x6A, 0x55, 0x4A, 0x5F, 0x4A, 0x40, 0xFE, 0x7F};
|
||||
|
||||
const unsigned char shrug[] PROGMEM = {0xC0, 0x03, 0x20, 0x04, 0x10, 0x08, 0x50, 0x0A, 0x10, 0x08, 0x90,
|
||||
0x09, 0x27, 0xE4, 0x49, 0x92, 0xAA, 0x55, 0x16, 0x68, 0x12, 0x48,
|
||||
0x02, 0x40, 0x02, 0x40, 0x0C, 0x30, 0x08, 0x10, 0xF8, 0x1F};
|
||||
|
||||
const unsigned char eyes[] PROGMEM = {0x00, 0x00, 0x3C, 0x3C, 0x42, 0x42, 0x81, 0x81, 0x85, 0x85, 0x8F,
|
||||
0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
|
||||
0x85, 0x85, 0x81, 0x81, 0x42, 0x42, 0x3C, 0x3C, 0x00, 0x00};
|
||||
|
||||
const unsigned char eye[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0xF8, 0x1F, 0xF4,
|
||||
0x2F, 0x7A, 0x5E, 0x39, 0x9C, 0x39, 0x9C, 0x7A, 0x5E, 0xF4, 0x2F,
|
||||
0xF8, 0x1F, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
#endif
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -22,33 +22,33 @@ extern const int numEmotes;
|
||||
extern const unsigned char thumbup[] PROGMEM;
|
||||
extern const unsigned char thumbdown[] PROGMEM;
|
||||
|
||||
#define Smiling_Eyes_height 16
|
||||
#define Smiling_Eyes_width 16
|
||||
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
||||
#define smiling_eyes_height 16
|
||||
#define smiling_eyes_width 16
|
||||
extern const unsigned char smiling_eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_height 16
|
||||
#define Grinning_width 16
|
||||
extern const unsigned char Grinning[] PROGMEM;
|
||||
#define grinning_height 16
|
||||
#define grinning_width 16
|
||||
extern const unsigned char grinning[] PROGMEM;
|
||||
|
||||
#define Slightly_Smiling_height 16
|
||||
#define Slightly_Smiling_width 16
|
||||
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
||||
#define slightly_smiling_height 16
|
||||
#define slightly_smiling_width 16
|
||||
extern const unsigned char slightly_smiling[] PROGMEM;
|
||||
|
||||
#define Winking_Face_height 16
|
||||
#define Winking_Face_width 16
|
||||
extern const unsigned char Winking_Face[] PROGMEM;
|
||||
#define winking_face_height 16
|
||||
#define winking_face_width 16
|
||||
extern const unsigned char winking_face[] PROGMEM;
|
||||
|
||||
#define Grinning_Smiling_Eyes_height 16
|
||||
#define Grinning_Smiling_Eyes_width 16
|
||||
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
||||
#define grinning_smiling_eyes_height 16
|
||||
#define grinning_smiling_eyes_width 16
|
||||
extern const unsigned char grinning_smiling_eyes[] PROGMEM;
|
||||
|
||||
#define heart_smile_height 16
|
||||
#define heart_smile_width 16
|
||||
extern const unsigned char heart_smile[] PROGMEM;
|
||||
|
||||
#define Heart_eyes_height 16
|
||||
#define Heart_eyes_width 16
|
||||
extern const unsigned char Heart_eyes[] PROGMEM;
|
||||
#define heart_eyes_height 16
|
||||
#define heart_eyes_width 16
|
||||
extern const unsigned char heart_eyes[] PROGMEM;
|
||||
|
||||
#define question_height 16
|
||||
#define question_width 16
|
||||
@@ -62,21 +62,21 @@ extern const unsigned char bang[] PROGMEM;
|
||||
#define haha_width 16
|
||||
extern const unsigned char haha[] PROGMEM;
|
||||
|
||||
#define ROFL_height 16
|
||||
#define ROFL_width 16
|
||||
extern const unsigned char ROFL[] PROGMEM;
|
||||
#define rofl_height 16
|
||||
#define rofl_width 16
|
||||
extern const unsigned char rofl[] PROGMEM;
|
||||
|
||||
#define Smiling_Closed_Eyes_height 16
|
||||
#define Smiling_Closed_Eyes_width 16
|
||||
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
||||
#define smiling_closed_eyes_height 16
|
||||
#define smiling_closed_eyes_width 16
|
||||
extern const unsigned char smiling_closed_eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_SmilingEyes2_height 16
|
||||
#define Grinning_SmilingEyes2_width 16
|
||||
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
||||
#define grinning_smiling_eyes_2_height 16
|
||||
#define grinning_smiling_eyes_2_width 16
|
||||
extern const unsigned char grinning_smiling_eyes_2[] PROGMEM;
|
||||
|
||||
#define Loudly_Crying_Face_height 16
|
||||
#define Loudly_Crying_Face_width 16
|
||||
extern const unsigned char Loudly_Crying_Face[] PROGMEM;
|
||||
#define loudly_crying_face_height 16
|
||||
#define loudly_crying_face_width 16
|
||||
extern const unsigned char loudly_crying_face[] PROGMEM;
|
||||
|
||||
#define wave_icon_height 16
|
||||
#define wave_icon_width 16
|
||||
@@ -126,21 +126,21 @@ extern const unsigned char bell_icon[] PROGMEM;
|
||||
#define cookie_height 16
|
||||
extern const unsigned char cookie[] PROGMEM;
|
||||
|
||||
#define Fire_width 16
|
||||
#define Fire_height 16
|
||||
extern const unsigned char Fire[] PROGMEM;
|
||||
#define fire_width 16
|
||||
#define fire_height 16
|
||||
extern const unsigned char fire[] PROGMEM;
|
||||
|
||||
#define peace_sign_width 16
|
||||
#define peace_sign_height 16
|
||||
extern const unsigned char peace_sign[] PROGMEM;
|
||||
|
||||
#define Praying_width 16
|
||||
#define Praying_height 16
|
||||
extern const unsigned char Praying[] PROGMEM;
|
||||
#define praying_width 16
|
||||
#define praying_height 16
|
||||
extern const unsigned char praying[] PROGMEM;
|
||||
|
||||
#define Sparkles_width 16
|
||||
#define Sparkles_height 16
|
||||
extern const unsigned char Sparkles[] PROGMEM;
|
||||
#define sparkles_width 16
|
||||
#define sparkles_height 16
|
||||
extern const unsigned char sparkles[] PROGMEM;
|
||||
|
||||
#define clown_width 16
|
||||
#define clown_height 16
|
||||
@@ -161,6 +161,178 @@ extern const unsigned char bowling[] PROGMEM;
|
||||
#define vulcan_salute_width 16
|
||||
#define vulcan_salute_height 16
|
||||
extern const unsigned char vulcan_salute[] PROGMEM;
|
||||
|
||||
#define jack_o_lantern_width 16
|
||||
#define jack_o_lantern_height 16
|
||||
extern const unsigned char jack_o_lantern[] PROGMEM;
|
||||
|
||||
#define ghost_width 16
|
||||
#define ghost_height 16
|
||||
extern const unsigned char ghost[] PROGMEM;
|
||||
|
||||
#define skull_width 16
|
||||
#define skull_height 16
|
||||
extern const unsigned char skull[] PROGMEM;
|
||||
|
||||
#define vomiting_width 16
|
||||
#define vomiting_height 16
|
||||
extern const unsigned char vomiting[] PROGMEM;
|
||||
|
||||
#define cool_width 16
|
||||
#define cool_height 16
|
||||
extern const unsigned char cool[] PROGMEM;
|
||||
|
||||
#define shortcake_width 16
|
||||
#define shortcake_height 16
|
||||
extern const unsigned char shortcake[] PROGMEM;
|
||||
|
||||
#define caution_width 16
|
||||
#define caution_height 16
|
||||
extern const unsigned char caution[] PROGMEM;
|
||||
|
||||
#define clipboard_width 16
|
||||
#define clipboard_height 16
|
||||
extern const unsigned char clipboard[] PROGMEM;
|
||||
|
||||
#define snowflake_width 16
|
||||
#define snowflake_height 16
|
||||
extern const unsigned char snowflake[] PROGMEM;
|
||||
|
||||
#define drop_width 16
|
||||
#define drop_height 16
|
||||
extern const unsigned char drop[] PROGMEM;
|
||||
|
||||
#define thermometer_width 16
|
||||
#define thermometer_height 16
|
||||
extern const unsigned char thermometer[] PROGMEM;
|
||||
|
||||
#define sun_behind_raincloud_width 16
|
||||
#define sun_behind_raincloud_height 16
|
||||
extern const unsigned char sun_behind_raincloud[] PROGMEM;
|
||||
|
||||
#define sun_behind_cloud_width 16
|
||||
#define sun_behind_cloud_height 16
|
||||
extern const unsigned char sun_behind_cloud[] PROGMEM;
|
||||
|
||||
#define cloud_with_snow_width 16
|
||||
#define cloud_with_snow_height 16
|
||||
extern const unsigned char cloud_with_snow[] PROGMEM;
|
||||
|
||||
#define cloud_with_lightning_width 16
|
||||
#define cloud_with_lightning_height 16
|
||||
extern const unsigned char cloud_with_lightning[] PROGMEM;
|
||||
|
||||
#define cloud_with_lightning_rain_width 16
|
||||
#define cloud_with_lightning_rain_height 16
|
||||
extern const unsigned char cloud_with_lightning_rain[] PROGMEM;
|
||||
|
||||
#define wind_face_width 16
|
||||
#define wind_face_height 16
|
||||
extern const unsigned char wind_face[] PROGMEM;
|
||||
|
||||
#define new_moon_width 16
|
||||
#define new_moon_height 16
|
||||
extern const unsigned char new_moon[] PROGMEM;
|
||||
|
||||
#define waxing_crescent_moon_width 16
|
||||
#define waxing_crescent_moon_height 16
|
||||
extern const unsigned char waxing_crescent_moon[] PROGMEM;
|
||||
|
||||
#define first_quarter_moon_width 16
|
||||
#define first_quarter_moon_height 16
|
||||
extern const unsigned char first_quarter_moon[] PROGMEM;
|
||||
|
||||
#define waxing_gibbous_moon_width 16
|
||||
#define waxing_gibbous_moon_height 16
|
||||
extern const unsigned char waxing_gibbous_moon[] PROGMEM;
|
||||
|
||||
#define full_moon_width 16
|
||||
#define full_moon_height 16
|
||||
extern const unsigned char full_moon[] PROGMEM;
|
||||
|
||||
#define waning_gibbous_moon_width 16
|
||||
#define waning_gibbous_moon_height 16
|
||||
extern const unsigned char waning_gibbous_moon[] PROGMEM;
|
||||
|
||||
#define last_quarter_moon_width 16
|
||||
#define last_quarter_moon_height 16
|
||||
extern const unsigned char last_quarter_moon[] PROGMEM;
|
||||
|
||||
#define waning_crescent_moon_width 16
|
||||
#define waning_crescent_moon_height 16
|
||||
extern const unsigned char waning_crescent_moon[] PROGMEM;
|
||||
|
||||
#define first_quarter_moon_face_width 16
|
||||
#define first_quarter_moon_face_height 16
|
||||
extern const unsigned char first_quarter_moon_face[] PROGMEM;
|
||||
|
||||
#define peach_width 16
|
||||
#define peach_height 16
|
||||
extern const unsigned char peach[] PROGMEM;
|
||||
|
||||
#define turkey_width 16
|
||||
#define turkey_height 16
|
||||
extern const unsigned char turkey[] PROGMEM;
|
||||
|
||||
#define turkey_leg_width 16
|
||||
#define turkey_leg_height 16
|
||||
extern const unsigned char turkey_leg[] PROGMEM;
|
||||
|
||||
#define south_west_arrow_width 16
|
||||
#define south_west_arrow_height 16
|
||||
extern const unsigned char south_west_arrow[] PROGMEM;
|
||||
|
||||
#define south_east_arrow_width 16
|
||||
#define south_east_arrow_height 16
|
||||
extern const unsigned char south_east_arrow[] PROGMEM;
|
||||
|
||||
#define north_west_arrow_width 16
|
||||
#define north_west_arrow_height 16
|
||||
extern const unsigned char north_west_arrow[] PROGMEM;
|
||||
|
||||
#define north_east_arrow_width 16
|
||||
#define north_east_arrow_height 16
|
||||
extern const unsigned char north_east_arrow[] PROGMEM;
|
||||
|
||||
#define downwards_arrow_width 16
|
||||
#define downwards_arrow_height 16
|
||||
extern const unsigned char downwards_arrow[] PROGMEM;
|
||||
|
||||
#define leftwards_arrow_width 16
|
||||
#define leftwards_arrow_height 16
|
||||
extern const unsigned char leftwards_arrow[] PROGMEM;
|
||||
|
||||
#define upwards_arrow_width 16
|
||||
#define upwards_arrow_height 16
|
||||
extern const unsigned char upwards_arrow[] PROGMEM;
|
||||
|
||||
#define rightwards_arrow_width 16
|
||||
#define rightwards_arrow_height 16
|
||||
extern const unsigned char rightwards_arrow[] PROGMEM;
|
||||
|
||||
#define strong_width 16
|
||||
#define strong_height 16
|
||||
extern const unsigned char strong[] PROGMEM;
|
||||
|
||||
#define check_mark_width 16
|
||||
#define check_mark_height 16
|
||||
extern const unsigned char check_mark[] PROGMEM;
|
||||
|
||||
#define house_width 16
|
||||
#define house_height 16
|
||||
extern const unsigned char house[] PROGMEM;
|
||||
|
||||
#define shrug_width 16
|
||||
#define shrug_height 16
|
||||
extern const unsigned char shrug[] PROGMEM;
|
||||
|
||||
#define eyes_width 16
|
||||
#define eyes_height 16
|
||||
extern const unsigned char eyes[] PROGMEM;
|
||||
|
||||
#define eye_width 16
|
||||
#define eye_height 16
|
||||
extern const unsigned char eye[] PROGMEM;
|
||||
#endif // EXCLUDE_EMOJI
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace graphics
|
||||
|
||||
@@ -28,7 +28,7 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
defined(USE_ST7796) || defined(HACKADAY_COMMUNICATOR) || ARCH_PORTDUINO) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||
|
||||
@@ -88,8 +88,14 @@ class Applet : public GFX
|
||||
virtual void onForeground() {}
|
||||
virtual void onBackground() {}
|
||||
virtual void onShutdown() {}
|
||||
virtual void onButtonShortPress() {} // (System Applets only)
|
||||
virtual void onButtonLongPress() {} // (System Applets only)
|
||||
virtual void onButtonShortPress() {}
|
||||
virtual void onButtonLongPress() {}
|
||||
virtual void onExitShort() {}
|
||||
virtual void onExitLong() {}
|
||||
virtual void onNavUp() {}
|
||||
virtual void onNavDown() {}
|
||||
virtual void onNavLeft() {}
|
||||
virtual void onNavRight() {}
|
||||
|
||||
virtual bool approveNotification(Notification &n); // Allow an applet to veto a notification
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ uint32_t InkHUD::AppletFont::toUtf32(std::string utf8)
|
||||
utf32 |= (utf8.at(3) & 0b00111111);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return utf32;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user