Compare commits

..
246 changed files with 3228 additions and 8973 deletions
+1 -1
View File
@@ -100,7 +100,7 @@ runs:
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
overwrite: true
+3 -3
View File
@@ -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 accidentally duplicating work etc...
is appreciated." This will allow other devs to potentially save you time by not accidentially 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 community 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 commnunity members can help test your changes.
- If your PR gets accepted you can request a "Contributor" role in the Meshtastic Discord
## 🤝 Attestations
+2 -2
View File
@@ -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@v7
uses: crazy-max/ghaction-import-gpg@v6
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@v7
uses: actions/upload-artifact@v6
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
overwrite: true
+2 -2
View File
@@ -111,7 +111,7 @@ jobs:
echo "</details>" >> $GITHUB_STEP_SUMMARY
- name: Store binaries as an artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
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@v7
uses: actions/upload-artifact@v6
id: upload-manifest
with:
name: manifest-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
+4 -4
View File
@@ -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@v8
- uses: actions/download-artifact@v7
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@v7
uses: actions/upload-artifact@v6
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@v8
- uses: actions/download-artifact@v7
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@v7
uses: actions/upload-artifact@v6
with:
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
overwrite: true
+1 -1
View File
@@ -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
+2 -2
View File
@@ -60,13 +60,13 @@ jobs:
- name: Docker login
if: ${{ inputs.push }}
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: meshtastic
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
uses: docker/setup-qemu-action@v3
- name: Docker setup
uses: docker/setup-buildx-action@v3
+1 -1
View File
@@ -139,7 +139,7 @@ jobs:
id: tags
- name: Docker login
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: meshtastic
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
+14 -13
View File
@@ -96,6 +96,7 @@ jobs:
pio_platform: ${{ matrix.check.platform }}
pio_env: ${{ matrix.check.board }}
pio_target: check
pio_opts: --fail-on-defect=low
build:
needs: [setup, version]
@@ -177,7 +178,7 @@ jobs:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
@@ -187,7 +188,7 @@ jobs:
run: ls -R
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
@@ -205,7 +206,7 @@ jobs:
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -224,7 +225,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@v7
uses: actions/upload-artifact@v6
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
@@ -250,13 +251,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@v8
uses: actions/download-artifact@v7
with:
path: ./manifests-new/
pattern: manifest-*
merge-multiple: true
- name: Upload combined manifests for later commit and global stats crunching.
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
id: upload-manifest
with:
name: manifests-${{ github.sha }}
@@ -324,14 +325,14 @@ jobs:
body: ${{ steps.release_notes.outputs.notes }}
- name: Download source deb
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -355,7 +356,7 @@ jobs:
}' > firmware-${{ needs.version.outputs.long }}.json
- name: Save Release manifest artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: manifest-${{ needs.version.outputs.long }}
overwrite: true
@@ -396,7 +397,7 @@ jobs:
with:
python-version: 3.x
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -413,7 +414,7 @@ jobs:
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
@@ -454,14 +455,14 @@ jobs:
python-version: 3.x
- name: Get firmware artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./publish
- name: Get manifest artifact
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
pattern: manifest-${{ needs.version.outputs.long }}
path: ./publish
+9 -9
View File
@@ -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@v8
- uses: actions/download-artifact@v7
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
@@ -160,7 +160,7 @@ jobs:
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
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@v8
- uses: actions/download-artifact@v7
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@v7
uses: actions/upload-artifact@v6
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@v8
uses: actions/download-artifact@v7
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
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@v8
- uses: actions/download-artifact@v7
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@v8
- uses: actions/download-artifact@v7
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@v8
- uses: actions/download-artifact@v7
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true
+1 -1
View File
@@ -58,7 +58,7 @@ jobs:
id: version
- name: Download artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true
+1 -11
View File
@@ -54,19 +54,9 @@ 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@v7
uses: actions/upload-artifact@v6
with:
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
overwrite: true
+2 -2
View File
@@ -46,7 +46,7 @@ jobs:
sudo apt-get install -y dput
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v7
uses: crazy-max/ghaction-import-gpg@v6
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@v8
uses: actions/download-artifact@v7
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true
+1 -1
View File
@@ -50,7 +50,7 @@ jobs:
- name: Download test artifacts
if: needs.native-tests.result != 'skipped'
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true
+1 -1
View File
@@ -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: |-
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
with:
name: report.sarif
overwrite: true
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Stale PR+Issues
uses: actions/stale@v10.2.0
uses: actions/stale@v10.1.1
with:
days-before-stale: 45
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
+7 -7
View File
@@ -59,7 +59,7 @@ jobs:
id: version
- name: Save coverage information
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
@@ -94,7 +94,7 @@ jobs:
- name: Save test results
if: always() # run this step even if previous step failed
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
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@v7
uses: actions/upload-artifact@v6
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
@@ -137,20 +137,20 @@ jobs:
id: version
- name: Download test artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
with:
name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true
- name: Test Report
uses: dorny/test-reporter@v2.6.0
uses: dorny/test-reporter@v2.5.0
with:
name: PlatformIO Tests
path: testreport.xml
reporter: java-junit
- name: Download coverage artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v7
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@v7
uses: actions/upload-artifact@v6
with:
name: code-coverage-report-${{ steps.version.outputs.long }}
path: code-coverage-report
+10 -10
View File
@@ -4,24 +4,24 @@ cli:
plugins:
sources:
- id: trunk
ref: v1.7.5
ref: v1.7.4
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- checkov@3.2.506
- renovate@43.52.0
- checkov@3.2.501
- renovate@43.10.3
- prettier@3.8.1
- trufflehog@3.93.6
- trufflehog@3.93.3
- yamllint@1.38.0
- bandit@1.9.4
- trivy@0.69.3
- bandit@1.9.3
- trivy@0.69.1
- taplo@0.10.0
- ruff@0.15.4
- isort@8.0.1
- markdownlint@0.48.0
- ruff@0.15.1
- isort@7.0.0
- markdownlint@0.47.0
- oxipng@10.1.0
- svgo@4.0.0
- actionlint@1.7.11
- actionlint@1.7.10
- flake8@7.3.0
- hadolint@2.14.0
- shfmt@3.6.0
-26
View File
@@ -1,26 +0,0 @@
# 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
View File
@@ -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=low --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=medium --fail-on-defect=high
-2
View File
@@ -187,7 +187,6 @@ 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
@@ -215,4 +214,3 @@ General:
AvailableDirectory: /etc/meshtasticd/available.d/
# MACAddress: AA:BB:CC:DD:EE:FF
# MACAddressSource: eth0
# APIPort: 4403
@@ -6,9 +6,6 @@ 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,8 +4,5 @@ Lora:
Reset: 24 # IO4
Busy: 19 # IO5
# Ant_sw: 23 # IO3
Enable_Pins:
- 26
- 23
spidev: spidev0.1
# CS: 7
@@ -1,16 +0,0 @@
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]
@@ -1,12 +0,0 @@
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]
+1 -5
View File
@@ -5,11 +5,7 @@ Lora:
IRQ: 22 #IO6
Reset: 16 # IO4
Busy: 24 # IO5
Enable_Pins:
- 12
- 13
# Ant_sw: 13 # IO3
DIO3_TCXO_VOLTAGE: true
DIO2_AS_RF_SWITCH: true
spidev: spidev0.0
# GPIO_DETECT_PA: 13
TX_GAIN_LORA: [8]
-16
View File
@@ -1,16 +0,0 @@
# 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
-17
View File
@@ -1,17 +0,0 @@
# 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
@@ -1,25 +0,0 @@
# 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
+2 -1
View File
@@ -13,7 +13,8 @@ Lora:
# USB_Serialnum: 12345678
SX126X_MAX_POWER: 22
# Reduce output power to improve EMI
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]
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
# 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).
+2 -1
View File
@@ -13,7 +13,8 @@ Lora:
# USB_Serialnum: 12345678
SX126X_MAX_POWER: 22
# Reduce output power to improve EMI
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]
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
# 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).
-44
View File
@@ -1,44 +0,0 @@
#!/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[*]}"
-40
View File
@@ -1,40 +0,0 @@
{
"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
View File
@@ -12,6 +12,6 @@ Ex:
- `logo_320x480.png`
- `logo_320x240.png`
This file is copied to `data/boot/logo.png` before filesystem image compilation.
This file is copied to `data/boot/logo.png` before filesytem image compilation.
For additional examples see the [`event/defcon33` branch](https://github.com/meshtastic/firmware/tree/event/defcon33).
-3
View File
@@ -3,9 +3,6 @@ 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
+1 -4
View File
@@ -9,10 +9,7 @@
PIO_ENV:=\
PLATFORMIO_CORE_DIR=pio/core \
PLATFORMIO_LIBDEPS_DIR=pio/libdeps \
PLATFORMIO_PACKAGES_DIR=pio/packages \
PLATFORMIO_SETTING_ENABLE_TELEMETRY=0 \
PLATFORMIO_SETTING_CHECK_PLATFORMIO_INTERVAL=3650 \
PLATFORMIO_SETTING_CHECK_PRUNE_SYSTEM_THRESHOLD=10240
PLATFORMIO_PACKAGES_DIR=pio/packages
# 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
View File
@@ -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.6
adafruit/Adafruit DPS310@1.1.5
# 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.6
adafruit/Adafruit AHTX0@2.0.5
# 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.6
adafruit/Adafruit MLX90614 Library@2.1.5
# 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.3
adafruit/Adafruit TSL2561@1.1.2
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE
wollewald/BH1750_WE@1.1.10
+3 -1
View File
@@ -51,7 +51,9 @@ class AudioThread : public concurrency::OSThread
i2sRtttl = nullptr;
}
rtttlFile = nullptr;
if (rtttlFile != nullptr) {
rtttlFile = nullptr;
}
setCPUFast(false);
#ifdef T_LORA_PAGER
+2 -8
View File
@@ -38,10 +38,7 @@ static bool isPowered()
return true;
#endif
bool isRouter = ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
? 1
: 0);
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 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
@@ -265,10 +262,7 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
? 1
: 0);
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d", hasPower ? 1 : 0);
-2
View File
@@ -35,8 +35,6 @@ 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
}
+6 -11
View File
@@ -1,29 +1,24 @@
#pragma once
#include <functional>
#include <utility>
#include "concurrency/OSThread.h"
namespace concurrency
{
/**
* @brief Periodically invoke a callback.
* Supports both legacy function pointers and modern callables.
* @brief Periodically invoke a callback. This just provides C-style callback conventions
* rather than a virtual function - FIXME, remove?
*/
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 (*cb)()) : OSThread(name), callback(cb) {}
Periodic(const char *name, std::function<int32_t()> cb) : OSThread(name), callback(std::move(cb)) {}
Periodic(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
protected:
int32_t runOnce() override { return callback ? callback() : 0; }
private:
std::function<int32_t()> callback;
int32_t runOnce() override { return callback(); }
};
} // namespace concurrency
-13
View File
@@ -149,12 +149,6 @@ 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
@@ -169,10 +163,6 @@ 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
// -----------------------------------------------------------------------------
@@ -271,8 +261,6 @@ 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
@@ -499,7 +487,6 @@ 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
+2 -2
View File
@@ -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, BMI270};
return firstOfOrNONE(10, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P, BMM150};
return firstOfOrNONE(9, types);
}
ScanI2C::FoundDevice ScanI2C::firstAQI() const
+1 -3
View File
@@ -89,12 +89,10 @@ class ScanI2C
DA217,
CHSC6X,
CST226SE,
BMI270,
SEN5X,
SFA30,
CW2015,
SCD30,
ADS1115
SCD30
} DeviceType;
// typedef uint8_t DeviceAddress;
+6 -20
View File
@@ -652,8 +652,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
case ICM20948_ADDR: // same as BMX160_ADDR, BMI270_ADDR_ALT, and SEN5X_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR, BMI270_ADDR
case ICM20948_ADDR: // same as BMX160_ADDR and SEN5X_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
// ICM20948 Register check
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
#ifdef HAS_ICM20948
type = ICM20948;
@@ -664,14 +665,6 @@ 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);
@@ -725,18 +718,11 @@ 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;
break;
}
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
if (registerValue == 0x8583 || registerValue == 0x8580) {
type = ADS1115;
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
break;
} else {
LOG_INFO("FT6336U touchscreen found");
type = FT6336U;
}
LOG_INFO("FT6336U touchscreen found");
type = FT6336U;
break;
}
+6 -6
View File
@@ -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
// indefinitely
// idefinitely
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 initial configuration of the device - these _should_ work for most AT6558 devices
// Set the intial 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 frequency to 1Hz
// Set the update frequence 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 at least 0.5s after reconfiguration of GNSS module, before sending next
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next
// commands for the M8 it tends to be more... 1 sec should be enough ;>)
delay(1000);
}
@@ -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 version 4.10 so we can see the additional sats.
// For M8 we want to enable NMEA vserion 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 infrequently (once every 5 secs?) to see if we need to wake.
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
return (powerState == GPS_ACTIVE) ? GPS_THREAD_INTERVAL : 5000;
}
+5 -5
View File
@@ -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 decimal representation to int32_t. I.e., 12.345 becomes 123450000
// Change decimial 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 decimal representation to int32_t. I.e., 12.345 becomes 123450000
// Change decimial 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 based on the passed-in point
* Create a new point bassed on the passed in poin
* Ported from http://www.edwilliams.org/avform147.htm#LL
* @param bearing
* The bearing in radians
* The bearing in raidans
* @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
View File
@@ -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 settable RTC, set it
// If this platform has a setable 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 calculating the number of days since the Unix epoch.
// First, get us to the start of tm->year, by calcuating the number of days since the Unix epoch.
int year = 1900 + tm->tm_year; // tm_year is years since 1900
int year_minus_one = year - 1;
int days_before_this_year = 0;
+1 -1
View File
@@ -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
// Quirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
// Qwirk: 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
View File
@@ -57,7 +57,7 @@ static const uint8_t _message_CFG_PM2[] PROGMEM = {
0x00, 0x00, 0x00, 0x00 // 0x64, 0x40, 0x01, 0x00 // reserved 11
};
// Constellation setup, none required for Neo-6
// Constallation 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 (Precise Point Positioning) (0 = false, 1 = true)
0x00, // usePPP (Precice 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 (Precise Point Positioning) (0 = false, 1 = true)
0x00, // usePPP (Precice 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 = Agressive 1Hz
0x03, // Power setup value 3 = Agresssive 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 acquisition after
// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition 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 definition of "Got Fix" doesn't seem to include SBAS. Much more too this...
The defination 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.
+2 -11
View File
@@ -101,7 +101,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
return true;
}
// End the update process - virtual method, overridden in derived class
// End the update process - virtual method, overriden in derived class
void EInkDisplay::endUpdate()
{
// Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep)
@@ -143,10 +143,6 @@ 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
@@ -206,8 +202,7 @@ 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(MINI_EPAPER_S3)
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
{
// Start HSPI
hspi = new SPIClass(HSPI);
@@ -221,13 +216,9 @@ 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)
+1 -2
View File
@@ -89,8 +89,7 @@ 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(MINI_EPAPER_S3)
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || defined(ELECROW_ThinkNode_M5)
SPIClass *hspi = NULL;
#endif
+3 -3
View File
@@ -95,7 +95,7 @@ void EInkDynamicDisplay::adjustRefreshCounters()
// Trigger the display update by calling base class
bool EInkDynamicDisplay::update()
{
// Determine the refresh mode to use, and start the update
// Detemine 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 occurred consecutively, since last full refresh?
// Have too many fast-refreshes occured 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
+2 -15
View File
@@ -433,15 +433,12 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
PMU->enablePowerOutput(XPOWERS_ALDO2);
#endif
// some screens seem to need a kick in the pants to turn back on
#if defined(MUZI_BASE) || defined(M5STACK_CARDPUTER_ADV)
#if defined(MUZI_BASE)
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
@@ -465,11 +462,9 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
#if defined(HELTEC_TRACKER_V1_X) || defined(HELTEC_WIRELESS_TRACKER_V2)
ui->init();
#endif
#if defined(USE_ST7789) && defined(VTFT_LEDA)
#ifdef VTFT_CTRL
#ifdef USE_ST7789
pinMode(VTFT_CTRL, OUTPUT);
digitalWrite(VTFT_CTRL, LOW);
#endif
ui->init();
#ifdef ESP_PLATFORM
analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT);
@@ -511,12 +506,8 @@ 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);
@@ -884,10 +875,6 @@ 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
-4
View File
@@ -765,11 +765,7 @@ 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;
+2 -2
View File
@@ -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 = __builtin_bswap16(TFT_MESH);
colorTftBlack = __builtin_bswap16(TFT_BLACK);
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);
y = 0;
while (y < displayHeight) {
+3 -3
View File
@@ -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 selectable options
uint8_t NotificationRenderer::alertBannerOptions = 0; // last x lines are seelctable 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 selectable options
alertBannerOptions = 0; // last x lines are seelctable options
optionsArrayPtr = nullptr;
optionsEnumPtr = nullptr;
alertBannerCallback = NULL;
@@ -781,4 +781,4 @@ void NotificationRenderer::showKeyboardMessagePopupWithTitle(const char *title,
}
} // namespace graphics
#endif
#endif
+1 -1
View File
@@ -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 selectable options
static uint8_t alertBannerOptions; // last x lines are seelctable options
static std::function<void(int)> alertBannerCallback;
static uint32_t numDigits;
static uint32_t currentNumber;
+6
View File
@@ -12,6 +12,7 @@
#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>
@@ -1422,6 +1423,11 @@ 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 overridden for a slight optimization
void finalizeUpdate() override; // Only overriden 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 overridden for a slight optimization
void finalizeUpdate() override; // Only overriden for a slight optimization
};
} // namespace NicheGraphics::Drivers
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
@@ -1,178 +0,0 @@
#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
@@ -1,55 +0,0 @@
/*
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
+1 -1
View File
@@ -19,7 +19,7 @@ void setupNicheGraphics()
SPIClass *hspi = new SPIClass(HSPI);
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS);
// Setup EInk driver
// Setup Enk driver
Drivers::EInk *driver = new Drivers::DEPG0290BNS800;
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY);
-203
View File
@@ -1,203 +0,0 @@
#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
-62
View File
@@ -1,62 +0,0 @@
// 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
+2 -2
View File
@@ -3,7 +3,7 @@
/*
Base class for InkHUD applets
Must be overridden
Must be overriden
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 overridden by derived applet, if custom scale required (fixed map size?)
// May be overriden 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,26 +120,9 @@ void InkHUD::NodeListApplet::onRender(bool full)
// Draw the main node list
// ========================
// 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;
};
// Imaginary vertical line dividing left-side and right-side info
// Long-name will crop here
const uint16_t dividerX = (width() - 1) - getTextWidth("X Hops");
// Y value (top) of the current card. Increases as we draw.
uint16_t cardTopY = headerDivY + padDivH;
@@ -158,7 +141,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);
@@ -202,49 +185,41 @@ void InkHUD::NodeListApplet::onRender(bool full)
setFont(fontMedium);
printAt(0, lineAY, shortName, LEFT, MIDDLE);
// Right-side labels and long name are rendered in small font.
// Print the distance
setFont(fontSmall);
uint16_t rightContentW = 0;
printAt(width() - 1, lineBY, distance, RIGHT, MIDDLE);
// 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 we have a direct connection to the node, draw the signal indicator
if (hopsAway == 0 && signal != SIGNAL_UNKNOWN) {
uint16_t signalW = getTextWidth("Xkm"); // Indicator width tuned to a short right-side label
uint16_t signalW = getTextWidth("Xkm"); // Indicator should be similar width to distance 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);
} else if (hopsAway != CardInfo::HOPS_UNKNOWN) {
std::string hopString = to_string(hopsAway) + (hopsAway == 1 ? " Hop" : " Hops");
rightContentW = std::max(rightContentW, getTextWidth(hopString));
}
// 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"
printAt(width() - 1, lineAY, hopString, RIGHT, 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);
// 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);
// 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);
}
// 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);
// Prepare to draw the next card
resetCrop();
cardTopY += cardH;
// Once we've run out of screen, stop drawing cards
@@ -313,4 +288,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 = 1; // Gap between cards (minimal to fit more rows)
uint8_t cardMarginH = fontSmall.lineHeight() / 2; // Gap between cards
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 every time the screen is updated
alwaysRender = true; // render everytime 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-screen keyboard
System Applet to render an on-screeen 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 report display health
// Used during shutdown, to resport 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 only for full joystick devices
if (settings->joystick.enabled && !inkhud->twoWayRocker)
// Open the on-screen keyboard if the joystick is enabled
if (settings->joystick.enabled)
inkhud->openKeyboard();
break;
case STORE_CANNEDMESSAGE_SELECTION:
if (!settings->joystick.enabled || inkhud->twoWayRocker)
if (!settings->joystick.enabled)
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 && !inkhud->twoWayRocker)
if (settings->joystick.enabled)
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 && !inkhud->twoWayRocker)
if (settings->joystick.enabled)
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 memory we'd used while selecting / sending canned messages
// Free up any heap mmemory we'd used while selecting / sending canned messages
void InkHUD::MenuApplet::freeCannedMessageResources()
{
cm.selectedMessageItem = nullptr;
@@ -152,11 +152,6 @@ 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.
const meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
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 preserve applet between reboots.
Several messages are saved to flash at shutdown, to preseve 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
+1 -4
View File
@@ -88,9 +88,6 @@ 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
@@ -133,4 +130,4 @@ class InkHUD
} // namespace NicheGraphics::InkHUD
#endif
#endif
+2 -2
View File
@@ -53,7 +53,7 @@ class Renderer : protected concurrency::OSThread
uint16_t height();
private:
// Make attempts to render / update, once triggered by requestUpdate or forceUpdate
// Make attemps 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
+5 -11
View File
@@ -143,7 +143,7 @@ void InkHUD::WindowManager::openMenu()
// Bring the AlignStick applet to the foreground
void InkHUD::WindowManager::openAlignStick()
{
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
if (settings->joystick.enabled) {
AlignStickApplet *alignStick = (AlignStickApplet *)inkhud->getSystemApplet("AlignStick");
alignStick->bringToForeground();
}
@@ -151,9 +151,6 @@ void InkHUD::WindowManager::openAlignStick()
void InkHUD::WindowManager::openKeyboard()
{
if (!settings->joystick.enabled || inkhud->twoWayRocker)
return;
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
if (keyboard) {
@@ -165,9 +162,6 @@ void InkHUD::WindowManager::openKeyboard()
void InkHUD::WindowManager::closeKeyboard()
{
if (!settings->joystick.enabled || inkhud->twoWayRocker)
return;
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
if (keyboard) {
@@ -483,7 +477,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 && !inkhud->twoWayRocker) {
if (settings->joystick.enabled) {
addSystemApplet("AlignStick", new AlignStickApplet, new Tile);
addSystemApplet("Keyboard", new KeyboardApplet, new Tile);
}
@@ -509,7 +503,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 && !inkhud->twoWayRocker) {
if (settings->joystick.enabled) {
inkhud->getSystemApplet("AlignStick")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
const uint16_t keyboardHeight = KeyboardApplet::getKeyboardHeight();
inkhud->getSystemApplet("Keyboard")
@@ -655,7 +649,7 @@ void InkHUD::WindowManager::refocusTile()
}
}
// Search for any applets which believe they are foreground, but no longer have a valid tile
// Seach 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()
{
@@ -685,4 +679,4 @@ void InkHUD::WindowManager::findOrphanApplets()
}
}
#endif
#endif
+1 -1
View File
@@ -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 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.
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.
```cpp
// -2 px of padding above, +1 px of padding below
+2 -2
View File
@@ -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 TwoButton class itself, it could be moved elsewhere.
// This helper method isn't used by the TweButton 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,24 +156,6 @@ 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);
@@ -247,13 +229,6 @@ 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,7 +45,6 @@ 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);
@@ -55,7 +54,6 @@ 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
+4 -5
View File
@@ -271,13 +271,12 @@ int32_t ButtonThread::runOnce()
break;
} // end multipress event
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediately.
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
case BUTTON_EVENT_LONG_RELEASED: {
LOG_INFO("LONG PRESS RELEASE AFTER %u MILLIS", millis() - buttonPressStartTime);
// Require press started after boot holdoff to avoid phantom shutdown from floating pins
if (millis() > 30000 && buttonPressStartTime > 30000 && _longLongPress != INPUT_BROKER_NONE &&
if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE &&
(millis() - buttonPressStartTime) >= _longLongPressTime && leadUpPlayed) {
evt.inputEvent = _longLongPress;
this->notifyObservers(&evt);
@@ -347,4 +346,4 @@ int ButtonThread::afterLightSleep(esp_sleep_wakeup_cause_t cause)
void ButtonThread::storeClickCount()
{
multipressClickCount = userButton.getNumberClicks();
}
}
-200
View File
@@ -1,200 +0,0 @@
#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
-26
View File
@@ -1,26 +0,0 @@
#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;
};
+1 -16
View File
@@ -100,28 +100,13 @@ void InputBroker::processInputEventQueue()
int InputBroker::handleInputEvent(const InputEvent *event)
{
#if HAS_SCREEN
bool screenWasOff = false;
if (screen) {
screenWasOff = !screen->isScreenOn();
}
#endif
powerFSM.trigger(EVENT_INPUT);
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
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;
}
-1
View File
@@ -70,7 +70,6 @@ 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)
+2 -2
View File
@@ -177,7 +177,7 @@ void MPR121Keyboard::reset()
delay(20);
writeRegister(_MPR121_REG_CONFIG2, 0x21);
delay(20);
// Enter run mode by setting partial filter calibration tracking, disable proximity detection, enable 12 channels
// Enter run mode by Seting 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);
}
}
}
+2 -2
View File
@@ -59,7 +59,7 @@ int32_t SeesawRotary::runOnce()
wasPressed = currentlyPressed;
int32_t new_position = ss.getEncoderPosition();
// did we move around?
// did we move arounde?
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
+1 -1
View File
@@ -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; // don't backspace on new key
should_backspace = false; // dont backspace on new key
} else {
char_idx += 1; // Cycle through characters if same key pressed
should_backspace = true; // allow backspace on same key
+2 -2
View File
@@ -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 turning off the screen
if (x < 0 || y < 0) // T-deck can emit phantom touch events with a negative value when turing 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 occurred within time
// fire TAP event when no 2nd tap occured within time
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
+1 -9
View File
@@ -8,14 +8,6 @@ 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.
@@ -54,4 +46,4 @@ void UpDownInterruptImpl1::handleIntUp()
void UpDownInterruptImpl1::handleIntPressed()
{
upDownInterruptImpl1->intPressHandler();
}
}
+1 -5
View File
@@ -7,8 +7,6 @@
#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
@@ -24,8 +22,6 @@ 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
@@ -491,7 +487,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 modifiers button.
// toggle moddifiers 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
+3 -13
View File
@@ -9,7 +9,6 @@
#include "PowerMon.h"
#include "RadioLibInterface.h"
#include "ReliableRouter.h"
#include "TransmitHistory.h"
#include "airtime.h"
#include "buzz.h"
#include "power/PowerHAL.h"
@@ -247,6 +246,7 @@ 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 > 2048 bytes
heap_caps_malloc_extmem_enable(2048);
// use PSRAM for malloc calls > 256 bytes
heap_caps_malloc_extmem_enable(256);
#endif
#endif
@@ -704,9 +704,6 @@ 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();
@@ -1128,13 +1125,6 @@ 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
+7 -3
View File
@@ -22,8 +22,6 @@ 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;
@@ -311,7 +309,13 @@ meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex)
return *ch;
} else {
LOG_ERROR("Invalid channel index %d > %d, malformed packet received?", chIndex, channelFile.channels_count);
return dummyChannel;
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;
}
}
+2 -4
View File
@@ -38,13 +38,11 @@ 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 ||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER)
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,
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER))
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_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