mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-10 14:01:00 +10:00
Compare commits
95
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
016e68ec53 | ||
|
|
79f469ce71 | ||
|
|
0501e177e9 | ||
|
|
b941dab900 | ||
|
|
0ed537a336 | ||
|
|
86dad90573 | ||
|
|
5b1ea922f3 | ||
|
|
5b94f580dc | ||
|
|
3d524be965 | ||
|
|
cb28c38828 | ||
|
|
969aefa551 | ||
|
|
afd5e29bce | ||
|
|
20f838a61e | ||
|
|
58736f5184 | ||
|
|
22031c5886 | ||
|
|
fe4e75eb66 | ||
|
|
6ba82ed5b6 | ||
|
|
a8fed3256e | ||
|
|
1626836a71 | ||
|
|
66161da2a7 | ||
|
|
7ea28d34b2 | ||
|
|
65bf1630b3 | ||
|
|
3972fe1fd0 | ||
|
|
5ced739a57 | ||
|
|
b7bf251798 | ||
|
|
90742fc87e | ||
|
|
f7f356e2e2 | ||
|
|
1fad7facd6 | ||
|
|
153ab81a9f | ||
|
|
8d73d67246 | ||
|
|
0d46943bb8 | ||
|
|
deb45e471c | ||
|
|
3601eabbf8 | ||
|
|
eb2f3cef89 | ||
|
|
85be5965b0 | ||
|
|
1e34c1ef1b | ||
|
|
5f852a1c05 | ||
|
|
1d90ea6f1d | ||
|
|
65eee22396 | ||
|
|
cb938266c7 | ||
|
|
8093e2ed5a | ||
|
|
80af726877 | ||
|
|
3f5dc78744 | ||
|
|
563adc6aaa | ||
|
|
67f806b0a5 | ||
|
|
c7dc536640 | ||
|
|
6920a5f8b1 | ||
|
|
2b7a230977 | ||
|
|
1e16185fdd | ||
|
|
60c2592694 | ||
|
|
fc0ad4956e | ||
|
|
43aa90fc3f | ||
|
|
c28bdbd7e6 | ||
|
|
857c7b3a3a | ||
|
|
83cac93ca8 | ||
|
|
d34fa3e7df | ||
|
|
75cb8bb5ea | ||
|
|
2a99cc6a25 | ||
|
|
b5f98d1270 | ||
|
|
ef697319da | ||
|
|
efd68f9fad | ||
|
|
3a74e049ab | ||
|
|
3b1b308357 | ||
|
|
5a068431ed | ||
|
|
25f086a64f | ||
|
|
a93d4d7e9d | ||
|
|
54781cf51a | ||
|
|
ad7d19c317 | ||
|
|
58496e56d2 | ||
|
|
2c18a41613 | ||
|
|
c65eecc295 | ||
|
|
cac45d9ced | ||
|
|
02d42f87d3 | ||
|
|
9c439f8d0a | ||
|
|
cf998f03b6 | ||
|
|
f9d1f2414a | ||
|
|
13b25c0614 | ||
|
|
607b631114 | ||
|
|
99e88bb499 | ||
|
|
4f84cf011d | ||
|
|
0726a9f774 | ||
|
|
f8cc1d6046 | ||
|
|
f615990c00 | ||
|
|
8f81b194d3 | ||
|
|
6bc3e31537 | ||
|
|
15460c8f97 | ||
|
|
a77ac21e0d | ||
|
|
2b6d8f6824 | ||
|
+19 |
4c91beeda9 | ||
|
|
d0cf79a991 | ||
|
|
5408e81de7 | ||
|
|
357a33f454 | ||
|
|
4fccda26c6 | ||
|
|
f94c01b452 | ||
|
|
321ccbf5e2 |
@@ -100,7 +100,7 @@ runs:
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
|
||||
- Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first
|
||||
to say "Hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
|
||||
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
||||
is appreciated." This will allow other devs to potentially save you time by not accidentally duplicating work etc...
|
||||
- Please do not check in files that don't have real changes
|
||||
- Please do not reformat lines that you didn't have to change the code on
|
||||
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (In beta for windows, WSL2 for the linux version),
|
||||
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (In beta for windows, WSL2 for the Linux version),
|
||||
because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines.
|
||||
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
||||
- If your other co-developers have comments on your PR please tweak as needed.
|
||||
- Please also enable "Allow edits by maintainers".
|
||||
- Please do not submit untested code.
|
||||
- If you do not have the affected hardware to test your code changes adequately against regressions, please indicate this, so that contributors and commnunity members can help test your changes.
|
||||
- If you do not have the affected hardware to test your code changes adequately against regressions, please indicate this, so that contributors and community members can help test your changes.
|
||||
- If your PR gets accepted you can request a "Contributor" role in the Meshtastic Discord
|
||||
|
||||
## 🤝 Attestations
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
sudo mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
uses: crazy-max/ghaction-import-gpg@v7
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.PPA_GPG_PRIVATE_KEY }}
|
||||
id: gpg
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
PKG_VERSION: ${{ steps.version.outputs.deb }}
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
overwrite: true
|
||||
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
echo "</details>" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-firmware
|
||||
with:
|
||||
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
release/device-*.bat
|
||||
|
||||
- name: Store manifests as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-manifest
|
||||
with:
|
||||
name: manifest-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
|
||||
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-*-*
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-*-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
|
||||
@@ -35,8 +35,8 @@ jobs:
|
||||
series:
|
||||
- jammy # 22.04 LTS
|
||||
- noble # 24.04 LTS
|
||||
- plucky # 25.04
|
||||
- questing # 25.10
|
||||
- resolute # 26.04 LTS
|
||||
uses: ./.github/workflows/package_ppa.yml
|
||||
with:
|
||||
ppa_repo: ppa:meshtastic/daily
|
||||
|
||||
@@ -60,13 +60,13 @@ jobs:
|
||||
|
||||
- name: Docker login
|
||||
if: ${{ inputs.push }}
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: meshtastic
|
||||
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Docker setup
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
id: tags
|
||||
|
||||
- name: Docker login
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: meshtastic
|
||||
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
|
||||
|
||||
@@ -96,7 +96,6 @@ jobs:
|
||||
pio_platform: ${{ matrix.check.platform }}
|
||||
pio_env: ${{ matrix.check.board }}
|
||||
pio_target: check
|
||||
pio_opts: --fail-on-defect=low
|
||||
|
||||
build:
|
||||
needs: [setup, version]
|
||||
@@ -178,7 +177,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
@@ -188,7 +187,7 @@ jobs:
|
||||
run: ls -R
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -206,7 +205,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -225,7 +224,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -251,13 +250,13 @@ jobs:
|
||||
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
|
||||
uses: actions/download-artifact@v8
|
||||
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
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-manifest
|
||||
with:
|
||||
name: manifests-${{ github.sha }}
|
||||
@@ -325,14 +324,14 @@ jobs:
|
||||
body: ${{ steps.release_notes.outputs.notes }}
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
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@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -356,7 +355,7 @@ jobs:
|
||||
}' > firmware-${{ needs.version.outputs.long }}.json
|
||||
|
||||
- name: Save Release manifest artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: manifest-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -397,7 +396,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -414,7 +413,7 @@ jobs:
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -455,14 +454,14 @@ jobs:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Get firmware artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./publish
|
||||
|
||||
- name: Get manifest artifact
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: manifest-${{ needs.version.outputs.long }}
|
||||
path: ./publish
|
||||
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
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@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -195,7 +195,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -235,14 +235,14 @@ jobs:
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
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@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -292,7 +292,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -347,7 +347,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
@@ -54,9 +54,19 @@ jobs:
|
||||
PLATFORMIO_LIBDEPS_DIR: pio/libdeps
|
||||
PLATFORMIO_PACKAGES_DIR: pio/packages
|
||||
PLATFORMIO_CORE_DIR: pio/core
|
||||
PLATFORMIO_SETTING_ENABLE_TELEMETRY: 0
|
||||
PLATFORMIO_SETTING_CHECK_PLATFORMIO_INTERVAL: 3650
|
||||
PLATFORMIO_SETTING_CHECK_PRUNE_SYSTEM_THRESHOLD: 10240
|
||||
|
||||
- name: Mangle platformio cache
|
||||
# Add "1" to epoch-timestamps of all downloads in the cache.
|
||||
# This is a hack to prevent internet access at build-time.
|
||||
run: |
|
||||
cp pio/core/.cache/downloads/usage.db pio/core/.cache/downloads/usage.db.bak
|
||||
jq -c 'with_entries(.value |= (. | tostring + "1" | tonumber))' pio/core/.cache/downloads/usage.db.bak > pio/core/.cache/downloads/usage.db
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
sudo apt-get install -y dput
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
uses: crazy-max/ghaction-import-gpg@v7
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.PPA_GPG_PRIVATE_KEY }}
|
||||
id: gpg
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
- name: Download test artifacts
|
||||
if: needs.native-tests.result != 'skipped'
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
@@ -23,8 +23,8 @@ jobs:
|
||||
series:
|
||||
- jammy # 22.04 LTS
|
||||
- noble # 24.04 LTS
|
||||
- plucky # 25.04
|
||||
- questing # 25.10
|
||||
- resolute # 26.04 LTS
|
||||
uses: ./.github/workflows/package_ppa.yml
|
||||
with:
|
||||
ppa_repo: |-
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
# step 3
|
||||
- name: save report as pipeline artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: report.sarif
|
||||
overwrite: true
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Stale PR+Issues
|
||||
uses: actions/stale@v10.1.1
|
||||
uses: actions/stale@v10.2.0
|
||||
with:
|
||||
days-before-stale: 45
|
||||
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
|
||||
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
|
||||
- name: Save test results
|
||||
if: always() # run this step even if previous step failed
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
|
||||
@@ -137,20 +137,20 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download test artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
- name: Test Report
|
||||
uses: dorny/test-reporter@v2.5.0
|
||||
uses: dorny/test-reporter@v2.6.0
|
||||
with:
|
||||
name: PlatformIO Tests
|
||||
path: testreport.xml
|
||||
reporter: java-junit
|
||||
|
||||
- name: Download coverage artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
|
||||
|
||||
- name: Save Code Coverage Report
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: code-coverage-report-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
|
||||
+10
-10
@@ -4,24 +4,24 @@ cli:
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.7.4
|
||||
ref: v1.7.5
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.501
|
||||
- renovate@43.10.3
|
||||
- checkov@3.2.506
|
||||
- renovate@43.52.0
|
||||
- prettier@3.8.1
|
||||
- trufflehog@3.93.3
|
||||
- trufflehog@3.93.6
|
||||
- yamllint@1.38.0
|
||||
- bandit@1.9.3
|
||||
- trivy@0.69.1
|
||||
- bandit@1.9.4
|
||||
- trivy@0.69.3
|
||||
- taplo@0.10.0
|
||||
- ruff@0.15.1
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.47.0
|
||||
- ruff@0.15.4
|
||||
- isort@8.0.1
|
||||
- markdownlint@0.48.0
|
||||
- oxipng@10.1.0
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.10
|
||||
- actionlint@1.7.11
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Lightweight container for running native PlatformIO tests on non-Linux hosts
|
||||
FROM python:3.14-slim-trixie
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PIP_ROOT_USER_ACTION=ignore
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
g++ git ca-certificates pkg-config \
|
||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
|
||||
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \
|
||||
libx11-dev libinput-dev libxkbcommon-x11-dev libsqlite3-dev libsdl2-dev \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir platformio==6.1.19 \
|
||||
&& useradd --create-home --shell /usr/sbin/nologin meshtastic
|
||||
|
||||
WORKDIR /firmware
|
||||
RUN chown -R meshtastic:meshtastic /firmware
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD platformio --version || exit 1
|
||||
|
||||
USER meshtastic
|
||||
|
||||
# Run tests by default; override with docker run args for specific filters
|
||||
CMD ["platformio", "test", "-e", "coverage", "-v"]
|
||||
+1
-1
@@ -23,4 +23,4 @@ for BOARD in $BOARDS; do
|
||||
CHECK="${CHECK} -e ${BOARD}"
|
||||
done
|
||||
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt --inline-suppr" $CHECK --skip-packages --pattern="src/" --fail-on-defect=medium --fail-on-defect=high
|
||||
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt --inline-suppr" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high
|
||||
|
||||
@@ -187,6 +187,7 @@ Logging:
|
||||
LogLevel: info # debug, info, warn, error
|
||||
# TraceFile: /var/log/meshtasticd.json
|
||||
# JSONFile: /packets.json # File location for JSON output of decoded packets
|
||||
# JSONFileRotate: 60 # Rotate JSON file every N minutes, or 0 for no rotation
|
||||
# JSONFilter: position # filter for packets to save to JSON file
|
||||
# AsciiLogs: true # default if not specified is !isatty() on stdout
|
||||
|
||||
@@ -214,3 +215,4 @@ General:
|
||||
AvailableDirectory: /etc/meshtasticd/available.d/
|
||||
# MACAddress: AA:BB:CC:DD:EE:FF
|
||||
# MACAddressSource: eth0
|
||||
# APIPort: 4403
|
||||
|
||||
@@ -6,6 +6,9 @@ Lora:
|
||||
Reset: 16 # IO4
|
||||
Busy: 24 # IO5
|
||||
# Ant_sw: 13 # IO3
|
||||
Enable_Pins:
|
||||
- 12
|
||||
- 13
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
|
||||
@@ -4,5 +4,8 @@ Lora:
|
||||
Reset: 24 # IO4
|
||||
Busy: 19 # IO5
|
||||
# Ant_sw: 23 # IO3
|
||||
Enable_Pins:
|
||||
- 26
|
||||
- 23
|
||||
spidev: spidev0.1
|
||||
# CS: 7
|
||||
@@ -0,0 +1,16 @@
|
||||
Lora:
|
||||
|
||||
### RAK13300in Slot 1
|
||||
Module: sx1262
|
||||
IRQ: 22 #IO6
|
||||
Reset: 16 # IO4
|
||||
Busy: 24 # IO5
|
||||
# Ant_sw: 13 # IO3
|
||||
Enable_Pins:
|
||||
- 12
|
||||
- 13
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
# CS: 8
|
||||
TX_GAIN_LORA: [8]
|
||||
@@ -0,0 +1,12 @@
|
||||
Lora:
|
||||
### RAK13300in Slot 2 pins
|
||||
IRQ: 18 #IO6
|
||||
Reset: 24 # IO4
|
||||
Busy: 19 # IO5
|
||||
# Ant_sw: 23 # IO3
|
||||
Enable_Pins:
|
||||
- 26
|
||||
- 23
|
||||
spidev: spidev0.1
|
||||
# CS: 7
|
||||
TX_GAIN_LORA: [8]
|
||||
@@ -5,7 +5,11 @@ Lora:
|
||||
IRQ: 22 #IO6
|
||||
Reset: 16 # IO4
|
||||
Busy: 24 # IO5
|
||||
# Ant_sw: 13 # IO3
|
||||
Enable_Pins:
|
||||
- 12
|
||||
- 13
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
# GPIO_DETECT_PA: 13
|
||||
TX_GAIN_LORA: [8]
|
||||
@@ -0,0 +1,16 @@
|
||||
# For use with Armbian luckfox-lyra-ultra-w
|
||||
# Enable overlay 'luckfox-lyra-ultra-w-spi0-cs0-spidev' with armbian-config
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/Luckfox%20Ultra%20Hat
|
||||
# 1 Watt Lyra Ultra hat
|
||||
Lora:
|
||||
Module: sx1262
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
CS: 10
|
||||
IRQ: 5
|
||||
Busy: 11
|
||||
Reset: 9
|
||||
RXen: 14
|
||||
|
||||
spidev: spidev0.0 #pins are (CS=10, CLK=8, MOSI=6, MISO=7)
|
||||
spiSpeed: 2000000
|
||||
@@ -0,0 +1,17 @@
|
||||
# For use with Armbian luckfox-lyra-ultra-w
|
||||
# Enable overlay 'luckfox-lyra-ultra-w-spi0-cs0-spidev' with armbian-config
|
||||
# https://github.com/wehooper4/Meshtastic-Hardware/tree/main/Luckfox%20Ultra%20Hat
|
||||
# 2 Watt Lyra Ultra hat
|
||||
Lora:
|
||||
Module: sx1262
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
SX126X_MAX_POWER: 8
|
||||
CS: 10
|
||||
IRQ: 5
|
||||
Busy: 11
|
||||
Reset: 9
|
||||
RXen: 14
|
||||
|
||||
spidev: spidev0.0 #pins are (CS=10, CLK=8, MOSI=6, MISO=7)
|
||||
spiSpeed: 2000000
|
||||
@@ -0,0 +1,25 @@
|
||||
# For use with Armbian luckfox-lyra // luckfox-lyra-plus
|
||||
# Enable overlay 'luckfox-lyra-plus-spi0-cs0_rmio13-spidev' with armbian-config
|
||||
# Waveshare LoRa HAT for Raspberry Pi Pico
|
||||
# https://www.waveshare.com/wiki/Pico-LoRa-SX1262
|
||||
Lora:
|
||||
Module: sx1262
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
spidev: spidev0.0
|
||||
CS: # GPIO0_B5
|
||||
pin: 13
|
||||
gpiochip: 0
|
||||
line: 13
|
||||
IRQ: # GPIO1_C2
|
||||
pin: 50
|
||||
gpiochip: 1
|
||||
line: 18
|
||||
Busy: # GPIO0_B4
|
||||
pin: 12
|
||||
gpiochip: 0
|
||||
line: 12
|
||||
Reset: # GPIO0_A2
|
||||
pin: 2
|
||||
gpiochip: 0
|
||||
line: 2
|
||||
@@ -13,8 +13,7 @@ Lora:
|
||||
# USB_Serialnum: 12345678
|
||||
SX126X_MAX_POWER: 22
|
||||
# Reduce output power to improve EMI
|
||||
NUM_PA_POINTS: 22
|
||||
TX_GAIN_LORA: 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 8, 8, 7
|
||||
TX_GAIN_LORA: [12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 8, 8, 7]
|
||||
# Note: This module integrates an additional PA to achieve higher output power.
|
||||
# The 'power' parameter here does not represent the actual RF output.
|
||||
# TX_GAIN_LORA defines the gain offset applied at each SX1262 input power step (1–22 dBm).
|
||||
|
||||
@@ -13,8 +13,7 @@ Lora:
|
||||
# USB_Serialnum: 12345678
|
||||
SX126X_MAX_POWER: 22
|
||||
# Reduce output power to improve EMI
|
||||
NUM_PA_POINTS: 22
|
||||
TX_GAIN_LORA: 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 8, 8, 7
|
||||
TX_GAIN_LORA: [12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 8, 8, 7]
|
||||
# Note: This module integrates an additional PA to achieve higher output power.
|
||||
# The 'power' parameter here does not represent the actual RF output.
|
||||
# TX_GAIN_LORA defines the gain offset applied at each SX1262 input power step (1–22 dBm).
|
||||
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run native PlatformIO tests inside Docker (for macOS / non-Linux hosts).
|
||||
#
|
||||
# Usage:
|
||||
# ./bin/test-native-docker.sh # run all native tests
|
||||
# ./bin/test-native-docker.sh -f test_transmit_history # run specific test filter
|
||||
# ./bin/test-native-docker.sh --rebuild # force rebuild the image
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
IMAGE_NAME="meshtastic-native-test"
|
||||
|
||||
REBUILD=false
|
||||
EXTRA_ARGS=()
|
||||
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--rebuild" ]]; then
|
||||
REBUILD=true
|
||||
else
|
||||
EXTRA_ARGS+=("$arg")
|
||||
fi
|
||||
done
|
||||
|
||||
if $REBUILD || ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
|
||||
echo "Building test image (first run may take a few minutes)..."
|
||||
docker build -t "$IMAGE_NAME" -f "$ROOT_DIR/Dockerfile.test" "$ROOT_DIR"
|
||||
fi
|
||||
|
||||
# Disable BUILD_EPOCH to avoid full rebuilds between test runs (matches CI)
|
||||
sed_cmd='s/-DBUILD_EPOCH=$UNIX_TIME/#-DBUILD_EPOCH=$UNIX_TIME/'
|
||||
|
||||
# Default: run all tests. Pass extra args (e.g. -f test_transmit_history) through.
|
||||
if [[ ${#EXTRA_ARGS[@]} -eq 0 ]]; then
|
||||
CMD=("platformio" "test" "-e" "coverage" "-v")
|
||||
else
|
||||
CMD=("platformio" "test" "-e" "coverage" "-v" "${EXTRA_ARGS[@]}")
|
||||
fi
|
||||
|
||||
exec docker run --rm \
|
||||
-v "$ROOT_DIR:/src:ro" \
|
||||
"$IMAGE_NAME" \
|
||||
bash -c "rm -rf /tmp/fw-test && cp -a /src /tmp/fw-test && cd /tmp/fw-test && sed -i '${sed_cmd}' platformio.ini && ${CMD[*]}"
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_ESP32S3_DEV",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": ["wifi"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "LilyGo Mini-Epaper-S3 (4 MB Flash, 2MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.lilygo.cc",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
+1
-1
@@ -12,6 +12,6 @@ Ex:
|
||||
- `logo_320x480.png`
|
||||
- `logo_320x240.png`
|
||||
|
||||
This file is copied to `data/boot/logo.png` before filesytem image compilation.
|
||||
This file is copied to `data/boot/logo.png` before filesystem image compilation.
|
||||
|
||||
For additional examples see the [`event/defcon33` branch](https://github.com/meshtastic/firmware/tree/event/defcon33).
|
||||
|
||||
Vendored
+3
@@ -3,6 +3,9 @@ export DEBEMAIL="jbennett@incomsystems.biz"
|
||||
export PLATFORMIO_LIBDEPS_DIR=pio/libdeps
|
||||
export PLATFORMIO_PACKAGES_DIR=pio/packages
|
||||
export PLATFORMIO_CORE_DIR=pio/core
|
||||
export PLATFORMIO_SETTING_ENABLE_TELEMETRY=0
|
||||
export PLATFORMIO_SETTING_CHECK_PLATFORMIO_INTERVAL=3650
|
||||
export PLATFORMIO_SETTING_CHECK_PRUNE_SYSTEM_THRESHOLD=10240
|
||||
|
||||
# Download libraries to `pio`
|
||||
platformio pkg install -e native-tft
|
||||
|
||||
Vendored
+4
-1
@@ -9,7 +9,10 @@
|
||||
PIO_ENV:=\
|
||||
PLATFORMIO_CORE_DIR=pio/core \
|
||||
PLATFORMIO_LIBDEPS_DIR=pio/libdeps \
|
||||
PLATFORMIO_PACKAGES_DIR=pio/packages
|
||||
PLATFORMIO_PACKAGES_DIR=pio/packages \
|
||||
PLATFORMIO_SETTING_ENABLE_TELEMETRY=0 \
|
||||
PLATFORMIO_SETTING_CHECK_PLATFORMIO_INTERVAL=3650 \
|
||||
PLATFORMIO_SETTING_CHECK_PRUNE_SYSTEM_THRESHOLD=10240
|
||||
|
||||
# Raspbian armhf builds should be compatible with armv6-hardfloat
|
||||
# https://www.valvers.com/open-software/raspberry-pi/bare-metal-programming-in-c-part-1/#rpi1-compiler-flags
|
||||
|
||||
+4
-4
@@ -138,7 +138,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library
|
||||
adafruit/Adafruit BME280 Library@2.3.0
|
||||
# renovate: datasource=custom.pio depName=Adafruit DPS310 packageName=adafruit/library/Adafruit DPS310
|
||||
adafruit/Adafruit DPS310@1.1.5
|
||||
adafruit/Adafruit DPS310@1.1.6
|
||||
# renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library
|
||||
adafruit/Adafruit MCP9808 Library@2.0.2
|
||||
# renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library
|
||||
@@ -150,7 +150,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=Adafruit LIS3DH packageName=adafruit/library/Adafruit LIS3DH
|
||||
adafruit/Adafruit LIS3DH@1.3.0
|
||||
# renovate: datasource=custom.pio depName=Adafruit AHTX0 packageName=adafruit/library/Adafruit AHTX0
|
||||
adafruit/Adafruit AHTX0@2.0.5
|
||||
adafruit/Adafruit AHTX0@2.0.6
|
||||
# renovate: datasource=custom.pio depName=Adafruit LSM6DS packageName=adafruit/library/Adafruit LSM6DS
|
||||
adafruit/Adafruit LSM6DS@4.7.4
|
||||
# renovate: datasource=custom.pio depName=Adafruit TSL2591 packageName=adafruit/library/Adafruit TSL2591 Library
|
||||
@@ -158,7 +158,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=EmotiBit MLX90632 packageName=emotibit/library/EmotiBit MLX90632
|
||||
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
|
||||
adafruit/Adafruit MLX90614 Library@2.1.6
|
||||
# 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
|
||||
@@ -180,7 +180,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150
|
||||
dfrobot/DFRobot_BMM150@1.0.0
|
||||
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
||||
adafruit/Adafruit TSL2561@1.1.2
|
||||
adafruit/Adafruit TSL2561@1.1.3
|
||||
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE
|
||||
wollewald/BH1750_WE@1.1.10
|
||||
|
||||
|
||||
+1
-1
Submodule protobufs updated: 44298d374f...a229208f29
+1
-3
@@ -51,9 +51,7 @@ class AudioThread : public concurrency::OSThread
|
||||
i2sRtttl = nullptr;
|
||||
}
|
||||
|
||||
if (rtttlFile != nullptr) {
|
||||
rtttlFile = nullptr;
|
||||
}
|
||||
rtttlFile = nullptr;
|
||||
|
||||
setCPUFast(false);
|
||||
#ifdef T_LORA_PAGER
|
||||
|
||||
+8
-2
@@ -38,7 +38,10 @@ static bool isPowered()
|
||||
return true;
|
||||
#endif
|
||||
|
||||
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
bool isRouter = ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
|
||||
? 1
|
||||
: 0);
|
||||
|
||||
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
|
||||
// We assume routers might be powered all the time, but from a low current (solar) source
|
||||
@@ -262,7 +265,10 @@ Fsm powerFSM(&stateBOOT);
|
||||
|
||||
void PowerFSM_setup()
|
||||
{
|
||||
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
|
||||
bool isRouter = ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
|
||||
? 1
|
||||
: 0);
|
||||
bool hasPower = isPowered();
|
||||
|
||||
LOG_INFO("PowerFSM init, USB power=%d", hasPower ? 1 : 0);
|
||||
|
||||
@@ -35,6 +35,8 @@ void consoleInit()
|
||||
#if defined(SERIAL_HAS_ON_RECEIVE)
|
||||
// onReceive does only exist for HardwareSerial not for USB CDC serial
|
||||
Port.onReceive([sc]() { sc->rxInt(); });
|
||||
#else
|
||||
(void)sc;
|
||||
#endif
|
||||
DEBUG_PORT.rpInit(); // Simply sets up semaphore
|
||||
}
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Periodically invoke a callback. This just provides C-style callback conventions
|
||||
* rather than a virtual function - FIXME, remove?
|
||||
* @brief Periodically invoke a callback.
|
||||
* Supports both legacy function pointers and modern callables.
|
||||
*/
|
||||
class Periodic : public OSThread
|
||||
{
|
||||
int32_t (*callback)();
|
||||
|
||||
public:
|
||||
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
|
||||
Periodic(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
|
||||
Periodic(const char *name, int32_t (*cb)()) : OSThread(name), callback(cb) {}
|
||||
Periodic(const char *name, std::function<int32_t()> cb) : OSThread(name), callback(std::move(cb)) {}
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override { return callback(); }
|
||||
int32_t runOnce() override { return callback ? callback() : 0; }
|
||||
|
||||
private:
|
||||
std::function<int32_t()> callback;
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
|
||||
@@ -149,6 +149,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
|
||||
#endif
|
||||
|
||||
#ifdef USE_KCT8103L_PA
|
||||
// Power Amps are often non-linear, so we can use an array of values for the power curve
|
||||
#define NUM_PA_POINTS 22
|
||||
#define TX_GAIN_LORA 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 10, 9, 8, 7
|
||||
#endif
|
||||
|
||||
#ifdef RAK13302
|
||||
#define NUM_PA_POINTS 22
|
||||
#define TX_GAIN_LORA 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8
|
||||
@@ -163,6 +169,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define TX_GAIN_LORA 0
|
||||
#endif
|
||||
|
||||
#ifndef HAS_LORA_FEM
|
||||
#define HAS_LORA_FEM 0
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Feature toggles
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -261,6 +271,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BHI260AP_ADDR 0x28
|
||||
#define BMM150_ADDR 0x13
|
||||
#define DA217_ADDR 0x26
|
||||
#define BMI270_ADDR 0x68
|
||||
#define BMI270_ADDR_ALT 0x69
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// LED
|
||||
@@ -487,6 +499,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MESHTASTIC_EXCLUDE_REMOTEHARDWARE 1
|
||||
#define MESHTASTIC_EXCLUDE_STOREFORWARD 1
|
||||
#define MESHTASTIC_EXCLUDE_TEXTMESSAGE 1
|
||||
#define MESHTASTIC_EXCLUDE_TRAFFIC_MANAGEMENT 1
|
||||
#define MESHTASTIC_EXCLUDE_ATAK 1
|
||||
#define MESHTASTIC_EXCLUDE_CANNEDMESSAGES 1
|
||||
#define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1
|
||||
|
||||
@@ -37,8 +37,8 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P, BMM150};
|
||||
return firstOfOrNONE(9, types);
|
||||
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P, BMM150, BMI270};
|
||||
return firstOfOrNONE(10, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAQI() const
|
||||
|
||||
@@ -89,10 +89,12 @@ class ScanI2C
|
||||
DA217,
|
||||
CHSC6X,
|
||||
CST226SE,
|
||||
BMI270,
|
||||
SEN5X,
|
||||
SFA30,
|
||||
CW2015,
|
||||
SCD30
|
||||
SCD30,
|
||||
ADS1115
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -652,9 +652,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
}
|
||||
break;
|
||||
|
||||
case ICM20948_ADDR: // same as BMX160_ADDR and SEN5X_ADDR
|
||||
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
|
||||
// ICM20948 Register check
|
||||
case ICM20948_ADDR: // same as BMX160_ADDR, BMI270_ADDR_ALT, and SEN5X_ADDR
|
||||
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR, BMI270_ADDR
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
||||
#ifdef HAS_ICM20948
|
||||
type = ICM20948;
|
||||
@@ -665,6 +664,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
type = ICM20948;
|
||||
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
||||
break;
|
||||
} else if (registerValue == 0x24) {
|
||||
type = BMI270;
|
||||
logFoundDevice("BMI270", (uint8_t)addr.address);
|
||||
break;
|
||||
} else if (registerValue == 0xD8) { // BMX160 chip ID at register 0x00
|
||||
type = BMX160;
|
||||
logFoundDevice("BMX160", (uint8_t)addr.address);
|
||||
break;
|
||||
} else {
|
||||
String prod = "";
|
||||
prod = readSEN5xProductName(i2cBus, addr.address);
|
||||
@@ -718,11 +725,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
if (len == 5 && memcmp(expectedInfo, info, len) == 0) {
|
||||
LOG_INFO("NXP SE050 crypto chip found");
|
||||
type = NXP_SE050;
|
||||
|
||||
} else {
|
||||
LOG_INFO("FT6336U touchscreen found");
|
||||
type = FT6336U;
|
||||
break;
|
||||
}
|
||||
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
|
||||
if (registerValue == 0x8583 || registerValue == 0x8580) {
|
||||
type = ADS1115;
|
||||
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INFO("FT6336U touchscreen found");
|
||||
type = FT6336U;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -93,7 +93,7 @@ static const char *getGPSPowerStateString(GPSPowerState state)
|
||||
|
||||
#ifdef PIN_GPS_SWITCH
|
||||
// If we have a hardware switch, define a periodic watcher outside of the GPS runOnce thread, since this can be sleeping
|
||||
// idefinitely
|
||||
// indefinitely
|
||||
|
||||
int lastState = LOW;
|
||||
bool firstrun = true;
|
||||
@@ -586,14 +586,14 @@ bool GPS::setup()
|
||||
_serial_gps->write("$PMTK301,2*2E\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_ATGM336H) {
|
||||
// Set the intial configuration of the device - these _should_ work for most AT6558 devices
|
||||
// Set the initial configuration of the device - these _should_ work for most AT6558 devices
|
||||
msglen = makeCASPacket(0x06, 0x07, sizeof(_message_CAS_CFG_NAVX_CONF), _message_CAS_CFG_NAVX_CONF);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACKCas(0x06, 0x07, 250) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("ATGM336H: Could not set Config");
|
||||
}
|
||||
|
||||
// Set the update frequence to 1Hz
|
||||
// Set the update frequency to 1Hz
|
||||
msglen = makeCASPacket(0x06, 0x04, sizeof(_message_CAS_CFG_RATE_1HZ), _message_CAS_CFG_RATE_1HZ);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACKCas(0x06, 0x04, 250) != GNSS_RESPONSE_OK) {
|
||||
@@ -700,7 +700,7 @@ bool GPS::setup()
|
||||
} else { // 8,9
|
||||
LOG_INFO("GPS+SBAS+GLONASS+Galileo configured");
|
||||
}
|
||||
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
|
||||
// Documentation say, we need wait at least 0.5s after reconfiguration of GNSS module, before sending next
|
||||
// commands for the M8 it tends to be more... 1 sec should be enough ;>)
|
||||
delay(1000);
|
||||
}
|
||||
@@ -733,7 +733,7 @@ bool GPS::setup()
|
||||
SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "enable powersave for GPS", 500);
|
||||
SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500);
|
||||
|
||||
// For M8 we want to enable NMEA vserion 4.10 so we can see the additional sats.
|
||||
// For M8 we want to enable NMEA version 4.10 so we can see the additional sats.
|
||||
if (gnssModel == GNSS_MODEL_UBLOX8) {
|
||||
clearBuffer();
|
||||
SEND_UBX_PACKET(0x06, 0x17, _message_NMEA, "enable NMEA 4.10", 500);
|
||||
@@ -1211,7 +1211,7 @@ int32_t GPS::runOnce()
|
||||
return disable(); // This should trigger when we have a fixed position, and get that first position
|
||||
|
||||
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
||||
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
||||
// if not awake we can run super infrequently (once every 5 secs?) to see if we need to wake.
|
||||
return (powerState == GPS_ACTIVE) ? GPS_THREAD_INTERVAL : 5000;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _lon
|
||||
|
||||
GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
||||
{
|
||||
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
// Change decimal representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
@@ -20,7 +20,7 @@ GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
||||
|
||||
GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt)
|
||||
{
|
||||
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
// Change decimal representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
@@ -467,10 +467,10 @@ int32_t GeoCoord::bearingTo(const GeoCoord &pointB)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new point bassed on the passed in poin
|
||||
* Create a new point based on the passed-in point
|
||||
* Ported from http://www.edwilliams.org/avform147.htm#LL
|
||||
* @param bearing
|
||||
* The bearing in raidans
|
||||
* The bearing in radians
|
||||
* @param range_meters
|
||||
* range in meters
|
||||
* @return GeoCoord object of point at bearing and range from initial point
|
||||
@@ -593,4 +593,4 @@ double GeoCoord::toRadians(double deg)
|
||||
double GeoCoord::toDegrees(double r)
|
||||
{
|
||||
return r * 180 / PI;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -223,7 +223,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
// This delta value works on all platforms
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
// If this platform has a setable RTC, set it
|
||||
// If this platform has a settable RTC, set it
|
||||
#ifdef RV3028_RTC
|
||||
if (rtc_found.address == RV3028_RTC) {
|
||||
Melopero_RV3028 rtc;
|
||||
@@ -402,7 +402,7 @@ time_t gm_mktime(const struct tm *tm)
|
||||
#if !MESHTASTIC_EXCLUDE_TZ
|
||||
time_t result = 0;
|
||||
|
||||
// First, get us to the start of tm->year, by calcuating the number of days since the Unix epoch.
|
||||
// First, get us to the start of tm->year, by calculating the number of days since the Unix epoch.
|
||||
int year = 1900 + tm->tm_year; // tm_year is years since 1900
|
||||
int year_minus_one = year - 1;
|
||||
int days_before_this_year = 0;
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ static const uint8_t _message_CAS_CFG_RATE_1HZ[] = {
|
||||
|
||||
// CFG-NAVX (0x06, 0x07)
|
||||
// Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system
|
||||
// Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
|
||||
// Quirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
|
||||
// and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used.
|
||||
static const uint8_t _message_CAS_CFG_NAVX_CONF[] = {
|
||||
0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings
|
||||
|
||||
+6
-6
@@ -57,7 +57,7 @@ static const uint8_t _message_CFG_PM2[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00 // 0x64, 0x40, 0x01, 0x00 // reserved 11
|
||||
};
|
||||
|
||||
// Constallation setup, none required for Neo-6
|
||||
// Constellation setup, none required for Neo-6
|
||||
|
||||
// For Neo-7 GPS & SBAS
|
||||
static const uint8_t _message_GNSS_7[] = {
|
||||
@@ -157,7 +157,7 @@ static const uint8_t _message_NAVX5[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // Reserved 9
|
||||
0x00, // Reserved 10
|
||||
0x00, // Reserved 11
|
||||
0x00, // usePPP (Precice Point Positioning) (0 = false, 1 = true)
|
||||
0x00, // usePPP (Precise Point Positioning) (0 = false, 1 = true)
|
||||
0x01, // useAOP (AssistNow Autonomous configuration) = 1 (enabled)
|
||||
0x00, // Reserved 12
|
||||
0x00, // Reserved 13
|
||||
@@ -185,7 +185,7 @@ static const uint8_t _message_NAVX5_8[] = {
|
||||
0x00, // Reserved 4
|
||||
0x00, 0x00, // Reserved 5
|
||||
0x00, 0x00, // Reserved 6
|
||||
0x00, // usePPP (Precice Point Positioning) (0 = false, 1 = true)
|
||||
0x00, // usePPP (Precise Point Positioning) (0 = false, 1 = true)
|
||||
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
|
||||
0x00, 0x00, // Reserved 7
|
||||
0x00, 0x00, // aopOrbMaxErr = 0 to reset to firmware default
|
||||
@@ -314,7 +314,7 @@ static const uint8_t _message_DISABLE_TXT_INFO[] = {
|
||||
// This command applies to M8 products
|
||||
static const uint8_t _message_PMS[] = {
|
||||
0x00, // Version (0)
|
||||
0x03, // Power setup value 3 = Agresssive 1Hz
|
||||
0x03, // Power setup value 3 = Agressive 1Hz
|
||||
0x00, 0x00, // period: not applicable, set to 0
|
||||
0x00, 0x00, // onTime: not applicable, set to 0
|
||||
0x00, 0x00 // reserved, generated by u-center
|
||||
@@ -337,7 +337,7 @@ static const uint8_t _message_SAVE_10[] = {
|
||||
// As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
|
||||
// BBR will survive a restart, and power off for a while, but modules with small backup
|
||||
// batteries or super caps will not retain the config for a long power off time.
|
||||
// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after
|
||||
// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast acquisition after
|
||||
// sleep
|
||||
|
||||
// VALSET Commands for M10
|
||||
@@ -462,7 +462,7 @@ Default GNSS configuration is: GPS, Galileo, BDS B1l, with QZSS and SBAS enabled
|
||||
The PMREQ puts the receiver to sleep and wakeup re-acquires really fast and seems to not need
|
||||
the PM config. Lets try without it.
|
||||
PMREQ sort of works with SBAS, but the awake time is too short to re-acquire any SBAS sats.
|
||||
The defination of "Got Fix" doesn't seem to include SBAS. Much more too this...
|
||||
The definition of "Got Fix" doesn't seem to include SBAS. Much more too this...
|
||||
Even if it was, it can take minutes (up to 12.5),
|
||||
even under good sat visibility conditions to re-acquire the SBAS data.
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
return true;
|
||||
}
|
||||
|
||||
// End the update process - virtual method, overriden in derived class
|
||||
// End the update process - virtual method, overridden in derived class
|
||||
void EInkDisplay::endUpdate()
|
||||
{
|
||||
// Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep)
|
||||
@@ -143,6 +143,10 @@ bool EInkDisplay::connect()
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
// ThinkNode M1 has a hardware dimmable backlight. Start enabled
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
#elif defined(MINI_EPAPER_S3)
|
||||
// T-Mini Epaper S3 requires panel power rail enabled before SPI transfer.
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
delay(10);
|
||||
#else
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
#endif
|
||||
@@ -202,7 +206,8 @@ bool EInkDisplay::connect()
|
||||
}
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
{
|
||||
// Start HSPI
|
||||
hspi = new SPIClass(HSPI);
|
||||
@@ -216,9 +221,13 @@ bool EInkDisplay::connect()
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
#if defined(MINI_EPAPER_S3)
|
||||
adafruitDisplay->setRotation(3);
|
||||
#else
|
||||
adafruitDisplay->setRotation(3);
|
||||
#if defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER)
|
||||
adafruitDisplay->setRotation(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#elif defined(PCA10059) || defined(ME25LS01)
|
||||
|
||||
@@ -89,7 +89,8 @@ class EInkDisplay : public OLEDDisplay
|
||||
// If display uses HSPI
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || defined(ELECROW_ThinkNode_M5)
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || defined(ELECROW_ThinkNode_M5) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ void EInkDynamicDisplay::adjustRefreshCounters()
|
||||
// Trigger the display update by calling base class
|
||||
bool EInkDynamicDisplay::update()
|
||||
{
|
||||
// Detemine the refresh mode to use, and start the update
|
||||
// Determine the refresh mode to use, and start the update
|
||||
bool refreshApproved = determineMode();
|
||||
if (refreshApproved) {
|
||||
EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system
|
||||
@@ -317,7 +317,7 @@ void EInkDynamicDisplay::checkFrameMatchesPrevious()
|
||||
LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS, frameFlags=0x%x", frameFlags);
|
||||
}
|
||||
|
||||
// Have too many fast-refreshes occured consecutively, since last full refresh?
|
||||
// Have too many fast-refreshes occurred consecutively, since last full refresh?
|
||||
void EInkDynamicDisplay::checkConsecutiveFastRefreshes()
|
||||
{
|
||||
// If a decision was already reached, don't run the check
|
||||
@@ -561,4 +561,4 @@ void EInkDynamicDisplay::awaitRefresh()
|
||||
}
|
||||
#endif // HAS_EINK_ASYNCFULL
|
||||
|
||||
#endif // USE_EINK_DYNAMICDISPLAY
|
||||
#endif // USE_EINK_DYNAMICDISPLAY
|
||||
|
||||
+15
-2
@@ -433,12 +433,15 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
|
||||
#if defined(MUZI_BASE)
|
||||
// some screens seem to need a kick in the pants to turn back on
|
||||
#if defined(MUZI_BASE) || defined(M5STACK_CARDPUTER_ADV)
|
||||
dispdev->init();
|
||||
dispdev->setBrightness(brightness);
|
||||
dispdev->flipScreenVertically();
|
||||
dispdev->resetDisplay();
|
||||
#ifdef SCREEN_12V_ENABLE
|
||||
digitalWrite(SCREEN_12V_ENABLE, HIGH);
|
||||
#endif
|
||||
delay(100);
|
||||
#endif
|
||||
#if !ARCH_PORTDUINO
|
||||
@@ -462,9 +465,11 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
#if defined(HELTEC_TRACKER_V1_X) || defined(HELTEC_WIRELESS_TRACKER_V2)
|
||||
ui->init();
|
||||
#endif
|
||||
#ifdef USE_ST7789
|
||||
#if defined(USE_ST7789) && defined(VTFT_LEDA)
|
||||
#ifdef VTFT_CTRL
|
||||
pinMode(VTFT_CTRL, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
ui->init();
|
||||
#ifdef ESP_PLATFORM
|
||||
analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT);
|
||||
@@ -506,8 +511,12 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
#ifdef USE_ST7789
|
||||
SPI1.end();
|
||||
#if defined(ARCH_ESP32)
|
||||
#ifdef VTFT_LEDA
|
||||
pinMode(VTFT_LEDA, ANALOG);
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
pinMode(VTFT_CTRL, ANALOG);
|
||||
#endif
|
||||
pinMode(ST7789_RESET, ANALOG);
|
||||
pinMode(ST7789_RS, ANALOG);
|
||||
pinMode(ST7789_NSS, ANALOG);
|
||||
@@ -875,6 +884,10 @@ int32_t Screen::runOnce()
|
||||
break;
|
||||
case Cmd::STOP_ALERT_FRAME:
|
||||
NotificationRenderer::pauseBanner = false;
|
||||
// Return from one-off alert mode back to regular frames.
|
||||
if (!showingNormalScreen && NotificationRenderer::current_notification_type != notificationTypeEnum::text_input) {
|
||||
setFrames();
|
||||
}
|
||||
break;
|
||||
case Cmd::STOP_BOOT_SCREEN:
|
||||
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame
|
||||
|
||||
@@ -765,7 +765,11 @@ class Screen : public concurrency::OSThread
|
||||
DebugInfo debugInfo;
|
||||
|
||||
/// Display device
|
||||
#ifdef USE_ST7789
|
||||
ST7789Spi *dispdev;
|
||||
#else
|
||||
OLEDDisplay *dispdev;
|
||||
#endif
|
||||
|
||||
/// UI helper for rendering to frames and switching between them
|
||||
OLEDDisplayUi *ui;
|
||||
|
||||
@@ -1209,8 +1209,8 @@ void TFTDisplay::display(bool fromBlank)
|
||||
bool somethingChanged = false;
|
||||
|
||||
// Store colors byte-reversed so that TFT_eSPI doesn't have to swap bytes in a separate step
|
||||
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
|
||||
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);
|
||||
colorTftMesh = __builtin_bswap16(TFT_MESH);
|
||||
colorTftBlack = __builtin_bswap16(TFT_BLACK);
|
||||
|
||||
y = 0;
|
||||
while (y < displayHeight) {
|
||||
|
||||
@@ -43,7 +43,7 @@ InputEvent NotificationRenderer::inEvent;
|
||||
int8_t NotificationRenderer::curSelected = 0;
|
||||
char NotificationRenderer::alertBannerMessage[256] = {0};
|
||||
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
|
||||
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable options
|
||||
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are selectable options
|
||||
const char **NotificationRenderer::optionsArrayPtr = nullptr;
|
||||
const int *NotificationRenderer::optionsEnumPtr = nullptr;
|
||||
std::function<void(int)> NotificationRenderer::alertBannerCallback = NULL;
|
||||
@@ -95,7 +95,7 @@ void NotificationRenderer::resetBanner()
|
||||
inEvent.inputEvent = INPUT_BROKER_NONE;
|
||||
inEvent.kbchar = 0;
|
||||
curSelected = 0;
|
||||
alertBannerOptions = 0; // last x lines are seelctable options
|
||||
alertBannerOptions = 0; // last x lines are selectable options
|
||||
optionsArrayPtr = nullptr;
|
||||
optionsEnumPtr = nullptr;
|
||||
alertBannerCallback = NULL;
|
||||
@@ -781,4 +781,4 @@ void NotificationRenderer::showKeyboardMessagePopupWithTitle(const char *title,
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@ class NotificationRenderer
|
||||
static uint32_t alertBannerUntil; // 0 is a special case meaning forever
|
||||
static const char **optionsArrayPtr;
|
||||
static const int *optionsEnumPtr;
|
||||
static uint8_t alertBannerOptions; // last x lines are seelctable options
|
||||
static uint8_t alertBannerOptions; // last x lines are selectable options
|
||||
static std::function<void(int)> alertBannerCallback;
|
||||
static uint32_t numDigits;
|
||||
static uint32_t currentNumber;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "graphics/TimeFormatters.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#include "target_specific.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <RTC.h>
|
||||
@@ -1423,11 +1422,6 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
const int totalWidth = (pageEnd - pageStart) * iconSize + (pageEnd - pageStart - 1) * spacing;
|
||||
const int xStart = (SCREEN_WIDTH - totalWidth) / 2;
|
||||
|
||||
// Suppress nav overlay entirely
|
||||
if (cannedMessageModule && cannedMessageModule->isFreeTextUIActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool navBarVisible = millis() - lastFrameChangeTime <= ICON_DISPLAY_DURATION_MS;
|
||||
int y = navBarVisible ? (SCREEN_HEIGHT - iconSize - 1) : SCREEN_HEIGHT;
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ class DEPG0213BNS800 : public SSD16XX
|
||||
void configWaveform() override;
|
||||
void configUpdateSequence() override;
|
||||
void detachFromUpdate() override;
|
||||
void finalizeUpdate() override; // Only overriden for a slight optimization
|
||||
void finalizeUpdate() override; // Only overridden for a slight optimization
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
@@ -35,8 +35,8 @@ class DEPG0290BNS800 : public SSD16XX
|
||||
void configWaveform() override;
|
||||
void configUpdateSequence() override;
|
||||
void detachFromUpdate() override;
|
||||
void finalizeUpdate() override; // Only overriden for a slight optimization
|
||||
void finalizeUpdate() override; // Only overridden for a slight optimization
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "./GDEW0102T4.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
// LUTs from GxEPD2_102.cpp (GDEW0102T4 / UC8175).
|
||||
static const uint8_t LUT_W_FULL[] = {
|
||||
0x60, 0x5A, 0x5A, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_B_FULL[] = {
|
||||
0x90, 0x5A, 0x5A, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_W_FAST[] = {
|
||||
0x60, 0x01, 0x01, 0x00, 0x00, 0x01, //
|
||||
0x80, 0x12, 0x00, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_B_FAST[] = {
|
||||
0x90, 0x01, 0x01, 0x00, 0x00, 0x01, //
|
||||
0x40, 0x14, 0x00, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
GDEW0102T4::GDEW0102T4() : UC8175(width, height, supported) {}
|
||||
|
||||
void GDEW0102T4::setFastConfig(FastConfig cfg)
|
||||
{
|
||||
// Clamp out only clearly invalid PLL settings.
|
||||
if (cfg.reg30 < 0x05)
|
||||
cfg.reg30 = 0x05;
|
||||
fastConfig = cfg;
|
||||
}
|
||||
|
||||
GDEW0102T4::FastConfig GDEW0102T4::getFastConfig() const
|
||||
{
|
||||
return fastConfig;
|
||||
}
|
||||
|
||||
void GDEW0102T4::configCommon()
|
||||
{
|
||||
// Init path aligned with GxEPD2_GDEW0102T4 (UC8175 family).
|
||||
sendCommand(0xD2);
|
||||
sendData(0x3F);
|
||||
|
||||
sendCommand(0x00);
|
||||
sendData(0x6F);
|
||||
|
||||
sendCommand(0x01);
|
||||
sendData(0x03);
|
||||
sendData(0x00);
|
||||
sendData(0x2B);
|
||||
sendData(0x2B);
|
||||
|
||||
sendCommand(0x06);
|
||||
sendData(0x3F);
|
||||
|
||||
sendCommand(0x2A);
|
||||
sendData(0x00);
|
||||
sendData(0x00);
|
||||
|
||||
sendCommand(0x30); // PLL / drive clock
|
||||
sendData(0x13);
|
||||
|
||||
sendCommand(0x50); // Last border/data interval; subtle but can affect artifacts
|
||||
sendData(0x57);
|
||||
|
||||
sendCommand(0x60);
|
||||
sendData(0x22);
|
||||
|
||||
sendCommand(0x61);
|
||||
sendData(width);
|
||||
sendData(height);
|
||||
|
||||
sendCommand(0x82); // VCOM DC setting
|
||||
sendData(0x12);
|
||||
|
||||
sendCommand(0xE3);
|
||||
sendData(0x33);
|
||||
}
|
||||
|
||||
void GDEW0102T4::configFull()
|
||||
{
|
||||
sendCommand(0x23);
|
||||
sendData(LUT_W_FULL, sizeof(LUT_W_FULL));
|
||||
sendCommand(0x24);
|
||||
sendData(LUT_B_FULL, sizeof(LUT_B_FULL));
|
||||
|
||||
powerOn();
|
||||
}
|
||||
|
||||
void GDEW0102T4::configFast()
|
||||
{
|
||||
uint8_t lutW[sizeof(LUT_W_FAST)];
|
||||
uint8_t lutB[sizeof(LUT_B_FAST)];
|
||||
memcpy(lutW, LUT_W_FAST, sizeof(LUT_W_FAST));
|
||||
memcpy(lutB, LUT_B_FAST, sizeof(LUT_B_FAST));
|
||||
|
||||
// Second stage duration bytes are the main "darkness vs ghosting" control for this panel.
|
||||
lutW[7] = fastConfig.lutW2;
|
||||
lutB[7] = fastConfig.lutB2;
|
||||
|
||||
sendCommand(0x30);
|
||||
sendData(fastConfig.reg30);
|
||||
|
||||
sendCommand(0x50);
|
||||
sendData(fastConfig.reg50);
|
||||
|
||||
sendCommand(0x82);
|
||||
sendData(fastConfig.reg82);
|
||||
|
||||
sendCommand(0x23);
|
||||
sendData(lutW, sizeof(lutW));
|
||||
sendCommand(0x24);
|
||||
sendData(lutB, sizeof(lutB));
|
||||
|
||||
powerOn();
|
||||
}
|
||||
|
||||
void GDEW0102T4::writeOldImage()
|
||||
{
|
||||
// On this panel, FULL refresh is most reliable when "old image" is all white.
|
||||
if (updateType == FULL) {
|
||||
sendCommand(0x10);
|
||||
// Use buffered writes of 0xFF to avoid per-byte SPI transactions.
|
||||
const uint16_t chunkSize = 64;
|
||||
uint8_t ffBuf[chunkSize];
|
||||
memset(ffBuf, 0xFF, sizeof(ffBuf));
|
||||
|
||||
uint32_t remaining = bufferSize;
|
||||
while (remaining > 0) {
|
||||
uint16_t toSend = remaining > chunkSize ? chunkSize : static_cast<uint16_t>(remaining);
|
||||
sendData(ffBuf, toSend);
|
||||
remaining -= toSend;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// FAST refresh uses differential data (previous frame as old image).
|
||||
if (previousBuffer) {
|
||||
writeImage(0x10, previousBuffer);
|
||||
} else {
|
||||
writeImage(0x10, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GDEW0102T4::finalizeUpdate()
|
||||
{
|
||||
// Keep panel out of deep-sleep between updates for better reliability of repeated FAST refresh.
|
||||
powerOff();
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
E-Ink display driver
|
||||
- GDEW0102T4
|
||||
- Controller: UC8175
|
||||
- Size: 1.02 inch
|
||||
- Resolution: 80px x 128px
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./UC8175.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
|
||||
class GDEW0102T4 : public UC8175
|
||||
{
|
||||
private:
|
||||
static constexpr uint16_t width = 80;
|
||||
static constexpr uint16_t height = 128;
|
||||
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||
|
||||
public:
|
||||
struct FastConfig {
|
||||
uint8_t reg30;
|
||||
uint8_t reg50;
|
||||
uint8_t reg82;
|
||||
uint8_t lutW2;
|
||||
uint8_t lutB2;
|
||||
};
|
||||
|
||||
GDEW0102T4();
|
||||
void setFastConfig(FastConfig cfg);
|
||||
FastConfig getFastConfig() const;
|
||||
|
||||
protected:
|
||||
void configCommon() override;
|
||||
void configFull() override;
|
||||
void configFast() override;
|
||||
void writeOldImage() override;
|
||||
void finalizeUpdate() override;
|
||||
|
||||
private:
|
||||
FastConfig fastConfig = {0x13, 0xF2, 0x12, 0x0E, 0x14};
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -19,7 +19,7 @@ void setupNicheGraphics()
|
||||
SPIClass *hspi = new SPIClass(HSPI);
|
||||
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS);
|
||||
|
||||
// Setup Enk driver
|
||||
// Setup EInk driver
|
||||
Drivers::EInk *driver = new Drivers::DEPG0290BNS800;
|
||||
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY);
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "./UC8175.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "SPILock.h"
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
UC8175::UC8175(uint16_t width, uint16_t height, UpdateTypes supported) : EInk(width, height, supported)
|
||||
{
|
||||
bufferRowSize = ((width - 1) / 8) + 1;
|
||||
bufferSize = bufferRowSize * height;
|
||||
}
|
||||
|
||||
void UC8175::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst)
|
||||
{
|
||||
this->spi = spi;
|
||||
this->pin_dc = pin_dc;
|
||||
this->pin_cs = pin_cs;
|
||||
this->pin_busy = pin_busy;
|
||||
this->pin_rst = pin_rst;
|
||||
|
||||
pinMode(pin_dc, OUTPUT);
|
||||
pinMode(pin_cs, OUTPUT);
|
||||
pinMode(pin_busy, INPUT);
|
||||
|
||||
// Reset is active LOW, hold HIGH when idle.
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
pinMode(pin_rst, OUTPUT);
|
||||
digitalWrite(pin_rst, HIGH);
|
||||
}
|
||||
|
||||
if (!previousBuffer) {
|
||||
previousBuffer = new uint8_t[bufferSize];
|
||||
if (previousBuffer)
|
||||
memset(previousBuffer, 0xFF, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
void UC8175::update(uint8_t *imageData, UpdateTypes type)
|
||||
{
|
||||
buffer = imageData;
|
||||
updateType = (type == UpdateTypes::UNSPECIFIED) ? UpdateTypes::FULL : type;
|
||||
|
||||
if (updateType == FAST && hasPreviousBuffer && previousBuffer && memcmp(previousBuffer, buffer, bufferSize) == 0)
|
||||
return;
|
||||
|
||||
reset();
|
||||
configCommon();
|
||||
|
||||
if (updateType == FAST)
|
||||
configFast();
|
||||
else
|
||||
configFull();
|
||||
|
||||
writeOldImage();
|
||||
writeNewImage();
|
||||
sendCommand(0x12); // Display refresh.
|
||||
|
||||
if (previousBuffer) {
|
||||
memcpy(previousBuffer, buffer, bufferSize);
|
||||
hasPreviousBuffer = true;
|
||||
}
|
||||
|
||||
detachFromUpdate();
|
||||
}
|
||||
|
||||
void UC8175::wait(uint32_t timeoutMs)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
uint32_t started = millis();
|
||||
while (digitalRead(pin_busy) == BUSY_ACTIVE) {
|
||||
if ((millis() - started) > timeoutMs) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void UC8175::reset()
|
||||
{
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
digitalWrite(pin_rst, LOW);
|
||||
delay(20);
|
||||
digitalWrite(pin_rst, HIGH);
|
||||
delay(20);
|
||||
} else {
|
||||
sendCommand(0x12); // Software reset.
|
||||
delay(10);
|
||||
}
|
||||
|
||||
wait(3000);
|
||||
}
|
||||
|
||||
void UC8175::sendCommand(uint8_t command)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spiLock->lock();
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, LOW);
|
||||
digitalWrite(pin_cs, LOW);
|
||||
spi->transfer(command);
|
||||
digitalWrite(pin_cs, HIGH);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
spi->endTransaction();
|
||||
spiLock->unlock();
|
||||
}
|
||||
|
||||
void UC8175::sendData(uint8_t data)
|
||||
{
|
||||
sendData(&data, 1);
|
||||
}
|
||||
|
||||
void UC8175::sendData(const uint8_t *data, uint32_t size)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spiLock->lock();
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
digitalWrite(pin_cs, LOW);
|
||||
|
||||
#if defined(ARCH_ESP32)
|
||||
spi->transferBytes(data, NULL, size);
|
||||
#elif defined(ARCH_NRF52)
|
||||
spi->transfer(data, NULL, size);
|
||||
#else
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
spi->transfer(data[i]);
|
||||
#endif
|
||||
|
||||
digitalWrite(pin_cs, HIGH);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
spi->endTransaction();
|
||||
spiLock->unlock();
|
||||
}
|
||||
|
||||
void UC8175::powerOn()
|
||||
{
|
||||
sendCommand(0x04);
|
||||
wait(2000);
|
||||
}
|
||||
|
||||
void UC8175::powerOff()
|
||||
{
|
||||
sendCommand(0x02); // Power off.
|
||||
wait(1500);
|
||||
}
|
||||
|
||||
void UC8175::writeImage(uint8_t command, const uint8_t *image)
|
||||
{
|
||||
sendCommand(command);
|
||||
sendData(image, bufferSize);
|
||||
}
|
||||
|
||||
void UC8175::writeOldImage()
|
||||
{
|
||||
if (updateType == FAST && previousBuffer)
|
||||
writeImage(0x10, previousBuffer);
|
||||
else
|
||||
writeImage(0x10, buffer);
|
||||
}
|
||||
|
||||
void UC8175::writeNewImage()
|
||||
{
|
||||
writeImage(0x13, buffer);
|
||||
}
|
||||
|
||||
void UC8175::detachFromUpdate()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
return beginPolling(50, 400);
|
||||
case FULL:
|
||||
default:
|
||||
return beginPolling(100, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
bool UC8175::isUpdateDone()
|
||||
{
|
||||
return digitalRead(pin_busy) != BUSY_ACTIVE;
|
||||
}
|
||||
|
||||
void UC8175::finalizeUpdate()
|
||||
{
|
||||
powerOff();
|
||||
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
sendCommand(0x07); // Deep sleep.
|
||||
sendData(0xA5);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -0,0 +1,62 @@
|
||||
// E-Ink base class for displays based on UC8175 / UC8176 style controller ICs.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./EInk.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
|
||||
class UC8175 : public EInk
|
||||
{
|
||||
public:
|
||||
UC8175(uint16_t width, uint16_t height, UpdateTypes supported);
|
||||
void begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst = -1) override;
|
||||
void update(uint8_t *imageData, UpdateTypes type) override;
|
||||
|
||||
protected:
|
||||
virtual void wait(uint32_t timeoutMs = 1000);
|
||||
virtual void reset();
|
||||
virtual void sendCommand(uint8_t command);
|
||||
virtual void sendData(uint8_t data);
|
||||
virtual void sendData(const uint8_t *data, uint32_t size);
|
||||
|
||||
virtual void configCommon() = 0; // Always run
|
||||
virtual void configFull() = 0; // Run when updateType == FULL
|
||||
virtual void configFast() = 0; // Run when updateType == FAST
|
||||
|
||||
virtual void powerOn();
|
||||
virtual void powerOff();
|
||||
virtual void writeOldImage();
|
||||
virtual void writeNewImage();
|
||||
virtual void writeImage(uint8_t command, const uint8_t *image);
|
||||
|
||||
virtual void detachFromUpdate();
|
||||
virtual bool isUpdateDone() override;
|
||||
virtual void finalizeUpdate() override;
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t BUSY_ACTIVE = LOW;
|
||||
|
||||
uint16_t bufferRowSize = 0;
|
||||
uint32_t bufferSize = 0;
|
||||
uint8_t *buffer = nullptr;
|
||||
uint8_t *previousBuffer = nullptr;
|
||||
bool hasPreviousBuffer = false;
|
||||
UpdateTypes updateType = UpdateTypes::UNSPECIFIED;
|
||||
|
||||
uint8_t pin_dc = (uint8_t)-1;
|
||||
uint8_t pin_cs = (uint8_t)-1;
|
||||
uint8_t pin_busy = (uint8_t)-1;
|
||||
uint8_t pin_rst = (uint8_t)-1;
|
||||
SPIClass *spi = nullptr;
|
||||
SPISettings spiSettings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
|
||||
Base class for InkHUD applets
|
||||
Must be overriden
|
||||
Must be overridden
|
||||
|
||||
An applet is one "program" which may show info on the display.
|
||||
|
||||
@@ -208,4 +208,4 @@ class Applet : public GFX
|
||||
|
||||
}; // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -525,7 +525,7 @@ void InkHUD::MapApplet::calculateAllMarkers()
|
||||
}
|
||||
|
||||
// Determine the conversion factor between metres, and pixels on screen
|
||||
// May be overriden by derived applet, if custom scale required (fixed map size?)
|
||||
// May be overridden by derived applet, if custom scale required (fixed map size?)
|
||||
void InkHUD::MapApplet::calculateMapScale()
|
||||
{
|
||||
// Aspect ratio of map and screen
|
||||
@@ -555,4 +555,4 @@ void InkHUD::MapApplet::drawCross(int16_t x, int16_t y, uint8_t size)
|
||||
drawLine(x0, y1, x1, y0, BLACK);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -120,9 +120,26 @@ void InkHUD::NodeListApplet::onRender(bool full)
|
||||
// Draw the main node list
|
||||
// ========================
|
||||
|
||||
// Imaginary vertical line dividing left-side and right-side info
|
||||
// Long-name will crop here
|
||||
const uint16_t dividerX = (width() - 1) - getTextWidth("X Hops");
|
||||
// Leave a small gutter between long-name text and right-side card content
|
||||
constexpr uint8_t rightContentGap = 2;
|
||||
|
||||
// Truncate with trailing "...", sized using the current font.
|
||||
auto ellipsizeToWidth = [this](std::string text, uint16_t maxWidth) {
|
||||
constexpr const char *ellipsis = "...";
|
||||
const uint16_t ellipsisW = getTextWidth(ellipsis);
|
||||
uint16_t textW = getTextWidth(text);
|
||||
if (maxWidth == 0)
|
||||
return std::string();
|
||||
if (textW <= maxWidth)
|
||||
return text;
|
||||
if (ellipsisW > maxWidth)
|
||||
return std::string();
|
||||
while (!text.empty() && (textW + ellipsisW > maxWidth)) {
|
||||
text.pop_back();
|
||||
textW = getTextWidth(text);
|
||||
}
|
||||
return text + ellipsis;
|
||||
};
|
||||
|
||||
// Y value (top) of the current card. Increases as we draw.
|
||||
uint16_t cardTopY = headerDivY + padDivH;
|
||||
@@ -141,7 +158,7 @@ void InkHUD::NodeListApplet::onRender(bool full)
|
||||
SignalStrength &signal = card->signal;
|
||||
std::string longName; // handled below
|
||||
std::string shortName; // handled below
|
||||
std::string distance; // handled below;
|
||||
std::string distance; // handled below
|
||||
const uint8_t &hopsAway = card->hopsAway;
|
||||
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeNum);
|
||||
@@ -185,41 +202,49 @@ void InkHUD::NodeListApplet::onRender(bool full)
|
||||
setFont(fontMedium);
|
||||
printAt(0, lineAY, shortName, LEFT, MIDDLE);
|
||||
|
||||
// Print the distance
|
||||
// Right-side labels and long name are rendered in small font.
|
||||
setFont(fontSmall);
|
||||
printAt(width() - 1, lineBY, distance, RIGHT, MIDDLE);
|
||||
uint16_t rightContentW = 0;
|
||||
|
||||
// If we have a direct connection to the node, draw the signal indicator
|
||||
// Bottom row right: distance.
|
||||
if (!distance.empty()) {
|
||||
rightContentW = std::max(rightContentW, getTextWidth(distance));
|
||||
printAt(width() - 1, lineBY, distance, RIGHT, MIDDLE);
|
||||
}
|
||||
|
||||
// Top row right: direct-link signal only.
|
||||
if (hopsAway == 0 && signal != SIGNAL_UNKNOWN) {
|
||||
uint16_t signalW = getTextWidth("Xkm"); // Indicator should be similar width to distance label
|
||||
uint16_t signalW = getTextWidth("Xkm"); // Indicator width tuned to a short right-side label
|
||||
uint16_t signalH = fontMedium.lineHeight() * 0.75;
|
||||
int16_t signalY = lineAY + (fontMedium.lineHeight() / 2) - (fontMedium.lineHeight() * 0.75);
|
||||
int16_t signalX = width() - signalW;
|
||||
rightContentW = std::max(rightContentW, signalW);
|
||||
drawSignalIndicator(signalX, signalY, signalW, signalH, signal);
|
||||
}
|
||||
// Otherwise, print "hops away" info, if available
|
||||
else if (hopsAway != CardInfo::HOPS_UNKNOWN && node) {
|
||||
std::string hopString = to_string(node->hops_away);
|
||||
hopString += " Hop";
|
||||
if (node->hops_away != 1)
|
||||
hopString += "s"; // Append s for "Hops", rather than "Hop"
|
||||
|
||||
} else if (hopsAway != CardInfo::HOPS_UNKNOWN) {
|
||||
std::string hopString = to_string(hopsAway) + (hopsAway == 1 ? " Hop" : " Hops");
|
||||
rightContentW = std::max(rightContentW, getTextWidth(hopString));
|
||||
printAt(width() - 1, lineAY, hopString, RIGHT, MIDDLE);
|
||||
}
|
||||
|
||||
// Print the long name, cropping to prevent overflow onto the right-side info
|
||||
setCrop(0, 0, dividerX - 1, height());
|
||||
printAt(0, lineBY, longName, LEFT, MIDDLE);
|
||||
// Give long names as much room as possible while still avoiding right side signal and hop space
|
||||
const uint16_t longNameMaxW =
|
||||
(rightContentW + rightContentGap < width()) ? (width() - rightContentW - rightContentGap) : 0;
|
||||
const std::string longNameShown = ellipsizeToWidth(longName, longNameMaxW);
|
||||
|
||||
// GFX effect: "hatch" the right edge of longName area
|
||||
// If a longName has been cropped, it will appear to fade out,
|
||||
// creating a soft barrier with the right-side info
|
||||
const int16_t hatchLeft = dividerX - 1 - (fontSmall.lineHeight());
|
||||
const int16_t hatchWidth = fontSmall.lineHeight();
|
||||
hatchRegion(hatchLeft, cardTopY, hatchWidth, cardH, 2, WHITE);
|
||||
// Safety crop
|
||||
setCrop(0, cardTopY, longNameMaxW, cardH);
|
||||
printAt(0, lineBY, longNameShown, LEFT, MIDDLE);
|
||||
|
||||
resetCrop();
|
||||
|
||||
// Draw separator between cards
|
||||
const int16_t separatorY = cardTopY + cardH - 1;
|
||||
if (separatorY < height() - 1 && (card + 1) != cards.end()) {
|
||||
for (int16_t xSep = 0; xSep < width(); xSep += 2)
|
||||
drawPixel(xSep, separatorY, BLACK);
|
||||
}
|
||||
|
||||
// Prepare to draw the next card
|
||||
resetCrop();
|
||||
cardTopY += cardH;
|
||||
|
||||
// Once we've run out of screen, stop drawing cards
|
||||
@@ -288,4 +313,4 @@ void InkHUD::NodeListApplet::drawSignalIndicator(int16_t x, int16_t y, uint16_t
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -65,10 +65,10 @@ class NodeListApplet : public Applet, public MeshModule
|
||||
|
||||
// Card Dimensions
|
||||
// - for rendering and for maxCards calc
|
||||
uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards
|
||||
uint8_t cardMarginH = 1; // Gap between cards (minimal to fit more rows)
|
||||
uint16_t cardH = fontMedium.lineHeight() + fontSmall.lineHeight() + cardMarginH; // Height of card
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@ using namespace NicheGraphics;
|
||||
|
||||
InkHUD::BatteryIconApplet::BatteryIconApplet()
|
||||
{
|
||||
alwaysRender = true; // render everytime the screen is updated
|
||||
alwaysRender = true; // render every time the screen is updated
|
||||
|
||||
// Show at boot, if user has previously enabled the feature
|
||||
if (settings->optionalFeatures.batteryIcon)
|
||||
@@ -91,4 +91,4 @@ void InkHUD::BatteryIconApplet::onRender(bool full)
|
||||
drawRect(sliceL, sliceT, sliceW, sliceH, BLACK);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
|
||||
System Applet to render an on-screeen keyboard
|
||||
System Applet to render an on-screen keyboard
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void InkHUD::LogoApplet::onRender(bool full)
|
||||
int16_t logoCY = Y(0.5 - 0.05);
|
||||
|
||||
// Invert colors if black-on-white
|
||||
// Used during shutdown, to resport display health
|
||||
// Used during shutdown, to report display health
|
||||
// Todo: handle this in InkHUD::Renderer instead
|
||||
if (inverted) {
|
||||
fillScreen(BLACK);
|
||||
@@ -186,4 +186,4 @@ int32_t InkHUD::LogoApplet::runOnce()
|
||||
return OSThread::disable();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -349,13 +349,13 @@ void InkHUD::MenuApplet::execute(MenuItem item)
|
||||
handleFreeText = true;
|
||||
cm.freeTextItem.rawText.erase(); // clear the previous freetext message
|
||||
freeTextMode = true; // render input field instead of normal menu
|
||||
// Open the on-screen keyboard if the joystick is enabled
|
||||
if (settings->joystick.enabled)
|
||||
// Open the on-screen keyboard only for full joystick devices
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
inkhud->openKeyboard();
|
||||
break;
|
||||
|
||||
case STORE_CANNEDMESSAGE_SELECTION:
|
||||
if (!settings->joystick.enabled)
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
cm.selectedMessageItem = &cm.messageItems.at(cursor - 1); // Minus one: offset for the initial "Send Ping" entry
|
||||
else
|
||||
cm.selectedMessageItem = &cm.messageItems.at(cursor - 2); // Minus two: offset for the "Send Ping" and free text entry
|
||||
@@ -922,7 +922,7 @@ void InkHUD::MenuApplet::showPage(MenuPage page)
|
||||
if (settings->userTiles.maxCount > 1)
|
||||
items.push_back(MenuItem("Layout", MenuAction::LAYOUT, MenuPage::OPTIONS));
|
||||
items.push_back(MenuItem("Rotate", MenuAction::ROTATE, MenuPage::OPTIONS));
|
||||
if (settings->joystick.enabled)
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
items.push_back(MenuItem("Align Joystick", MenuAction::ALIGN_JOYSTICK, MenuPage::EXIT));
|
||||
items.push_back(MenuItem("Notifications", MenuAction::TOGGLE_NOTIFICATIONS, MenuPage::OPTIONS,
|
||||
&settings->optionalFeatures.notifications));
|
||||
@@ -1751,7 +1751,7 @@ void InkHUD::MenuApplet::populateSendPage()
|
||||
items.push_back(MenuItem("Ping", MenuAction::SEND_PING, MenuPage::EXIT));
|
||||
|
||||
// If joystick is available, include the Free Text option
|
||||
if (settings->joystick.enabled)
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
items.push_back(MenuItem("Free Text", MenuAction::FREE_TEXT, MenuPage::SEND));
|
||||
|
||||
// One menu item for each canned message
|
||||
@@ -2028,7 +2028,7 @@ void InkHUD::MenuApplet::sendText(NodeNum dest, ChannelIndex channel, const char
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true); // Send to mesh, cc to phone
|
||||
}
|
||||
|
||||
// Free up any heap mmemory we'd used while selecting / sending canned messages
|
||||
// Free up any heap memory we'd used while selecting / sending canned messages
|
||||
void InkHUD::MenuApplet::freeCannedMessageResources()
|
||||
{
|
||||
cm.selectedMessageItem = nullptr;
|
||||
|
||||
@@ -152,6 +152,11 @@ void InkHUD::TipsApplet::onRender(bool full)
|
||||
drawBullet("User Button");
|
||||
drawBullet("- short press: next");
|
||||
drawBullet("- long press: select or open menu");
|
||||
} else if (inkhud->twoWayRocker) {
|
||||
drawBullet("Rocker + Button");
|
||||
drawBullet("- center press: open menu or select");
|
||||
drawBullet("- left/right: applet nav");
|
||||
drawBullet("- in menu: up/down");
|
||||
} else {
|
||||
drawBullet("Joystick");
|
||||
drawBullet("- press: open menu or select");
|
||||
|
||||
@@ -73,7 +73,7 @@ ProcessMessage InkHUD::FavoritesMapApplet::handleReceived(const meshtastic_MeshP
|
||||
}
|
||||
} else {
|
||||
// For non-local packets, this applet only reacts to favorited nodes.
|
||||
meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
|
||||
const meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
|
||||
if (!sender || !sender->is_favorite)
|
||||
return ProcessMessage::CONTINUE;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Displays a thread-view of incoming and outgoing message for a specific channel
|
||||
The channel for this applet is set in the constructor,
|
||||
when the applet is added to WindowManager in the setupNicheGraphics method.
|
||||
|
||||
Several messages are saved to flash at shutdown, to preseve applet between reboots.
|
||||
Several messages are saved to flash at shutdown, to preserve applet between reboots.
|
||||
This class has its own internal method for saving and loading to fs, which interacts directly with the FSCommon layer.
|
||||
If the amount of flash usage is unacceptable, we could keep these in RAM only.
|
||||
|
||||
@@ -55,4 +55,4 @@ class ThreadedMessageApplet : public Applet, public SinglePortModule
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -88,6 +88,9 @@ class InkHUD
|
||||
// Used by TipsApplet to force menu to start on Region selection
|
||||
bool forceRegionMenu = false;
|
||||
|
||||
// Input mode hint for devices that use a left/right rocker plus center button
|
||||
bool twoWayRocker = false;
|
||||
|
||||
// Updating the display
|
||||
// - called by various InkHUD components
|
||||
|
||||
@@ -130,4 +133,4 @@ class InkHUD
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ class Renderer : protected concurrency::OSThread
|
||||
uint16_t height();
|
||||
|
||||
private:
|
||||
// Make attemps to render / update, once triggered by requestUpdate or forceUpdate
|
||||
// Make attempts to render / update, once triggered by requestUpdate or forceUpdate
|
||||
int32_t runOnce() override;
|
||||
|
||||
// Apply the display rotation to handled pixels
|
||||
@@ -95,4 +95,4 @@ class Renderer : protected concurrency::OSThread
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -143,7 +143,7 @@ void InkHUD::WindowManager::openMenu()
|
||||
// Bring the AlignStick applet to the foreground
|
||||
void InkHUD::WindowManager::openAlignStick()
|
||||
{
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
AlignStickApplet *alignStick = (AlignStickApplet *)inkhud->getSystemApplet("AlignStick");
|
||||
alignStick->bringToForeground();
|
||||
}
|
||||
@@ -151,6 +151,9 @@ void InkHUD::WindowManager::openAlignStick()
|
||||
|
||||
void InkHUD::WindowManager::openKeyboard()
|
||||
{
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
return;
|
||||
|
||||
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
|
||||
|
||||
if (keyboard) {
|
||||
@@ -162,6 +165,9 @@ void InkHUD::WindowManager::openKeyboard()
|
||||
|
||||
void InkHUD::WindowManager::closeKeyboard()
|
||||
{
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
return;
|
||||
|
||||
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
|
||||
|
||||
if (keyboard) {
|
||||
@@ -477,7 +483,7 @@ void InkHUD::WindowManager::createSystemApplets()
|
||||
addSystemApplet("Logo", new LogoApplet, new Tile);
|
||||
addSystemApplet("Pairing", new PairingApplet, new Tile);
|
||||
addSystemApplet("Tips", new TipsApplet, new Tile);
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
addSystemApplet("AlignStick", new AlignStickApplet, new Tile);
|
||||
addSystemApplet("Keyboard", new KeyboardApplet, new Tile);
|
||||
}
|
||||
@@ -503,7 +509,7 @@ void InkHUD::WindowManager::placeSystemTiles()
|
||||
inkhud->getSystemApplet("Logo")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
inkhud->getSystemApplet("Pairing")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
inkhud->getSystemApplet("Tips")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
inkhud->getSystemApplet("AlignStick")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
const uint16_t keyboardHeight = KeyboardApplet::getKeyboardHeight();
|
||||
inkhud->getSystemApplet("Keyboard")
|
||||
@@ -649,7 +655,7 @@ void InkHUD::WindowManager::refocusTile()
|
||||
}
|
||||
}
|
||||
|
||||
// Seach for any applets which believe they are foreground, but no longer have a valid tile
|
||||
// Search for any applets which believe they are foreground, but no longer have a valid tile
|
||||
// Tidies up after layout changes at runtime
|
||||
void InkHUD::WindowManager::findOrphanApplets()
|
||||
{
|
||||
@@ -679,4 +685,4 @@ void InkHUD::WindowManager::findOrphanApplets()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -733,7 +733,7 @@ To add support for additional encodings, add to the `AppletFont::Encodings` enum
|
||||
|
||||
#### Custom Line Height
|
||||
|
||||
Some fonts may have a handful of especially tall characters, especially extended-ASCII fonts with diacritcs. Ideally, the font should be modified to help resolve this, but if the problem remains, manual offsets to the automatically determined line height can be specified in the constructor.
|
||||
Some fonts may have a handful of especially tall characters, especially extended-ASCII fonts with diacritics. Ideally, the font should be modified to help resolve this, but if the problem remains, manual offsets to the automatically determined line height can be specified in the constructor.
|
||||
|
||||
```cpp
|
||||
// -2 px of padding above, +1 px of padding below
|
||||
|
||||
@@ -59,7 +59,7 @@ void TwoButton::stop()
|
||||
}
|
||||
|
||||
// Attempt to resolve a GPIO pin for the user button, honoring userPrefs.jsonc and device settings
|
||||
// This helper method isn't used by the TweButton class itself, it could be moved elsewhere.
|
||||
// This helper method isn't used by the TwoButton class itself, it could be moved elsewhere.
|
||||
// Intention is to pass this value to TwoButton::setWiring in the setupNicheGraphics method.
|
||||
uint8_t TwoButton::getUserButtonPin()
|
||||
{
|
||||
@@ -308,4 +308,4 @@ int TwoButton::afterLightSleep(esp_sleep_wakeup_cause_t cause)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -156,6 +156,24 @@ void TwoButtonExtended::setJoystickWiring(uint8_t uPin, uint8_t dPin, uint8_t lP
|
||||
pinMode(joystick[Direction::RIGHT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
}
|
||||
|
||||
// Configures only left/right joystick directions for a two-way rocker
|
||||
void TwoButtonExtended::setTwoWayRockerWiring(uint8_t leftPin, uint8_t rightPin, bool internalPullup)
|
||||
{
|
||||
if (leftPin == rightPin) {
|
||||
LOG_WARN("Attempted reuse of TwoWayRocker GPIO. Ignoring assignment");
|
||||
return;
|
||||
}
|
||||
|
||||
joystick[Direction::UP].pin = 0xFF;
|
||||
joystick[Direction::DOWN].pin = 0xFF;
|
||||
joystick[Direction::LEFT].pin = leftPin;
|
||||
joystick[Direction::RIGHT].pin = rightPin;
|
||||
joystickActiveLogic = LOW;
|
||||
|
||||
pinMode(joystick[Direction::LEFT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
pinMode(joystick[Direction::RIGHT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
}
|
||||
|
||||
void TwoButtonExtended::setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs)
|
||||
{
|
||||
assert(whichButton < 2);
|
||||
@@ -229,6 +247,13 @@ void TwoButtonExtended::setJoystickPressHandlers(Callback uPress, Callback dPres
|
||||
joystick[Direction::RIGHT].onPress = rPress;
|
||||
}
|
||||
|
||||
// Set press handlers for a two-way rocker mapped to left/right directions
|
||||
void TwoButtonExtended::setTwoWayRockerPressHandlers(Callback lPress, Callback rPress)
|
||||
{
|
||||
joystick[Direction::LEFT].onPress = lPress;
|
||||
joystick[Direction::RIGHT].onPress = rPress;
|
||||
}
|
||||
|
||||
// Handle the start of a press to the primary button
|
||||
// Wakes our button thread
|
||||
void TwoButtonExtended::isrPrimary()
|
||||
|
||||
@@ -45,6 +45,7 @@ class TwoButtonExtended : protected concurrency::OSThread
|
||||
void stop(); // Stop handling button input (disconnect ISRs for sleep)
|
||||
void setWiring(uint8_t whichButton, uint8_t pin, bool internalPullup = false);
|
||||
void setJoystickWiring(uint8_t uPin, uint8_t dPin, uint8_t lPin, uint8_t rPin, bool internalPullup = false);
|
||||
void setTwoWayRockerWiring(uint8_t leftPin, uint8_t rightPin, bool internalPullup = false);
|
||||
void setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs);
|
||||
void setJoystickDebounce(uint32_t debounceMs);
|
||||
void setHandlerDown(uint8_t whichButton, Callback onDown);
|
||||
@@ -54,6 +55,7 @@ class TwoButtonExtended : protected concurrency::OSThread
|
||||
void setJoystickDownHandlers(Callback uDown, Callback dDown, Callback ldown, Callback rDown);
|
||||
void setJoystickUpHandlers(Callback uUp, Callback dUp, Callback lUp, Callback rUp);
|
||||
void setJoystickPressHandlers(Callback uPress, Callback dPress, Callback lPress, Callback rPress);
|
||||
void setTwoWayRockerPressHandlers(Callback lPress, Callback rPress);
|
||||
|
||||
// Disconnect and reconnect interrupts for light sleep
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
@@ -271,12 +271,13 @@ int32_t ButtonThread::runOnce()
|
||||
break;
|
||||
} // end multipress event
|
||||
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediately.
|
||||
case BUTTON_EVENT_LONG_RELEASED: {
|
||||
|
||||
LOG_INFO("LONG PRESS RELEASE AFTER %u MILLIS", millis() - buttonPressStartTime);
|
||||
if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE &&
|
||||
// Require press started after boot holdoff to avoid phantom shutdown from floating pins
|
||||
if (millis() > 30000 && buttonPressStartTime > 30000 && _longLongPress != INPUT_BROKER_NONE &&
|
||||
(millis() - buttonPressStartTime) >= _longLongPressTime && leadUpPlayed) {
|
||||
evt.inputEvent = _longLongPress;
|
||||
this->notifyObservers(&evt);
|
||||
@@ -346,4 +347,4 @@ int ButtonThread::afterLightSleep(esp_sleep_wakeup_cause_t cause)
|
||||
void ButtonThread::storeClickCount()
|
||||
{
|
||||
multipressClickCount = userButton.getNumberClicks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
#if defined(M5STACK_CARDPUTER_ADV)
|
||||
|
||||
#include "CardputerKeyboard.h"
|
||||
#include "main.h"
|
||||
|
||||
#define _TCA8418_COLS 8
|
||||
#define _TCA8418_ROWS 7
|
||||
#define _TCA8418_NUM_KEYS 56
|
||||
|
||||
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
||||
|
||||
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||
|
||||
constexpr uint8_t modifierFnKey = 2;
|
||||
constexpr uint8_t modifierFn = 0b0010;
|
||||
constexpr uint8_t modifierCtrlKey = 3;
|
||||
constexpr uint8_t modifierShiftKey = 6;
|
||||
constexpr uint8_t modifierShift = 0b0001;
|
||||
constexpr uint8_t modifierOptKey = 7;
|
||||
constexpr uint8_t modifierAltKey = 11;
|
||||
|
||||
// Num chars per key, Modulus for rotating through characters
|
||||
static uint8_t CardputerTapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
|
||||
|
||||
static unsigned char CardputerTapMap[_TCA8418_NUM_KEYS][3] = {{'`', '~', Key::ESC},
|
||||
{Key::TAB, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{'1', '!', 0x00},
|
||||
{'q', 'Q', Key::REBOOT},
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{'2', '@', 0x00},
|
||||
{'w', 'W', 0x00},
|
||||
{'a', 'A', 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{'3', '#', 0x00},
|
||||
{'e', 'E', 0x00},
|
||||
{'s', 'S', 0x00},
|
||||
{'z', 'Z', 0x00},
|
||||
{'4', '$', 0x00},
|
||||
{'r', 'R', 0x00},
|
||||
{'d', 'D', 0x00},
|
||||
{'x', 'X', 0x00},
|
||||
{'5', '%', 0x00},
|
||||
{'t', 'T', 0x00},
|
||||
{'f', 'F', 0x00},
|
||||
{'c', 'C', 0x00},
|
||||
{'6', '^', 0x00},
|
||||
{'y', 'Y', 0x00},
|
||||
{'g', 'G', Key::GPS_TOGGLE},
|
||||
{'v', 'V', 0x00},
|
||||
{'7', '&', 0x00},
|
||||
{'u', 'U', 0x00},
|
||||
{'h', 'H', 0x00},
|
||||
{'b', 'B', Key::BT_TOGGLE},
|
||||
{'8', '*', 0x00},
|
||||
{'i', 'I', 0x00},
|
||||
{'j', 'J', 0x00},
|
||||
{'n', 'N', 0x00},
|
||||
{'9', '(', 0x00},
|
||||
{'o', 'O', 0x00},
|
||||
{'k', 'K', 0x00},
|
||||
{'m', 'M', Key::MUTE_TOGGLE},
|
||||
{'0', ')', 0x00},
|
||||
{'p', 'P', Key::SEND_PING},
|
||||
{'l', 'L', 0x00},
|
||||
{',', '<', Key::LEFT},
|
||||
{'_', '-', 0x00},
|
||||
{'[', '{', 0x00},
|
||||
{';', ':', Key::UP},
|
||||
{'.', '>', Key::DOWN},
|
||||
{'=', '+', 0x00},
|
||||
{']', '}', 0x00},
|
||||
{'\'', '"', 0x00},
|
||||
{'/', '?', Key::RIGHT},
|
||||
{Key::BSP, 0x00, 0x00},
|
||||
{'\\', '|', 0x00},
|
||||
{Key::SELECT, 0x00, 0x00},
|
||||
{' ', ' ', ' '}};
|
||||
|
||||
CardputerKeyboard::CardputerKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void CardputerKeyboard::reset(void)
|
||||
{
|
||||
TCA8418KeyboardBase::reset();
|
||||
}
|
||||
|
||||
// handle multi-key presses (shift and alt)
|
||||
void CardputerKeyboard::trigger()
|
||||
{
|
||||
uint8_t count = keyCount();
|
||||
if (count == 0)
|
||||
return;
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
|
||||
uint8_t key = k & 0x7F;
|
||||
if (k & 0x80) {
|
||||
pressed(key);
|
||||
} else {
|
||||
released();
|
||||
state = Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardputerKeyboard::pressed(uint8_t key)
|
||||
{
|
||||
if (state == Init || state == Busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||
return; // Invalid key
|
||||
}
|
||||
|
||||
next_key = row * _TCA8418_COLS + col;
|
||||
state = Held;
|
||||
|
||||
uint32_t now = millis();
|
||||
tap_interval = now - last_tap;
|
||||
|
||||
updateModifierFlag(next_key);
|
||||
if (isModifierKey(next_key)) {
|
||||
last_modifier_time = now;
|
||||
}
|
||||
|
||||
if (tap_interval < 0) {
|
||||
last_tap = 0;
|
||||
state = Busy;
|
||||
return;
|
||||
}
|
||||
|
||||
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||
char_idx = 0;
|
||||
} else {
|
||||
char_idx += 1;
|
||||
}
|
||||
|
||||
last_key = next_key;
|
||||
last_tap = now;
|
||||
}
|
||||
|
||||
void CardputerKeyboard::released()
|
||||
{
|
||||
if (state != Held) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t now = millis();
|
||||
last_tap = now;
|
||||
|
||||
if (inputBroker->menuMode && modifierFlag == 0) {
|
||||
if (last_key == 0 || last_key == 43 || last_key == 46 || last_key == 47 ||
|
||||
last_key == 51) { // esc, left, up, down, right key
|
||||
modifierFlag = modifierFn;
|
||||
}
|
||||
}
|
||||
|
||||
queueEvent(CardputerTapMap[last_key][modifierFlag % CardputerTapMod[last_key]]);
|
||||
if (isModifierKey(last_key) == false)
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
void CardputerKeyboard::updateModifierFlag(uint8_t key)
|
||||
{
|
||||
if (key == modifierShiftKey) {
|
||||
modifierFlag ^= modifierShift;
|
||||
} else if (key == modifierFnKey) {
|
||||
modifierFlag ^= modifierFn;
|
||||
}
|
||||
}
|
||||
|
||||
bool CardputerKeyboard::isModifierKey(uint8_t key)
|
||||
{
|
||||
return (key == modifierShiftKey || key == modifierFnKey);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "TCA8418KeyboardBase.h"
|
||||
|
||||
class CardputerKeyboard : public TCA8418KeyboardBase
|
||||
{
|
||||
public:
|
||||
CardputerKeyboard();
|
||||
void reset(void);
|
||||
void trigger(void) override;
|
||||
virtual ~CardputerKeyboard() {}
|
||||
|
||||
protected:
|
||||
void pressed(uint8_t key) override;
|
||||
void released(void) override;
|
||||
|
||||
void updateModifierFlag(uint8_t key);
|
||||
bool isModifierKey(uint8_t key);
|
||||
|
||||
private:
|
||||
uint8_t modifierFlag;
|
||||
uint32_t last_modifier_time;
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
};
|
||||
@@ -100,13 +100,28 @@ void InputBroker::processInputEventQueue()
|
||||
|
||||
int InputBroker::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
|
||||
#if HAS_SCREEN
|
||||
bool screenWasOff = false;
|
||||
if (screen) {
|
||||
screenWasOff = !screen->isScreenOn();
|
||||
}
|
||||
#endif
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
|
||||
if (event && event->inputEvent != INPUT_BROKER_NONE && externalNotificationModule &&
|
||||
moduleConfig.external_notification.enabled && externalNotificationModule->nagging()) {
|
||||
externalNotificationModule->stopNow();
|
||||
// If this turns off a notification, don't further process the event
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAS_SCREEN
|
||||
if (screen && screenWasOff) {
|
||||
// If the screen was off, it is in the process of turning on, and we just drop the event
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
this->notifyObservers(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class InputBroker : public Observable<const InputEvent *>
|
||||
|
||||
public:
|
||||
InputBroker();
|
||||
bool menuMode = true;
|
||||
void registerSource(Observable<const InputEvent *> *source);
|
||||
void injectInputEvent(const InputEvent *event) { handleInputEvent(event); }
|
||||
#if defined(HAS_FREE_RTOS) && !defined(ARCH_RP2040)
|
||||
|
||||
@@ -177,7 +177,7 @@ void MPR121Keyboard::reset()
|
||||
delay(20);
|
||||
writeRegister(_MPR121_REG_CONFIG2, 0x21);
|
||||
delay(20);
|
||||
// Enter run mode by Seting partial filter calibration tracking, disable proximity detection, enable 12 channels
|
||||
// Enter run mode by setting partial filter calibration tracking, disable proximity detection, enable 12 channels
|
||||
writeRegister(_MPR121_REG_ELECTRODE_CONFIG,
|
||||
ECR_CALIBRATION_TRACK_FROM_FULL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH);
|
||||
delay(100);
|
||||
@@ -430,4 +430,4 @@ void MPR121Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||
if (writeCallback) {
|
||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ int32_t SeesawRotary::runOnce()
|
||||
wasPressed = currentlyPressed;
|
||||
|
||||
int32_t new_position = ss.getEncoderPosition();
|
||||
// did we move arounde?
|
||||
// did we move around?
|
||||
if (encoder_position != new_position) {
|
||||
if (encoder_position == 0 && new_position != 1) {
|
||||
e.inputEvent = INPUT_BROKER_ALT_PRESS;
|
||||
@@ -80,4 +80,4 @@ int32_t SeesawRotary::runOnce()
|
||||
|
||||
return 50;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -88,7 +88,7 @@ void TCA8418Keyboard::pressed(uint8_t key)
|
||||
// Check if the key is the same as the last one or if the time interval has passed
|
||||
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||
char_idx = 0; // Reset char index if new key or long press
|
||||
should_backspace = false; // dont backspace on new key
|
||||
should_backspace = false; // don't backspace on new key
|
||||
} else {
|
||||
char_idx += 1; // Cycle through characters if same key pressed
|
||||
should_backspace = true; // allow backspace on same key
|
||||
|
||||
@@ -43,7 +43,7 @@ int32_t TouchScreenBase::runOnce()
|
||||
// process touch events
|
||||
int16_t x, y;
|
||||
bool touched = getTouch(x, y);
|
||||
if (x < 0 || y < 0) // T-deck can emit phantom touch events with a negative value when turing off the screen
|
||||
if (x < 0 || y < 0) // T-deck can emit phantom touch events with a negative value when turning off the screen
|
||||
touched = false;
|
||||
if (touched) {
|
||||
this->setInterval(20);
|
||||
@@ -123,7 +123,7 @@ int32_t TouchScreenBase::runOnce()
|
||||
}
|
||||
}
|
||||
#else
|
||||
// fire TAP event when no 2nd tap occured within time
|
||||
// fire TAP event when no 2nd tap occurred within time
|
||||
if (_tapped) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
|
||||
|
||||
@@ -8,6 +8,14 @@ UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
|
||||
|
||||
bool UpDownInterruptImpl1::init()
|
||||
{
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER) && defined(INPUTDRIVER_TWO_WAY_ROCKER_LEFT) && defined(INPUTDRIVER_TWO_WAY_ROCKER_RIGHT)
|
||||
moduleConfig.canned_message.updown1_enabled = true;
|
||||
moduleConfig.canned_message.inputbroker_pin_a = INPUTDRIVER_TWO_WAY_ROCKER_LEFT;
|
||||
moduleConfig.canned_message.inputbroker_pin_b = INPUTDRIVER_TWO_WAY_ROCKER_RIGHT;
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER_BTN)
|
||||
moduleConfig.canned_message.inputbroker_pin_press = INPUTDRIVER_TWO_WAY_ROCKER_BTN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!moduleConfig.canned_message.updown1_enabled) {
|
||||
// Input device is disabled.
|
||||
@@ -46,4 +54,4 @@ void UpDownInterruptImpl1::handleIntUp()
|
||||
void UpDownInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
upDownInterruptImpl1->intPressHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "TDeckProKeyboard.h"
|
||||
#elif defined(T_LORA_PAGER)
|
||||
#include "TLoraPagerKeyboard.h"
|
||||
#elif defined(M5STACK_CARDPUTER_ADV)
|
||||
#include "CardputerKeyboard.h"
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
#include "HackadayCommunicatorKeyboard.h"
|
||||
#else
|
||||
@@ -22,6 +24,8 @@ KbI2cBase::KbI2cBase(const char *name)
|
||||
TCAKeyboard(*(new TDeckProKeyboard()))
|
||||
#elif defined(T_LORA_PAGER)
|
||||
TCAKeyboard(*(new TLoraPagerKeyboard()))
|
||||
#elif defined(M5STACK_CARDPUTER_ADV)
|
||||
TCAKeyboard(*(new CardputerKeyboard()))
|
||||
#elif defined(HACKADAY_COMMUNICATOR)
|
||||
TCAKeyboard(*(new HackadayCommunicatorKeyboard()))
|
||||
#else
|
||||
@@ -487,7 +491,7 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = 0;
|
||||
break;
|
||||
case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
|
||||
// toggle moddifiers button.
|
||||
// toggle modifiers button.
|
||||
is_sym = !is_sym;
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = is_sym ? INPUT_BROKER_MSG_FN_SYMBOL_ON // send 0xf1 to tell CannedMessages to display that the
|
||||
|
||||
+13
-3
@@ -9,6 +9,7 @@
|
||||
#include "PowerMon.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "ReliableRouter.h"
|
||||
#include "TransmitHistory.h"
|
||||
#include "airtime.h"
|
||||
#include "buzz.h"
|
||||
#include "power/PowerHAL.h"
|
||||
@@ -246,7 +247,6 @@ uint32_t timeLastPowered = 0;
|
||||
static OSThread *powerFSMthread;
|
||||
OSThread *ambientLightingThread;
|
||||
|
||||
RadioInterface *rIf = NULL;
|
||||
RadioLibHal *RadioLibHAL = NULL;
|
||||
|
||||
/**
|
||||
@@ -389,8 +389,8 @@ void setup()
|
||||
|
||||
#if defined(ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
#ifndef SENSECAP_INDICATOR
|
||||
// use PSRAM for malloc calls > 256 bytes
|
||||
heap_caps_malloc_extmem_enable(256);
|
||||
// use PSRAM for malloc calls > 2048 bytes
|
||||
heap_caps_malloc_extmem_enable(2048);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -704,6 +704,9 @@ void setup()
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB = new NodeDB;
|
||||
|
||||
// Initialize transmit history to persist broadcast throttle timers across reboots
|
||||
TransmitHistory::getInstance()->loadFromDisk();
|
||||
#if HAS_TFT
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
tftSetup();
|
||||
@@ -1125,6 +1128,13 @@ void loop()
|
||||
lastRadioMissedIrqPoll = millis();
|
||||
RadioLibInterface::instance->pollMissedIrqs();
|
||||
}
|
||||
|
||||
// Periodic AGC reset — warm sleep + recalibrate to prevent stuck AGC gain
|
||||
static uint32_t lastAgcReset;
|
||||
if (!Throttle::isWithinTimespanMs(lastAgcReset, AGC_RESET_INTERVAL_MS)) {
|
||||
lastAgcReset = millis();
|
||||
RadioLibInterface::instance->resetAGC();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_STACK
|
||||
|
||||
@@ -22,6 +22,8 @@ const char *Channels::serialChannel = "serial";
|
||||
const char *Channels::mqttChannel = "mqtt";
|
||||
#endif
|
||||
|
||||
meshtastic_Channel dummyChannel = {.index = -1};
|
||||
|
||||
uint8_t xorHash(const uint8_t *p, size_t len)
|
||||
{
|
||||
uint8_t code = 0;
|
||||
@@ -309,13 +311,7 @@ meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex)
|
||||
return *ch;
|
||||
} else {
|
||||
LOG_ERROR("Invalid channel index %d > %d, malformed packet received?", chIndex, channelFile.channels_count);
|
||||
|
||||
static meshtastic_Channel *ch = (meshtastic_Channel *)malloc(sizeof(meshtastic_Channel));
|
||||
memset(ch, 0, sizeof(meshtastic_Channel));
|
||||
// ch.index -1 means we don't know the channel locally and need to look it up by settings.name
|
||||
// not sure this is handled right everywhere
|
||||
ch->index = -1;
|
||||
return *ch;
|
||||
return dummyChannel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,13 @@ uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultVa
|
||||
uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes)
|
||||
{
|
||||
// If we are a router, we don't scale the value. It's already significantly higher.
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER)
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
|
||||
return getConfiguredOrDefaultMs(configured, defaultValue);
|
||||
|
||||
// Additionally if we're a tracker or sensor, we want priority to send position and telemetry
|
||||
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_TRACKER))
|
||||
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER))
|
||||
return getConfiguredOrDefaultMs(configured, defaultValue);
|
||||
|
||||
return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user