mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-16 15:52:34 +00:00
Compare commits
16 Commits
self-hoste
...
on-screen-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c95991cee2 | ||
|
|
f901166f16 | ||
|
|
ddc66c5e84 | ||
|
|
0544998c9b | ||
|
|
dca615fe3d | ||
|
|
cca2ead2c1 | ||
|
|
53afebae41 | ||
|
|
4f4ede9c8c | ||
|
|
fbd4138d98 | ||
|
|
f4bb2ec0f0 | ||
|
|
995752e31d | ||
|
|
75b12d318d | ||
|
|
eea4d734d2 | ||
|
|
e98c6debb2 | ||
|
|
ace45c1236 | ||
|
|
6c7da1e6b1 |
@@ -76,7 +76,7 @@ bool loopCanSleep()
|
|||||||
// Called just prior to starting Meshtastic. Allows for setting config values before startup.
|
// Called just prior to starting Meshtastic. Allows for setting config values before startup.
|
||||||
void lateInitVariant()
|
void lateInitVariant()
|
||||||
{
|
{
|
||||||
portduino_config.logoutputlevel = level_error;
|
settingsMap[logoutputlevel] = level_error;
|
||||||
channelFile.channels[0] = meshtastic_Channel{
|
channelFile.channels[0] = meshtastic_Channel{
|
||||||
.has_settings = true,
|
.has_settings = true,
|
||||||
.settings =
|
.settings =
|
||||||
@@ -132,7 +132,7 @@ int portduino_main(int argc, char **argv); // Renamed "main" function from Mesht
|
|||||||
// Start Meshtastic in a thread and wait till it has reached the ON state.
|
// Start Meshtastic in a thread and wait till it has reached the ON state.
|
||||||
int LLVMFuzzerInitialize(int *argc, char ***argv)
|
int LLVMFuzzerInitialize(int *argc, char ***argv)
|
||||||
{
|
{
|
||||||
portduino_config.maxtophone = 5;
|
settingsMap[maxtophone] = 5;
|
||||||
|
|
||||||
meshtasticThread = std::thread([program = *argv[0]]() {
|
meshtasticThread = std::thread([program = *argv[0]]() {
|
||||||
char nodeIdStr[12];
|
char nodeIdStr[12];
|
||||||
|
|||||||
7
.github/actions/setup-base/action.yml
vendored
7
.github/actions/setup-base/action.yml
vendored
@@ -11,6 +11,11 @@ runs:
|
|||||||
ref: ${{github.event.pull_request.head.ref}}
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
|
||||||
|
- name: Uncomment build epoch
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -18,7 +23,7 @@ runs:
|
|||||||
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev lsb-release
|
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev lsb-release
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
cache: pip
|
cache: pip
|
||||||
|
|||||||
4
.github/workflows/build_firmware.yml
vendored
4
.github/workflows/build_firmware.yml
vendored
@@ -18,7 +18,7 @@ permissions: read-all
|
|||||||
jobs:
|
jobs:
|
||||||
pio-build:
|
pio-build:
|
||||||
name: build-${{ inputs.platform }}
|
name: build-${{ inputs.platform }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build ${{ inputs.platform }}
|
- name: Build ${{ inputs.platform }}
|
||||||
id: build
|
id: build
|
||||||
uses: fifieldt/gh-action-firmware@fifield
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
pio_platform: ${{ inputs.platform }}
|
pio_platform: ${{ inputs.platform }}
|
||||||
pio_env: ${{ inputs.pio_env }}
|
pio_env: ${{ inputs.pio_env }}
|
||||||
|
|||||||
500
.github/workflows/build_one_arch.yml
vendored
500
.github/workflows/build_one_arch.yml
vendored
@@ -1,500 +0,0 @@
|
|||||||
name: Build One Arch
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
arch:
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
- native
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
setup:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
cache: pip
|
|
||||||
- run: pip install -U platformio
|
|
||||||
- name: Generate matrix
|
|
||||||
id: jsonStep
|
|
||||||
run: |
|
|
||||||
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
|
|
||||||
TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} extra)
|
|
||||||
else
|
|
||||||
TARGETS=$(./bin/generate_ci_matrix.py ${{inputs.arch}} pr)
|
|
||||||
fi
|
|
||||||
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS"
|
|
||||||
echo "${{inputs.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
|
|
||||||
outputs:
|
|
||||||
esp32: ${{ steps.jsonStep.outputs.esp32 }}
|
|
||||||
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
|
|
||||||
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
|
|
||||||
esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }}
|
|
||||||
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
|
|
||||||
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
|
|
||||||
rp2350: ${{ steps.jsonStep.outputs.rp2350 }}
|
|
||||||
stm32: ${{ steps.jsonStep.outputs.stm32 }}
|
|
||||||
check: ${{ steps.jsonStep.outputs.check }}
|
|
||||||
|
|
||||||
version:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- name: Get release version string
|
|
||||||
run: |
|
|
||||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
|
||||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
|
||||||
id: version
|
|
||||||
env:
|
|
||||||
BUILD_LOCATION: local
|
|
||||||
outputs:
|
|
||||||
long: ${{ steps.version.outputs.long }}
|
|
||||||
deb: ${{ steps.version.outputs.deb }}
|
|
||||||
|
|
||||||
build-esp32:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32
|
|
||||||
|
|
||||||
build-esp32s3:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32s3'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32s3
|
|
||||||
|
|
||||||
build-esp32c3:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c3'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32c3
|
|
||||||
|
|
||||||
build-esp32c6:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'esp32c6'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32c6
|
|
||||||
|
|
||||||
build-nrf52840:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'nrf52840'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: nrf52840
|
|
||||||
|
|
||||||
build-rp2040:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2040'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: rp2040
|
|
||||||
|
|
||||||
build-rp2350:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'rp2350'}}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.rp2350) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: rp2350
|
|
||||||
|
|
||||||
build-stm32:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'stm32' }}
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.stm32) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: stm32
|
|
||||||
|
|
||||||
build-debian-src:
|
|
||||||
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/build_debian_src.yml
|
|
||||||
with:
|
|
||||||
series: UNRELEASED
|
|
||||||
build_location: local
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
package-pio-deps-native-tft:
|
|
||||||
if: ${{ inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/package_pio_deps.yml
|
|
||||||
with:
|
|
||||||
pio_env: native-tft
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
test-native:
|
|
||||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/test_native.yml
|
|
||||||
|
|
||||||
docker-deb-amd64:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-amd64-tft:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-alp-amd64:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-alp-amd64-tft:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-deb-arm64:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-armv7:
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm/v7
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
gather-artifacts:
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
version,
|
|
||||||
build-esp32,
|
|
||||||
build-esp32s3,
|
|
||||||
build-esp32c3,
|
|
||||||
build-esp32c6,
|
|
||||||
build-nrf52840,
|
|
||||||
build-rp2040,
|
|
||||||
build-rp2350,
|
|
||||||
build-stm32,
|
|
||||||
]
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{github.event.pull_request.head.ref}}
|
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
path: ./
|
|
||||||
pattern: firmware-${{inputs.arch}}-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Move files up
|
|
||||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
|
||||||
|
|
||||||
- name: Repackage in single firmware zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
overwrite: true
|
|
||||||
path: |
|
|
||||||
./firmware-*.bin
|
|
||||||
./firmware-*.uf2
|
|
||||||
./firmware-*.hex
|
|
||||||
./firmware-*-ota.zip
|
|
||||||
./device-*.sh
|
|
||||||
./device-*.bat
|
|
||||||
./littlefs-*.bin
|
|
||||||
./bleota*bin
|
|
||||||
./Meshtastic_nRF52_factory_erase*.uf2
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
name: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Show artifacts
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- name: Repackage in single elfs zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
overwrite: true
|
|
||||||
path: ./*.elf
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: scruplelesswizard/comment-artifact@main
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
with:
|
|
||||||
name: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
description: "Download firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-artifacts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
outputs:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
needs:
|
|
||||||
- version
|
|
||||||
- gather-artifacts
|
|
||||||
- build-debian-src
|
|
||||||
- package-pio-deps-native-tft
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
id: create_release
|
|
||||||
with:
|
|
||||||
draft: true
|
|
||||||
prerelease: true
|
|
||||||
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
|
|
||||||
tag_name: v${{ needs.version.outputs.long }}
|
|
||||||
body: |
|
|
||||||
Autogenerated by github action, developer should edit as required before publishing...
|
|
||||||
|
|
||||||
- name: Download source deb
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/debian-src
|
|
||||||
|
|
||||||
- name: Download `native-tft` pio deps
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/pio-deps-native-tft
|
|
||||||
|
|
||||||
- name: Zip Linux sources
|
|
||||||
working-directory: output
|
|
||||||
run: |
|
|
||||||
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
|
|
||||||
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add Linux sources to GtiHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-firmware:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
needs: [release-artifacts, version]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
name: debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./elfs
|
|
||||||
|
|
||||||
- name: Zip debug elfs
|
|
||||||
run: zip -j -9 -r ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip ./elfs
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add bins and debug elfs to GitHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
publish-firmware:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
needs: [release-firmware, version]
|
|
||||||
env:
|
|
||||||
targets: |-
|
|
||||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./publish
|
|
||||||
|
|
||||||
- name: Publish firmware to meshtastic.github.io
|
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
|
||||||
env:
|
|
||||||
# On event/* branches, use the event name as the destination prefix
|
|
||||||
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
|
|
||||||
with:
|
|
||||||
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
|
|
||||||
external_repository: meshtastic/meshtastic.github.io
|
|
||||||
publish_branch: master
|
|
||||||
publish_dir: ./publish
|
|
||||||
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
|
|
||||||
keep_files: true
|
|
||||||
user_name: github-actions[bot]
|
|
||||||
user_email: github-actions[bot]@users.noreply.github.com
|
|
||||||
commit_message: ${{ needs.version.outputs.long }}
|
|
||||||
enable_jekyll: true
|
|
||||||
395
.github/workflows/build_one_target.yml
vendored
395
.github/workflows/build_one_target.yml
vendored
@@ -1,395 +0,0 @@
|
|||||||
name: Build One Target
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
arch:
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
- native
|
|
||||||
target:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets.
|
|
||||||
|
|
||||||
# find-target:
|
|
||||||
# type: boolean
|
|
||||||
# default: true
|
|
||||||
# description: 'Find the available targets'
|
|
||||||
jobs:
|
|
||||||
find-targets:
|
|
||||||
if: ${{ inputs.target == '' }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
cache: pip
|
|
||||||
- run: pip install -U platformio
|
|
||||||
- name: Generate matrix
|
|
||||||
id: jsonStep
|
|
||||||
run: |
|
|
||||||
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} extra)
|
|
||||||
echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Targets:" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo $TARGETS | sed 's/[][]//g; s/", "/\n- /g; s/"//g; s/^/- /' >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
|
||||||
version:
|
|
||||||
if: ${{ inputs.target != '' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- name: Get release version string
|
|
||||||
run: |
|
|
||||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
|
||||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
|
||||||
id: version
|
|
||||||
env:
|
|
||||||
BUILD_LOCATION: local
|
|
||||||
outputs:
|
|
||||||
long: ${{ steps.version.outputs.long }}
|
|
||||||
deb: ${{ steps.version.outputs.deb }}
|
|
||||||
|
|
||||||
build-arch:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch != 'native' }}
|
|
||||||
needs: [version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ inputs.target }}
|
|
||||||
platform: ${{ inputs.arch }}
|
|
||||||
|
|
||||||
build-debian-src:
|
|
||||||
if: ${{ github.repository == 'meshtastic/firmware' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/build_debian_src.yml
|
|
||||||
with:
|
|
||||||
series: UNRELEASED
|
|
||||||
build_location: local
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
package-pio-deps-native-tft:
|
|
||||||
if: ${{ inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/package_pio_deps.yml
|
|
||||||
with:
|
|
||||||
pio_env: native-tft
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
test-native:
|
|
||||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' && inputs.target != '' }}
|
|
||||||
uses: ./.github/workflows/test_native.yml
|
|
||||||
|
|
||||||
docker-deb-amd64:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-amd64-tft:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-alp-amd64:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-alp-amd64-tft:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-deb-arm64:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-armv7:
|
|
||||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm/v7
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
gather-artifacts:
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [version, build-arch]
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{github.event.pull_request.head.ref}}
|
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
path: ./
|
|
||||||
pattern: firmware-*-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Move files up
|
|
||||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
|
||||||
|
|
||||||
- name: Repackage in single firmware zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
|
|
||||||
overwrite: true
|
|
||||||
path: |
|
|
||||||
./firmware-*.bin
|
|
||||||
./firmware-*.uf2
|
|
||||||
./firmware-*.hex
|
|
||||||
./firmware-*-ota.zip
|
|
||||||
./device-*.sh
|
|
||||||
./device-*.bat
|
|
||||||
./littlefs-*.bin
|
|
||||||
./bleota*bin
|
|
||||||
./Meshtastic_nRF52_factory_erase*.uf2
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-*-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Show artifacts
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- name: Repackage in single elfs zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
overwrite: true
|
|
||||||
path: ./*.elf
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: scruplelesswizard/comment-artifact@main
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
with:
|
|
||||||
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
|
|
||||||
description: "Download firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-artifacts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}}
|
|
||||||
outputs:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
needs:
|
|
||||||
- version
|
|
||||||
- gather-artifacts
|
|
||||||
- build-debian-src
|
|
||||||
- package-pio-deps-native-tft
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
id: create_release
|
|
||||||
with:
|
|
||||||
draft: true
|
|
||||||
prerelease: true
|
|
||||||
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
|
|
||||||
tag_name: v${{ needs.version.outputs.long }}
|
|
||||||
body: |
|
|
||||||
Autogenerated by github action, developer should edit as required before publishing...
|
|
||||||
|
|
||||||
- name: Download source deb
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/debian-src
|
|
||||||
|
|
||||||
- name: Download `native-tft` pio deps
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/pio-deps-native-tft
|
|
||||||
|
|
||||||
- name: Zip Linux sources
|
|
||||||
working-directory: output
|
|
||||||
run: |
|
|
||||||
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
|
|
||||||
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add Linux sources to GtiHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-firmware:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.target != ''}}
|
|
||||||
needs: [release-artifacts, version]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-*-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: debug-elfs-*-${{ needs.version.outputs.long }}.zip
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./elfs
|
|
||||||
|
|
||||||
- name: Zip debug elfs
|
|
||||||
run: zip -j -9 -r ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./elfs
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add bins and debug elfs to GitHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
publish-firmware:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && inputs.target != '' }}
|
|
||||||
needs: [release-firmware, version]
|
|
||||||
env:
|
|
||||||
targets: |-
|
|
||||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./publish
|
|
||||||
|
|
||||||
- name: Publish firmware to meshtastic.github.io
|
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
|
||||||
env:
|
|
||||||
# On event/* branches, use the event name as the destination prefix
|
|
||||||
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
|
|
||||||
with:
|
|
||||||
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
|
|
||||||
external_repository: meshtastic/meshtastic.github.io
|
|
||||||
publish_branch: master
|
|
||||||
publish_dir: ./publish
|
|
||||||
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
|
|
||||||
keep_files: true
|
|
||||||
user_name: github-actions[bot]
|
|
||||||
user_email: github-actions[bot]@users.noreply.github.com
|
|
||||||
commit_message: ${{ needs.version.outputs.long }}
|
|
||||||
enable_jekyll: true
|
|
||||||
8
.github/workflows/daily_packaging.yml
vendored
8
.github/workflows/daily_packaging.yml
vendored
@@ -21,20 +21,18 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker-multiarch:
|
docker-multiarch:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_manifest.yml
|
uses: ./.github/workflows/docker_manifest.yml
|
||||||
with:
|
with:
|
||||||
release_channel: daily
|
release_channel: daily
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
package-ppa:
|
package-ppa:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
series:
|
series:
|
||||||
- jammy # 22.04 LTS
|
- jammy # 22.04
|
||||||
- noble # 24.04 LTS
|
- noble # 24.04
|
||||||
- plucky # 25.04
|
- plucky # 25.04
|
||||||
- questing # 25.10
|
- questing # 25.10
|
||||||
uses: ./.github/workflows/package_ppa.yml
|
uses: ./.github/workflows/package_ppa.yml
|
||||||
@@ -44,7 +42,6 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
package-obs:
|
package-obs:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/package_obs.yml
|
uses: ./.github/workflows/package_obs.yml
|
||||||
with:
|
with:
|
||||||
obs_project: network:Meshtastic:daily
|
obs_project: network:Meshtastic:daily
|
||||||
@@ -52,7 +49,6 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
hook-copr:
|
hook-copr:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/hook_copr.yml
|
uses: ./.github/workflows/hook_copr.yml
|
||||||
with:
|
with:
|
||||||
copr_project: daily
|
copr_project: daily
|
||||||
|
|||||||
35
.github/workflows/main_matrix.yml
vendored
35
.github/workflows/main_matrix.yml
vendored
@@ -3,7 +3,7 @@ concurrency:
|
|||||||
group: ci-${{ github.head_ref || github.run_id }}
|
group: ci-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
on:
|
on:
|
||||||
# # Triggers the workflow on push but only for the main branches
|
# # Triggers the workflow on push but only for the master branch
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
@@ -19,7 +19,6 @@ on:
|
|||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
- event/*
|
- event/*
|
||||||
- self-hosted-testing
|
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "**.md"
|
- "**.md"
|
||||||
#- "**.yml"
|
#- "**.yml"
|
||||||
@@ -28,7 +27,6 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -42,18 +40,14 @@ jobs:
|
|||||||
- rp2350
|
- rp2350
|
||||||
- stm32
|
- stm32
|
||||||
- check
|
- check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-python@v6
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
cache: pip
|
cache: pip
|
||||||
- run: pip install -U platformio
|
- run: pip install -U platformio
|
||||||
- name: Uncomment build epoch
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
|
||||||
- name: Generate matrix
|
- name: Generate matrix
|
||||||
id: jsonStep
|
id: jsonStep
|
||||||
run: |
|
run: |
|
||||||
@@ -76,7 +70,6 @@ jobs:
|
|||||||
check: ${{ steps.jsonStep.outputs.check }}
|
check: ${{ steps.jsonStep.outputs.check }}
|
||||||
|
|
||||||
version:
|
version:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
@@ -98,7 +91,7 @@ jobs:
|
|||||||
matrix: ${{ fromJson(needs.setup.outputs.check) }}
|
matrix: ${{ fromJson(needs.setup.outputs.check) }}
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- name: Build base
|
- name: Build base
|
||||||
@@ -211,11 +204,10 @@ jobs:
|
|||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
test-native:
|
test-native:
|
||||||
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }}
|
if: ${{ !contains(github.ref_name, 'event/') }}
|
||||||
uses: ./.github/workflows/test_native.yml
|
uses: ./.github/workflows/test_native.yml
|
||||||
|
|
||||||
docker-deb-amd64:
|
docker-deb-amd64:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: debian
|
distro: debian
|
||||||
@@ -224,7 +216,6 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
|
|
||||||
docker-deb-amd64-tft:
|
docker-deb-amd64-tft:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: debian
|
distro: debian
|
||||||
@@ -234,7 +225,6 @@ jobs:
|
|||||||
pio_env: native-tft
|
pio_env: native-tft
|
||||||
|
|
||||||
docker-alp-amd64:
|
docker-alp-amd64:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: alpine
|
distro: alpine
|
||||||
@@ -243,7 +233,6 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
|
|
||||||
docker-alp-amd64-tft:
|
docker-alp-amd64-tft:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: alpine
|
distro: alpine
|
||||||
@@ -253,7 +242,6 @@ jobs:
|
|||||||
pio_env: native-tft
|
pio_env: native-tft
|
||||||
|
|
||||||
docker-deb-arm64:
|
docker-deb-arm64:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: debian
|
distro: debian
|
||||||
@@ -262,7 +250,6 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
|
|
||||||
docker-deb-armv7:
|
docker-deb-armv7:
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
uses: ./.github/workflows/docker_build.yml
|
||||||
with:
|
with:
|
||||||
distro: debian
|
distro: debian
|
||||||
@@ -271,8 +258,6 @@ jobs:
|
|||||||
push: false
|
push: false
|
||||||
|
|
||||||
gather-artifacts:
|
gather-artifacts:
|
||||||
# trunk-ignore(checkov/CKV2_GHA_1)
|
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -372,7 +357,7 @@ jobs:
|
|||||||
|
|
||||||
release-artifacts:
|
release-artifacts:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
outputs:
|
outputs:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
needs:
|
needs:
|
||||||
@@ -385,7 +370,7 @@ jobs:
|
|||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
@@ -447,14 +432,14 @@ jobs:
|
|||||||
- rp2350
|
- rp2350
|
||||||
- stm32
|
- stm32
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware'}}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
needs: [release-artifacts, version]
|
needs: [release-artifacts, version]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
@@ -509,7 +494,7 @@ jobs:
|
|||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
|
|||||||
508
.github/workflows/merge_queue.yml
vendored
508
.github/workflows/merge_queue.yml
vendored
@@ -1,508 +0,0 @@
|
|||||||
name: Merge Queue
|
|
||||||
# Not sure how concurrency works in merge_queue, removing for now.
|
|
||||||
# concurrency:
|
|
||||||
# group: merge-queue-${{ github.head_ref || github.run_id }}
|
|
||||||
# cancel-in-progress: true
|
|
||||||
on:
|
|
||||||
# Merge group is a special trigger that is used to trigger the workflow when a merge group is created.
|
|
||||||
merge_group:
|
|
||||||
|
|
||||||
env:
|
|
||||||
FAIL_FAST_PER_ARCH: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
setup:
|
|
||||||
strategy:
|
|
||||||
fail-fast: true
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
- check
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
cache: pip
|
|
||||||
- run: pip install -U platformio
|
|
||||||
- name: Generate matrix
|
|
||||||
id: jsonStep
|
|
||||||
run: |
|
|
||||||
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
|
|
||||||
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
|
|
||||||
else
|
|
||||||
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} pr)
|
|
||||||
fi
|
|
||||||
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF Targets: $TARGETS"
|
|
||||||
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
|
|
||||||
outputs:
|
|
||||||
esp32: ${{ steps.jsonStep.outputs.esp32 }}
|
|
||||||
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
|
|
||||||
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
|
|
||||||
esp32c6: ${{ steps.jsonStep.outputs.esp32c6 }}
|
|
||||||
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
|
|
||||||
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
|
|
||||||
rp2350: ${{ steps.jsonStep.outputs.rp2350 }}
|
|
||||||
stm32: ${{ steps.jsonStep.outputs.stm32 }}
|
|
||||||
check: ${{ steps.jsonStep.outputs.check }}
|
|
||||||
|
|
||||||
version:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- name: Get release version string
|
|
||||||
run: |
|
|
||||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
|
||||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
|
||||||
id: version
|
|
||||||
env:
|
|
||||||
BUILD_LOCATION: local
|
|
||||||
outputs:
|
|
||||||
long: ${{ steps.version.outputs.long }}
|
|
||||||
deb: ${{ steps.version.outputs.deb }}
|
|
||||||
|
|
||||||
check:
|
|
||||||
needs: setup
|
|
||||||
strategy:
|
|
||||||
fail-fast: true
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.check) }}
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
- name: Build base
|
|
||||||
id: base
|
|
||||||
uses: ./.github/actions/setup-base
|
|
||||||
- name: Check ${{ matrix.board }}
|
|
||||||
run: bin/check-all.sh ${{ matrix.board }}
|
|
||||||
|
|
||||||
build-esp32:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32
|
|
||||||
|
|
||||||
build-esp32s3:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32s3
|
|
||||||
|
|
||||||
build-esp32c3:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32c3
|
|
||||||
|
|
||||||
build-esp32c6:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.esp32c6) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: esp32c6
|
|
||||||
|
|
||||||
build-nrf52840:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: nrf52840
|
|
||||||
|
|
||||||
build-rp2040:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: rp2040
|
|
||||||
|
|
||||||
build-rp2350:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.rp2350) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: rp2350
|
|
||||||
|
|
||||||
build-stm32:
|
|
||||||
needs: [setup, version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: ${{ vars.FAIL_FAST_PER_ARCH == true }}
|
|
||||||
matrix: ${{ fromJson(needs.setup.outputs.stm32) }}
|
|
||||||
uses: ./.github/workflows/build_firmware.yml
|
|
||||||
with:
|
|
||||||
version: ${{ needs.version.outputs.long }}
|
|
||||||
pio_env: ${{ matrix.board }}
|
|
||||||
platform: stm32
|
|
||||||
|
|
||||||
build-debian-src:
|
|
||||||
if: github.repository == 'meshtastic/firmware'
|
|
||||||
uses: ./.github/workflows/build_debian_src.yml
|
|
||||||
with:
|
|
||||||
series: UNRELEASED
|
|
||||||
build_location: local
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
package-pio-deps-native-tft:
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
uses: ./.github/workflows/package_pio_deps.yml
|
|
||||||
with:
|
|
||||||
pio_env: native-tft
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
test-native:
|
|
||||||
if: ${{ !contains(github.ref_name, 'event/') }}
|
|
||||||
uses: ./.github/workflows/test_native.yml
|
|
||||||
|
|
||||||
docker-deb-amd64:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-amd64-tft:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-alp-amd64:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-alp-amd64-tft:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: alpine
|
|
||||||
platform: linux/amd64
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
push: false
|
|
||||||
pio_env: native-tft
|
|
||||||
|
|
||||||
docker-deb-arm64:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm64
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
docker-deb-armv7:
|
|
||||||
uses: ./.github/workflows/docker_build.yml
|
|
||||||
with:
|
|
||||||
distro: debian
|
|
||||||
platform: linux/arm/v7
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
push: false
|
|
||||||
|
|
||||||
gather-artifacts:
|
|
||||||
# trunk-ignore(checkov/CKV2_GHA_1)
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
version,
|
|
||||||
build-esp32,
|
|
||||||
build-esp32s3,
|
|
||||||
build-esp32c3,
|
|
||||||
build-esp32c6,
|
|
||||||
build-nrf52840,
|
|
||||||
build-rp2040,
|
|
||||||
build-rp2350,
|
|
||||||
build-stm32,
|
|
||||||
]
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: ${{github.event.pull_request.head.ref}}
|
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
path: ./
|
|
||||||
pattern: firmware-${{matrix.arch}}-*
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Move files up
|
|
||||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
|
||||||
|
|
||||||
- name: Repackage in single firmware zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
overwrite: true
|
|
||||||
path: |
|
|
||||||
./firmware-*.bin
|
|
||||||
./firmware-*.uf2
|
|
||||||
./firmware-*.hex
|
|
||||||
./firmware-*-ota.zip
|
|
||||||
./device-*.sh
|
|
||||||
./device-*.bat
|
|
||||||
./littlefs-*.bin
|
|
||||||
./bleota*bin
|
|
||||||
./Meshtastic_nRF52_factory_erase*.uf2
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Show artifacts
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- name: Repackage in single elfs zip
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
overwrite: true
|
|
||||||
path: ./*.elf
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- uses: scruplelesswizard/comment-artifact@main
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
with:
|
|
||||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
description: "Download firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-artifacts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
outputs:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
needs:
|
|
||||||
- version
|
|
||||||
- gather-artifacts
|
|
||||||
- build-debian-src
|
|
||||||
- package-pio-deps-native-tft
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
id: create_release
|
|
||||||
with:
|
|
||||||
draft: true
|
|
||||||
prerelease: true
|
|
||||||
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
|
|
||||||
tag_name: v${{ needs.version.outputs.long }}
|
|
||||||
body: |
|
|
||||||
Autogenerated by github action, developer should edit as required before publishing...
|
|
||||||
|
|
||||||
- name: Download source deb
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/debian-src
|
|
||||||
|
|
||||||
- name: Download `native-tft` pio deps
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output/pio-deps-native-tft
|
|
||||||
|
|
||||||
- name: Zip Linux sources
|
|
||||||
working-directory: output
|
|
||||||
run: |
|
|
||||||
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
|
|
||||||
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add Linux sources to GtiHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-firmware:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
arch:
|
|
||||||
- esp32
|
|
||||||
- esp32s3
|
|
||||||
- esp32c3
|
|
||||||
- esp32c6
|
|
||||||
- nrf52840
|
|
||||||
- rp2040
|
|
||||||
- rp2350
|
|
||||||
- stm32
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
needs: [release-artifacts, version]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./output
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Device scripts permissions
|
|
||||||
run: |
|
|
||||||
chmod +x ./output/device-install.sh
|
|
||||||
chmod +x ./output/device-update.sh
|
|
||||||
|
|
||||||
- name: Zip firmware
|
|
||||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./elfs
|
|
||||||
|
|
||||||
- name: Zip debug elfs
|
|
||||||
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./elfs
|
|
||||||
|
|
||||||
# For diagnostics
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -lR
|
|
||||||
|
|
||||||
- name: Add bins and debug elfs to GitHub Release
|
|
||||||
# Only run when targeting master branch with workflow_dispatch
|
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
publish-firmware:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
needs: [release-firmware, version]
|
|
||||||
env:
|
|
||||||
targets: |-
|
|
||||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
|
||||||
merge-multiple: true
|
|
||||||
path: ./publish
|
|
||||||
|
|
||||||
- name: Publish firmware to meshtastic.github.io
|
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
|
||||||
env:
|
|
||||||
# On event/* branches, use the event name as the destination prefix
|
|
||||||
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
|
|
||||||
with:
|
|
||||||
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
|
|
||||||
external_repository: meshtastic/meshtastic.github.io
|
|
||||||
publish_branch: master
|
|
||||||
publish_dir: ./publish
|
|
||||||
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
|
|
||||||
keep_files: true
|
|
||||||
user_name: github-actions[bot]
|
|
||||||
user_email: github-actions[bot]@users.noreply.github.com
|
|
||||||
commit_message: ${{ needs.version.outputs.long }}
|
|
||||||
enable_jekyll: true
|
|
||||||
2
.github/workflows/package_pio_deps.yml
vendored
2
.github/workflows/package_pio_deps.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
|||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/pr_enforce_labels.yml
vendored
4
.github/workflows/pr_enforce_labels.yml
vendored
@@ -10,10 +10,10 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-label:
|
check-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Check for PR labels
|
- name: Check for PR labels
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const labels = context.payload.pull_request.labels.map(label => label.name);
|
const labels = context.payload.pull_request.labels.map(label => label.name);
|
||||||
|
|||||||
2
.github/workflows/pr_tests.yml
vendored
2
.github/workflows/pr_tests.yml
vendored
@@ -177,7 +177,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Comment test results on PR
|
- name: Comment test results on PR
|
||||||
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|||||||
8
.github/workflows/release_channels.yml
vendored
8
.github/workflows/release_channels.yml
vendored
@@ -21,10 +21,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
series:
|
series:
|
||||||
- jammy # 22.04 LTS
|
- jammy # 22.04
|
||||||
- noble # 24.04 LTS
|
- noble # 24.04
|
||||||
- plucky # 25.04
|
- plucky # 25.04
|
||||||
- questing # 25.10
|
# - questing # 25.10
|
||||||
uses: ./.github/workflows/package_ppa.yml
|
uses: ./.github/workflows/package_ppa.yml
|
||||||
with:
|
with:
|
||||||
ppa_repo: |-
|
ppa_repo: |-
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/stale_bot.yml
vendored
2
.github/workflows/stale_bot.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Stale PR+Issues
|
- name: Stale PR+Issues
|
||||||
uses: actions/stale@v10.0.0
|
uses: actions/stale@v9.1.0
|
||||||
with:
|
with:
|
||||||
days-before-stale: 45
|
days-before-stale: 45
|
||||||
exempt-issue-labels: pinned,3.0
|
exempt-issue-labels: pinned,3.0
|
||||||
|
|||||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
|||||||
pio upgrade
|
pio upgrade
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/trunk_format_pr.yml
vendored
2
.github/workflows/trunk_format_pr.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
git push
|
git push
|
||||||
|
|
||||||
- name: Comment on PR
|
- name: Comment on PR
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
script: |
|
script: |
|
||||||
|
|||||||
@@ -4,28 +4,28 @@ cli:
|
|||||||
plugins:
|
plugins:
|
||||||
sources:
|
sources:
|
||||||
- id: trunk
|
- id: trunk
|
||||||
ref: v1.7.2
|
ref: v1.7.1
|
||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.471
|
- checkov@3.2.461
|
||||||
- renovate@41.115.6
|
- renovate@41.74.0
|
||||||
- prettier@3.6.2
|
- prettier@3.6.2
|
||||||
- trufflehog@3.90.6
|
- trufflehog@3.90.5
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.8.6
|
- bandit@1.8.6
|
||||||
- trivy@0.66.0
|
- trivy@0.64.1
|
||||||
- taplo@0.10.0
|
- taplo@0.9.3
|
||||||
- ruff@0.13.0
|
- ruff@0.12.7
|
||||||
- isort@6.0.1
|
- isort@6.0.1
|
||||||
- markdownlint@0.45.0
|
- markdownlint@0.45.0
|
||||||
- oxipng@9.1.5
|
- oxipng@9.1.5
|
||||||
- svgo@4.0.0
|
- svgo@4.0.0
|
||||||
- actionlint@1.7.7
|
- actionlint@1.7.7
|
||||||
- flake8@7.3.0
|
- flake8@7.3.0
|
||||||
- hadolint@2.13.1
|
- hadolint@2.12.1-beta
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.11.0
|
- shellcheck@0.10.0
|
||||||
- black@25.1.0
|
- black@25.1.0
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.28.0
|
- gitleaks@8.28.0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
[portduino_base]
|
[portduino_base]
|
||||||
platform =
|
platform =
|
||||||
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
||||||
https://github.com/meshtastic/platform-native/archive/c490bcd019e0658404088a61b96e653c9da22c45.zip
|
https://github.com/meshtastic/platform-native/archive/37d986499ce24511952d7146db72d667c6bdaff7.zip
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
@@ -31,8 +31,6 @@ lib_deps =
|
|||||||
https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip
|
https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip
|
||||||
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
||||||
adafruit/Adafruit seesaw Library@1.7.9
|
adafruit/Adafruit seesaw Library@1.7.9
|
||||||
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
|
||||||
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
|
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ lib_deps =
|
|||||||
${radiolib_base.lib_deps}
|
${radiolib_base.lib_deps}
|
||||||
|
|
||||||
# renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main
|
# renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main
|
||||||
https://github.com/caveman99/Crypto/archive/1aa30eb536bd52a576fde6dfa393bf7349cf102d.zip
|
https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
OneButton
|
OneButton
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||||
|
|
||||||
export PIP_BREAK_SYSTEM_PACKAGES=1
|
export PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
|
|
||||||
if (echo $2 | grep -q "esp32"); then
|
if (echo $2 | grep -q "esp32"); then
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ SET "DEBUG=0"
|
|||||||
SET "PYTHON="
|
SET "PYTHON="
|
||||||
SET "TFT_BUILD=0"
|
SET "TFT_BUILD=0"
|
||||||
SET "BIGDB8=0"
|
SET "BIGDB8=0"
|
||||||
SET "MUIDB8=0"
|
|
||||||
SET "BIGDB16=0"
|
SET "BIGDB16=0"
|
||||||
SET "ESPTOOL_BAUD=115200"
|
SET "ESPTOOL_BAUD=115200"
|
||||||
SET "ESPTOOL_CMD="
|
SET "ESPTOOL_CMD="
|
||||||
@@ -15,12 +14,11 @@ SET "LOGCOUNTER=0"
|
|||||||
SET "BPS_RESET=0"
|
SET "BPS_RESET=0"
|
||||||
|
|
||||||
@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable.
|
@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable.
|
||||||
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone t-eth-elite tlora-pager mesh-tab dreamcatcher ESP32-S3-Pico seeed-sensecap-indicator heltec_capsule_sensor_v3 vision-master icarus tracksenger elecrow-adv"
|
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone"
|
||||||
SET "C3=esp32c3"
|
SET "C3=esp32c3"
|
||||||
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
|
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
|
||||||
SET "BIGDB_8MB=crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
|
SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
|
||||||
SET "MUIDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator"
|
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite t-watch-s3"
|
||||||
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite tlora-pager t-watch-s3 elecrow-adv"
|
|
||||||
|
|
||||||
GOTO getopts
|
GOTO getopts
|
||||||
:help
|
:help
|
||||||
@@ -102,6 +100,7 @@ IF NOT "!FILENAME:update=!"=="!FILENAME!" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
:skip-filename
|
:skip-filename
|
||||||
|
SET "ESPTOOL_BAUD=1200"
|
||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
||||||
IF NOT "__%PYTHON%__"=="____" (
|
IF NOT "__%PYTHON%__"=="____" (
|
||||||
@@ -121,10 +120,11 @@ IF NOT "__%PYTHON%__"=="____" (
|
|||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||||
!ESPTOOL_CMD! >nul 2>&1
|
!ESPTOOL_CMD! >nul 2>&1
|
||||||
IF %ERRORLEVEL% EQU 9009 (
|
IF %ERRORLEVEL% GEQ 2 (
|
||||||
@REM 9009 = command not found on Windows
|
@REM esptool exits with code 1 if help is displayed.
|
||||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
|
GOTO eof
|
||||||
)
|
)
|
||||||
IF %DEBUG% EQU 1 (
|
IF %DEBUG% EQU 1 (
|
||||||
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
||||||
@@ -142,7 +142,7 @@ CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
|||||||
|
|
||||||
IF %BPS_RESET% EQU 1 (
|
IF %BPS_RESET% EQU 1 (
|
||||||
@REM Attempt to change mode via 1200bps Reset.
|
@REM Attempt to change mode via 1200bps Reset.
|
||||||
CALL :RUN_ESPTOOL 1200 --after no_reset read_flash_status
|
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! --after no_reset read_flash_status
|
||||||
GOTO eof
|
GOTO eof
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -164,15 +164,6 @@ FOR %%a IN (%BIGDB_8MB%) DO (
|
|||||||
)
|
)
|
||||||
:end_loop_bigdb_8mb
|
:end_loop_bigdb_8mb
|
||||||
|
|
||||||
FOR %%a IN (%MUIDB_8MB%) DO (
|
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
|
||||||
@REM We are working with any of %MUIDB_8MB%.
|
|
||||||
SET "MUIDB8=1"
|
|
||||||
GOTO end_loop_muidb_8mb
|
|
||||||
)
|
|
||||||
)
|
|
||||||
:end_loop_muidb_8mb
|
|
||||||
|
|
||||||
FOR %%a IN (%BIGDB_16MB%) DO (
|
FOR %%a IN (%BIGDB_16MB%) DO (
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||||
@REM We are working with any of %BIGDB_16MB%.
|
@REM We are working with any of %BIGDB_16MB%.
|
||||||
@@ -183,7 +174,6 @@ FOR %%a IN (%BIGDB_16MB%) DO (
|
|||||||
:end_loop_bigdb_16mb
|
:end_loop_bigdb_16mb
|
||||||
|
|
||||||
IF %BIGDB8% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 8mb partition selected."
|
IF %BIGDB8% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 8mb partition selected."
|
||||||
IF %MUIDB8% EQU 1 CALL :LOG_MESSAGE INFO "MUIDB 8mb partition selected."
|
|
||||||
IF %BIGDB16% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 16mb partition selected."
|
IF %BIGDB16% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 16mb partition selected."
|
||||||
|
|
||||||
@REM Extract BASENAME from %FILENAME% for later use.
|
@REM Extract BASENAME from %FILENAME% for later use.
|
||||||
@@ -228,12 +218,6 @@ IF %BIGDB8% EQU 1 (
|
|||||||
SET "SPIFFS_OFFSET=0x670000"
|
SET "SPIFFS_OFFSET=0x670000"
|
||||||
)
|
)
|
||||||
|
|
||||||
@REM Offsets for MUIDB 8mb.
|
|
||||||
IF %MUIDB8% EQU 1 (
|
|
||||||
SET "OTA_OFFSET=0x5D0000"
|
|
||||||
SET "SPIFFS_OFFSET=0x670000"
|
|
||||||
)
|
|
||||||
|
|
||||||
@REM Offsets for BigDB 16mb.
|
@REM Offsets for BigDB 16mb.
|
||||||
IF %BIGDB16% EQU 1 (
|
IF %BIGDB16% EQU 1 (
|
||||||
SET "OTA_OFFSET=0x650000"
|
SET "OTA_OFFSET=0x650000"
|
||||||
|
|||||||
@@ -1,47 +1,42 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
|
|
||||||
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
||||||
BPS_RESET=false
|
BPS_RESET=false
|
||||||
TFT_BUILD=false
|
TFT_BUILD=false
|
||||||
MCU=""
|
MCU=""
|
||||||
|
|
||||||
# Constants
|
|
||||||
RESET_BAUD=1200
|
|
||||||
FIRMWARE_OFFSET=0x00
|
|
||||||
|
|
||||||
# Variant groups
|
# Variant groups
|
||||||
BIGDB_8MB=(
|
BIGDB_8MB=(
|
||||||
"crowpanel-esp32s3"
|
"picomputer-s3"
|
||||||
"heltec_capsule_sensor_v3"
|
"unphone"
|
||||||
"heltec-v3"
|
"seeed-sensecap-indicator"
|
||||||
"heltec-vision-master-e213"
|
"crowpanel-esp32s3"
|
||||||
"heltec-vision-master-e290"
|
"heltec_capsule_sensor_v3"
|
||||||
"heltec-vision-master-t190"
|
"heltec-v3"
|
||||||
"heltec-wireless-paper"
|
"heltec-vision-master-e213"
|
||||||
"heltec-wireless-tracker"
|
"heltec-vision-master-e290"
|
||||||
"heltec-wsl-v3"
|
"heltec-vision-master-t190"
|
||||||
"icarus"
|
"heltec-wireless-paper"
|
||||||
"seeed-xiao-s3"
|
"heltec-wireless-tracker"
|
||||||
"tbeam-s3-core"
|
"heltec-wsl-v3"
|
||||||
"tracksenger"
|
"icarus"
|
||||||
)
|
"seeed-xiao-s3"
|
||||||
MUIDB_8MB=(
|
"tbeam-s3-core"
|
||||||
"picomputer-s3"
|
"tracksenger"
|
||||||
"unphone"
|
|
||||||
"seeed-sensecap-indicator"
|
|
||||||
)
|
)
|
||||||
BIGDB_16MB=(
|
BIGDB_16MB=(
|
||||||
"t-deck"
|
"t-deck"
|
||||||
"mesh-tab"
|
"mesh-tab"
|
||||||
"t-energy-s3"
|
"t-energy-s3"
|
||||||
"dreamcatcher"
|
"dreamcatcher"
|
||||||
"ESP32-S3-Pico"
|
"ESP32-S3-Pico"
|
||||||
"m5stack-cores3"
|
"m5stack-cores3"
|
||||||
"station-g2"
|
"station-g2"
|
||||||
"t-eth-elite"
|
"t-eth-elite"
|
||||||
"tlora-pager"
|
|
||||||
"t-watch-s3"
|
"t-watch-s3"
|
||||||
"elecrow-adv"
|
"elecrow-adv-35-tft"
|
||||||
|
"elecrow-adv-24-28-tft"
|
||||||
|
"elecrow-adv1-43-50-70-tft"
|
||||||
)
|
)
|
||||||
S3_VARIANTS=(
|
S3_VARIANTS=(
|
||||||
"s3"
|
"s3"
|
||||||
@@ -52,7 +47,6 @@ S3_VARIANTS=(
|
|||||||
"station-g2"
|
"station-g2"
|
||||||
"unphone"
|
"unphone"
|
||||||
"t-eth-elite"
|
"t-eth-elite"
|
||||||
"tlora-pager"
|
|
||||||
"mesh-tab"
|
"mesh-tab"
|
||||||
"dreamcatcher"
|
"dreamcatcher"
|
||||||
"ESP32-S3-Pico"
|
"ESP32-S3-Pico"
|
||||||
@@ -112,8 +106,8 @@ while [ $# -gt 0 ]; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--1200bps-reset)
|
--1200bps-reset)
|
||||||
BPS_RESET=true
|
BPS_RESET=true
|
||||||
;;
|
;;
|
||||||
--) # Stop parsing options
|
--) # Stop parsing options
|
||||||
shift
|
shift
|
||||||
break
|
break
|
||||||
@@ -127,7 +121,7 @@ while [ $# -gt 0 ]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [[ $BPS_RESET == true ]]; then
|
if [[ $BPS_RESET == true ]]; then
|
||||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
$ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -164,13 +158,6 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
for variant in "${MUIDB_8MB[@]}"; do
|
|
||||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
|
||||||
OFFSET=0x670000
|
|
||||||
OTA_OFFSET=0x5D0000
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# littlefs* offset for BigDB 16mb and OTA OFFSET.
|
# littlefs* offset for BigDB 16mb and OTA OFFSET.
|
||||||
for variant in "${BIGDB_16MB[@]}"; do
|
for variant in "${BIGDB_16MB[@]}"; do
|
||||||
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
if [ -z "${FILENAME##*"$variant"*}" ]; then
|
||||||
@@ -214,8 +201,8 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||||
$ESPTOOL_CMD erase-flash
|
$ESPTOOL_CMD erase_flash
|
||||||
$ESPTOOL_CMD write-flash $FIRMWARE_OFFSET "${FILENAME}"
|
$ESPTOOL_CMD write_flash 0x00 "${FILENAME}"
|
||||||
echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}"
|
echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}"
|
||||||
$ESPTOOL_CMD write_flash $OTA_OFFSET "${OTAFILE}"
|
$ESPTOOL_CMD write_flash $OTA_OFFSET "${OTAFILE}"
|
||||||
echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}"
|
echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}"
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ SET "SCRIPT_NAME=%~nx0"
|
|||||||
SET "DEBUG=0"
|
SET "DEBUG=0"
|
||||||
SET "PYTHON="
|
SET "PYTHON="
|
||||||
SET "ESPTOOL_BAUD=115200"
|
SET "ESPTOOL_BAUD=115200"
|
||||||
SET "RESET_BAUD=1200"
|
|
||||||
SET "UPDATE_OFFSET=0x10000"
|
|
||||||
SET "ESPTOOL_CMD="
|
SET "ESPTOOL_CMD="
|
||||||
SET "LOGCOUNTER=0"
|
SET "LOGCOUNTER=0"
|
||||||
SET "CHANGE_MODE=0"
|
SET "CHANGE_MODE=0"
|
||||||
@@ -87,13 +85,14 @@ IF "!FILENAME:update=!"=="!FILENAME!" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
:skip-filename
|
:skip-filename
|
||||||
|
SET "ESPTOOL_BAUD=1200"
|
||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..."
|
||||||
IF NOT "__%PYTHON%__"=="____" (
|
IF NOT "__%PYTHON%__"=="____" (
|
||||||
SET "ESPTOOL_CMD=""!PYTHON!"" -m esptool"
|
SET "ESPTOOL_CMD=!PYTHON! -m esptool"
|
||||||
CALL :LOG_MESSAGE DEBUG "Python interpreter supplied."
|
CALL :LOG_MESSAGE DEBUG "Python interpreter supplied."
|
||||||
) ELSE (
|
) ELSE (
|
||||||
CALL :LOG_MESSAGE DEBUG "Python interpreter NOT supplied. Looking for esptool..."
|
CALL :LOG_MESSAGE DEBUG "Python interpreter NOT supplied. Looking for esptool...
|
||||||
WHERE esptool >nul 2>&1
|
WHERE esptool >nul 2>&1
|
||||||
IF %ERRORLEVEL% EQU 0 (
|
IF %ERRORLEVEL% EQU 0 (
|
||||||
@REM WHERE exits with code 0 if esptool is found.
|
@REM WHERE exits with code 0 if esptool is found.
|
||||||
@@ -106,11 +105,11 @@ IF NOT "__%PYTHON%__"=="____" (
|
|||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||||
!ESPTOOL_CMD! >nul 2>&1
|
!ESPTOOL_CMD! >nul 2>&1
|
||||||
CALL :LOG_MESSAGE DEBUG "esptool exit code: %ERRORLEVEL%"
|
IF %ERRORLEVEL% GEQ 2 (
|
||||||
IF %ERRORLEVEL% EQU 9009 (
|
@REM esptool exits with code 1 if help is displayed.
|
||||||
@REM 9009 = command not found on Windows
|
|
||||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
|
GOTO eof
|
||||||
)
|
)
|
||||||
IF %DEBUG% EQU 1 (
|
IF %DEBUG% EQU 1 (
|
||||||
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps."
|
||||||
@@ -128,13 +127,13 @@ CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
|||||||
|
|
||||||
IF %CHANGE_MODE% EQU 1 (
|
IF %CHANGE_MODE% EQU 1 (
|
||||||
@REM Attempt to change mode via 1200bps Reset.
|
@REM Attempt to change mode via 1200bps Reset.
|
||||||
CALL :RUN_ESPTOOL !RESET_BAUD! --after no_reset read_flash_status
|
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! --after no_reset read_flash_status
|
||||||
GOTO eof
|
GOTO eof
|
||||||
)
|
)
|
||||||
|
|
||||||
@REM Flashing operations.
|
@REM Flashing operations.
|
||||||
CALL :LOG_MESSAGE INFO "Trying to flash update "!FILENAME!" at OFFSET !UPDATE_OFFSET!..."
|
CALL :LOG_MESSAGE INFO "Trying to flash update "!FILENAME!" at OFFSET 0x10000..."
|
||||||
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write-flash !UPDATE_OFFSET! "!FILENAME!" || GOTO eof
|
CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write_flash 0x10000 "!FILENAME!" || GOTO eof
|
||||||
|
|
||||||
CALL :LOG_MESSAGE INFO "Script complete!."
|
CALL :LOG_MESSAGE INFO "Script complete!."
|
||||||
|
|
||||||
@@ -146,9 +145,9 @@ EXIT /B %ERRORLEVEL%
|
|||||||
:RUN_ESPTOOL
|
:RUN_ESPTOOL
|
||||||
@REM Subroutine used to run ESPTOOL_CMD with arguments.
|
@REM Subroutine used to run ESPTOOL_CMD with arguments.
|
||||||
@REM Also handles %ERRORLEVEL%.
|
@REM Also handles %ERRORLEVEL%.
|
||||||
@REM CALL :RUN_ESPTOOL [Baud] [erase-flash|write-flash] [OFFSET] [Filename]
|
@REM CALL :RUN_ESPTOOL [Baud] [erase_flash|write_flash] [OFFSET] [Filename]
|
||||||
@REM.
|
@REM.
|
||||||
@REM Example:: CALL :RUN_ESPTOOL 115200 write-flash 0x10000 "firmwarefile.bin"
|
@REM Example:: CALL :RUN_ESPTOOL 115200 write_flash 0x10000 "firmwarefile.bin"
|
||||||
IF %DEBUG% EQU 1 CALL :LOG_MESSAGE DEBUG "About to run command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4"
|
IF %DEBUG% EQU 1 CALL :LOG_MESSAGE DEBUG "About to run command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4"
|
||||||
CALL :RESET_ERROR
|
CALL :RESET_ERROR
|
||||||
!ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4
|
!ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
|
|
||||||
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
|
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
|
||||||
CHANGE_MODE=false
|
CHANGE_MODE=false
|
||||||
|
|
||||||
# Constants
|
|
||||||
FLASH_BAUD=115200
|
|
||||||
RESET_BAUD=1200
|
|
||||||
UPDATE_OFFSET=0x10000
|
|
||||||
|
|
||||||
# Determine the correct esptool command to use
|
# Determine the correct esptool command to use
|
||||||
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
||||||
ESPTOOL_CMD="$PYTHON -m esptool"
|
ESPTOOL_CMD="$PYTHON -m esptool"
|
||||||
@@ -69,7 +64,7 @@ done
|
|||||||
shift "$((OPTIND-1))"
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
if [ "$CHANGE_MODE" = true ]; then
|
if [ "$CHANGE_MODE" = true ]; then
|
||||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
$ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -80,7 +75,7 @@ fi
|
|||||||
|
|
||||||
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
|
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
|
||||||
echo "Trying to flash update ${FILENAME}"
|
echo "Trying to flash update ${FILENAME}"
|
||||||
$ESPTOOL_CMD --baud $FLASH_BAUD write-flash $UPDATE_OFFSET "${FILENAME}"
|
$ESPTOOL_CMD --baud 115200 write_flash 0x10000 "${FILENAME}"
|
||||||
else
|
else
|
||||||
show_help
|
show_help
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
|
|||||||
@@ -87,18 +87,6 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
<release version="2.7.10" date="2025-09-18">
|
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.10</url>
|
|
||||||
</release>
|
|
||||||
<release version="2.7.9" date="2025-09-03">
|
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.9</url>
|
|
||||||
</release>
|
|
||||||
<release version="2.7.8" date="2025-08-30">
|
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.8</url>
|
|
||||||
</release>
|
|
||||||
<release version="2.7.7" date="2025-08-28">
|
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.7</url>
|
|
||||||
</release>
|
|
||||||
<release version="2.7.6" date="2025-08-12">
|
<release version="2.7.6" date="2025-08-12">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.6</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.6</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ from os.path import join
|
|||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from readprops import readProps
|
from readprops import readProps
|
||||||
|
|
||||||
@@ -127,16 +125,11 @@ for pref in userPrefs:
|
|||||||
pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "")
|
pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "")
|
||||||
|
|
||||||
# General options that are passed to the C and C++ compilers
|
# General options that are passed to the C and C++ compilers
|
||||||
# Calculate unix epoch for current day (midnight)
|
|
||||||
current_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
||||||
build_epoch = int(current_date.timestamp())
|
|
||||||
|
|
||||||
flags = [
|
flags = [
|
||||||
"-DAPP_VERSION=" + verObj["long"],
|
"-DAPP_VERSION=" + verObj["long"],
|
||||||
"-DAPP_VERSION_SHORT=" + verObj["short"],
|
"-DAPP_VERSION_SHORT=" + verObj["short"],
|
||||||
"-DAPP_ENV=" + env.get("PIOENV"),
|
"-DAPP_ENV=" + env.get("PIOENV"),
|
||||||
"-DAPP_REPO=" + repo_owner,
|
"-DAPP_REPO=" + repo_owner,
|
||||||
"-DBUILD_EPOCH=" + str(build_epoch),
|
|
||||||
] + pref_flags
|
] + pref_flags
|
||||||
|
|
||||||
print ("Using flags:")
|
print ("Using flags:")
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"build": {
|
|
||||||
"arduino": {
|
|
||||||
"ldscript": "nrf52840_s140_v6.ld"
|
|
||||||
},
|
|
||||||
"core": "nRF5",
|
|
||||||
"cpu": "cortex-m4",
|
|
||||||
"extra_flags": "-DNRF52840_XXAA",
|
|
||||||
"f_cpu": "64000000L",
|
|
||||||
"hwids": [
|
|
||||||
["0x239A", "0x4405"],
|
|
||||||
["0x239A", "0x0029"],
|
|
||||||
["0x239A", "0x002A"],
|
|
||||||
["0x239A", "0x0071"]
|
|
||||||
],
|
|
||||||
"usb_product": "HT-n5262",
|
|
||||||
"mcu": "nrf52840",
|
|
||||||
"variant": "heltec_mesh_solar",
|
|
||||||
"variants_dir": "variants",
|
|
||||||
"bsp": {
|
|
||||||
"name": "adafruit"
|
|
||||||
},
|
|
||||||
"softdevice": {
|
|
||||||
"sd_flags": "-DS140",
|
|
||||||
"sd_name": "s140",
|
|
||||||
"sd_version": "6.1.1",
|
|
||||||
"sd_fwid": "0x00B6"
|
|
||||||
},
|
|
||||||
"bootloader": {
|
|
||||||
"settings_addr": "0xFF000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"connectivity": ["bluetooth"],
|
|
||||||
"debug": {
|
|
||||||
"jlink_device": "nRF52840_xxAA",
|
|
||||||
"onboard_tools": ["jlink"],
|
|
||||||
"svd_path": "nrf52840.svd",
|
|
||||||
"openocd_target": "nrf52840-mdk-rs"
|
|
||||||
},
|
|
||||||
"frameworks": ["arduino"],
|
|
||||||
"name": "Heltec nrf (Adafruit BSP)",
|
|
||||||
"upload": {
|
|
||||||
"maximum_ram_size": 248832,
|
|
||||||
"maximum_size": 815104,
|
|
||||||
"speed": 115200,
|
|
||||||
"protocol": "nrfutil",
|
|
||||||
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
|
||||||
"use_1200bps_touch": true,
|
|
||||||
"require_upload_port": true,
|
|
||||||
"wait_for_upload_port": true
|
|
||||||
},
|
|
||||||
"url": "https://heltec.org/project/meshsolar/",
|
|
||||||
"vendor": "Heltec"
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"build": {
|
|
||||||
"arduino": {
|
|
||||||
"ldscript": "esp32s3_out.ld",
|
|
||||||
"partitions": "default_16MB.csv",
|
|
||||||
"memory_type": "qio_qspi"
|
|
||||||
},
|
|
||||||
"core": "esp32",
|
|
||||||
"extra_flags": [
|
|
||||||
"-DBOARD_HAS_PSRAM",
|
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
|
||||||
"-DARDUINO_USB_MODE=0",
|
|
||||||
"-DARDUINO_RUNNING_CORE=1",
|
|
||||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
|
||||||
],
|
|
||||||
"f_cpu": "240000000L",
|
|
||||||
"f_flash": "80000000L",
|
|
||||||
"flash_mode": "qio",
|
|
||||||
"psram_type": "qspi",
|
|
||||||
"hwids": [["0x303A", "0x1001"]],
|
|
||||||
"mcu": "esp32s3",
|
|
||||||
"variant": "heltec_v4"
|
|
||||||
},
|
|
||||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
|
||||||
"debug": {
|
|
||||||
"default_tool": "esp-builtin",
|
|
||||||
"onboard_tools": ["esp-builtin"],
|
|
||||||
"openocd_target": "esp32s3.cfg"
|
|
||||||
},
|
|
||||||
"frameworks": ["arduino", "espidf"],
|
|
||||||
"name": "heltec_wifi_lora_32 v4 (16 MB FLASH, 2 MB PSRAM)",
|
|
||||||
"upload": {
|
|
||||||
"flash_size": "16MB",
|
|
||||||
"maximum_ram_size": 2097152,
|
|
||||||
"maximum_size": 16777216,
|
|
||||||
"use_1200bps_touch": true,
|
|
||||||
"wait_for_upload_port": true,
|
|
||||||
"require_upload_port": true,
|
|
||||||
"speed": 921600
|
|
||||||
},
|
|
||||||
"url": "https://heltec.org/",
|
|
||||||
"vendor": "heltec"
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"arduino": {
|
"arduino": {
|
||||||
"ldscript": "esp32s3_out.ld",
|
"ldscript": "esp32s3_out.ld",
|
||||||
"partitions": "partition-table-8MB.csv",
|
"partitions": "default_8MB.csv",
|
||||||
"memory_type": "qio_opi"
|
"memory_type": "qio_opi"
|
||||||
},
|
},
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"arduino": {
|
"arduino": {
|
||||||
"ldscript": "esp32s3_out.ld",
|
"ldscript": "esp32s3_out.ld",
|
||||||
"memory_type": "qio_opi",
|
"memory_type": "qio_opi",
|
||||||
"partitions": "partition-table-8MB.csv"
|
"partitions": "default_8MB.csv"
|
||||||
},
|
},
|
||||||
"core": "esp32",
|
"core": "esp32",
|
||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
},
|
},
|
||||||
"core": "stm32",
|
"core": "stm32",
|
||||||
"cpu": "cortex-m4",
|
"cpu": "cortex-m4",
|
||||||
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_RAK3172_MODULE",
|
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
|
||||||
"f_cpu": "48000000L",
|
"f_cpu": "48000000L",
|
||||||
"mcu": "stm32wle5ccu",
|
"mcu": "stm32wle5ccu",
|
||||||
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
|
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
|
||||||
|
|||||||
20
debian/changelog
vendored
20
debian/changelog
vendored
@@ -1,7 +1,11 @@
|
|||||||
meshtasticd (2.7.10.0) UNRELEASED; urgency=medium
|
meshtasticd (2.7.6.0) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
|
[ Austin Lane ]
|
||||||
* Initial packaging
|
* Initial packaging
|
||||||
* Version 2.5.19
|
* GitHub Actions Automatic version bump
|
||||||
|
* GitHub Actions Automatic version bump
|
||||||
|
* GitHub Actions Automatic version bump
|
||||||
|
* GitHub Actions Automatic version bump
|
||||||
|
|
||||||
[ ]
|
[ ]
|
||||||
* GitHub Actions Automatic version bump
|
* GitHub Actions Automatic version bump
|
||||||
@@ -35,15 +39,5 @@ meshtasticd (2.7.10.0) UNRELEASED; urgency=medium
|
|||||||
|
|
||||||
[ ]
|
[ ]
|
||||||
* GitHub Actions Automatic version bump
|
* GitHub Actions Automatic version bump
|
||||||
* GitHub Actions Automatic version bump
|
|
||||||
|
|
||||||
[ ]
|
-- <github-actions[bot]@users.noreply.github.com> Tue, 12 Aug 2025 23:48:48 +0000
|
||||||
* GitHub Actions Automatic version bump
|
|
||||||
|
|
||||||
[ ]
|
|
||||||
* GitHub Actions Automatic version bump
|
|
||||||
|
|
||||||
[ ]
|
|
||||||
* GitHub Actions Automatic version bump
|
|
||||||
|
|
||||||
-- <github-actions[bot]@users.noreply.github.com> Thu, 18 Sep 2025 22:11:37 +0000
|
|
||||||
|
|||||||
5
debian/ci_changelog.sh
vendored
5
debian/ci_changelog.sh
vendored
@@ -1,8 +1,7 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
export DEBFULLNAME="GitHub Actions"
|
|
||||||
export DEBEMAIL="github-actions[bot]@users.noreply.github.com"
|
export DEBEMAIL="github-actions[bot]@users.noreply.github.com"
|
||||||
PKG_VERSION=$(python3 bin/buildinfo.py short)
|
PKG_VERSION=$(python3 bin/buildinfo.py short)
|
||||||
|
|
||||||
dch --newversion "$PKG_VERSION.0" \
|
dch --newversion "$PKG_VERSION.0" \
|
||||||
--distribution unstable \
|
--distribution UNRELEASED \
|
||||||
"Version $PKG_VERSION"
|
"GitHub Actions Automatic version bump"
|
||||||
|
|||||||
2
debian/meshtasticd.postinst
vendored
2
debian/meshtasticd.postinst
vendored
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
# postinst script for meshtasticd
|
# postinst script for meshtasticd
|
||||||
#
|
#
|
||||||
# see: dh_installdeb(1)
|
# see: dh_installdeb(1)
|
||||||
|
|||||||
2
debian/meshtasticd.postrm
vendored
2
debian/meshtasticd.postrm
vendored
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
# postrm script for meshtasticd
|
# postrm script for meshtasticd
|
||||||
#
|
#
|
||||||
# see: dh_installdeb(1)
|
# see: dh_installdeb(1)
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# This is a layout for 8MB of flash for MUI devices
|
|
||||||
# Name, Type, SubType, Offset, Size, Flags
|
|
||||||
nvs, data, nvs, 0x9000, 0x5000,
|
|
||||||
otadata, data, ota, 0xe000, 0x2000,
|
|
||||||
app0, app, ota_0, 0x10000, 0x5C0000,
|
|
||||||
flashApp, app, ota_1, 0x5D0000,0x0A0000,
|
|
||||||
spiffs, data, spiffs, 0x670000,0x180000
|
|
||||||
|
@@ -53,15 +53,14 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||||
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
||||||
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
|
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
|
||||||
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
|
#-DBUILD_EPOCH=$UNIX_TIME
|
||||||
#-D OLED_PL=1
|
#-D OLED_PL=1
|
||||||
#-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs
|
|
||||||
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
||||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/0cbc26b1f8f61957af0475f486b362eafe7cc4e2.zip
|
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/9573abb64dc9c94f3051348f2bf4fc5cedf03c22.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
||||||
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
||||||
@@ -114,18 +113,18 @@ lib_deps =
|
|||||||
[radiolib_base]
|
[radiolib_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
|
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
|
||||||
jgromes/RadioLib@7.3.0
|
jgromes/RadioLib@7.2.1
|
||||||
|
|
||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/9ed5355a24059750e9b2eb5d669574d9ea42a37b.zip
|
https://github.com/meshtastic/device-ui/archive/3dc7cf3e233aaa8cc23492cca50541fc099ebfa1.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO
|
# renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO
|
||||||
adafruit/Adafruit BusIO@1.17.3
|
adafruit/Adafruit BusIO@1.17.2
|
||||||
# renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor
|
# renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor
|
||||||
adafruit/Adafruit Unified Sensor@1.1.15
|
adafruit/Adafruit Unified Sensor@1.1.15
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library
|
# renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library
|
||||||
@@ -158,8 +157,8 @@ lib_deps =
|
|||||||
emotibit/EmotiBit MLX90632@1.0.8
|
emotibit/EmotiBit MLX90632@1.0.8
|
||||||
# renovate: datasource=custom.pio depName=Adafruit MLX90614 packageName=adafruit/library/Adafruit MLX90614 Library
|
# renovate: datasource=custom.pio depName=Adafruit MLX90614 packageName=adafruit/library/Adafruit MLX90614 Library
|
||||||
adafruit/Adafruit MLX90614 Library@2.1.5
|
adafruit/Adafruit MLX90614 Library@2.1.5
|
||||||
# renovate: datasource=github-tags depName=INA3221 packageName=sgtwilko/INA3221
|
# renovate: datasource=github-tags depName=INA3221 packageName=KodinLanewave/INA3221
|
||||||
https://github.com/sgtwilko/INA3221#bb03d7e9bfcc74fc798838a54f4f99738f29fc6a
|
https://github.com/KodinLanewave/INA3221/archive/1.0.1.zip
|
||||||
# renovate: datasource=custom.pio depName=QMC5883L Compass packageName=mprograms/library/QMC5883LCompass
|
# renovate: datasource=custom.pio depName=QMC5883L Compass packageName=mprograms/library/QMC5883LCompass
|
||||||
mprograms/QMC5883LCompass@1.2.3
|
mprograms/QMC5883LCompass@1.2.3
|
||||||
# renovate: datasource=custom.pio depName=DFRobot_RTU packageName=dfrobot/library/DFRobot_RTU
|
# renovate: datasource=custom.pio depName=DFRobot_RTU packageName=dfrobot/library/DFRobot_RTU
|
||||||
@@ -178,8 +177,6 @@ lib_deps =
|
|||||||
adafruit/Adafruit PCT2075@1.0.5
|
adafruit/Adafruit PCT2075@1.0.5
|
||||||
# renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150
|
# renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150
|
||||||
dfrobot/DFRobot_BMM150@1.0.0
|
dfrobot/DFRobot_BMM150@1.0.0
|
||||||
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
|
||||||
adafruit/Adafruit TSL2561@1.1.2
|
|
||||||
|
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
[environmental_extra]
|
[environmental_extra]
|
||||||
|
|||||||
Submodule protobufs updated: 46b81e822a...8985852d75
@@ -8,7 +8,6 @@
|
|||||||
"replacements:all",
|
"replacements:all",
|
||||||
"workarounds:all"
|
"workarounds:all"
|
||||||
],
|
],
|
||||||
"baseBranchPatterns": ["master"],
|
|
||||||
"forkProcessing": "enabled",
|
"forkProcessing": "enabled",
|
||||||
"ignoreDeps": [
|
"ignoreDeps": [
|
||||||
"protobufs"
|
"protobufs"
|
||||||
|
|||||||
@@ -183,9 +183,9 @@ class AmbientLightingThread : public concurrency::OSThread
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
pixels.show();
|
pixels.show();
|
||||||
// LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
|
LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
|
||||||
// moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red,
|
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red,
|
||||||
// moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||||
#endif
|
#endif
|
||||||
#ifdef RGBLED_CA
|
#ifdef RGBLED_CA
|
||||||
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
|
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess
|
|||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
bool utf = !portduino_config.ascii_logs;
|
bool utf = !settingsMap[ascii_logs];
|
||||||
#else
|
#else
|
||||||
bool utf = true;
|
bool utf = true;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
#if defined(DEBUG_HEAP)
|
|
||||||
class MemGet;
|
|
||||||
extern MemGet memGet;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// DEBUG LED
|
// DEBUG LED
|
||||||
#ifndef LED_STATE_ON
|
#ifndef LED_STATE_ON
|
||||||
#define LED_STATE_ON 1
|
#define LED_STATE_ON 1
|
||||||
@@ -29,7 +23,6 @@ extern MemGet memGet;
|
|||||||
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
||||||
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
||||||
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
||||||
#define MESHTASTIC_LOG_LEVEL_HEAP "HEAP"
|
|
||||||
|
|
||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
|
|
||||||
@@ -69,25 +62,6 @@ extern MemGet memGet;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(DEBUG_HEAP)
|
|
||||||
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
|
|
||||||
|
|
||||||
// Macro-based heap debugging
|
|
||||||
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
|
|
||||||
#define DEBUG_HEAP_AFTER(context, ptr) \
|
|
||||||
do { \
|
|
||||||
auto heapAfter = memGet.getFreeHeap(); \
|
|
||||||
if (heapBefore != heapAfter) { \
|
|
||||||
LOG_HEAP("Alloc in %s pointer 0x%x, size: %u, free: %u", context, ptr, heapBefore - heapAfter, heapAfter); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define LOG_HEAP(...)
|
|
||||||
#define DEBUG_HEAP_BEFORE
|
|
||||||
#define DEBUG_HEAP_AFTER(context, ptr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
|
/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
|
||||||
extern "C" void logLegacy(const char *level, const char *fmt, ...);
|
extern "C" void logLegacy(const char *level, const char *fmt, ...);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
#include "DisplayFormatters.h"
|
#include "DisplayFormatters.h"
|
||||||
|
|
||||||
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
|
||||||
bool usePreset)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// If use_preset is false, always return "Custom"
|
|
||||||
if (!usePreset) {
|
|
||||||
return "Custom";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
|
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
|
||||||
return useShortName ? "ShortT" : "ShortTurbo";
|
return useShortName ? "ShortT" : "ShortTurbo";
|
||||||
@@ -38,49 +31,4 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
|
|||||||
return useShortName ? "Custom" : "Invalid";
|
return useShortName ? "Custom" : "Invalid";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const char *DisplayFormatters::getDeviceRole(meshtastic_Config_DeviceConfig_Role role)
|
|
||||||
{
|
|
||||||
switch (role) {
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_CLIENT:
|
|
||||||
return "Client";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE:
|
|
||||||
return "Client Mute";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN:
|
|
||||||
return "Client Hidden";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_CLIENT_BASE:
|
|
||||||
return "Client Base";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND:
|
|
||||||
return "Lost and Found";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_TRACKER:
|
|
||||||
return "Tracker";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_SENSOR:
|
|
||||||
return "Sensor";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_TAK:
|
|
||||||
return "TAK";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_TAK_TRACKER:
|
|
||||||
return "TAK Tracker";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_ROUTER:
|
|
||||||
return "Router";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE:
|
|
||||||
return "Router Late";
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_DeviceConfig_Role_REPEATER:
|
|
||||||
return "Repeater";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,5 @@
|
|||||||
class DisplayFormatters
|
class DisplayFormatters
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
|
||||||
bool usePreset);
|
|
||||||
static const char *getDeviceRole(meshtastic_Config_DeviceConfig_Role role);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,9 +22,6 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
meshtastic_Position p = meshtastic_Position_init_default;
|
meshtastic_Position p = meshtastic_Position_init_default;
|
||||||
|
|
||||||
/// Time of last valid GPS fix (millis since boot)
|
|
||||||
uint32_t lastFixMillis = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||||
|
|
||||||
@@ -86,9 +83,6 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
uint32_t getNumSatellites() const { return p.sats_in_view; }
|
uint32_t getNumSatellites() const { return p.sats_in_view; }
|
||||||
|
|
||||||
/// Return millis() when the last GPS fix occurred (0 = never)
|
|
||||||
uint32_t getLastFixMillis() const { return lastFixMillis; }
|
|
||||||
|
|
||||||
bool matches(const GPSStatus *newStatus) const
|
bool matches(const GPSStatus *newStatus) const
|
||||||
{
|
{
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
@@ -120,9 +114,6 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
if (isDirty) {
|
if (isDirty) {
|
||||||
if (hasLock) {
|
if (hasLock) {
|
||||||
// Record time of last valid GPS fix
|
|
||||||
lastFixMillis = millis();
|
|
||||||
|
|
||||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d", p.timestamp,
|
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d", p.timestamp,
|
||||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||||
|
|||||||
153
src/Power.cpp
153
src/Power.cpp
@@ -128,7 +128,6 @@ RAK9154Sensor rak9154Sensor;
|
|||||||
#ifdef HAS_PPM
|
#ifdef HAS_PPM
|
||||||
// note: XPOWERS_CHIP_XXX must be defined in variant.h
|
// note: XPOWERS_CHIP_XXX must be defined in variant.h
|
||||||
#include <XPowersLib.h>
|
#include <XPowersLib.h>
|
||||||
XPowersPPM *PPM = NULL;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_BQ27220
|
#ifdef HAS_BQ27220
|
||||||
@@ -682,8 +681,6 @@ bool Power::setup()
|
|||||||
found = true;
|
found = true;
|
||||||
} else if (lipoChargerInit()) {
|
} else if (lipoChargerInit()) {
|
||||||
found = true;
|
found = true;
|
||||||
} else if (meshSolarInit()) {
|
|
||||||
found = true;
|
|
||||||
} else if (analogInit()) {
|
} else if (analogInit()) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@@ -746,11 +743,7 @@ void Power::shutdown()
|
|||||||
|
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
if (screen) {
|
if (screen) {
|
||||||
#ifdef T_DECK_PRO
|
|
||||||
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
|
|
||||||
#else
|
|
||||||
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !defined(ARCH_STM32WL)
|
#if !defined(ARCH_STM32WL)
|
||||||
@@ -768,7 +761,7 @@ void Power::shutdown()
|
|||||||
#ifdef PIN_LED3
|
#ifdef PIN_LED3
|
||||||
ledOff(PIN_LED3);
|
ledOff(PIN_LED3);
|
||||||
#endif
|
#endif
|
||||||
doDeepSleep(DELAY_FOREVER, true, true);
|
doDeepSleep(DELAY_FOREVER, false, true);
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
#else
|
#else
|
||||||
@@ -833,27 +826,18 @@ void Power::readPowerStatus()
|
|||||||
newStatus.notifyObservers(&powerStatus2);
|
newStatus.notifyObservers(&powerStatus2);
|
||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
if (lastheap != memGet.getFreeHeap()) {
|
if (lastheap != memGet.getFreeHeap()) {
|
||||||
// Use stack-allocated buffer to avoid heap allocations in monitoring code
|
std::string threadlist = "Threads running:";
|
||||||
char threadlist[256] = "Threads running:";
|
|
||||||
int threadlistLen = strlen(threadlist);
|
|
||||||
int running = 0;
|
int running = 0;
|
||||||
for (int i = 0; i < MAX_THREADS; i++) {
|
for (int i = 0; i < MAX_THREADS; i++) {
|
||||||
auto thread = concurrency::mainController.get(i);
|
auto thread = concurrency::mainController.get(i);
|
||||||
if ((thread != nullptr) && (thread->enabled)) {
|
if ((thread != nullptr) && (thread->enabled)) {
|
||||||
// Use snprintf to safely append to stack buffer without heap allocation
|
threadlist += vformat(" %s", thread->ThreadName.c_str());
|
||||||
int remaining = sizeof(threadlist) - threadlistLen - 1;
|
|
||||||
if (remaining > 0) {
|
|
||||||
int written = snprintf(threadlist + threadlistLen, remaining, " %s", thread->ThreadName.c_str());
|
|
||||||
if (written > 0 && written < remaining) {
|
|
||||||
threadlistLen += written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
running++;
|
running++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_HEAP(threadlist);
|
LOG_DEBUG(threadlist.c_str());
|
||||||
LOG_HEAP("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||||
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||||
lastheap = memGet.getFreeHeap();
|
lastheap = memGet.getFreeHeap();
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_HEAP_MQTT
|
#ifdef DEBUG_HEAP_MQTT
|
||||||
@@ -865,19 +849,15 @@ void Power::readPowerStatus()
|
|||||||
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
||||||
|
|
||||||
auto newHeap = memGet.getFreeHeap();
|
auto newHeap = memGet.getFreeHeap();
|
||||||
// Use stack-allocated buffers to avoid heap allocations in monitoring code
|
std::string heapTopic =
|
||||||
char heapTopic[128];
|
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
|
||||||
snprintf(heapTopic, sizeof(heapTopic), "%s/2/heap/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
std::string heapString = std::to_string(newHeap);
|
||||||
char heapString[16];
|
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
|
||||||
snprintf(heapString, sizeof(heapString), "%u", newHeap);
|
|
||||||
mqtt->pubSub.publish(heapTopic, heapString, false);
|
|
||||||
|
|
||||||
auto wifiRSSI = WiFi.RSSI();
|
auto wifiRSSI = WiFi.RSSI();
|
||||||
char wifiTopic[128];
|
std::string wifiTopic =
|
||||||
snprintf(wifiTopic, sizeof(wifiTopic), "%s/2/wifi/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
|
||||||
char wifiString[16];
|
std::string wifiString = std::to_string(wifiRSSI);
|
||||||
snprintf(wifiString, sizeof(wifiString), "%d", wifiRSSI);
|
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
|
||||||
mqtt->pubSub.publish(wifiTopic, wifiString, false);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1338,6 +1318,7 @@ bool Power::lipoInit()
|
|||||||
class LipoCharger : public HasBatteryLevel
|
class LipoCharger : public HasBatteryLevel
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
XPowersPPM *ppm = nullptr;
|
||||||
BQ27220 *bq = nullptr;
|
BQ27220 *bq = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -1346,41 +1327,41 @@ class LipoCharger : public HasBatteryLevel
|
|||||||
*/
|
*/
|
||||||
bool runOnce()
|
bool runOnce()
|
||||||
{
|
{
|
||||||
if (PPM == nullptr) {
|
if (ppm == nullptr) {
|
||||||
PPM = new XPowersPPM;
|
ppm = new XPowersPPM;
|
||||||
bool result = PPM->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
bool result = ppm->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
||||||
if (result) {
|
if (result) {
|
||||||
LOG_INFO("PPM BQ25896 init succeeded");
|
LOG_INFO("PPM BQ25896 init succeeded");
|
||||||
// Set the minimum operating voltage. Below this voltage, the PPM will protect
|
// Set the minimum operating voltage. Below this voltage, the PPM will protect
|
||||||
// PPM->setSysPowerDownVoltage(3100);
|
// ppm->setSysPowerDownVoltage(3100);
|
||||||
|
|
||||||
// Set input current limit, default is 500mA
|
// Set input current limit, default is 500mA
|
||||||
// PPM->setInputCurrentLimit(800);
|
// ppm->setInputCurrentLimit(800);
|
||||||
|
|
||||||
// Disable current limit pin
|
// Disable current limit pin
|
||||||
// PPM->disableCurrentLimitPin();
|
// ppm->disableCurrentLimitPin();
|
||||||
|
|
||||||
// Set the charging target voltage, Range:3840 ~ 4608mV ,step:16 mV
|
// Set the charging target voltage, Range:3840 ~ 4608mV ,step:16 mV
|
||||||
PPM->setChargeTargetVoltage(4288);
|
ppm->setChargeTargetVoltage(4288);
|
||||||
|
|
||||||
// Set the precharge current , Range: 64mA ~ 1024mA ,step:64mA
|
// Set the precharge current , Range: 64mA ~ 1024mA ,step:64mA
|
||||||
// PPM->setPrechargeCurr(64);
|
// ppm->setPrechargeCurr(64);
|
||||||
|
|
||||||
// The premise is that limit pin is disabled, or it will
|
// The premise is that limit pin is disabled, or it will
|
||||||
// only follow the maximum charging current set by limit pin.
|
// only follow the maximum charging current set by limit pin.
|
||||||
// Set the charging current , Range:0~5056mA ,step:64mA
|
// Set the charging current , Range:0~5056mA ,step:64mA
|
||||||
PPM->setChargerConstantCurr(1024);
|
ppm->setChargerConstantCurr(1024);
|
||||||
|
|
||||||
// To obtain voltage data, the ADC must be enabled first
|
// To obtain voltage data, the ADC must be enabled first
|
||||||
PPM->enableMeasure();
|
ppm->enableMeasure();
|
||||||
|
|
||||||
// Turn on charging function
|
// Turn on charging function
|
||||||
// If there is no battery connected, do not turn on the charging function
|
// If there is no battery connected, do not turn on the charging function
|
||||||
PPM->enableCharge();
|
ppm->enableCharge();
|
||||||
} else {
|
} else {
|
||||||
LOG_WARN("PPM BQ25896 init failed");
|
LOG_WARN("PPM BQ25896 init failed");
|
||||||
delete PPM;
|
delete ppm;
|
||||||
PPM = nullptr;
|
ppm = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1421,23 +1402,23 @@ class LipoCharger : public HasBatteryLevel
|
|||||||
/**
|
/**
|
||||||
* return true if there is a battery installed in this unit
|
* return true if there is a battery installed in this unit
|
||||||
*/
|
*/
|
||||||
virtual bool isBatteryConnect() override { return PPM->getBattVoltage() > 0; }
|
virtual bool isBatteryConnect() override { return ppm->getBattVoltage() > 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if there is an external power source detected
|
* return true if there is an external power source detected
|
||||||
*/
|
*/
|
||||||
virtual bool isVbusIn() override { return PPM->getVbusVoltage() > 0; }
|
virtual bool isVbusIn() override { return ppm->getVbusVoltage() > 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if the battery is currently charging
|
* return true if the battery is currently charging
|
||||||
*/
|
*/
|
||||||
virtual bool isCharging() override
|
virtual bool isCharging() override
|
||||||
{
|
{
|
||||||
bool isCharging = PPM->isCharging();
|
bool isCharging = ppm->isCharging();
|
||||||
if (isCharging) {
|
if (isCharging) {
|
||||||
LOG_DEBUG("BQ27220 time to full charge: %d min", bq->getTimeToFull());
|
LOG_DEBUG("BQ27220 time to full charge: %d min", bq->getTimeToFull());
|
||||||
} else {
|
} else {
|
||||||
if (!PPM->isVbusIn()) {
|
if (!ppm->isVbusIn()) {
|
||||||
LOG_DEBUG("BQ27220 time to empty: %d min (%d mAh)", bq->getTimeToEmpty(), bq->getRemainingCapacity());
|
LOG_DEBUG("BQ27220 time to empty: %d min (%d mAh)", bq->getTimeToEmpty(), bq->getRemainingCapacity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1469,73 +1450,3 @@ bool Power::lipoChargerInit()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HELTEC_MESH_SOLAR
|
|
||||||
#include "meshSolarApp.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meshSolar class for an SMBUS battery sensor.
|
|
||||||
*/
|
|
||||||
class meshSolarBatteryLevel : public HasBatteryLevel
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Init the I2C meshSolar battery level sensor
|
|
||||||
*/
|
|
||||||
bool runOnce()
|
|
||||||
{
|
|
||||||
meshSolarStart();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Battery state of charge, from 0 to 100 or -1 for unknown
|
|
||||||
*/
|
|
||||||
virtual int getBatteryPercent() override { return meshSolarGetBatteryPercent(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The raw voltage of the battery in millivolts, or NAN if unknown
|
|
||||||
*/
|
|
||||||
virtual uint16_t getBattVoltage() override { return meshSolarGetBattVoltage(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return true if there is a battery installed in this unit
|
|
||||||
*/
|
|
||||||
virtual bool isBatteryConnect() override { return meshSolarIsBatteryConnect(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return true if there is an external power source detected
|
|
||||||
*/
|
|
||||||
virtual bool isVbusIn() override { return meshSolarIsVbusIn(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return true if the battery is currently charging
|
|
||||||
*/
|
|
||||||
virtual bool isCharging() override { return meshSolarIsCharging(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
meshSolarBatteryLevel meshSolarLevel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the meshSolar battery level sensor
|
|
||||||
*/
|
|
||||||
bool Power::meshSolarInit()
|
|
||||||
{
|
|
||||||
bool result = meshSolarLevel.runOnce();
|
|
||||||
LOG_DEBUG("Power::meshSolarInit mesh solar sensor is %s", result ? "ready" : "not ready yet");
|
|
||||||
if (!result)
|
|
||||||
return false;
|
|
||||||
batteryLevel = &meshSolarLevel;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/**
|
|
||||||
* The meshSolar battery level sensor is unavailable - default to AnalogBatteryLevel
|
|
||||||
*/
|
|
||||||
bool Power::meshSolarInit()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "memGet.h"
|
|
||||||
#include "mesh/generated/meshtastic/mesh.pb.h"
|
#include "mesh/generated/meshtastic/mesh.pb.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -58,7 +57,7 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
bool color = !portduino_config.ascii_logs;
|
bool color = !settingsMap[ascii_logs];
|
||||||
#else
|
#else
|
||||||
bool color = true;
|
bool color = true;
|
||||||
#endif
|
#endif
|
||||||
@@ -100,7 +99,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
|||||||
size_t r = 0;
|
size_t r = 0;
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
bool color = !portduino_config.ascii_logs;
|
bool color = !settingsMap[ascii_logs];
|
||||||
#else
|
#else
|
||||||
bool color = true;
|
bool color = true;
|
||||||
#endif
|
#endif
|
||||||
@@ -167,16 +166,6 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
|||||||
print(thread->ThreadName);
|
print(thread->ThreadName);
|
||||||
print("] ");
|
print("] ");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_HEAP
|
|
||||||
// Add heap free space bytes prefix before every log message
|
|
||||||
#ifdef ARCH_PORTDUINO
|
|
||||||
::printf("[heap %u] ", memGet.getFreeHeap());
|
|
||||||
#else
|
|
||||||
printf("[heap %u] ", memGet.getFreeHeap());
|
|
||||||
#endif
|
|
||||||
#endif // DEBUG_HEAP
|
|
||||||
|
|
||||||
r += vprintf(logLevel, format, arg);
|
r += vprintf(logLevel, format, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +288,7 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
|||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
// level trace is special, two possible ways to handle it.
|
// level trace is special, two possible ways to handle it.
|
||||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
||||||
if (portduino_config.traceFilename != "") {
|
if (settingsStrings[traceFilename] != "") {
|
||||||
va_list arg;
|
va_list arg;
|
||||||
va_start(arg, format);
|
va_start(arg, format);
|
||||||
try {
|
try {
|
||||||
@@ -308,18 +297,18 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
|||||||
}
|
}
|
||||||
va_end(arg);
|
va_end(arg);
|
||||||
}
|
}
|
||||||
if (portduino_config.logoutputlevel < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
||||||
delete[] newFormat;
|
delete[] newFormat;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (portduino_config.logoutputlevel < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
|
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
|
||||||
delete[] newFormat;
|
delete[] newFormat;
|
||||||
return;
|
return;
|
||||||
} else if (portduino_config.logoutputlevel < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
|
} else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
|
||||||
delete[] newFormat;
|
delete[] newFormat;
|
||||||
return;
|
return;
|
||||||
} else if (portduino_config.logoutputlevel < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
|
} else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
|
||||||
delete[] newFormat;
|
delete[] newFormat;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,14 +64,6 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
|
|||||||
|
|
||||||
int32_t SerialConsole::runOnce()
|
int32_t SerialConsole::runOnce()
|
||||||
{
|
{
|
||||||
#ifdef HELTEC_MESH_SOLAR
|
|
||||||
//After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module.
|
|
||||||
if(moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port
|
|
||||||
&& moduleConfig.serial.mode==meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG)
|
|
||||||
{
|
|
||||||
return 250;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return runOncePart();
|
return runOncePart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ void OSThread::run()
|
|||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
auto newHeap = memGet.getFreeHeap();
|
auto newHeap = memGet.getFreeHeap();
|
||||||
if (newHeap < heap)
|
if (newHeap < heap)
|
||||||
LOG_HEAP("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||||
if (heap < newHeap)
|
if (heap < newHeap)
|
||||||
LOG_HEAP("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
runned();
|
runned();
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#if __has_include("Melopero_RV3028.h")
|
#ifdef RV3028_RTC
|
||||||
#include "Melopero_RV3028.h"
|
#include "Melopero_RV3028.h"
|
||||||
#endif
|
#endif
|
||||||
#if __has_include("pcf8563.h")
|
#ifdef PCF8563_RTC
|
||||||
#include "pcf8563.h"
|
#include "pcf8563.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// OLED & Input
|
// OLED & Input
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
#if defined(SEEED_WIO_TRACKER_L1) && !defined(SEEED_WIO_TRACKER_L1_EINK)
|
#if defined(SEEED_WIO_TRACKER_L1)
|
||||||
#define SSD1306_ADDRESS 0x3D
|
#define SSD1306_ADDRESS 0x3D
|
||||||
#define USE_SH1106
|
#define USE_SH1106
|
||||||
#else
|
#else
|
||||||
@@ -262,13 +262,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define VEXT_ON_VALUE LOW
|
#define VEXT_ON_VALUE LOW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Rotary encoder
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
#ifndef ROTARY_DELAY
|
|
||||||
#define ROTARY_DELAY 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// GPS
|
// GPS
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -79,9 +79,7 @@ class ScanI2C
|
|||||||
BQ27220,
|
BQ27220,
|
||||||
LTR553ALS,
|
LTR553ALS,
|
||||||
BHI260AP,
|
BHI260AP,
|
||||||
BMM150,
|
BMM150
|
||||||
TSL2561,
|
|
||||||
DRV2605
|
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
// typedef uint8_t DeviceAddress;
|
// typedef uint8_t DeviceAddress;
|
||||||
|
|||||||
@@ -294,7 +294,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
type = AHT10;
|
type = AHT10;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
case INA_ADDR:
|
case INA_ADDR:
|
||||||
case INA_ADDR_ALTERNATE:
|
case INA_ADDR_ALTERNATE:
|
||||||
case INA_ADDR_WAVESHARE_UPS:
|
case INA_ADDR_WAVESHARE_UPS:
|
||||||
@@ -341,7 +340,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
// else: probably a RAK12500/UBLOX GPS on I2C
|
// else: probably a RAK12500/UBLOX GPS on I2C
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case MCP9808_ADDR:
|
case MCP9808_ADDR:
|
||||||
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
|
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
|
||||||
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
|
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
|
||||||
@@ -463,17 +461,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
||||||
case TSL25911_ADDR:
|
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
|
||||||
if (registerValue == 0x50) {
|
|
||||||
type = TSL2591;
|
|
||||||
logFoundDevice("TSL25911", (uint8_t)addr.address);
|
|
||||||
} else {
|
|
||||||
type = TSL2561;
|
|
||||||
logFoundDevice("TSL2561", (uint8_t)addr.address);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
||||||
@@ -495,14 +483,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
type = MLX90614;
|
type = MLX90614;
|
||||||
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
||||||
} else {
|
} else {
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // DRV2605_REG_STATUS
|
type = MPR121KB;
|
||||||
if (registerValue == 0xe0) {
|
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
||||||
type = DRV2605;
|
|
||||||
logFoundDevice("DRV2605", (uint8_t)addr.address);
|
|
||||||
} else {
|
|
||||||
type = MPR121KB;
|
|
||||||
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
153
src/gps/GPS.cpp
153
src/gps/GPS.cpp
@@ -1,4 +1,5 @@
|
|||||||
#include <cstring> // Include for strstr
|
#include <cstring> // Include for strstr
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
@@ -516,7 +517,6 @@ bool GPS::setup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rare Serial Speeds
|
// Rare Serial Speeds
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32C6
|
|
||||||
if (probeTries == GPS_PROBETRIES) {
|
if (probeTries == GPS_PROBETRIES) {
|
||||||
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
|
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
|
||||||
gnssModel = probe(rareSerialSpeeds[speedSelect]);
|
gnssModel = probe(rareSerialSpeeds[speedSelect]);
|
||||||
@@ -527,7 +527,6 @@ bool GPS::setup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
||||||
@@ -809,14 +808,6 @@ bool GPS::setup()
|
|||||||
} else {
|
} else {
|
||||||
LOG_INFO("GNSS module configuration saved!");
|
LOG_INFO("GNSS module configuration saved!");
|
||||||
}
|
}
|
||||||
} else if (gnssModel == GNSS_MODEL_CM121) {
|
|
||||||
// only ask for RMC and GGA
|
|
||||||
// enable GGA
|
|
||||||
_serial_gps->write("$CFGMSG,0,0,1,1*1B\r\n");
|
|
||||||
delay(250);
|
|
||||||
// enable RMC
|
|
||||||
_serial_gps->write("$CFGMSG,0,4,1,1*1F\r\n");
|
|
||||||
delay(250);
|
|
||||||
}
|
}
|
||||||
didSerialInit = true;
|
didSerialInit = true;
|
||||||
}
|
}
|
||||||
@@ -852,6 +843,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
|||||||
setPowerPMU(true); // Power (PMU): on
|
setPowerPMU(true); // Power (PMU): on
|
||||||
writePinStandby(false); // Standby (pin): awake (not standby)
|
writePinStandby(false); // Standby (pin): awake (not standby)
|
||||||
setPowerUBLOX(true); // Standby (UBLOX): awake
|
setPowerUBLOX(true); // Standby (UBLOX): awake
|
||||||
|
#ifdef GNSS_AIROHA
|
||||||
|
lastFixStartMsec = 0;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GPS_SOFTSLEEP:
|
case GPS_SOFTSLEEP:
|
||||||
@@ -869,7 +863,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
|||||||
writePinStandby(true); // Standby (pin): asleep (not awake)
|
writePinStandby(true); // Standby (pin): asleep (not awake)
|
||||||
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
|
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
|
||||||
#ifdef GNSS_AIROHA
|
#ifdef GNSS_AIROHA
|
||||||
digitalWrite(PIN_GPS_EN, LOW);
|
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||||
|
digitalWrite(PIN_GPS_EN, LOW);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -881,7 +877,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
|||||||
writePinStandby(true); // Standby (pin): asleep
|
writePinStandby(true); // Standby (pin): asleep
|
||||||
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
|
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
|
||||||
#ifdef GNSS_AIROHA
|
#ifdef GNSS_AIROHA
|
||||||
digitalWrite(PIN_GPS_EN, LOW);
|
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
|
||||||
|
digitalWrite(PIN_GPS_EN, LOW);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1064,8 +1062,6 @@ void GPS::down()
|
|||||||
}
|
}
|
||||||
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
// If update interval long enough (or softsleep unsupported): hardsleep instead
|
||||||
setPowerState(GPS_HARDSLEEP, sleepTime);
|
setPowerState(GPS_HARDSLEEP, sleepTime);
|
||||||
// Reset the fix quality to 0, since we're off.
|
|
||||||
fixQual = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,19 +1121,11 @@ int32_t GPS::runOnce()
|
|||||||
shouldPublish = true;
|
shouldPublish = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t prev_fixQual = fixQual;
|
|
||||||
bool gotLoc = lookForLocation();
|
bool gotLoc = lookForLocation();
|
||||||
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
||||||
LOG_DEBUG("hasValidLocation RISING EDGE");
|
LOG_DEBUG("hasValidLocation RISING EDGE");
|
||||||
hasValidLocation = true;
|
hasValidLocation = true;
|
||||||
shouldPublish = true;
|
shouldPublish = true;
|
||||||
// Hold for 20secs after getting a lock to download ephemeris etc
|
|
||||||
fixHoldEnds = millis() + 20000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on.
|
|
||||||
fixHoldEnds = millis() + 20000;
|
|
||||||
shouldPublish = true; // Publish immediately, since next publish is at end of hold
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tooLong = scheduling.searchedTooLong();
|
bool tooLong = scheduling.searchedTooLong();
|
||||||
@@ -1146,7 +1134,8 @@ int32_t GPS::runOnce()
|
|||||||
|
|
||||||
// Once we get a location we no longer desperately want an update
|
// Once we get a location we no longer desperately want an update
|
||||||
if ((gotLoc && gotTime) || tooLong) {
|
if ((gotLoc && gotTime) || tooLong) {
|
||||||
if (tooLong && !gotLoc) {
|
|
||||||
|
if (tooLong) {
|
||||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||||
if (hasValidLocation) {
|
if (hasValidLocation) {
|
||||||
LOG_DEBUG("hasValidLocation FALLING EDGE");
|
LOG_DEBUG("hasValidLocation FALLING EDGE");
|
||||||
@@ -1154,15 +1143,9 @@ int32_t GPS::runOnce()
|
|||||||
p = meshtastic_Position_init_default;
|
p = meshtastic_Position_init_default;
|
||||||
hasValidLocation = false;
|
hasValidLocation = false;
|
||||||
}
|
}
|
||||||
if (millis() > fixHoldEnds) {
|
|
||||||
shouldPublish = true; // publish our update at the end of the lock hold
|
down();
|
||||||
publishUpdate();
|
shouldPublish = true; // publish our update for this just finished acquisition window
|
||||||
down();
|
|
||||||
#ifdef GPS_DEBUG
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If state has changed do a publish
|
// If state has changed do a publish
|
||||||
@@ -1215,7 +1198,7 @@ static const char *DETECTED_MESSAGE = "%s detected";
|
|||||||
LOG_DEBUG(PROBE_MESSAGE, COMMAND, FAMILY_NAME); \
|
LOG_DEBUG(PROBE_MESSAGE, COMMAND, FAMILY_NAME); \
|
||||||
clearBuffer(); \
|
clearBuffer(); \
|
||||||
_serial_gps->write(COMMAND "\r\n"); \
|
_serial_gps->write(COMMAND "\r\n"); \
|
||||||
GnssModel_t detectedDriver = getProbeResponse(TIMEOUT, RESPONSE_MAP, serialSpeed); \
|
GnssModel_t detectedDriver = getProbeResponse(TIMEOUT, RESPONSE_MAP); \
|
||||||
if (detectedDriver != GNSS_MODEL_UNKNOWN) { \
|
if (detectedDriver != GNSS_MODEL_UNKNOWN) { \
|
||||||
return detectedDriver; \
|
return detectedDriver; \
|
||||||
} \
|
} \
|
||||||
@@ -1249,15 +1232,9 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
|
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
|
||||||
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
|
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
|
||||||
delay(20);
|
delay(20);
|
||||||
// Close NMEA sequences on CM121
|
|
||||||
_serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n");
|
|
||||||
_serial_gps->write("$CFGMSG,0,2,0,1*18\r\n");
|
|
||||||
_serial_gps->write("$CFGMSG,0,3,0,1*19\r\n");
|
|
||||||
delay(20);
|
|
||||||
|
|
||||||
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
|
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A
|
||||||
std::vector<ChipInfo> unicore = {
|
std::vector<ChipInfo> unicore = {{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}};
|
||||||
{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
|
|
||||||
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
|
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
|
||||||
|
|
||||||
std::vector<ChipInfo> atgm = {
|
std::vector<ChipInfo> atgm = {
|
||||||
@@ -1383,55 +1360,36 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
return GNSS_MODEL_UNKNOWN;
|
return GNSS_MODEL_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap, int serialSpeed)
|
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap)
|
||||||
{
|
{
|
||||||
// Calculate buffer size based on baud rate - 256 bytes for 9600 baud as baseline
|
String response = "";
|
||||||
// Higher baud rates get proportionally larger buffers to handle more data
|
|
||||||
int bufferSize = (serialSpeed * 256) / 9600;
|
|
||||||
// Clamp buffer size between reasonable limits
|
|
||||||
if (bufferSize < 128)
|
|
||||||
bufferSize = 128;
|
|
||||||
if (bufferSize > 2048)
|
|
||||||
bufferSize = 2048;
|
|
||||||
|
|
||||||
char *response = new char[bufferSize](); // Dynamically allocate based on baud rate
|
|
||||||
uint16_t responseLen = 0;
|
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
while (millis() - start < timeout) {
|
while (millis() - start < timeout) {
|
||||||
if (_serial_gps->available()) {
|
if (_serial_gps->available()) {
|
||||||
char c = _serial_gps->read();
|
response += (char)_serial_gps->read();
|
||||||
|
|
||||||
// Add char to buffer if there's space
|
if (response.endsWith(",") || response.endsWith("\r\n")) {
|
||||||
if (responseLen < bufferSize - 1) {
|
|
||||||
response[responseLen++] = c;
|
|
||||||
response[responseLen] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG(response);
|
LOG_DEBUG(response.c_str());
|
||||||
#endif
|
#endif
|
||||||
// check if we can see our chips
|
// check if we can see our chips
|
||||||
for (const auto &chipInfo : responseMap) {
|
for (const auto &chipInfo : responseMap) {
|
||||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
if (strstr(response.c_str(), chipInfo.detectionString.c_str()) != nullptr) {
|
||||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||||
delete[] response; // Cleanup before return
|
|
||||||
return chipInfo.driver;
|
return chipInfo.driver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
if (response.endsWith("\r\n")) {
|
||||||
// Reset the response buffer for the next potential message
|
response.trim();
|
||||||
responseLen = 0;
|
response = ""; // Reset the response string for the next potential message
|
||||||
response[0] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG(response);
|
LOG_DEBUG(response.c_str());
|
||||||
#endif
|
#endif
|
||||||
delete[] response; // Cleanup before return
|
return GNSS_MODEL_UNKNOWN; // Return empty string on timeout
|
||||||
return GNSS_MODEL_UNKNOWN; // Return unknown on timeout
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPS *GPS::createGps()
|
GPS *GPS::createGps()
|
||||||
@@ -1456,7 +1414,7 @@ GPS *GPS::createGps()
|
|||||||
_en_gpio = PIN_GPS_EN;
|
_en_gpio = PIN_GPS_EN;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
if (!portduino_config.has_gps)
|
if (!settingsMap[has_gps])
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
|
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
|
||||||
@@ -1546,10 +1504,28 @@ static int32_t toDegInt(RawDegrees d)
|
|||||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
||||||
* Override this method to check for new locations
|
* Override this method to check for new locations
|
||||||
*
|
*
|
||||||
* @return true if we've set a new time
|
* @return true if we've acquired a new location
|
||||||
*/
|
*/
|
||||||
bool GPS::lookForTime()
|
bool GPS::lookForTime()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef GNSS_AIROHA
|
||||||
|
uint8_t fix = reader.fixQuality();
|
||||||
|
if (fix >= 1 && fix <= 5) {
|
||||||
|
if (lastFixStartMsec > 0) {
|
||||||
|
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
clearBuffer();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastFixStartMsec = millis();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
auto ti = reader.time;
|
auto ti = reader.time;
|
||||||
auto d = reader.date;
|
auto d = reader.date;
|
||||||
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
|
||||||
@@ -1566,13 +1542,13 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
|||||||
t.tm_year = d.year() - 1900;
|
t.tm_year = d.year() - 1900;
|
||||||
t.tm_isdst = false;
|
t.tm_isdst = false;
|
||||||
if (t.tm_mon > -1) {
|
if (t.tm_mon > -1) {
|
||||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultSuccess) {
|
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
|
||||||
LOG_DEBUG("NMEA GPS time set %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour,
|
t.tm_sec, ti.age());
|
||||||
t.tm_min, t.tm_sec, ti.age());
|
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultInvalidTime) {
|
||||||
return true;
|
// Clear the GPS buffer if we got an invalid time
|
||||||
} else {
|
clearBuffer();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
@@ -1587,6 +1563,25 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
|||||||
*/
|
*/
|
||||||
bool GPS::lookForLocation()
|
bool GPS::lookForLocation()
|
||||||
{
|
{
|
||||||
|
#ifdef GNSS_AIROHA
|
||||||
|
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
|
||||||
|
uint8_t fix = reader.fixQuality();
|
||||||
|
if (fix >= 1 && fix <= 5) {
|
||||||
|
if (lastFixStartMsec > 0) {
|
||||||
|
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
clearBuffer();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastFixStartMsec = millis();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
// By default, TinyGPS++ does not parse GPGSA lines, which give us
|
||||||
// the 2D/3D fixType (see NMEAGPS.h)
|
// the 2D/3D fixType (see NMEAGPS.h)
|
||||||
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ typedef enum {
|
|||||||
GNSS_MODEL_MTK_PA1616S,
|
GNSS_MODEL_MTK_PA1616S,
|
||||||
GNSS_MODEL_AG3335,
|
GNSS_MODEL_AG3335,
|
||||||
GNSS_MODEL_AG3352,
|
GNSS_MODEL_AG3352,
|
||||||
GNSS_MODEL_LS20031,
|
GNSS_MODEL_LS20031
|
||||||
GNSS_MODEL_CM121
|
|
||||||
} GnssModel_t;
|
} GnssModel_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -160,7 +159,7 @@ class GPS : private concurrency::OSThread
|
|||||||
uint8_t fixType = 0; // fix type from GPGSA
|
uint8_t fixType = 0; // fix type from GPGSA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t fixHoldEnds = 0;
|
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
|
||||||
uint32_t rx_gpio = 0;
|
uint32_t rx_gpio = 0;
|
||||||
uint32_t tx_gpio = 0;
|
uint32_t tx_gpio = 0;
|
||||||
|
|
||||||
@@ -237,7 +236,7 @@ class GPS : private concurrency::OSThread
|
|||||||
|
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
GnssModel_t getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap, int serialSpeed);
|
GnssModel_t getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap);
|
||||||
|
|
||||||
// Get GNSS model
|
// Get GNSS model
|
||||||
GnssModel_t probe(int serialSpeed);
|
GnssModel_t probe(int serialSpeed);
|
||||||
|
|||||||
112
src/gps/RTC.cpp
112
src/gps/RTC.cpp
@@ -9,9 +9,6 @@
|
|||||||
static RTCQuality currentQuality = RTCQualityNone;
|
static RTCQuality currentQuality = RTCQualityNone;
|
||||||
uint32_t lastSetFromPhoneNtpOrGps = 0;
|
uint32_t lastSetFromPhoneNtpOrGps = 0;
|
||||||
|
|
||||||
static uint32_t lastTimeValidationWarning = 0;
|
|
||||||
static const uint32_t TIME_VALIDATION_WARNING_INTERVAL_MS = 15000; // 15 seconds
|
|
||||||
|
|
||||||
RTCQuality getRTCQuality()
|
RTCQuality getRTCQuality()
|
||||||
{
|
{
|
||||||
return currentQuality;
|
return currentQuality;
|
||||||
@@ -26,7 +23,7 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
|
|||||||
* Reads the current date and time from the RTC module and updates the system time.
|
* Reads the current date and time from the RTC module and updates the system time.
|
||||||
* @return True if the RTC was successfully read and the system time was updated, false otherwise.
|
* @return True if the RTC was successfully read and the system time was updated, false otherwise.
|
||||||
*/
|
*/
|
||||||
RTCSetResult readFromRTC()
|
void readFromRTC()
|
||||||
{
|
{
|
||||||
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
||||||
#ifdef RV3028_RTC
|
#ifdef RV3028_RTC
|
||||||
@@ -47,25 +44,15 @@ RTCSetResult readFromRTC()
|
|||||||
t.tm_sec = rtc.getSecond();
|
t.tm_sec = rtc.getSecond();
|
||||||
tv.tv_sec = gm_mktime(&t);
|
tv.tv_sec = gm_mktime(&t);
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||||
|
|
||||||
#ifdef BUILD_EPOCH
|
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LOG_DEBUG("Read RTC time from RV3028 getTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
|
LOG_DEBUG("Read RTC time from RV3028 getTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
|
||||||
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
||||||
|
timeStartMsec = now;
|
||||||
|
zeroOffsetSecs = tv.tv_sec;
|
||||||
if (currentQuality == RTCQualityNone) {
|
if (currentQuality == RTCQualityNone) {
|
||||||
timeStartMsec = now;
|
|
||||||
zeroOffsetSecs = tv.tv_sec;
|
|
||||||
currentQuality = RTCQualityDevice;
|
currentQuality = RTCQualityDevice;
|
||||||
}
|
}
|
||||||
return RTCSetResultSuccess;
|
|
||||||
}
|
}
|
||||||
#elif defined(PCF8563_RTC)
|
#elif defined(PCF8563_RTC)
|
||||||
if (rtc_found.address == PCF8563_RTC) {
|
if (rtc_found.address == PCF8563_RTC) {
|
||||||
@@ -88,26 +75,15 @@ RTCSetResult readFromRTC()
|
|||||||
t.tm_sec = tc.second;
|
t.tm_sec = tc.second;
|
||||||
tv.tv_sec = gm_mktime(&t);
|
tv.tv_sec = gm_mktime(&t);
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||||
|
|
||||||
#ifdef BUILD_EPOCH
|
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
|
||||||
lastTimeValidationWarning = millis();
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LOG_DEBUG("Read RTC time from PCF8563 getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
|
LOG_DEBUG("Read RTC time from PCF8563 getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
|
||||||
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
|
||||||
|
timeStartMsec = now;
|
||||||
|
zeroOffsetSecs = tv.tv_sec;
|
||||||
if (currentQuality == RTCQualityNone) {
|
if (currentQuality == RTCQualityNone) {
|
||||||
timeStartMsec = now;
|
|
||||||
zeroOffsetSecs = tv.tv_sec;
|
|
||||||
currentQuality = RTCQualityDevice;
|
currentQuality = RTCQualityDevice;
|
||||||
}
|
}
|
||||||
return RTCSetResultSuccess;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!gettimeofday(&tv, NULL)) {
|
if (!gettimeofday(&tv, NULL)) {
|
||||||
@@ -116,10 +92,8 @@ RTCSetResult readFromRTC()
|
|||||||
LOG_DEBUG("Read RTC time as %ld", printableEpoch);
|
LOG_DEBUG("Read RTC time as %ld", printableEpoch);
|
||||||
timeStartMsec = now;
|
timeStartMsec = now;
|
||||||
zeroOffsetSecs = tv.tv_sec;
|
zeroOffsetSecs = tv.tv_sec;
|
||||||
return RTCSetResultSuccess;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return RTCSetResultNotSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +101,7 @@ RTCSetResult readFromRTC()
|
|||||||
*
|
*
|
||||||
* @param q The quality of the provided time.
|
* @param q The quality of the provided time.
|
||||||
* @param tv A pointer to a timeval struct containing the time to potentially set the RTC to.
|
* @param tv A pointer to a timeval struct containing the time to potentially set the RTC to.
|
||||||
* @return RTCSetResult
|
* @return True if the RTC was set, false otherwise.
|
||||||
*
|
*
|
||||||
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
* If we haven't yet set our RTC this boot, set it from a GPS derived time
|
||||||
*/
|
*/
|
||||||
@@ -138,20 +112,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
|||||||
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||||
#ifdef BUILD_EPOCH
|
#ifdef BUILD_EPOCH
|
||||||
if (tv->tv_sec < BUILD_EPOCH) {
|
if (tv->tv_sec < BUILD_EPOCH) {
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
|
||||||
lastTimeValidationWarning = millis();
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
|
||||||
} else if ((uint64_t)tv->tv_sec > ((uint64_t)BUILD_EPOCH + FORTY_YEARS)) {
|
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
|
||||||
// Calculate max allowed time safely to avoid overflow in logging
|
|
||||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
|
||||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
|
||||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
|
||||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
|
||||||
lastTimeValidationWarning = millis();
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
return RTCSetResultInvalidTime;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -269,20 +230,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||||
#ifdef BUILD_EPOCH
|
#ifdef BUILD_EPOCH
|
||||||
if (tv.tv_sec < BUILD_EPOCH) {
|
if (tv.tv_sec < BUILD_EPOCH) {
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
|
||||||
lastTimeValidationWarning = millis();
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
|
||||||
} else if ((uint64_t)tv.tv_sec > ((uint64_t)BUILD_EPOCH + FORTY_YEARS)) {
|
|
||||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
|
||||||
// Calculate max allowed time safely to avoid overflow in logging
|
|
||||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
|
||||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
|
||||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
|
||||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
|
||||||
lastTimeValidationWarning = millis();
|
|
||||||
}
|
|
||||||
return RTCSetResultInvalidTime;
|
return RTCSetResultInvalidTime;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -342,40 +290,14 @@ uint32_t getValidTime(RTCQuality minQuality, bool local)
|
|||||||
time_t gm_mktime(struct tm *tm)
|
time_t gm_mktime(struct tm *tm)
|
||||||
{
|
{
|
||||||
#if !MESHTASTIC_EXCLUDE_TZ
|
#if !MESHTASTIC_EXCLUDE_TZ
|
||||||
time_t result = 0;
|
setenv("TZ", "GMT0", 1);
|
||||||
|
time_t res = mktime(tm);
|
||||||
// First, get us to the start of tm->year, by calcuating the number of days since the Unix epoch.
|
if (*config.device.tzdef) {
|
||||||
int year = 1900 + tm->tm_year; // tm_year is years since 1900
|
setenv("TZ", config.device.tzdef, 1);
|
||||||
int year_minus_one = year - 1;
|
} else {
|
||||||
int days_before_this_year = 0;
|
setenv("TZ", "UTC0", 1);
|
||||||
days_before_this_year += year_minus_one * 365;
|
|
||||||
// leap days: every 4 years, except 100s, but including 400s.
|
|
||||||
days_before_this_year += year_minus_one / 4 - year_minus_one / 100 + year_minus_one / 400;
|
|
||||||
// subtract from 1970-01-01 to get days since epoch
|
|
||||||
days_before_this_year -= 719162; // (1969 * 365 + 1969 / 4 - 1969 / 100 + 1969 / 400);
|
|
||||||
|
|
||||||
// Now, within this tm->year, compute the days *before* this tm->month starts.
|
|
||||||
int days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // non-leap year
|
|
||||||
int days_this_year_before_this_month = days_before_month[tm->tm_mon]; // tm->tm_mon is 0..11
|
|
||||||
|
|
||||||
// If this is a leap year, and we're past February, add a day:
|
|
||||||
if (tm->tm_mon >= 2 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
|
|
||||||
days_this_year_before_this_month += 1;
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
// And within this month:
|
|
||||||
int days_this_month_before_today = tm->tm_mday - 1; // tm->tm_mday is 1..31
|
|
||||||
|
|
||||||
// Now combine them all together, and convert days to seconds:
|
|
||||||
result += (days_before_this_year + days_this_year_before_this_month + days_this_month_before_today);
|
|
||||||
result *= 86400L;
|
|
||||||
|
|
||||||
// Finally, add in the hours, minutes, and seconds of today:
|
|
||||||
result += tm->tm_hour * 3600;
|
|
||||||
result += tm->tm_min * 60;
|
|
||||||
result += tm->tm_sec;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
#else
|
#else
|
||||||
return mktime(tm);
|
return mktime(tm);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -48,13 +48,10 @@ uint32_t getTime(bool local = false);
|
|||||||
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
|
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
|
||||||
uint32_t getValidTime(RTCQuality minQuality, bool local = false);
|
uint32_t getValidTime(RTCQuality minQuality, bool local = false);
|
||||||
|
|
||||||
RTCSetResult readFromRTC();
|
void readFromRTC();
|
||||||
|
|
||||||
time_t gm_mktime(struct tm *tm);
|
time_t gm_mktime(struct tm *tm);
|
||||||
|
|
||||||
#define SEC_PER_DAY 86400
|
#define SEC_PER_DAY 86400
|
||||||
#define SEC_PER_HOUR 3600
|
#define SEC_PER_HOUR 3600
|
||||||
#define SEC_PER_MIN 60
|
#define SEC_PER_MIN 60
|
||||||
#ifdef BUILD_EPOCH
|
|
||||||
static constexpr uint64_t FORTY_YEARS = (40ULL * 365 * SEC_PER_DAY); // Use 64-bit arithmetic to prevent overflow
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -67,28 +67,20 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
|
|
||||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||||
const bool flipped = config.display.flip_screen;
|
const bool flipped = config.display.flip_screen;
|
||||||
// HACK for L1 EInk
|
|
||||||
#if defined(SEEED_WIO_TRACKER_L1_EINK)
|
|
||||||
// For SEEED_WIO_TRACKER_L1_EINK, setRotation(3) is correct but mirrored; flip both axes
|
|
||||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
|
||||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
|
||||||
auto isset = b & (1 << (y & 7));
|
|
||||||
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||||
|
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
auto b = buffer[x + (y / 8) * displayWidth];
|
||||||
auto isset = b & (1 << (y & 7));
|
auto isset = b & (1 << (y & 7));
|
||||||
|
|
||||||
|
// Handle flip here, rather than with setRotation(),
|
||||||
|
// Avoids issues when display width is not a multiple of 8
|
||||||
if (flipped)
|
if (flipped)
|
||||||
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||||
else
|
else
|
||||||
adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Trigger the refresh in GxEPD2
|
// Trigger the refresh in GxEPD2
|
||||||
LOG_DEBUG("Update E-Paper");
|
LOG_DEBUG("Update E-Paper");
|
||||||
@@ -243,7 +235,7 @@ bool EInkDisplay::connect()
|
|||||||
adafruitDisplay->setRotation(1);
|
adafruitDisplay->setRotation(1);
|
||||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||||
}
|
}
|
||||||
#elif defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK)
|
#elif defined(HELTEC_MESH_POCKET)
|
||||||
{
|
{
|
||||||
spi1 = &SPI1;
|
spi1 = &SPI1;
|
||||||
spi1->begin();
|
spi1->begin();
|
||||||
@@ -257,7 +249,6 @@ bool EInkDisplay::connect()
|
|||||||
// Init GxEPD2
|
// Init GxEPD2
|
||||||
adafruitDisplay->init();
|
adafruitDisplay->init();
|
||||||
adafruitDisplay->setRotation(3);
|
adafruitDisplay->setRotation(3);
|
||||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
|
||||||
}
|
}
|
||||||
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class EInkDisplay : public OLEDDisplay
|
|||||||
SPIClass *hspi = NULL;
|
SPIClass *hspi = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK)
|
#if defined(HELTEC_MESH_POCKET)
|
||||||
SPIClass *spi1 = NULL;
|
SPIClass *spi1 = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "PowerMon.h"
|
#include "PowerMon.h"
|
||||||
#include "Throttle.h"
|
#include "Throttle.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "meshUtils.h"
|
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
|
|
||||||
@@ -59,6 +58,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||||||
|
#include "meshUtils.h"
|
||||||
#include "modules/ExternalNotificationModule.h"
|
#include "modules/ExternalNotificationModule.h"
|
||||||
#include "modules/TextMessageModule.h"
|
#include "modules/TextMessageModule.h"
|
||||||
#include "modules/WaypointModule.h"
|
#include "modules/WaypointModule.h"
|
||||||
@@ -355,16 +355,8 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
|||||||
#elif defined(USE_SSD1306)
|
#elif defined(USE_SSD1306)
|
||||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
#elif defined(USE_SPISSD1306)
|
|
||||||
dispdev = new SSD1306Spi(SSD1306_RESET, SSD1306_RS, SSD1306_NSS, GEOMETRY_64_48);
|
|
||||||
if (!dispdev->init()) {
|
|
||||||
LOG_DEBUG("Error: SSD1306 not detected!");
|
|
||||||
} else {
|
|
||||||
static_cast<SSD1306Spi *>(dispdev)->setHorizontalOffset(32);
|
|
||||||
LOG_INFO("SSD1306 init success");
|
|
||||||
}
|
|
||||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
||||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
||||||
@@ -378,7 +370,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
|||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
#elif ARCH_PORTDUINO
|
#elif ARCH_PORTDUINO
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
if (portduino_config.displayPanel != no_screen) {
|
if (settingsMap[displayPanel] != no_screen) {
|
||||||
LOG_DEBUG("Make TFTDisplay!");
|
LOG_DEBUG("Make TFTDisplay!");
|
||||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
@@ -553,7 +545,7 @@ void Screen::setup()
|
|||||||
// === Apply loaded brightness ===
|
// === Apply loaded brightness ===
|
||||||
#if defined(ST7789_CS)
|
#if defined(ST7789_CS)
|
||||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SPISSD1306)
|
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||||
dispdev->setBrightness(brightness);
|
dispdev->setBrightness(brightness);
|
||||||
#endif
|
#endif
|
||||||
LOG_INFO("Applied screen brightness: %d", brightness);
|
LOG_INFO("Applied screen brightness: %d", brightness);
|
||||||
@@ -596,11 +588,11 @@ void Screen::setup()
|
|||||||
#else
|
#else
|
||||||
if (!config.display.flip_screen) {
|
if (!config.display.flip_screen) {
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||||
#elif defined(USE_ST7789)
|
#elif defined(USE_ST7789)
|
||||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||||
#elif !defined(M5STACK_UNITC6L)
|
#else
|
||||||
dispdev->flipScreenVertically();
|
dispdev->flipScreenVertically();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -626,7 +618,7 @@ void Screen::setup()
|
|||||||
|
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
if (portduino_config.touchscreenModule) {
|
if (settingsMap[touchscreenModule]) {
|
||||||
touchScreenImpl1 =
|
touchScreenImpl1 =
|
||||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||||
touchScreenImpl1->init();
|
touchScreenImpl1->init();
|
||||||
@@ -738,11 +730,7 @@ int32_t Screen::runOnce()
|
|||||||
|
|
||||||
#ifndef DISABLE_WELCOME_UNSET
|
#ifndef DISABLE_WELCOME_UNSET
|
||||||
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
menuHandler::LoraRegionPicker();
|
|
||||||
#else
|
|
||||||
menuHandler::OnboardMessage();
|
menuHandler::OnboardMessage();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
|
if (!NotificationRenderer::isOverlayBannerShowing() && rebootAtMsec != 0) {
|
||||||
@@ -953,95 +941,71 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DISPLAY_CLOCK_FRAME)
|
#if defined(DISPLAY_CLOCK_FRAME)
|
||||||
if (!hiddenFrames.clock) {
|
fsi.positions.clock = numframes;
|
||||||
fsi.positions.clock = numframes;
|
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||||
#if defined(M5STACK_UNITC6L)
|
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||||
normalFrames[numframes++] = graphics::ClockRenderer::drawAnalogClockFrame;
|
indicatorIcons.push_back(digital_icon_clock);
|
||||||
#else
|
|
||||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
|
||||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
|
||||||
#endif
|
|
||||||
indicatorIcons.push_back(digital_icon_clock);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Declare this early so it’s available in FOCUS_PRESERVE block
|
// Declare this early so it’s available in FOCUS_PRESERVE block
|
||||||
bool willInsertTextMessage = shouldDrawMessage(&devicestate.rx_text_message);
|
bool willInsertTextMessage = shouldDrawMessage(&devicestate.rx_text_message);
|
||||||
|
|
||||||
if (!hiddenFrames.home) {
|
fsi.positions.home = numframes;
|
||||||
fsi.positions.home = numframes;
|
normalFrames[numframes++] = graphics::UIRenderer::drawDeviceFocused;
|
||||||
normalFrames[numframes++] = graphics::UIRenderer::drawDeviceFocused;
|
indicatorIcons.push_back(icon_home);
|
||||||
indicatorIcons.push_back(icon_home);
|
|
||||||
}
|
|
||||||
|
|
||||||
fsi.positions.textMessage = numframes;
|
fsi.positions.textMessage = numframes;
|
||||||
normalFrames[numframes++] = graphics::MessageRenderer::drawTextMessageFrame;
|
normalFrames[numframes++] = graphics::MessageRenderer::drawTextMessageFrame;
|
||||||
indicatorIcons.push_back(icon_mail);
|
indicatorIcons.push_back(icon_mail);
|
||||||
|
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
if (!hiddenFrames.nodelist) {
|
fsi.positions.nodelist = numframes;
|
||||||
fsi.positions.nodelist = numframes;
|
normalFrames[numframes++] = graphics::NodeListRenderer::drawDynamicNodeListScreen;
|
||||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawDynamicNodeListScreen;
|
indicatorIcons.push_back(icon_nodes);
|
||||||
indicatorIcons.push_back(icon_nodes);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Show detailed node views only on E-Ink builds
|
// Show detailed node views only on E-Ink builds
|
||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
if (!hiddenFrames.nodelist_lastheard) {
|
fsi.positions.nodelist_lastheard = numframes;
|
||||||
fsi.positions.nodelist_lastheard = numframes;
|
normalFrames[numframes++] = graphics::NodeListRenderer::drawLastHeardScreen;
|
||||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawLastHeardScreen;
|
indicatorIcons.push_back(icon_nodes);
|
||||||
indicatorIcons.push_back(icon_nodes);
|
|
||||||
}
|
fsi.positions.nodelist_hopsignal = numframes;
|
||||||
if (!hiddenFrames.nodelist_hopsignal) {
|
normalFrames[numframes++] = graphics::NodeListRenderer::drawHopSignalScreen;
|
||||||
fsi.positions.nodelist_hopsignal = numframes;
|
indicatorIcons.push_back(icon_signal);
|
||||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawHopSignalScreen;
|
|
||||||
indicatorIcons.push_back(icon_signal);
|
fsi.positions.nodelist_distance = numframes;
|
||||||
}
|
normalFrames[numframes++] = graphics::NodeListRenderer::drawDistanceScreen;
|
||||||
if (!hiddenFrames.nodelist_distance) {
|
indicatorIcons.push_back(icon_distance);
|
||||||
fsi.positions.nodelist_distance = numframes;
|
|
||||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawDistanceScreen;
|
|
||||||
indicatorIcons.push_back(icon_distance);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#if HAS_GPS
|
#if HAS_GPS
|
||||||
if (!hiddenFrames.nodelist_bearings) {
|
fsi.positions.nodelist_bearings = numframes;
|
||||||
fsi.positions.nodelist_bearings = numframes;
|
normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses;
|
||||||
normalFrames[numframes++] = graphics::NodeListRenderer::drawNodeListWithCompasses;
|
indicatorIcons.push_back(icon_list);
|
||||||
indicatorIcons.push_back(icon_list);
|
|
||||||
}
|
fsi.positions.gps = numframes;
|
||||||
if (!hiddenFrames.gps) {
|
normalFrames[numframes++] = graphics::UIRenderer::drawCompassAndLocationScreen;
|
||||||
fsi.positions.gps = numframes;
|
indicatorIcons.push_back(icon_compass);
|
||||||
normalFrames[numframes++] = graphics::UIRenderer::drawCompassAndLocationScreen;
|
|
||||||
indicatorIcons.push_back(icon_compass);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (RadioLibInterface::instance && !hiddenFrames.lora) {
|
if (RadioLibInterface::instance) {
|
||||||
fsi.positions.lora = numframes;
|
fsi.positions.lora = numframes;
|
||||||
normalFrames[numframes++] = graphics::DebugRenderer::drawLoRaFocused;
|
normalFrames[numframes++] = graphics::DebugRenderer::drawLoRaFocused;
|
||||||
indicatorIcons.push_back(icon_radio);
|
indicatorIcons.push_back(icon_radio);
|
||||||
}
|
}
|
||||||
if (!hiddenFrames.system) {
|
if (!dismissedFrames.memory) {
|
||||||
fsi.positions.system = numframes;
|
fsi.positions.memory = numframes;
|
||||||
normalFrames[numframes++] = graphics::DebugRenderer::drawSystemScreen;
|
normalFrames[numframes++] = graphics::DebugRenderer::drawMemoryUsage;
|
||||||
indicatorIcons.push_back(icon_system);
|
indicatorIcons.push_back(icon_memory);
|
||||||
}
|
}
|
||||||
#if !defined(DISPLAY_CLOCK_FRAME)
|
#if !defined(DISPLAY_CLOCK_FRAME)
|
||||||
if (!hiddenFrames.clock) {
|
fsi.positions.clock = numframes;
|
||||||
fsi.positions.clock = numframes;
|
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
: graphics::ClockRenderer::drawDigitalClockFrame;
|
||||||
: graphics::ClockRenderer::drawDigitalClockFrame;
|
indicatorIcons.push_back(digital_icon_clock);
|
||||||
indicatorIcons.push_back(digital_icon_clock);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (!hiddenFrames.chirpy) {
|
|
||||||
fsi.positions.chirpy = numframes;
|
|
||||||
normalFrames[numframes++] = graphics::DebugRenderer::drawChirpy;
|
|
||||||
indicatorIcons.push_back(chirpy_small);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||||
if (!hiddenFrames.wifi && isWifiAvailable()) {
|
if (!dismissedFrames.wifi && isWifiAvailable()) {
|
||||||
fsi.positions.wifi = numframes;
|
fsi.positions.wifi = numframes;
|
||||||
normalFrames[numframes++] = graphics::DebugRenderer::drawDebugInfoWiFiTrampoline;
|
normalFrames[numframes++] = graphics::DebugRenderer::drawDebugInfoWiFiTrampoline;
|
||||||
indicatorIcons.push_back(icon_wifi);
|
indicatorIcons.push_back(icon_wifi);
|
||||||
@@ -1083,29 +1047,27 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
if (numMeshNodes > 0)
|
if (numMeshNodes > 0)
|
||||||
numMeshNodes--;
|
numMeshNodes--;
|
||||||
|
|
||||||
if (!hiddenFrames.show_favorites) {
|
// Temporary array to hold favorite node frames
|
||||||
// Temporary array to hold favorite node frames
|
std::vector<FrameCallback> favoriteFrames;
|
||||||
std::vector<FrameCallback> favoriteFrames;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||||
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||||
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
||||||
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
|
favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert favorite frames *after* collecting them all
|
// Insert favorite frames *after* collecting them all
|
||||||
if (!favoriteFrames.empty()) {
|
if (!favoriteFrames.empty()) {
|
||||||
fsi.positions.firstFavorite = numframes;
|
fsi.positions.firstFavorite = numframes;
|
||||||
for (const auto &f : favoriteFrames) {
|
for (const auto &f : favoriteFrames) {
|
||||||
normalFrames[numframes++] = f;
|
normalFrames[numframes++] = f;
|
||||||
indicatorIcons.push_back(icon_node);
|
indicatorIcons.push_back(icon_node);
|
||||||
}
|
|
||||||
fsi.positions.lastFavorite = numframes - 1;
|
|
||||||
} else {
|
|
||||||
fsi.positions.firstFavorite = 255;
|
|
||||||
fsi.positions.lastFavorite = 255;
|
|
||||||
}
|
}
|
||||||
|
fsi.positions.lastFavorite = numframes - 1;
|
||||||
|
} else {
|
||||||
|
fsi.positions.firstFavorite = 255;
|
||||||
|
fsi.positions.lastFavorite = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
||||||
@@ -1144,7 +1106,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
ui->switchToFrame(fsi.positions.clock);
|
ui->switchToFrame(fsi.positions.clock);
|
||||||
break;
|
break;
|
||||||
case FOCUS_SYSTEM:
|
case FOCUS_SYSTEM:
|
||||||
ui->switchToFrame(fsi.positions.system);
|
ui->switchToFrame(fsi.positions.memory);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FOCUS_PRESERVE:
|
case FOCUS_PRESERVE:
|
||||||
@@ -1172,101 +1134,30 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
|
|||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::toggleFrameVisibility(const std::string &frameName)
|
|
||||||
{
|
|
||||||
#ifndef USE_EINK
|
|
||||||
if (frameName == "nodelist") {
|
|
||||||
hiddenFrames.nodelist = !hiddenFrames.nodelist;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef USE_EINK
|
|
||||||
if (frameName == "nodelist_lastheard") {
|
|
||||||
hiddenFrames.nodelist_lastheard = !hiddenFrames.nodelist_lastheard;
|
|
||||||
}
|
|
||||||
if (frameName == "nodelist_hopsignal") {
|
|
||||||
hiddenFrames.nodelist_hopsignal = !hiddenFrames.nodelist_hopsignal;
|
|
||||||
}
|
|
||||||
if (frameName == "nodelist_distance") {
|
|
||||||
hiddenFrames.nodelist_distance = !hiddenFrames.nodelist_distance;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if HAS_GPS
|
|
||||||
if (frameName == "nodelist_bearings") {
|
|
||||||
hiddenFrames.nodelist_bearings = !hiddenFrames.nodelist_bearings;
|
|
||||||
}
|
|
||||||
if (frameName == "gps") {
|
|
||||||
hiddenFrames.gps = !hiddenFrames.gps;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (frameName == "lora") {
|
|
||||||
hiddenFrames.lora = !hiddenFrames.lora;
|
|
||||||
}
|
|
||||||
if (frameName == "clock") {
|
|
||||||
hiddenFrames.clock = !hiddenFrames.clock;
|
|
||||||
}
|
|
||||||
if (frameName == "show_favorites") {
|
|
||||||
hiddenFrames.show_favorites = !hiddenFrames.show_favorites;
|
|
||||||
}
|
|
||||||
if (frameName == "chirpy") {
|
|
||||||
hiddenFrames.chirpy = !hiddenFrames.chirpy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Screen::isFrameHidden(const std::string &frameName) const
|
|
||||||
{
|
|
||||||
#ifndef USE_EINK
|
|
||||||
if (frameName == "nodelist")
|
|
||||||
return hiddenFrames.nodelist;
|
|
||||||
#endif
|
|
||||||
#ifdef USE_EINK
|
|
||||||
if (frameName == "nodelist_lastheard")
|
|
||||||
return hiddenFrames.nodelist_lastheard;
|
|
||||||
if (frameName == "nodelist_hopsignal")
|
|
||||||
return hiddenFrames.nodelist_hopsignal;
|
|
||||||
if (frameName == "nodelist_distance")
|
|
||||||
return hiddenFrames.nodelist_distance;
|
|
||||||
#endif
|
|
||||||
#if HAS_GPS
|
|
||||||
if (frameName == "nodelist_bearings")
|
|
||||||
return hiddenFrames.nodelist_bearings;
|
|
||||||
if (frameName == "gps")
|
|
||||||
return hiddenFrames.gps;
|
|
||||||
#endif
|
|
||||||
if (frameName == "lora")
|
|
||||||
return hiddenFrames.lora;
|
|
||||||
if (frameName == "clock")
|
|
||||||
return hiddenFrames.clock;
|
|
||||||
if (frameName == "show_favorites")
|
|
||||||
return hiddenFrames.show_favorites;
|
|
||||||
if (frameName == "chirpy")
|
|
||||||
return hiddenFrames.chirpy;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dismisses the currently displayed screen frame, if possible
|
// Dismisses the currently displayed screen frame, if possible
|
||||||
// Relevant for text message, waypoint, others in future?
|
// Relevant for text message, waypoint, others in future?
|
||||||
// Triggered with a CardKB keycombo
|
// Triggered with a CardKB keycombo
|
||||||
void Screen::hideCurrentFrame()
|
void Screen::dismissCurrentFrame()
|
||||||
{
|
{
|
||||||
uint8_t currentFrame = ui->getUiState()->currentFrame;
|
uint8_t currentFrame = ui->getUiState()->currentFrame;
|
||||||
bool dismissed = false;
|
bool dismissed = false;
|
||||||
|
|
||||||
if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
|
if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
|
||||||
LOG_INFO("Hide Text Message");
|
LOG_INFO("Dismiss Text Message");
|
||||||
devicestate.has_rx_text_message = false;
|
devicestate.has_rx_text_message = false;
|
||||||
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
|
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
|
||||||
} else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
|
} else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
|
||||||
LOG_DEBUG("Hide Waypoint");
|
LOG_DEBUG("Dismiss Waypoint");
|
||||||
devicestate.has_rx_waypoint = false;
|
devicestate.has_rx_waypoint = false;
|
||||||
hiddenFrames.waypoint = true;
|
dismissedFrames.waypoint = true;
|
||||||
dismissed = true;
|
dismissed = true;
|
||||||
} else if (currentFrame == framesetInfo.positions.wifi) {
|
} else if (currentFrame == framesetInfo.positions.wifi) {
|
||||||
LOG_DEBUG("Hide WiFi Screen");
|
LOG_DEBUG("Dismiss WiFi Screen");
|
||||||
hiddenFrames.wifi = true;
|
dismissedFrames.wifi = true;
|
||||||
dismissed = true;
|
dismissed = true;
|
||||||
} else if (currentFrame == framesetInfo.positions.lora) {
|
} else if (currentFrame == framesetInfo.positions.memory) {
|
||||||
LOG_INFO("Hide LoRa");
|
LOG_INFO("Dismiss Memory");
|
||||||
hiddenFrames.lora = true;
|
dismissedFrames.memory = true;
|
||||||
dismissed = true;
|
dismissed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,8 +1190,7 @@ void Screen::blink()
|
|||||||
delay(50);
|
delay(50);
|
||||||
count = count - 1;
|
count = count - 1;
|
||||||
}
|
}
|
||||||
// The dispdev->setBrightness does not work for t-deck display, it seems to run the setBrightness function in
|
// The dispdev->setBrightness does not work for t-deck display, it seems to run the setBrightness function in OLEDDisplay.
|
||||||
// OLEDDisplay.
|
|
||||||
dispdev->setBrightness(brightness);
|
dispdev->setBrightness(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1388,10 +1278,6 @@ void Screen::handleShowNextFrame()
|
|||||||
|
|
||||||
void Screen::setFastFramerate()
|
void Screen::setFastFramerate()
|
||||||
{
|
{
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
dispdev->clear();
|
|
||||||
dispdev->display();
|
|
||||||
#endif
|
|
||||||
// We are about to start a transition so speed up fps
|
// We are about to start a transition so speed up fps
|
||||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||||
|
|
||||||
@@ -1423,7 +1309,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
|||||||
// Outgoing message (likely sent from phone)
|
// Outgoing message (likely sent from phone)
|
||||||
devicestate.has_rx_text_message = false;
|
devicestate.has_rx_text_message = false;
|
||||||
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
|
memset(&devicestate.rx_text_message, 0, sizeof(devicestate.rx_text_message));
|
||||||
hiddenFrames.textMessage = true;
|
dismissedFrames.textMessage = true;
|
||||||
hasUnreadMessage = false; // Clear unread state when user replies
|
hasUnreadMessage = false; // Clear unread state when user replies
|
||||||
|
|
||||||
setFrames(FOCUS_PRESERVE); // Stay on same frame, silently update frame list
|
setFrames(FOCUS_PRESERVE); // Stay on same frame, silently update frame list
|
||||||
@@ -1463,23 +1349,13 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (longName && longName[0]) {
|
if (longName && longName[0]) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
strcpy(banner, "New Message");
|
|
||||||
#else
|
|
||||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
strcpy(banner, "New Message");
|
strcpy(banner, "New Message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
screen->setOn(true);
|
|
||||||
screen->showSimpleBanner(banner, 1500);
|
|
||||||
playLongBeep();
|
|
||||||
#else
|
|
||||||
screen->showSimpleBanner(banner, 3000);
|
screen->showSimpleBanner(banner, 3000);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1563,7 +1439,7 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
} else if (event->inputEvent == INPUT_BROKER_SELECT) {
|
||||||
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
if (this->ui->getUiState()->currentFrame == framesetInfo.positions.home) {
|
||||||
menuHandler::homeBaseMenu();
|
menuHandler::homeBaseMenu();
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.system) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.memory) {
|
||||||
menuHandler::systemBaseMenu();
|
menuHandler::systemBaseMenu();
|
||||||
#if HAS_GPS
|
#if HAS_GPS
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.gps && gps) {
|
||||||
@@ -1572,16 +1448,12 @@ int Screen::handleInputEvent(const InputEvent *event)
|
|||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.clock) {
|
||||||
menuHandler::clockMenu();
|
menuHandler::clockMenu();
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
|
||||||
menuHandler::loraMenu();
|
menuHandler::LoraRegionPicker();
|
||||||
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
|
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
|
||||||
if (devicestate.rx_text_message.from) {
|
if (devicestate.rx_text_message.from) {
|
||||||
menuHandler::messageResponseMenu();
|
menuHandler::messageResponseMenu();
|
||||||
} else {
|
} else {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
menuHandler::textMessageMenu();
|
|
||||||
#else
|
|
||||||
menuHandler::textMessageBaseMenu();
|
menuHandler::textMessageBaseMenu();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
} else if (framesetInfo.positions.firstFavorite != 255 &&
|
||||||
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
this->ui->getUiState()->currentFrame >= framesetInfo.positions.firstFavorite &&
|
||||||
@@ -1640,15 +1512,13 @@ bool shouldWakeOnReceivedMessage()
|
|||||||
/*
|
/*
|
||||||
The goal here is to determine when we do NOT wake up the screen on message received:
|
The goal here is to determine when we do NOT wake up the screen on message received:
|
||||||
- Any ext. notifications are turned on
|
- Any ext. notifications are turned on
|
||||||
- If role is not CLIENT / CLIENT_MUTE / CLIENT_HIDDEN / CLIENT_BASE
|
- If role is not client / client_mute
|
||||||
- If the battery level is very low
|
- If the battery level is very low
|
||||||
*/
|
*/
|
||||||
if (moduleConfig.external_notification.enabled) {
|
if (moduleConfig.external_notification.enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_CLIENT,
|
if (!meshtastic_Config_DeviceConfig_Role_CLIENT && !meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) {
|
||||||
meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE, meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN,
|
|
||||||
meshtastic_Config_DeviceConfig_Role_CLIENT_BASE)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (powerStatus && powerStatus->getBatteryChargePercent() < 10) {
|
if (powerStatus && powerStatus->getBatteryChargePercent() < 10) {
|
||||||
|
|||||||
@@ -81,8 +81,6 @@ class Screen
|
|||||||
#include <SSD1306Wire.h>
|
#include <SSD1306Wire.h>
|
||||||
#elif defined(USE_ST7789)
|
#elif defined(USE_ST7789)
|
||||||
#include <ST7789Spi.h>
|
#include <ST7789Spi.h>
|
||||||
#elif defined(USE_SPISSD1306)
|
|
||||||
#include <SSD1306Spi.h>
|
|
||||||
#else
|
#else
|
||||||
// the SH1106/SSD1306 variant is auto-detected
|
// the SH1106/SSD1306 variant is auto-detected
|
||||||
#include <AutoOLEDWire.h>
|
#include <AutoOLEDWire.h>
|
||||||
@@ -595,11 +593,7 @@ class Screen : public concurrency::OSThread
|
|||||||
void setSSLFrames();
|
void setSSLFrames();
|
||||||
|
|
||||||
// Dismiss the currently focussed frame, if possible (e.g. text message, waypoint)
|
// Dismiss the currently focussed frame, if possible (e.g. text message, waypoint)
|
||||||
void hideCurrentFrame();
|
void dismissCurrentFrame();
|
||||||
|
|
||||||
// Menu-driven Show / Hide Toggle
|
|
||||||
void toggleFrameVisibility(const std::string &frameName);
|
|
||||||
bool isFrameHidden(const std::string &frameName) const;
|
|
||||||
|
|
||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
/// Draw an image to remain on E-Ink display after screen off
|
/// Draw an image to remain on E-Ink display after screen off
|
||||||
@@ -661,7 +655,7 @@ class Screen : public concurrency::OSThread
|
|||||||
uint8_t settings = 255;
|
uint8_t settings = 255;
|
||||||
uint8_t wifi = 255;
|
uint8_t wifi = 255;
|
||||||
uint8_t deviceFocused = 255;
|
uint8_t deviceFocused = 255;
|
||||||
uint8_t system = 255;
|
uint8_t memory = 255;
|
||||||
uint8_t gps = 255;
|
uint8_t gps = 255;
|
||||||
uint8_t home = 255;
|
uint8_t home = 255;
|
||||||
uint8_t textMessage = 255;
|
uint8_t textMessage = 255;
|
||||||
@@ -671,7 +665,6 @@ class Screen : public concurrency::OSThread
|
|||||||
uint8_t nodelist_distance = 255;
|
uint8_t nodelist_distance = 255;
|
||||||
uint8_t nodelist_bearings = 255;
|
uint8_t nodelist_bearings = 255;
|
||||||
uint8_t clock = 255;
|
uint8_t clock = 255;
|
||||||
uint8_t chirpy = 255;
|
|
||||||
uint8_t firstFavorite = 255;
|
uint8_t firstFavorite = 255;
|
||||||
uint8_t lastFavorite = 255;
|
uint8_t lastFavorite = 255;
|
||||||
uint8_t lora = 255;
|
uint8_t lora = 255;
|
||||||
@@ -680,29 +673,12 @@ class Screen : public concurrency::OSThread
|
|||||||
uint8_t frameCount = 0;
|
uint8_t frameCount = 0;
|
||||||
} framesetInfo;
|
} framesetInfo;
|
||||||
|
|
||||||
struct hiddenFrames {
|
struct DismissedFrames {
|
||||||
bool textMessage = false;
|
bool textMessage = false;
|
||||||
bool waypoint = false;
|
bool waypoint = false;
|
||||||
bool wifi = false;
|
bool wifi = false;
|
||||||
bool system = false;
|
bool memory = false;
|
||||||
bool home = false;
|
} dismissedFrames;
|
||||||
bool clock = false;
|
|
||||||
#ifndef USE_EINK
|
|
||||||
bool nodelist = false;
|
|
||||||
#endif
|
|
||||||
#ifdef USE_EINK
|
|
||||||
bool nodelist_lastheard = false;
|
|
||||||
bool nodelist_hopsignal = false;
|
|
||||||
bool nodelist_distance = false;
|
|
||||||
#endif
|
|
||||||
#if HAS_GPS
|
|
||||||
bool nodelist_bearings = false;
|
|
||||||
bool gps = false;
|
|
||||||
#endif
|
|
||||||
bool lora = false;
|
|
||||||
bool show_favorites = false;
|
|
||||||
bool chirpy = true;
|
|
||||||
} hiddenFrames;
|
|
||||||
|
|
||||||
/// Try to start drawing ASAP
|
/// Try to start drawing ASAP
|
||||||
void setFastFramerate();
|
void setFastFramerate();
|
||||||
|
|||||||
@@ -73,16 +73,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
// The screen is bigger so use bigger fonts
|
// The screen is bigger so use bigger fonts
|
||||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||||
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
||||||
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
||||||
#elif defined(M5STACK_UNITC6L)
|
|
||||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
|
||||||
#define FONT_MEDIUM FONT_SMALL_LOCAL // Height: 13
|
|
||||||
#define FONT_LARGE FONT_SMALL_LOCAL // Height: 13
|
|
||||||
#else
|
#else
|
||||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
||||||
#define FONT_MEDIUM FONT_MEDIUM_LOCAL // Height: 19
|
#define FONT_MEDIUM FONT_MEDIUM_LOCAL // Height: 19
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/draw/UIRenderer.h"
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshtastic/config.pb.h"
|
#include "meshtastic/config.pb.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
@@ -17,10 +16,6 @@ void determineResolution(int16_t screenheight, int16_t screenwidth)
|
|||||||
isHighResolution = true;
|
isHighResolution = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (screenwidth > 128 && screenheight <= 64) {
|
|
||||||
isHighResolution = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for Heltec Wireless Tracker v1.1
|
// Special case for Heltec Wireless Tracker v1.1
|
||||||
if (screenwidth == 160 && screenheight == 80) {
|
if (screenwidth == 160 && screenheight == 80) {
|
||||||
isHighResolution = false;
|
isHighResolution = false;
|
||||||
@@ -58,7 +53,7 @@ void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w,
|
|||||||
// *************************
|
// *************************
|
||||||
// * Common Header Drawing *
|
// * Common Header Drawing *
|
||||||
// *************************
|
// *************************
|
||||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool force_no_invert, bool show_date)
|
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only)
|
||||||
{
|
{
|
||||||
constexpr int HEADER_OFFSET_Y = 1;
|
constexpr int HEADER_OFFSET_Y = 1;
|
||||||
y += HEADER_OFFSET_Y;
|
y += HEADER_OFFSET_Y;
|
||||||
@@ -74,7 +69,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
const int screenW = display->getWidth();
|
const int screenW = display->getWidth();
|
||||||
const int screenH = display->getHeight();
|
const int screenH = display->getHeight();
|
||||||
|
|
||||||
if (!force_no_invert) {
|
if (!battery_only) {
|
||||||
// === Inverted Header Background ===
|
// === Inverted Header Background ===
|
||||||
if (isInverted) {
|
if (isInverted) {
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
@@ -129,7 +124,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
|
|
||||||
int batteryX = 1;
|
int batteryX = 1;
|
||||||
int batteryY = HEADER_OFFSET_Y + 1;
|
int batteryY = HEADER_OFFSET_Y + 1;
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
// === Battery Icons ===
|
// === Battery Icons ===
|
||||||
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
||||||
batteryX += 1;
|
batteryX += 1;
|
||||||
@@ -192,28 +187,13 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
int timeStrWidth = display->getStringWidth("12:34"); // Default alignment
|
int timeStrWidth = display->getStringWidth("12:34"); // Default alignment
|
||||||
int timeX = screenW - xOffset - timeStrWidth + 4;
|
int timeX = screenW - xOffset - timeStrWidth + 4;
|
||||||
|
|
||||||
if (rtc_sec > 0) {
|
if (rtc_sec > 0 && !battery_only) {
|
||||||
// === Build Time String ===
|
// === Build Time String ===
|
||||||
long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY;
|
long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY;
|
||||||
int hour = hms / SEC_PER_HOUR;
|
int hour = hms / SEC_PER_HOUR;
|
||||||
int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||||
snprintf(timeStr, sizeof(timeStr), "%d:%02d", hour, minute);
|
snprintf(timeStr, sizeof(timeStr), "%d:%02d", hour, minute);
|
||||||
|
|
||||||
// === Build Date String ===
|
|
||||||
char datetimeStr[25];
|
|
||||||
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, false);
|
|
||||||
char dateLine[40];
|
|
||||||
|
|
||||||
if (isHighResolution) {
|
|
||||||
snprintf(dateLine, sizeof(dateLine), "%s", datetimeStr);
|
|
||||||
} else {
|
|
||||||
if (hasUnreadMessage) {
|
|
||||||
snprintf(dateLine, sizeof(dateLine), "%s", &datetimeStr[5]);
|
|
||||||
} else {
|
|
||||||
snprintf(dateLine, sizeof(dateLine), "%s", &datetimeStr[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.display.use_12h_clock) {
|
if (config.display.use_12h_clock) {
|
||||||
bool isPM = hour >= 12;
|
bool isPM = hour >= 12;
|
||||||
hour %= 12;
|
hour %= 12;
|
||||||
@@ -222,11 +202,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
snprintf(timeStr, sizeof(timeStr), "%d:%02d%s", hour, minute, isPM ? "p" : "a");
|
snprintf(timeStr, sizeof(timeStr), "%d:%02d%s", hour, minute, isPM ? "p" : "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_date) {
|
timeStrWidth = display->getStringWidth(timeStr);
|
||||||
timeStrWidth = display->getStringWidth(dateLine);
|
|
||||||
} else {
|
|
||||||
timeStrWidth = display->getStringWidth(timeStr);
|
|
||||||
}
|
|
||||||
timeX = screenW - xOffset - timeStrWidth + 3;
|
timeX = screenW - xOffset - timeStrWidth + 3;
|
||||||
|
|
||||||
// === Show Mail or Mute Icon to the Left of Time ===
|
// === Show Mail or Mute Icon to the Left of Time ===
|
||||||
@@ -253,7 +229,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
int iconW = 16, iconH = 12;
|
int iconW = 16, iconH = 12;
|
||||||
int iconX = iconRightEdge - iconW;
|
int iconX = iconRightEdge - iconW;
|
||||||
int iconY = textY + (FONT_HEIGHT_SMALL - iconH) / 2 - 1;
|
int iconY = textY + (FONT_HEIGHT_SMALL - iconH) / 2 - 1;
|
||||||
if (isInverted && !force_no_invert) {
|
if (isInverted) {
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
display->fillRect(iconX - 1, iconY - 1, iconW + 3, iconH + 2);
|
display->fillRect(iconX - 1, iconY - 1, iconW + 3, iconH + 2);
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
@@ -268,7 +244,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
} else {
|
} else {
|
||||||
int iconX = iconRightEdge - (mail_width - 2);
|
int iconX = iconRightEdge - (mail_width - 2);
|
||||||
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
||||||
if (isInverted && !force_no_invert) {
|
if (isInverted) {
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
display->fillRect(iconX - 1, iconY - 1, mail_width + 2, mail_height + 2);
|
display->fillRect(iconX - 1, iconY - 1, mail_width + 2, mail_height + 2);
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
@@ -311,17 +287,10 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_date) {
|
// === Draw Time ===
|
||||||
// === Draw Date ===
|
display->drawString(timeX, textY, timeStr);
|
||||||
display->drawString(timeX, textY, dateLine);
|
if (isBold)
|
||||||
if (isBold)
|
display->drawString(timeX - 1, textY, timeStr);
|
||||||
display->drawString(timeX - 1, textY, dateLine);
|
|
||||||
} else {
|
|
||||||
// === Draw Time ===
|
|
||||||
display->drawString(timeX, textY, timeStr);
|
|
||||||
if (isBold)
|
|
||||||
display->drawString(timeX - 1, textY, timeStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// === No Time Available: Mail/Mute Icon Moves to Far Right ===
|
// === No Time Available: Mail/Mute Icon Moves to Far Right ===
|
||||||
@@ -368,7 +337,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
display->setColor(WHITE); // Reset for other UI
|
display->setColor(WHITE); // Reset for other UI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ void determineResolution(int16_t screenheight, int16_t screenwidth);
|
|||||||
void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r);
|
void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r);
|
||||||
|
|
||||||
// Shared battery/time/mail header
|
// Shared battery/time/mail header
|
||||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool force_no_invert = false,
|
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool battery_only = false);
|
||||||
bool show_date = false);
|
|
||||||
|
|
||||||
const int *getTextPositions(OLEDDisplay *display);
|
const int *getTextPositions(OLEDDisplay *display);
|
||||||
|
|
||||||
|
|||||||
@@ -562,91 +562,6 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
|
|
||||||
static LGFX *tft = nullptr;
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(ST7796_CS)
|
|
||||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7796 driver chip
|
|
||||||
|
|
||||||
class LGFX : public lgfx::LGFX_Device
|
|
||||||
{
|
|
||||||
lgfx::Panel_ST7796 _panel_instance;
|
|
||||||
lgfx::Bus_SPI _bus_instance;
|
|
||||||
lgfx::Light_PWM _light_instance;
|
|
||||||
|
|
||||||
public:
|
|
||||||
LGFX(void)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
auto cfg = _bus_instance.config();
|
|
||||||
|
|
||||||
// SPI
|
|
||||||
cfg.spi_host = ST7796_SPI_HOST;
|
|
||||||
cfg.spi_mode = 0;
|
|
||||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
|
||||||
// 80MHz by an integer)
|
|
||||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
|
||||||
cfg.spi_3wire = false;
|
|
||||||
cfg.use_lock = true; // Set to true to use transaction locking
|
|
||||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
|
||||||
// SPI_DMA_CH_AUTO=auto setting)
|
|
||||||
cfg.pin_sclk = ST7796_SCK; // Set SPI SCLK pin number
|
|
||||||
cfg.pin_mosi = ST7796_SDA; // Set SPI MOSI pin number
|
|
||||||
cfg.pin_miso = ST7796_MISO; // Set SPI MISO pin number (-1 = disable)
|
|
||||||
cfg.pin_dc = ST7796_RS; // Set SPI DC pin number (-1 = disable)
|
|
||||||
|
|
||||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
|
||||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Set the display panel control.
|
|
||||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
|
||||||
|
|
||||||
cfg.pin_cs = ST7796_CS; // Pin number where CS is connected (-1 = disable)
|
|
||||||
cfg.pin_rst = ST7796_RESET; // Pin number where RST is connected (-1 = disable)
|
|
||||||
cfg.pin_busy = ST7796_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
|
||||||
|
|
||||||
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
|
||||||
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
|
||||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
|
||||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
|
||||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
|
||||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
|
||||||
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
|
||||||
#ifdef TFT_DUMMY_READ_PIXELS
|
|
||||||
cfg.dummy_read_pixel = TFT_DUMMY_READ_PIXELS; // Number of bits for dummy read before pixel readout
|
|
||||||
#else
|
|
||||||
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
|
||||||
#endif
|
|
||||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
|
||||||
cfg.readable = true; // Set to true if data can be read
|
|
||||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
|
||||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
|
||||||
cfg.dlen_16bit =
|
|
||||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
|
||||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
|
||||||
|
|
||||||
_panel_instance.config(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ST7796_BL
|
|
||||||
// Set the backlight control. (delete if not necessary)
|
|
||||||
{
|
|
||||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
|
||||||
|
|
||||||
cfg.pin_bl = ST7796_BL; // Pin number to which the backlight is connected
|
|
||||||
cfg.invert = false; // true to invert the brightness of the backlight
|
|
||||||
cfg.freq = 44100;
|
|
||||||
cfg.pwm_channel = 7;
|
|
||||||
|
|
||||||
_light_instance.config(cfg);
|
|
||||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setPanel(&_panel_instance); // Sets the panel to use.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static LGFX *tft = nullptr;
|
|
||||||
|
|
||||||
#elif defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER)
|
#elif defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER)
|
||||||
|
|
||||||
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341/ILI9342 driver chip
|
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341/ILI9342 driver chip
|
||||||
@@ -767,24 +682,24 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
|
|
||||||
LGFX(void)
|
LGFX(void)
|
||||||
{
|
{
|
||||||
if (portduino_config.displayPanel == st7789)
|
if (settingsMap[displayPanel] == st7789)
|
||||||
_panel_instance = new lgfx::Panel_ST7789;
|
_panel_instance = new lgfx::Panel_ST7789;
|
||||||
else if (portduino_config.displayPanel == st7735)
|
else if (settingsMap[displayPanel] == st7735)
|
||||||
_panel_instance = new lgfx::Panel_ST7735;
|
_panel_instance = new lgfx::Panel_ST7735;
|
||||||
else if (portduino_config.displayPanel == st7735s)
|
else if (settingsMap[displayPanel] == st7735s)
|
||||||
_panel_instance = new lgfx::Panel_ST7735S;
|
_panel_instance = new lgfx::Panel_ST7735S;
|
||||||
else if (portduino_config.displayPanel == st7796)
|
else if (settingsMap[displayPanel] == st7796)
|
||||||
_panel_instance = new lgfx::Panel_ST7796;
|
_panel_instance = new lgfx::Panel_ST7796;
|
||||||
else if (portduino_config.displayPanel == ili9341)
|
else if (settingsMap[displayPanel] == ili9341)
|
||||||
_panel_instance = new lgfx::Panel_ILI9341;
|
_panel_instance = new lgfx::Panel_ILI9341;
|
||||||
else if (portduino_config.displayPanel == ili9342)
|
else if (settingsMap[displayPanel] == ili9342)
|
||||||
_panel_instance = new lgfx::Panel_ILI9342;
|
_panel_instance = new lgfx::Panel_ILI9342;
|
||||||
else if (portduino_config.displayPanel == ili9488)
|
else if (settingsMap[displayPanel] == ili9488)
|
||||||
_panel_instance = new lgfx::Panel_ILI9488;
|
_panel_instance = new lgfx::Panel_ILI9488;
|
||||||
else if (portduino_config.displayPanel == hx8357d)
|
else if (settingsMap[displayPanel] == hx8357d)
|
||||||
_panel_instance = new lgfx::Panel_HX8357D;
|
_panel_instance = new lgfx::Panel_HX8357D;
|
||||||
#if defined(LGFX_SDL)
|
#if defined(LGFX_SDL)
|
||||||
else if (portduino_config.displayPanel == x11) {
|
else if (settingsMap[displayPanel] == x11) {
|
||||||
_panel_instance = new lgfx::Panel_sdl;
|
_panel_instance = new lgfx::Panel_sdl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -795,61 +710,61 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
|
|
||||||
auto buscfg = _bus_instance.config();
|
auto buscfg = _bus_instance.config();
|
||||||
buscfg.spi_mode = 0;
|
buscfg.spi_mode = 0;
|
||||||
buscfg.spi_host = portduino_config.display_spi_dev_int;
|
buscfg.spi_host = settingsMap[displayspidev];
|
||||||
|
|
||||||
buscfg.pin_dc = portduino_config.displayDC.pin; // Set SPI DC pin number (-1 = disable)
|
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
_bus_instance.config(buscfg); // applies the set value to the bus.
|
_bus_instance.config(buscfg); // applies the set value to the bus.
|
||||||
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
|
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
|
||||||
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
|
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
|
||||||
LOG_DEBUG("Width: %d, Height: %d", portduino_config.displayWidth, portduino_config.displayHeight);
|
LOG_DEBUG("Width: %d, Height: %d", settingsMap[displayWidth], settingsMap[displayHeight]);
|
||||||
cfg.pin_cs = portduino_config.displayCS.pin; // Pin number where CS is connected (-1 = disable)
|
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
|
||||||
cfg.pin_rst = portduino_config.displayReset.pin;
|
cfg.pin_rst = settingsMap[displayReset];
|
||||||
if (portduino_config.displayRotate) {
|
if (settingsMap[displayRotate]) {
|
||||||
cfg.panel_width = portduino_config.displayHeight; // actual displayable width
|
cfg.panel_width = settingsMap[displayHeight]; // actual displayable width
|
||||||
cfg.panel_height = portduino_config.displayWidth; // actual displayable height
|
cfg.panel_height = settingsMap[displayWidth]; // actual displayable height
|
||||||
} else {
|
} else {
|
||||||
cfg.panel_width = portduino_config.displayWidth; // actual displayable width
|
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||||
cfg.panel_height = portduino_config.displayHeight; // actual displayable height
|
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||||
}
|
}
|
||||||
cfg.offset_x = portduino_config.displayOffsetX; // Panel offset amount in X direction
|
cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
|
||||||
cfg.offset_y = portduino_config.displayOffsetY; // Panel offset amount in Y direction
|
cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
|
||||||
cfg.offset_rotation = portduino_config.displayOffsetRotate; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
cfg.offset_rotation = settingsMap[displayOffsetRotate]; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||||
cfg.invert = portduino_config.displayInvert; // Set to true if the light/darkness of the panel is reversed
|
cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
|
||||||
_panel_instance->config(cfg);
|
_panel_instance->config(cfg);
|
||||||
|
|
||||||
// Configure settings for touch control.
|
// Configure settings for touch control.
|
||||||
if (portduino_config.touchscreenModule) {
|
if (settingsMap[touchscreenModule]) {
|
||||||
if (portduino_config.touchscreenModule == xpt2046) {
|
if (settingsMap[touchscreenModule] == xpt2046) {
|
||||||
_touch_instance = new lgfx::Touch_XPT2046;
|
_touch_instance = new lgfx::Touch_XPT2046;
|
||||||
} else if (portduino_config.touchscreenModule == stmpe610) {
|
} else if (settingsMap[touchscreenModule] == stmpe610) {
|
||||||
_touch_instance = new lgfx::Touch_STMPE610;
|
_touch_instance = new lgfx::Touch_STMPE610;
|
||||||
} else if (portduino_config.touchscreenModule == ft5x06) {
|
} else if (settingsMap[touchscreenModule] == ft5x06) {
|
||||||
_touch_instance = new lgfx::Touch_FT5x06;
|
_touch_instance = new lgfx::Touch_FT5x06;
|
||||||
}
|
}
|
||||||
auto touch_cfg = _touch_instance->config();
|
auto touch_cfg = _touch_instance->config();
|
||||||
|
|
||||||
touch_cfg.pin_cs = portduino_config.touchscreenCS.pin;
|
touch_cfg.pin_cs = settingsMap[touchscreenCS];
|
||||||
touch_cfg.x_min = 0;
|
touch_cfg.x_min = 0;
|
||||||
touch_cfg.x_max = portduino_config.displayHeight - 1;
|
touch_cfg.x_max = settingsMap[displayHeight] - 1;
|
||||||
touch_cfg.y_min = 0;
|
touch_cfg.y_min = 0;
|
||||||
touch_cfg.y_max = portduino_config.displayWidth - 1;
|
touch_cfg.y_max = settingsMap[displayWidth] - 1;
|
||||||
touch_cfg.pin_int = portduino_config.touchscreenIRQ.pin;
|
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||||
touch_cfg.bus_shared = true;
|
touch_cfg.bus_shared = true;
|
||||||
touch_cfg.offset_rotation = portduino_config.touchscreenRotate;
|
touch_cfg.offset_rotation = settingsMap[touchscreenRotate];
|
||||||
if (portduino_config.touchscreenI2CAddr != -1) {
|
if (settingsMap[touchscreenI2CAddr] != -1) {
|
||||||
touch_cfg.i2c_addr = portduino_config.touchscreenI2CAddr;
|
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
|
||||||
} else {
|
} else {
|
||||||
touch_cfg.spi_host = portduino_config.touchscreen_spi_dev_int;
|
touch_cfg.spi_host = settingsMap[touchscreenspidev];
|
||||||
}
|
}
|
||||||
|
|
||||||
_touch_instance->config(touch_cfg);
|
_touch_instance->config(touch_cfg);
|
||||||
_panel_instance->setTouch(_touch_instance);
|
_panel_instance->setTouch(_touch_instance);
|
||||||
}
|
}
|
||||||
#if defined(LGFX_SDL)
|
#if defined(LGFX_SDL)
|
||||||
if (portduino_config.displayPanel == x11) {
|
if (settingsMap[displayPanel] == x11) {
|
||||||
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)_panel_instance;
|
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)_panel_instance;
|
||||||
sdl_panel_->setup();
|
sdl_panel_->setup();
|
||||||
sdl_panel_->addKeyCodeMapping(SDLK_RETURN, SDL_SCANCODE_KP_ENTER);
|
sdl_panel_->addKeyCodeMapping(SDLK_RETURN, SDL_SCANCODE_KP_ENTER);
|
||||||
@@ -1082,9 +997,8 @@ static LGFX *tft = nullptr;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ST7796_CS) || defined(ILI9341_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||||
defined(ILI9342_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || \
|
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || (ARCH_PORTDUINO && HAS_SCREEN != 0)
|
||||||
(ARCH_PORTDUINO && HAS_SCREEN != 0)
|
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "TFTDisplay.h"
|
#include "TFTDisplay.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
@@ -1115,10 +1029,10 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
|||||||
backlightEnable = p;
|
backlightEnable = p;
|
||||||
|
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (portduino_config.displayRotate) {
|
if (settingsMap[displayRotate]) {
|
||||||
setGeometry(GEOMETRY_RAWMODE, portduino_config.displayWidth, portduino_config.displayWidth);
|
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayWidth], settingsMap[configNames::displayHeight]);
|
||||||
} else {
|
} else {
|
||||||
setGeometry(GEOMETRY_RAWMODE, portduino_config.displayHeight, portduino_config.displayHeight);
|
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(SCREEN_ROTATE)
|
#elif defined(SCREEN_ROTATE)
|
||||||
@@ -1128,111 +1042,37 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TFTDisplay::~TFTDisplay()
|
|
||||||
{
|
|
||||||
// Clean up allocated line pixel buffer to prevent memory leak
|
|
||||||
if (linePixelBuffer != nullptr) {
|
|
||||||
free(linePixelBuffer);
|
|
||||||
linePixelBuffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
void TFTDisplay::display(bool fromBlank)
|
void TFTDisplay::display(bool fromBlank)
|
||||||
{
|
{
|
||||||
if (fromBlank)
|
if (fromBlank)
|
||||||
tft->fillScreen(TFT_BLACK);
|
tft->fillScreen(TFT_BLACK);
|
||||||
|
// tft->clear();
|
||||||
concurrency::LockGuard g(spiLock);
|
concurrency::LockGuard g(spiLock);
|
||||||
|
|
||||||
uint32_t x, y;
|
uint16_t x, y;
|
||||||
uint32_t y_byteIndex;
|
|
||||||
uint8_t y_byteMask;
|
|
||||||
uint32_t x_FirstPixelUpdate;
|
|
||||||
uint32_t x_LastPixelUpdate;
|
|
||||||
bool isset, dblbuf_isset;
|
|
||||||
uint16_t colorTftMesh, colorTftBlack;
|
|
||||||
bool somethingChanged = false;
|
|
||||||
|
|
||||||
// Store colors byte-reversed so that TFT_eSPI doesn't have to swap bytes in a separate step
|
for (y = 0; y < displayHeight; y++) {
|
||||||
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
|
for (x = 0; x < displayWidth; x++) {
|
||||||
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);
|
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
|
|
||||||
y = 0;
|
|
||||||
while (y < displayHeight) {
|
|
||||||
y_byteIndex = (y / 8) * displayWidth;
|
|
||||||
y_byteMask = (1 << (y & 7));
|
|
||||||
|
|
||||||
// Step 1: Do a quick scan of 8 rows together. This allows fast-forwarding over unchanged screen areas.
|
|
||||||
if (y_byteMask == 1) {
|
|
||||||
if (!fromBlank) {
|
if (!fromBlank) {
|
||||||
for (x = 0; x < displayWidth; x++) {
|
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||||
if (buffer[x + y_byteIndex] != buffer_back[x + y_byteIndex])
|
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (x = 0; x < displayWidth; x++) {
|
|
||||||
if (buffer[x + y_byteIndex] != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x >= displayWidth) {
|
|
||||||
// No changed pixels found in these 8 rows, fast-forward to the next 8
|
|
||||||
y = y + 8;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: Scan each of the 8 rows individually. Find the first pixel in each row that needs updating
|
|
||||||
for (x_FirstPixelUpdate = 0; x_FirstPixelUpdate < displayWidth; x_FirstPixelUpdate++) {
|
|
||||||
isset = buffer[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
|
||||||
|
|
||||||
if (!fromBlank) {
|
|
||||||
// get src pixel in the page based ordering the OLED lib uses
|
|
||||||
dblbuf_isset = buffer_back[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
|
||||||
if (isset != dblbuf_isset) {
|
if (isset != dblbuf_isset) {
|
||||||
break;
|
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||||
}
|
}
|
||||||
} else if (isset) {
|
} else if (isset) {
|
||||||
break;
|
tft->drawPixel(x, y, TFT_MESH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did we find a pixel that needs updating on this row?
|
|
||||||
if (x_FirstPixelUpdate < displayWidth) {
|
|
||||||
|
|
||||||
// Quickly write out the first changed pixel (saves another array lookup)
|
|
||||||
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
|
|
||||||
x_LastPixelUpdate = x_FirstPixelUpdate;
|
|
||||||
|
|
||||||
// Step 3: copy all remaining pixels in this row into the pixel line buffer,
|
|
||||||
// while also recording the last pixel in the row that needs updating
|
|
||||||
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
|
|
||||||
isset = buffer[x + y_byteIndex] & y_byteMask;
|
|
||||||
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
|
|
||||||
|
|
||||||
if (!fromBlank) {
|
|
||||||
dblbuf_isset = buffer_back[x + y_byteIndex] & y_byteMask;
|
|
||||||
if (isset != dblbuf_isset) {
|
|
||||||
x_LastPixelUpdate = x;
|
|
||||||
}
|
|
||||||
} else if (isset) {
|
|
||||||
x_LastPixelUpdate = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4: Send the changed pixels on this line to the screen as a single block transfer.
|
|
||||||
// This function accepts pixel data MSB first so it can dump the memory straight out the SPI port.
|
|
||||||
tft->pushRect(x_FirstPixelUpdate, y, (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1,
|
|
||||||
&linePixelBuffer[x_FirstPixelUpdate]);
|
|
||||||
|
|
||||||
somethingChanged = true;
|
|
||||||
}
|
|
||||||
y++;
|
|
||||||
}
|
}
|
||||||
// Copy the Buffer to the Back Buffer
|
// Copy the Buffer to the Back Buffer
|
||||||
if (somethingChanged)
|
for (y = 0; y < (displayHeight / 8); y++) {
|
||||||
memcpy(buffer_back, buffer, displayBufferSize);
|
for (x = 0; x < displayWidth; x++) {
|
||||||
|
uint16_t pos = x + y * displayWidth;
|
||||||
|
buffer_back[pos] = buffer[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFTDisplay::sdlLoop()
|
void TFTDisplay::sdlLoop()
|
||||||
@@ -1240,7 +1080,7 @@ void TFTDisplay::sdlLoop()
|
|||||||
#if defined(LGFX_SDL)
|
#if defined(LGFX_SDL)
|
||||||
static int lastPressed = 0;
|
static int lastPressed = 0;
|
||||||
static int shuttingDown = false;
|
static int shuttingDown = false;
|
||||||
if (portduino_config.displayPanel == x11) {
|
if (settingsMap[displayPanel] == x11) {
|
||||||
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)tft->_panel_instance;
|
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)tft->_panel_instance;
|
||||||
if (sdl_panel_->loop() && !shuttingDown) {
|
if (sdl_panel_->loop() && !shuttingDown) {
|
||||||
LOG_WARN("Window Closed!");
|
LOG_WARN("Window Closed!");
|
||||||
@@ -1288,8 +1128,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
backlightEnable->set(true);
|
backlightEnable->set(true);
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
display(true);
|
display(true);
|
||||||
if (portduino_config.displayBacklight.pin > 0)
|
if (settingsMap[displayBacklight] > 0)
|
||||||
digitalWrite(portduino_config.displayBacklight.pin, TFT_BACKLIGHT_ON);
|
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
|
||||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||||
tft->wakeup();
|
tft->wakeup();
|
||||||
tft->powerSaveOff();
|
tft->powerSaveOff();
|
||||||
@@ -1312,8 +1152,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
backlightEnable->set(false);
|
backlightEnable->set(false);
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
tft->clear();
|
tft->clear();
|
||||||
if (portduino_config.displayBacklight.pin > 0)
|
if (settingsMap[displayBacklight] > 0)
|
||||||
digitalWrite(portduino_config.displayBacklight.pin, !TFT_BACKLIGHT_ON);
|
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
|
||||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||||
tft->sleep();
|
tft->sleep();
|
||||||
tft->powerSaveOn();
|
tft->powerSaveOn();
|
||||||
@@ -1424,21 +1264,13 @@ bool TFTDisplay::connect()
|
|||||||
tft->setRotation(1); // T-Deck has the TFT in landscape
|
tft->setRotation(1); // T-Deck has the TFT in landscape
|
||||||
#elif defined(T_WATCH_S3)
|
#elif defined(T_WATCH_S3)
|
||||||
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
||||||
#elif ARCH_PORTDUINO || defined(SENSECAP_INDICATOR) || defined(T_LORA_PAGER)
|
#elif ARCH_PORTDUINO || defined(SENSECAP_INDICATOR)
|
||||||
tft->setRotation(0); // use config.yaml to set rotation
|
tft->setRotation(0); // use config.yaml to set rotation
|
||||||
#else
|
#else
|
||||||
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||||
#endif
|
#endif
|
||||||
tft->fillScreen(TFT_BLACK);
|
tft->fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
if (this->linePixelBuffer == NULL) {
|
|
||||||
this->linePixelBuffer = (uint16_t *)malloc(sizeof(uint16_t) * displayWidth);
|
|
||||||
|
|
||||||
if (!this->linePixelBuffer) {
|
|
||||||
LOG_ERROR("Not enough memory to create TFT line buffer\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
*/
|
*/
|
||||||
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||||
|
|
||||||
// Destructor to clean up allocated memory
|
|
||||||
~TFTDisplay();
|
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
virtual void display() override { display(false); };
|
virtual void display() override { display(false); };
|
||||||
virtual void display(bool fromBlank);
|
virtual void display(bool fromBlank);
|
||||||
@@ -61,6 +58,4 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
|
|
||||||
// Connect to the display
|
// Connect to the display
|
||||||
virtual bool connect() override;
|
virtual bool connect() override;
|
||||||
|
|
||||||
uint16_t *linePixelBuffer = nullptr;
|
|
||||||
};
|
};
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
#include "graphics/draw/UIRenderer.h"
|
|
||||||
#include "graphics/emotes.h"
|
#include "graphics/emotes.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@@ -191,8 +190,7 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
// === Set Title, Blank for Clock
|
// === Set Title, Blank for Clock
|
||||||
const char *titleStr = "";
|
const char *titleStr = "";
|
||||||
// === Header ===
|
// === Header ===
|
||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true);
|
||||||
int line = 0;
|
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
#ifdef T_WATCH_S3
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
||||||
@@ -296,7 +294,6 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
||||||
isPM ? "pm" : "am");
|
isPM ? "pm" : "am");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
xOffset = (isHighResolution) ? 18 : 10;
|
xOffset = (isHighResolution) ? 18 : 10;
|
||||||
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset,
|
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset,
|
||||||
@@ -316,8 +313,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
// === Set Title, Blank for Clock
|
// === Set Title, Blank for Clock
|
||||||
const char *titleStr = "";
|
const char *titleStr = "";
|
||||||
// === Header ===
|
// === Header ===
|
||||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
graphics::drawCommonHeader(display, x, y, titleStr, true);
|
||||||
int line = 0;
|
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
#ifdef T_WATCH_S3
|
||||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
||||||
|
|||||||
@@ -94,8 +94,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
||||||
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||||||
ARCH_PORTDUINO) && \
|
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
||||||
8, imgQuestionL1);
|
8, imgQuestionL1);
|
||||||
@@ -107,7 +106,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
||||||
8, imgSFL1);
|
8, imgSFL1);
|
||||||
@@ -122,8 +121,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
} else {
|
} else {
|
||||||
// TODO: Raspberry Pi supports more than just the one screen size
|
// TODO: Raspberry Pi supports more than just the one screen size
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||||||
ARCH_PORTDUINO) && \
|
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
imgInfoL1);
|
imgInfoL1);
|
||||||
@@ -263,6 +261,12 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
display->drawString(x + 1, y, "USB");
|
display->drawString(x + 1, y, "USB");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||||||
|
|
||||||
|
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||||
|
// if (config.display.heading_bold)
|
||||||
|
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||||
|
|
||||||
uint32_t currentMillis = millis();
|
uint32_t currentMillis = millis();
|
||||||
uint32_t seconds = currentMillis / 1000;
|
uint32_t seconds = currentMillis / 1000;
|
||||||
uint32_t minutes = seconds / 60;
|
uint32_t minutes = seconds / 60;
|
||||||
@@ -277,13 +281,12 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
std::string uptime = UIRenderer::drawTimeDelta(days, hours, minutes, seconds);
|
std::string uptime = UIRenderer::drawTimeDelta(days, hours, minutes, seconds);
|
||||||
|
|
||||||
// Line 1 (Still)
|
// Line 1 (Still)
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||||
if (config.display.heading_bold)
|
if (config.display.heading_bold)
|
||||||
display->drawString(x - 1 + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
display->drawString(x - 1 + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||||
|
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
#endif
|
|
||||||
// Setup string to assemble analogClock string
|
// Setup string to assemble analogClock string
|
||||||
std::string analogClock = "";
|
std::string analogClock = "";
|
||||||
|
|
||||||
@@ -330,7 +333,8 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
#if HAS_GPS
|
#if HAS_GPS
|
||||||
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||||
// Line 3
|
// Line 3
|
||||||
if (uiconfig.gps_format != meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
|
if (config.display.gps_format !=
|
||||||
|
meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
|
||||||
UIRenderer::drawGpsAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
UIRenderer::drawGpsAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||||||
|
|
||||||
// Line 4
|
// Line 4
|
||||||
@@ -386,56 +390,31 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
char shortnameble[35];
|
char shortnameble[35];
|
||||||
getMacAddr(dmac);
|
getMacAddr(dmac);
|
||||||
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
snprintf(shortnameble, sizeof(shortnameble), "%s", screen->ourId);
|
|
||||||
#else
|
|
||||||
snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId);
|
snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId);
|
||||||
#endif
|
|
||||||
int textWidth = display->getStringWidth(shortnameble);
|
int textWidth = display->getStringWidth(shortnameble);
|
||||||
int nameX = (SCREEN_WIDTH - textWidth);
|
int nameX = (SCREEN_WIDTH - textWidth);
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||||
|
|
||||||
// === Second Row: Role ===
|
// === Second Row: Radio Preset ===
|
||||||
auto role = DisplayFormatters::getDeviceRole(config.device.role);
|
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
|
||||||
char device_role[25];
|
|
||||||
snprintf(device_role, sizeof(device_role), "Role: %s", role);
|
|
||||||
textWidth = display->getStringWidth(device_role);
|
|
||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], device_role);
|
|
||||||
|
|
||||||
// === Third Row: Radio Preset ===
|
|
||||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
|
||||||
|
|
||||||
char regionradiopreset[25];
|
char regionradiopreset[25];
|
||||||
const char *region = myRegion ? myRegion->name : NULL;
|
const char *region = myRegion ? myRegion->name : NULL;
|
||||||
if (region != nullptr) {
|
if (region != nullptr) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s", region);
|
|
||||||
#else
|
|
||||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
|
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
textWidth = display->getStringWidth(regionradiopreset);
|
textWidth = display->getStringWidth(regionradiopreset);
|
||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], regionradiopreset);
|
display->drawString(nameX, getTextPositions(display)[line++], regionradiopreset);
|
||||||
|
|
||||||
// === Fourth Row: Frequency / ChanNum ===
|
// === Third Row: Frequency / ChanNum ===
|
||||||
char frequencyslot[35];
|
char frequencyslot[35];
|
||||||
char freqStr[16];
|
char freqStr[16];
|
||||||
float freq = RadioLibInterface::instance->getFreq();
|
float freq = RadioLibInterface::instance->getFreq();
|
||||||
snprintf(freqStr, sizeof(freqStr), "%.3f", freq);
|
snprintf(freqStr, sizeof(freqStr), "%.3f", freq);
|
||||||
if (config.lora.channel_num == 0) {
|
if (config.lora.channel_num == 0) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz", freqStr);
|
|
||||||
#else
|
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz", freqStr);
|
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz", freqStr);
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num);
|
|
||||||
#else
|
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
size_t len = strlen(frequencyslot);
|
size_t len = strlen(frequencyslot);
|
||||||
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
if (len >= 4 && strcmp(frequencyslot + len - 4, " (0)") == 0) {
|
||||||
@@ -445,8 +424,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
||||||
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
// === Fourth Row: Channel Utilization ===
|
||||||
// === Fifth Row: Channel Utilization ===
|
|
||||||
const char *chUtil = "ChUtil:";
|
const char *chUtil = "ChUtil:";
|
||||||
char chUtilPercentage[10];
|
char chUtilPercentage[10];
|
||||||
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
||||||
@@ -463,7 +441,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
int total_line_content_width = (chUtil_x + chutil_bar_width + display->getStringWidth(chUtilPercentage) + extraoffset) / 2;
|
int total_line_content_width = (chUtil_x + chutil_bar_width + display->getStringWidth(chUtilPercentage) + extraoffset) / 2;
|
||||||
int starting_position = centerofscreen - total_line_content_width;
|
int starting_position = centerofscreen - total_line_content_width;
|
||||||
|
|
||||||
display->drawString(starting_position, getTextPositions(display)[line], chUtil);
|
display->drawString(starting_position, getTextPositions(display)[line++], chUtil);
|
||||||
|
|
||||||
// Force 56% or higher to show a full 100% bar, text would still show related percent.
|
// Force 56% or higher to show a full 100% bar, text would still show related percent.
|
||||||
if (chutil_percent >= 61) {
|
if (chutil_percent >= 61) {
|
||||||
@@ -500,15 +478,14 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
display->fillRect(starting_position + chUtil_x, chUtil_y, fillRight, chutil_bar_height);
|
display->fillRect(starting_position + chUtil_x, chUtil_y, fillRight, chutil_bar_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[line++],
|
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[4],
|
||||||
chUtilPercentage);
|
chUtilPercentage);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************
|
// ****************************
|
||||||
// * System Screen *
|
// * System Screen *
|
||||||
// ****************************
|
// ****************************
|
||||||
void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
display->clear();
|
display->clear();
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
@@ -528,11 +505,8 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
barsOffset -= 12;
|
barsOffset -= 12;
|
||||||
#endif
|
#endif
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
const int barX = x + 45 + barsOffset;
|
|
||||||
#else
|
|
||||||
const int barX = x + 40 + barsOffset;
|
const int barX = x + 40 + barsOffset;
|
||||||
#endif
|
|
||||||
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
auto drawUsageRow = [&](const char *label, uint32_t used, uint32_t total, bool isHeap = false) {
|
||||||
if (total == 0)
|
if (total == 0)
|
||||||
return;
|
return;
|
||||||
@@ -557,7 +531,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
// Label
|
// Label
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->drawString(labelX, getTextPositions(display)[line], label);
|
display->drawString(labelX, getTextPositions(display)[line], label);
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
// Bar
|
// Bar
|
||||||
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
@@ -565,7 +539,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
|
|
||||||
display->fillRect(barX, barY, fillWidth, barHeight);
|
display->fillRect(barX, barY, fillWidth, barHeight);
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
#endif
|
|
||||||
// Value string
|
// Value string
|
||||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||||
@@ -618,16 +592,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
line += 1;
|
line += 1;
|
||||||
}
|
}
|
||||||
line += 1;
|
line += 1;
|
||||||
|
|
||||||
char appversionstr[35];
|
char appversionstr[35];
|
||||||
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
snprintf(appversionstr, sizeof(appversionstr), "Ver: %s", optstr(APP_VERSION));
|
||||||
char appversionstr_formatted[40];
|
char appversionstr_formatted[40];
|
||||||
char *lastDot = strrchr(appversionstr, '.');
|
char *lastDot = strrchr(appversionstr, '.');
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
if (lastDot != nullptr) {
|
|
||||||
*lastDot = '\0'; // truncate string
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (lastDot) {
|
if (lastDot) {
|
||||||
size_t prefixLen = lastDot - appversionstr;
|
size_t prefixLen = lastDot - appversionstr;
|
||||||
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
strncpy(appversionstr_formatted, appversionstr, prefixLen);
|
||||||
@@ -638,12 +606,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
strncpy(appversionstr, appversionstr_formatted, sizeof(appversionstr) - 1);
|
||||||
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
appversionstr[sizeof(appversionstr) - 1] = '\0';
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
int textWidth = display->getStringWidth(appversionstr);
|
int textWidth = display->getStringWidth(appversionstr);
|
||||||
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
int nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
|
|
||||||
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
display->drawString(nameX, getTextPositions(display)[line], appversionstr);
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it
|
if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it
|
||||||
line += 1;
|
line += 1;
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
@@ -662,36 +628,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line], uptimeStr);
|
display->drawString(nameX, getTextPositions(display)[line], uptimeStr);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************
|
|
||||||
// * Chirpy Screen *
|
|
||||||
// ****************************
|
|
||||||
void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
|
||||||
{
|
|
||||||
display->clear();
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
int line = 1;
|
|
||||||
int iconX = SCREEN_WIDTH - chirpy_width - (chirpy_width / 3);
|
|
||||||
int iconY = (SCREEN_HEIGHT - chirpy_height) / 2;
|
|
||||||
int textX_offset = 10;
|
|
||||||
if (isHighResolution) {
|
|
||||||
iconX = SCREEN_WIDTH - chirpy_width_hirez - (chirpy_width_hirez / 3);
|
|
||||||
iconY = (SCREEN_HEIGHT - chirpy_height_hirez) / 2;
|
|
||||||
textX_offset = textX_offset * 4;
|
|
||||||
display->drawXbm(iconX, iconY, chirpy_width_hirez, chirpy_height_hirez, chirpy_hirez);
|
|
||||||
} else {
|
|
||||||
display->drawXbm(iconX, iconY, chirpy_width, chirpy_height, chirpy);
|
|
||||||
}
|
|
||||||
|
|
||||||
int textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("Hello") / 2);
|
|
||||||
display->drawString(textX, getTextPositions(display)[line++], "Hello");
|
|
||||||
textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("World!") / 2);
|
|
||||||
display->drawString(textX, getTextPositions(display)[line++], "World!");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace DebugRenderer
|
} // namespace DebugRenderer
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
#endif
|
#endif
|
||||||
@@ -31,10 +31,8 @@ void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
// LoRa information display
|
// LoRa information display
|
||||||
void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
|
||||||
// System screen display
|
// Memory screen display
|
||||||
void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
void drawMemoryUsage(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
// Chirpy screen display
|
|
||||||
void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
|
||||||
} // namespace DebugRenderer
|
} // namespace DebugRenderer
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|||||||
@@ -29,28 +29,6 @@ menuHandler::screenMenus menuHandler::menuQueue = menu_none;
|
|||||||
bool test_enabled = false;
|
bool test_enabled = false;
|
||||||
uint8_t test_count = 0;
|
uint8_t test_count = 0;
|
||||||
|
|
||||||
void menuHandler::loraMenu()
|
|
||||||
{
|
|
||||||
static const char *optionsArray[] = {"Back", "Device Role", "Radio Preset", "LoRa Region"};
|
|
||||||
enum optionsNumbers { Back = 0, device_role_picker = 1, radio_preset_picker = 2, lora_picker = 3 };
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "LoRa Actions";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = 4;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == Back) {
|
|
||||||
// No action
|
|
||||||
} else if (selected == device_role_picker) {
|
|
||||||
menuHandler::menuQueue = menuHandler::device_role_picker;
|
|
||||||
} else if (selected == radio_preset_picker) {
|
|
||||||
menuHandler::menuQueue = menuHandler::radio_preset_picker;
|
|
||||||
} else if (selected == lora_picker) {
|
|
||||||
menuHandler::menuQueue = menuHandler::lora_picker;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::OnboardMessage()
|
void menuHandler::OnboardMessage()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"OK", "Got it!"};
|
static const char *optionsArray[] = {"OK", "Got it!"};
|
||||||
@@ -104,11 +82,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
|||||||
"NP_865",
|
"NP_865",
|
||||||
"BR_902"};
|
"BR_902"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "LoRa Region";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Set the LoRa region";
|
bannerOptions.message = "Set the LoRa region";
|
||||||
#endif
|
|
||||||
bannerOptions.durationMs = duration;
|
bannerOptions.durationMs = duration;
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 27;
|
bannerOptions.optionsCount = 27;
|
||||||
@@ -148,87 +122,6 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
|||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler::DeviceRolePicker()
|
|
||||||
{
|
|
||||||
static const char *optionsArray[] = {"Back", "Client", "Client Mute", "Lost and Found", "Tracker"};
|
|
||||||
enum optionsNumbers {
|
|
||||||
Back = 0,
|
|
||||||
devicerole_client = 1,
|
|
||||||
devicerole_clientmute = 2,
|
|
||||||
devicerole_lostandfound = 3,
|
|
||||||
devicerole_tracker = 4
|
|
||||||
};
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "Device Role";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = 5;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == Back) {
|
|
||||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
|
||||||
screen->runNow();
|
|
||||||
return;
|
|
||||||
} else if (selected == devicerole_client) {
|
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
|
||||||
} else if (selected == devicerole_clientmute) {
|
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE;
|
|
||||||
} else if (selected == devicerole_lostandfound) {
|
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND;
|
|
||||||
} else if (selected == devicerole_tracker) {
|
|
||||||
config.device.role = meshtastic_Config_DeviceConfig_Role_TRACKER;
|
|
||||||
}
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
|
||||||
};
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::RadioPresetPicker()
|
|
||||||
{
|
|
||||||
static const char *optionsArray[] = {"Back", "LongSlow", "LongModerate", "LongFast", "MediumSlow",
|
|
||||||
"MediumFast", "ShortSlow", "ShortFast", "ShortTurbo"};
|
|
||||||
enum optionsNumbers {
|
|
||||||
Back = 0,
|
|
||||||
radiopreset_LongSlow = 1,
|
|
||||||
radiopreset_LongModerate = 2,
|
|
||||||
radiopreset_LongFast = 3,
|
|
||||||
radiopreset_MediumSlow = 4,
|
|
||||||
radiopreset_MediumFast = 5,
|
|
||||||
radiopreset_ShortSlow = 6,
|
|
||||||
radiopreset_ShortFast = 7,
|
|
||||||
radiopreset_ShortTurbo = 8
|
|
||||||
};
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "Radio Preset";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = 9;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == Back) {
|
|
||||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
|
||||||
screen->runNow();
|
|
||||||
return;
|
|
||||||
} else if (selected == radiopreset_LongSlow) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW;
|
|
||||||
} else if (selected == radiopreset_LongModerate) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE;
|
|
||||||
} else if (selected == radiopreset_LongFast) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
|
||||||
} else if (selected == radiopreset_MediumSlow) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW;
|
|
||||||
} else if (selected == radiopreset_MediumFast) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST;
|
|
||||||
} else if (selected == radiopreset_ShortSlow) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW;
|
|
||||||
} else if (selected == radiopreset_ShortFast) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST;
|
|
||||||
} else if (selected == radiopreset_ShortTurbo) {
|
|
||||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO;
|
|
||||||
}
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
|
||||||
};
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::TwelveHourPicker()
|
void menuHandler::TwelveHourPicker()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
|
static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
|
||||||
@@ -370,11 +263,7 @@ void menuHandler::TZPicker()
|
|||||||
|
|
||||||
void menuHandler::clockMenu()
|
void menuHandler::clockMenu()
|
||||||
{
|
{
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static const char *optionsArray[] = {"Back", "Time Format", "Timezone"};
|
|
||||||
#else
|
|
||||||
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
||||||
#endif
|
|
||||||
enum optionsNumbers { Back = 0, Clock = 1, Time = 2, Timezone = 3 };
|
enum optionsNumbers { Back = 0, Clock = 1, Time = 2, Timezone = 3 };
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Clock Action";
|
bannerOptions.message = "Clock Action";
|
||||||
@@ -398,11 +287,8 @@ void menuHandler::clockMenu()
|
|||||||
void menuHandler::messageResponseMenu()
|
void menuHandler::messageResponseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 };
|
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 };
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply Preset"};
|
|
||||||
#else
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"};
|
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"};
|
||||||
#endif
|
|
||||||
static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset};
|
static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset};
|
||||||
int options = 3;
|
int options = 3;
|
||||||
|
|
||||||
@@ -416,17 +302,13 @@ void menuHandler::messageResponseMenu()
|
|||||||
optionsEnumArray[options++] = Aloud;
|
optionsEnumArray[options++] = Aloud;
|
||||||
#endif
|
#endif
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Message";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Message Action";
|
bannerOptions.message = "Message Action";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == Dismiss) {
|
if (selected == Dismiss) {
|
||||||
screen->hideCurrentFrame();
|
screen->dismissCurrentFrame();
|
||||||
} else if (selected == Preset) {
|
} else if (selected == Preset) {
|
||||||
if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
|
if (devicestate.rx_text_message.to == NODENUM_BROADCAST) {
|
||||||
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
|
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST, devicestate.rx_text_message.channel);
|
||||||
@@ -467,17 +349,10 @@ void menuHandler::homeBaseMenu()
|
|||||||
optionsArray[options] = "Sleep Screen";
|
optionsArray[options] = "Sleep Screen";
|
||||||
optionsEnumArray[options++] = Sleep;
|
optionsEnumArray[options++] = Sleep;
|
||||||
#endif
|
#endif
|
||||||
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
|
||||||
optionsArray[options] = "Send Position";
|
optionsArray[options] = "Send Position";
|
||||||
} else {
|
|
||||||
optionsArray[options] = "Send Node Info";
|
|
||||||
}
|
|
||||||
optionsEnumArray[options++] = Position;
|
optionsEnumArray[options++] = Position;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
optionsArray[options] = "New Preset";
|
|
||||||
#else
|
|
||||||
optionsArray[options] = "New Preset Msg";
|
optionsArray[options] = "New Preset Msg";
|
||||||
#endif
|
|
||||||
optionsEnumArray[options++] = Preset;
|
optionsEnumArray[options++] = Preset;
|
||||||
if (kb_found) {
|
if (kb_found) {
|
||||||
optionsArray[options] = "New Freetext Msg";
|
optionsArray[options] = "New Freetext Msg";
|
||||||
@@ -485,11 +360,7 @@ void menuHandler::homeBaseMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Home";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Home Action";
|
bannerOptions.message = "Home Action";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
@@ -528,11 +399,6 @@ void menuHandler::homeBaseMenu()
|
|||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler::textMessageMenu()
|
|
||||||
{
|
|
||||||
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::textMessageBaseMenu()
|
void menuHandler::textMessageBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Preset, Freetext, enumEnd };
|
enum optionsNumbers { Back, Preset, Freetext, enumEnd };
|
||||||
@@ -564,32 +430,23 @@ void menuHandler::textMessageBaseMenu()
|
|||||||
|
|
||||||
void menuHandler::systemBaseMenu()
|
void menuHandler::systemBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, PowerMenu, FrameToggles, Test, enumEnd };
|
enum optionsNumbers { Back, Notifications, ScreenOptions, Bluetooth, PowerMenu, Test, enumEnd };
|
||||||
static const char *optionsArray[enumEnd] = {"Back"};
|
static const char *optionsArray[enumEnd] = {"Back"};
|
||||||
static int optionsEnumArray[enumEnd] = {Back};
|
static int optionsEnumArray[enumEnd] = {Back};
|
||||||
int options = 1;
|
int options = 1;
|
||||||
|
|
||||||
optionsArray[options] = "Notifications";
|
optionsArray[options] = "Notifications";
|
||||||
optionsEnumArray[options++] = Notifications;
|
optionsEnumArray[options++] = Notifications;
|
||||||
#if defined(ST7789_CS) || defined(ST7796_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || \
|
#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || \
|
||||||
defined(USE_SH1107) || defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
||||||
optionsArray[options] = "Screen Options";
|
optionsArray[options] = "Screen Options";
|
||||||
optionsEnumArray[options++] = ScreenOptions;
|
optionsEnumArray[options++] = ScreenOptions;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
optionsArray[options] = "Frame Visiblity Toggle";
|
|
||||||
optionsEnumArray[options++] = FrameToggles;
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
optionsArray[options] = "Bluetooth";
|
|
||||||
#else
|
|
||||||
optionsArray[options] = "Bluetooth Toggle";
|
optionsArray[options] = "Bluetooth Toggle";
|
||||||
#endif
|
|
||||||
optionsEnumArray[options++] = Bluetooth;
|
optionsEnumArray[options++] = Bluetooth;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
optionsArray[options] = "Power";
|
|
||||||
#else
|
|
||||||
optionsArray[options] = "Reboot/Shutdown";
|
optionsArray[options] = "Reboot/Shutdown";
|
||||||
#endif
|
|
||||||
optionsEnumArray[options++] = PowerMenu;
|
optionsEnumArray[options++] = PowerMenu;
|
||||||
|
|
||||||
if (test_enabled) {
|
if (test_enabled) {
|
||||||
@@ -598,11 +455,7 @@ void menuHandler::systemBaseMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "System";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "System Action";
|
bannerOptions.message = "System Action";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
@@ -616,9 +469,6 @@ void menuHandler::systemBaseMenu()
|
|||||||
} else if (selected == PowerMenu) {
|
} else if (selected == PowerMenu) {
|
||||||
menuHandler::menuQueue = menuHandler::power_menu;
|
menuHandler::menuQueue = menuHandler::power_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == FrameToggles) {
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == Test) {
|
} else if (selected == Test) {
|
||||||
menuHandler::menuQueue = menuHandler::test_menu;
|
menuHandler::menuQueue = menuHandler::test_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
@@ -638,11 +488,7 @@ void menuHandler::systemBaseMenu()
|
|||||||
void menuHandler::favoriteBaseMenu()
|
void menuHandler::favoriteBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Preset, Freetext, Remove, TraceRoute, enumEnd };
|
enum optionsNumbers { Back, Preset, Freetext, Remove, TraceRoute, enumEnd };
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset"};
|
|
||||||
#else
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"};
|
static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"};
|
||||||
#endif
|
|
||||||
static int optionsEnumArray[enumEnd] = {Back, Preset};
|
static int optionsEnumArray[enumEnd] = {Back, Preset};
|
||||||
int options = 2;
|
int options = 2;
|
||||||
|
|
||||||
@@ -650,19 +496,13 @@ void menuHandler::favoriteBaseMenu()
|
|||||||
optionsArray[options] = "New Freetext Msg";
|
optionsArray[options] = "New Freetext Msg";
|
||||||
optionsEnumArray[options++] = Freetext;
|
optionsEnumArray[options++] = Freetext;
|
||||||
}
|
}
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
optionsArray[options] = "Trace Route";
|
optionsArray[options] = "Trace Route";
|
||||||
optionsEnumArray[options++] = TraceRoute;
|
optionsEnumArray[options++] = TraceRoute;
|
||||||
#endif
|
|
||||||
optionsArray[options] = "Remove Favorite";
|
optionsArray[options] = "Remove Favorite";
|
||||||
optionsEnumArray[options++] = Remove;
|
optionsEnumArray[options++] = Remove;
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Favorites";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Favorites Action";
|
bannerOptions.message = "Favorites Action";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
@@ -685,17 +525,16 @@ void menuHandler::favoriteBaseMenu()
|
|||||||
|
|
||||||
void menuHandler::positionBaseMenu()
|
void menuHandler::positionBaseMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, GPSToggle, GPSFormat, CompassMenu, CompassCalibrate, enumEnd };
|
enum optionsNumbers { Back, GPSToggle, CompassMenu, CompassCalibrate, enumEnd };
|
||||||
|
|
||||||
static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "GPS Format", "Compass"};
|
static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "Compass"};
|
||||||
static int optionsEnumArray[enumEnd] = {Back, GPSToggle, GPSFormat, CompassMenu};
|
static int optionsEnumArray[enumEnd] = {Back, GPSToggle, CompassMenu};
|
||||||
int options = 4;
|
int options = 3;
|
||||||
|
|
||||||
if (accelerometerThread) {
|
if (accelerometerThread) {
|
||||||
optionsArray[options] = "Compass Calibrate";
|
optionsArray[options] = "Compass Calibrate";
|
||||||
optionsEnumArray[options++] = CompassCalibrate;
|
optionsEnumArray[options++] = CompassCalibrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Position Action";
|
bannerOptions.message = "Position Action";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
@@ -705,9 +544,6 @@ void menuHandler::positionBaseMenu()
|
|||||||
if (selected == GPSToggle) {
|
if (selected == GPSToggle) {
|
||||||
menuQueue = gps_toggle_menu;
|
menuQueue = gps_toggle_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == GPSFormat) {
|
|
||||||
menuQueue = gps_format_menu;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == CompassMenu) {
|
} else if (selected == CompassMenu) {
|
||||||
menuQueue = compass_point_north_menu;
|
menuQueue = compass_point_north_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
@@ -721,19 +557,11 @@ void menuHandler::positionBaseMenu()
|
|||||||
void menuHandler::nodeListMenu()
|
void menuHandler::nodeListMenu()
|
||||||
{
|
{
|
||||||
enum optionsNumbers { Back, Favorite, TraceRoute, Verify, Reset, enumEnd };
|
enum optionsNumbers { Back, Favorite, TraceRoute, Verify, Reset, enumEnd };
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Reset Node"};
|
|
||||||
#else
|
|
||||||
static const char *optionsArray[] = {"Back", "Add Favorite", "Trace Route", "Key Verification", "Reset NodeDB"};
|
static const char *optionsArray[] = {"Back", "Add Favorite", "Trace Route", "Key Verification", "Reset NodeDB"};
|
||||||
#endif
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Node Action";
|
bannerOptions.message = "Node Action";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.optionsCount = 3;
|
|
||||||
#else
|
|
||||||
bannerOptions.optionsCount = 5;
|
bannerOptions.optionsCount = 5;
|
||||||
#endif
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == Favorite) {
|
if (selected == Favorite) {
|
||||||
menuQueue = add_favorite;
|
menuQueue = add_favorite;
|
||||||
@@ -834,62 +662,13 @@ void menuHandler::GPSToggleMenu()
|
|||||||
bannerOptions.InitialSelected = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED ? 1 : 2;
|
bannerOptions.InitialSelected = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED ? 1 : 2;
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
void menuHandler::GPSFormatMenu()
|
|
||||||
{
|
|
||||||
|
|
||||||
static const char *optionsArray[] = {"Back",
|
|
||||||
isHighResolution ? "Decimal Degrees" : "DEC",
|
|
||||||
isHighResolution ? "Degrees Minutes Seconds" : "DMS",
|
|
||||||
isHighResolution ? "Universal Transverse Mercator" : "UTM",
|
|
||||||
isHighResolution ? "Military Grid Reference System" : "MGRS",
|
|
||||||
isHighResolution ? "Open Location Code" : "OLC",
|
|
||||||
isHighResolution ? "Ordnance Survey Grid Ref" : "OSGR",
|
|
||||||
isHighResolution ? "Maidenhead Locator" : "MLS"};
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "GPS Format";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = 8;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == 1) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 2) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 3) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_UTM;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 4) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_MGRS;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 5) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 6) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_OSGR;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else if (selected == 7) {
|
|
||||||
uiconfig.gps_format = meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
} else {
|
|
||||||
menuQueue = position_base_menu;
|
|
||||||
screen->runNow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
bannerOptions.InitialSelected = uiconfig.gps_format + 1;
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void menuHandler::BluetoothToggleMenu()
|
void menuHandler::BluetoothToggleMenu()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Bluetooth";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Toggle Bluetooth";
|
bannerOptions.message = "Toggle Bluetooth";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 3;
|
bannerOptions.optionsCount = 3;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
@@ -949,7 +728,7 @@ void menuHandler::BrightnessPickerMenu()
|
|||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
|
||||||
// For HELTEC devices, use analogWrite to control backlight
|
// For HELTEC devices, use analogWrite to control backlight
|
||||||
analogWrite(VTFT_LEDA, uiconfig.screen_brightness);
|
analogWrite(VTFT_LEDA, uiconfig.screen_brightness);
|
||||||
#elif defined(ST7789_CS) || defined(ST7796_CS)
|
#elif defined(ST7789_CS)
|
||||||
static_cast<TFTDisplay *>(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness);
|
static_cast<TFTDisplay *>(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness);
|
||||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||||
screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness);
|
screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness);
|
||||||
@@ -992,7 +771,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
|||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 10;
|
bannerOptions.optionsCount = 10;
|
||||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||||
uint8_t TFT_MESH_r = 0;
|
uint8_t TFT_MESH_r = 0;
|
||||||
uint8_t TFT_MESH_g = 0;
|
uint8_t TFT_MESH_g = 0;
|
||||||
uint8_t TFT_MESH_b = 0;
|
uint8_t TFT_MESH_b = 0;
|
||||||
@@ -1081,11 +860,7 @@ void menuHandler::rebootMenu()
|
|||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Reboot";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Reboot Device?";
|
bannerOptions.message = "Reboot Device?";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 2;
|
bannerOptions.optionsCount = 2;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
@@ -1105,11 +880,7 @@ void menuHandler::shutdownMenu()
|
|||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Shutdown";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Shutdown Device?";
|
bannerOptions.message = "Shutdown Device?";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 2;
|
bannerOptions.optionsCount = 2;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
@@ -1126,12 +897,7 @@ void menuHandler::shutdownMenu()
|
|||||||
|
|
||||||
void menuHandler::addFavoriteMenu()
|
void menuHandler::addFavoriteMenu()
|
||||||
{
|
{
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
screen->showNodePicker("Node Favorite", 30000, [](uint32_t nodenum) -> void {
|
|
||||||
#else
|
|
||||||
screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void {
|
screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void {
|
||||||
|
|
||||||
#endif
|
|
||||||
LOG_WARN("Nodenum: %u", nodenum);
|
LOG_WARN("Nodenum: %u", nodenum);
|
||||||
nodeDB->set_favorite(true, nodenum);
|
nodeDB->set_favorite(true, nodenum);
|
||||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||||
@@ -1174,33 +940,16 @@ void menuHandler::traceRouteMenu()
|
|||||||
void menuHandler::testMenu()
|
void menuHandler::testMenu()
|
||||||
{
|
{
|
||||||
|
|
||||||
enum optionsNumbers { Back, NumberPicker, ShowChirpy };
|
static const char *optionsArray[] = {"Back", "Number Picker"};
|
||||||
static const char *optionsArray[4] = {"Back"};
|
|
||||||
static int optionsEnumArray[4] = {Back};
|
|
||||||
int options = 1;
|
|
||||||
|
|
||||||
optionsArray[options] = "Number Picker";
|
|
||||||
optionsEnumArray[options++] = NumberPicker;
|
|
||||||
|
|
||||||
optionsArray[options] = screen->isFrameHidden("chirpy") ? "Show Chirpy" : "Hide Chirpy";
|
|
||||||
optionsEnumArray[options++] = ShowChirpy;
|
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Hidden Test Menu";
|
std::string message = "Test to Run?\n";
|
||||||
|
bannerOptions.message = message.c_str();
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = 2;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == NumberPicker) {
|
if (selected == 1) {
|
||||||
menuQueue = number_test;
|
menuQueue = number_test;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
} else if (selected == ShowChirpy) {
|
|
||||||
screen->toggleFrameVisibility("chirpy");
|
|
||||||
screen->setFrames(Screen::FOCUS_SYSTEM);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
menuQueue = system_base_menu;
|
|
||||||
screen->runNow();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
@@ -1299,7 +1048,7 @@ void menuHandler::screenOptionsMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only show screen color for TFT displays
|
// Only show screen color for TFT displays
|
||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||||
optionsArray[options] = "Screen Color";
|
optionsArray[options] = "Screen Color";
|
||||||
optionsEnumArray[options++] = ScreenColor;
|
optionsEnumArray[options++] = ScreenColor;
|
||||||
#endif
|
#endif
|
||||||
@@ -1344,11 +1093,7 @@ void menuHandler::powerMenu()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
bannerOptions.message = "Power";
|
|
||||||
#else
|
|
||||||
bannerOptions.message = "Reboot / Shutdown";
|
bannerOptions.message = "Reboot / Shutdown";
|
||||||
#endif
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = options;
|
bannerOptions.optionsCount = options;
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||||
@@ -1401,116 +1146,6 @@ void menuHandler::keyVerificationFinalPrompt()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler::FrameToggles_menu()
|
|
||||||
{
|
|
||||||
enum optionsNumbers {
|
|
||||||
Finish,
|
|
||||||
nodelist,
|
|
||||||
nodelist_lastheard,
|
|
||||||
nodelist_hopsignal,
|
|
||||||
nodelist_distance,
|
|
||||||
nodelist_bearings,
|
|
||||||
gps,
|
|
||||||
lora,
|
|
||||||
clock,
|
|
||||||
show_favorites,
|
|
||||||
enumEnd
|
|
||||||
};
|
|
||||||
static const char *optionsArray[enumEnd] = {"Finish"};
|
|
||||||
static int optionsEnumArray[enumEnd] = {Finish};
|
|
||||||
int options = 1;
|
|
||||||
|
|
||||||
// Track last selected index (not enum value!)
|
|
||||||
static int lastSelectedIndex = 0;
|
|
||||||
|
|
||||||
#ifndef USE_EINK
|
|
||||||
optionsArray[options] = screen->isFrameHidden("nodelist") ? "Show Node List" : "Hide Node List";
|
|
||||||
optionsEnumArray[options++] = nodelist;
|
|
||||||
#endif
|
|
||||||
#ifdef USE_EINK
|
|
||||||
optionsArray[options] = screen->isFrameHidden("nodelist_lastheard") ? "Show NL - Last Heard" : "Hide NL - Last Heard";
|
|
||||||
optionsEnumArray[options++] = nodelist_lastheard;
|
|
||||||
optionsArray[options] = screen->isFrameHidden("nodelist_hopsignal") ? "Show NL - Hops/Signal" : "Hide NL - Hops/Signal";
|
|
||||||
optionsEnumArray[options++] = nodelist_hopsignal;
|
|
||||||
optionsArray[options] = screen->isFrameHidden("nodelist_distance") ? "Show NL - Distance" : "Hide NL - Distance";
|
|
||||||
optionsEnumArray[options++] = nodelist_distance;
|
|
||||||
#endif
|
|
||||||
#if HAS_GPS
|
|
||||||
optionsArray[options] = screen->isFrameHidden("nodelist_bearings") ? "Show Bearings" : "Hide Bearings";
|
|
||||||
optionsEnumArray[options++] = nodelist_bearings;
|
|
||||||
|
|
||||||
optionsArray[options] = screen->isFrameHidden("gps") ? "Show Position" : "Hide Position";
|
|
||||||
optionsEnumArray[options++] = gps;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
optionsArray[options] = screen->isFrameHidden("lora") ? "Show LoRa" : "Hide LoRa";
|
|
||||||
optionsEnumArray[options++] = lora;
|
|
||||||
|
|
||||||
optionsArray[options] = screen->isFrameHidden("clock") ? "Show Clock" : "Hide Clock";
|
|
||||||
optionsEnumArray[options++] = clock;
|
|
||||||
|
|
||||||
optionsArray[options] = screen->isFrameHidden("show_favorites") ? "Show Favorites" : "Hide Favorites";
|
|
||||||
optionsEnumArray[options++] = show_favorites;
|
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "Show/Hide Frames";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsCount = options;
|
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
|
||||||
bannerOptions.InitialSelected = lastSelectedIndex; // Use index, not enum value
|
|
||||||
|
|
||||||
bannerOptions.bannerCallback = [options](int selected) mutable -> void {
|
|
||||||
// Find the index of selected in optionsEnumArray
|
|
||||||
int idx = 0;
|
|
||||||
for (; idx < options; ++idx) {
|
|
||||||
if (optionsEnumArray[idx] == selected)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastSelectedIndex = idx;
|
|
||||||
|
|
||||||
if (selected == Finish) {
|
|
||||||
screen->setFrames(Screen::FOCUS_DEFAULT);
|
|
||||||
} else if (selected == nodelist) {
|
|
||||||
screen->toggleFrameVisibility("nodelist");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == nodelist_lastheard) {
|
|
||||||
screen->toggleFrameVisibility("nodelist_lastheard");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == nodelist_hopsignal) {
|
|
||||||
screen->toggleFrameVisibility("nodelist_hopsignal");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == nodelist_distance) {
|
|
||||||
screen->toggleFrameVisibility("nodelist_distance");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == nodelist_bearings) {
|
|
||||||
screen->toggleFrameVisibility("nodelist_bearings");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == gps) {
|
|
||||||
screen->toggleFrameVisibility("gps");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == lora) {
|
|
||||||
screen->toggleFrameVisibility("lora");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == clock) {
|
|
||||||
screen->toggleFrameVisibility("clock");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
} else if (selected == show_favorites) {
|
|
||||||
screen->toggleFrameVisibility("show_favorites");
|
|
||||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
|
||||||
screen->runNow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
||||||
{
|
{
|
||||||
if (menuQueue != menu_none)
|
if (menuQueue != menu_none)
|
||||||
@@ -1518,18 +1153,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
switch (menuQueue) {
|
switch (menuQueue) {
|
||||||
case menu_none:
|
case menu_none:
|
||||||
break;
|
break;
|
||||||
case lora_Menu:
|
|
||||||
loraMenu();
|
|
||||||
break;
|
|
||||||
case lora_picker:
|
case lora_picker:
|
||||||
LoraRegionPicker();
|
LoraRegionPicker();
|
||||||
break;
|
break;
|
||||||
case device_role_picker:
|
|
||||||
DeviceRolePicker();
|
|
||||||
break;
|
|
||||||
case radio_preset_picker:
|
|
||||||
RadioPresetPicker();
|
|
||||||
break;
|
|
||||||
case no_timeout_lora_picker:
|
case no_timeout_lora_picker:
|
||||||
LoraRegionPicker(0);
|
LoraRegionPicker(0);
|
||||||
break;
|
break;
|
||||||
@@ -1555,9 +1181,6 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case gps_toggle_menu:
|
case gps_toggle_menu:
|
||||||
GPSToggleMenu();
|
GPSToggleMenu();
|
||||||
break;
|
break;
|
||||||
case gps_format_menu:
|
|
||||||
GPSFormatMenu();
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case compass_point_north_menu:
|
case compass_point_north_menu:
|
||||||
compassNorthMenu();
|
compassNorthMenu();
|
||||||
@@ -1619,9 +1242,6 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case power_menu:
|
case power_menu:
|
||||||
powerMenu();
|
powerMenu();
|
||||||
break;
|
break;
|
||||||
case FrameToggles:
|
|
||||||
FrameToggles_menu();
|
|
||||||
break;
|
|
||||||
case throttle_message:
|
case throttle_message:
|
||||||
screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000);
|
screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ class menuHandler
|
|||||||
public:
|
public:
|
||||||
enum screenMenus {
|
enum screenMenus {
|
||||||
menu_none,
|
menu_none,
|
||||||
lora_Menu,
|
|
||||||
lora_picker,
|
lora_picker,
|
||||||
device_role_picker,
|
|
||||||
radio_preset_picker,
|
|
||||||
no_timeout_lora_picker,
|
no_timeout_lora_picker,
|
||||||
TZ_picker,
|
TZ_picker,
|
||||||
twelve_hour_picker,
|
twelve_hour_picker,
|
||||||
@@ -20,7 +17,6 @@ class menuHandler
|
|||||||
clock_menu,
|
clock_menu,
|
||||||
position_base_menu,
|
position_base_menu,
|
||||||
gps_toggle_menu,
|
gps_toggle_menu,
|
||||||
gps_format_menu,
|
|
||||||
compass_point_north_menu,
|
compass_point_north_menu,
|
||||||
reset_node_db_menu,
|
reset_node_db_menu,
|
||||||
buzzermodemenupicker,
|
buzzermodemenupicker,
|
||||||
@@ -43,15 +39,11 @@ class menuHandler
|
|||||||
key_verification_final_prompt,
|
key_verification_final_prompt,
|
||||||
trace_route_menu,
|
trace_route_menu,
|
||||||
throttle_message,
|
throttle_message,
|
||||||
FrameToggles
|
|
||||||
};
|
};
|
||||||
static screenMenus menuQueue;
|
static screenMenus menuQueue;
|
||||||
|
|
||||||
static void OnboardMessage();
|
static void OnboardMessage();
|
||||||
static void LoraRegionPicker(uint32_t duration = 30000);
|
static void LoraRegionPicker(uint32_t duration = 30000);
|
||||||
static void loraMenu();
|
|
||||||
static void DeviceRolePicker();
|
|
||||||
static void RadioPresetPicker();
|
|
||||||
static void handleMenuSwitch(OLEDDisplay *display);
|
static void handleMenuSwitch(OLEDDisplay *display);
|
||||||
static void showConfirmationBanner(const char *message, std::function<void()> onConfirm);
|
static void showConfirmationBanner(const char *message, std::function<void()> onConfirm);
|
||||||
static void clockMenu();
|
static void clockMenu();
|
||||||
@@ -66,7 +58,6 @@ class menuHandler
|
|||||||
static void positionBaseMenu();
|
static void positionBaseMenu();
|
||||||
static void compassNorthMenu();
|
static void compassNorthMenu();
|
||||||
static void GPSToggleMenu();
|
static void GPSToggleMenu();
|
||||||
static void GPSFormatMenu();
|
|
||||||
static void BuzzerModeMenu();
|
static void BuzzerModeMenu();
|
||||||
static void switchToMUIMenu();
|
static void switchToMUIMenu();
|
||||||
static void TFTColorPickerMenu(OLEDDisplay *display);
|
static void TFTColorPickerMenu(OLEDDisplay *display);
|
||||||
@@ -85,8 +76,6 @@ class menuHandler
|
|||||||
static void notificationsMenu();
|
static void notificationsMenu();
|
||||||
static void screenOptionsMenu();
|
static void screenOptionsMenu();
|
||||||
static void powerMenu();
|
static void powerMenu();
|
||||||
static void FrameToggles_menu();
|
|
||||||
static void textMessageMenu();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void saveUIConfig();
|
static void saveUIConfig();
|
||||||
|
|||||||
@@ -181,19 +181,12 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
display->clear();
|
display->clear();
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
const int fixedTopHeight = 24;
|
|
||||||
const int windowX = 0;
|
|
||||||
const int windowY = fixedTopHeight;
|
|
||||||
const int windowWidth = 64;
|
|
||||||
const int windowHeight = SCREEN_HEIGHT - fixedTopHeight;
|
|
||||||
#else
|
|
||||||
const int navHeight = FONT_HEIGHT_SMALL;
|
const int navHeight = FONT_HEIGHT_SMALL;
|
||||||
const int scrollBottom = SCREEN_HEIGHT - navHeight;
|
const int scrollBottom = SCREEN_HEIGHT - navHeight;
|
||||||
const int usableHeight = scrollBottom;
|
const int usableHeight = scrollBottom;
|
||||||
const int textWidth = SCREEN_WIDTH;
|
const int textWidth = SCREEN_WIDTH;
|
||||||
|
|
||||||
#endif
|
|
||||||
bool isInverted = (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED);
|
bool isInverted = (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED);
|
||||||
bool isBold = config.display.heading_bold;
|
bool isBold = config.display.heading_bold;
|
||||||
|
|
||||||
@@ -208,11 +201,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||||
const char *messageString = "No messages";
|
const char *messageString = "No messages";
|
||||||
int center_text = (SCREEN_WIDTH / 2) - (display->getStringWidth(messageString) / 2);
|
int center_text = (SCREEN_WIDTH / 2) - (display->getStringWidth(messageString) / 2);
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
display->drawString(center_text, windowY + (windowHeight / 2) - (FONT_HEIGHT_SMALL / 2) - 5, messageString);
|
|
||||||
#else
|
|
||||||
display->drawString(center_text, getTextPositions(display)[2], messageString);
|
display->drawString(center_text, getTextPositions(display)[2], messageString);
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,10 +209,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
|
||||||
char headerStr[80];
|
char headerStr[80];
|
||||||
const char *sender = "???";
|
const char *sender = "???";
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
if (node && node->has_user)
|
|
||||||
sender = node->user.short_name;
|
|
||||||
#else
|
|
||||||
if (node && node->has_user) {
|
if (node && node->has_user) {
|
||||||
if (SCREEN_WIDTH >= 200 && strlen(node->user.long_name) > 0) {
|
if (SCREEN_WIDTH >= 200 && strlen(node->user.long_name) > 0) {
|
||||||
sender = node->user.long_name;
|
sender = node->user.long_name;
|
||||||
@@ -231,7 +216,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
sender = node->user.short_name;
|
sender = node->user.short_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
uint32_t seconds = sinceReceived(&mp), minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
uint32_t seconds = sinceReceived(&mp), minutes = seconds / 60, hours = minutes / 60, days = hours / 24;
|
||||||
uint8_t timestampHours, timestampMinutes;
|
uint8_t timestampHours, timestampMinutes;
|
||||||
int32_t daysAgo;
|
int32_t daysAgo;
|
||||||
@@ -251,61 +235,10 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
sender);
|
sender);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
snprintf(headerStr, sizeof(headerStr), "%s from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
|
||||||
sender);
|
|
||||||
#else
|
|
||||||
snprintf(headerStr, sizeof(headerStr), "%s ago from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
snprintf(headerStr, sizeof(headerStr), "%s ago from %s", UIRenderer::drawTimeDelta(days, hours, minutes, seconds).c_str(),
|
||||||
sender);
|
sender);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
|
||||||
int headerY = getTextPositions(display)[1];
|
|
||||||
display->drawString(x, headerY, headerStr);
|
|
||||||
for (int separatorX = 0; separatorX < SCREEN_WIDTH; separatorX += 2) {
|
|
||||||
display->setPixel(separatorX, fixedTopHeight - 1);
|
|
||||||
}
|
|
||||||
cachedLines.clear();
|
|
||||||
std::string fullMsg(messageBuf);
|
|
||||||
std::string currentLine;
|
|
||||||
for (size_t i = 0; i < fullMsg.size();) {
|
|
||||||
unsigned char c = fullMsg[i];
|
|
||||||
size_t charLen = 1;
|
|
||||||
if ((c & 0xE0) == 0xC0)
|
|
||||||
charLen = 2;
|
|
||||||
else if ((c & 0xF0) == 0xE0)
|
|
||||||
charLen = 3;
|
|
||||||
else if ((c & 0xF8) == 0xF0)
|
|
||||||
charLen = 4;
|
|
||||||
std::string nextChar = fullMsg.substr(i, charLen);
|
|
||||||
std::string testLine = currentLine + nextChar;
|
|
||||||
if (display->getStringWidth(testLine.c_str()) > windowWidth) {
|
|
||||||
cachedLines.push_back(currentLine);
|
|
||||||
currentLine = nextChar;
|
|
||||||
} else {
|
|
||||||
currentLine = testLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += charLen;
|
|
||||||
}
|
|
||||||
if (!currentLine.empty())
|
|
||||||
cachedLines.push_back(currentLine);
|
|
||||||
cachedHeights = calculateLineHeights(cachedLines, emotes);
|
|
||||||
int yOffset = windowY;
|
|
||||||
int linesDrawn = 0;
|
|
||||||
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
|
||||||
if (linesDrawn >= 2)
|
|
||||||
break;
|
|
||||||
int lineHeight = cachedHeights[i];
|
|
||||||
if (yOffset + lineHeight > windowY + windowHeight)
|
|
||||||
break;
|
|
||||||
drawStringWithEmotes(display, windowX, yOffset, cachedLines[i], emotes, numEmotes);
|
|
||||||
yOffset += lineHeight;
|
|
||||||
linesDrawn++;
|
|
||||||
}
|
|
||||||
screen->forceDisplay();
|
|
||||||
#else
|
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
#ifndef EXCLUDE_EMOJI
|
#ifndef EXCLUDE_EMOJI
|
||||||
// === Bounce animation setup ===
|
// === Bounce animation setup ===
|
||||||
@@ -422,7 +355,6 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
|
|
||||||
// Draw header at the end to sort out overlapping elements
|
// Draw header at the end to sort out overlapping elements
|
||||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth)
|
std::vector<std::string> generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth)
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ extern bool haveGlyphs(const char *str);
|
|||||||
// Global screen instance
|
// Global screen instance
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static uint32_t lastSwitchTime = 0;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
namespace graphics
|
namespace graphics
|
||||||
{
|
{
|
||||||
namespace NodeListRenderer
|
namespace NodeListRenderer
|
||||||
@@ -397,11 +393,9 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
{
|
{
|
||||||
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
const int COMMON_HEADER_HEIGHT = FONT_HEIGHT_SMALL - 1;
|
||||||
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
const int rowYOffset = FONT_HEIGHT_SMALL - 3;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
int columnWidth = display->getWidth();
|
|
||||||
#else
|
|
||||||
int columnWidth = display->getWidth() / 2;
|
int columnWidth = display->getWidth() / 2;
|
||||||
#endif
|
|
||||||
display->clear();
|
display->clear();
|
||||||
|
|
||||||
// Draw the battery/time header
|
// Draw the battery/time header
|
||||||
@@ -414,11 +408,8 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
int totalRowsAvailable = (display->getHeight() - y) / rowYOffset;
|
||||||
|
|
||||||
int visibleNodeRows = totalRowsAvailable;
|
int visibleNodeRows = totalRowsAvailable;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
int totalColumns = 1;
|
|
||||||
#else
|
|
||||||
int totalColumns = 2;
|
int totalColumns = 2;
|
||||||
#endif
|
|
||||||
int startIndex = scrollIndex * visibleNodeRows * totalColumns;
|
int startIndex = scrollIndex * visibleNodeRows * totalColumns;
|
||||||
if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) {
|
if (nodeDB->getMeshNodeByIndex(startIndex)->num == nodeDB->getNodeNum()) {
|
||||||
startIndex++; // skip own node
|
startIndex++; // skip own node
|
||||||
@@ -454,14 +445,12 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
// Draw column separator
|
// Draw column separator
|
||||||
if (shownCount > 0) {
|
if (shownCount > 0) {
|
||||||
const int firstNodeY = y + 3;
|
const int firstNodeY = y + 3;
|
||||||
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
drawColumnSeparator(display, x, firstNodeY, lastNodeY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
const int scrollStartY = y + 3;
|
const int scrollStartY = y + 3;
|
||||||
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY);
|
||||||
}
|
}
|
||||||
@@ -479,13 +468,6 @@ void drawDynamicNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
|
|||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
display->clear();
|
|
||||||
if (now - lastSwitchTime >= 3000) {
|
|
||||||
display->display();
|
|
||||||
lastSwitchTime = now;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// On very first call (on boot or state enter)
|
// On very first call (on boot or state enter)
|
||||||
if (lastRenderedMode == MODE_COUNT) {
|
if (lastRenderedMode == MODE_COUNT) {
|
||||||
currentMode = MODE_LAST_HEARD;
|
currentMode = MODE_LAST_HEARD;
|
||||||
@@ -540,14 +522,6 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
|||||||
double lat = DegD(ourNode->position.latitude_i);
|
double lat = DegD(ourNode->position.latitude_i);
|
||||||
double lon = DegD(ourNode->position.longitude_i);
|
double lon = DegD(ourNode->position.longitude_i);
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
display->clear();
|
|
||||||
uint32_t now = millis();
|
|
||||||
if (now - lastSwitchTime >= 2000) {
|
|
||||||
display->display();
|
|
||||||
lastSwitchTime = now;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
|
||||||
#if HAS_GPS
|
#if HAS_GPS
|
||||||
if (screen->hasHeading()) {
|
if (screen->hasHeading()) {
|
||||||
|
|||||||
@@ -250,11 +250,9 @@ void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle input
|
// Handle input
|
||||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_LEFT ||
|
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
|
||||||
curSelected--;
|
curSelected--;
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_RIGHT ||
|
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
|
||||||
curSelected++;
|
curSelected++;
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||||
alertBannerCallback(selectedNodenum);
|
alertBannerCallback(selectedNodenum);
|
||||||
@@ -367,11 +365,9 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
|
|||||||
|
|
||||||
// Handle input
|
// Handle input
|
||||||
if (alertBannerOptions > 0) {
|
if (alertBannerOptions > 0) {
|
||||||
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_LEFT ||
|
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||||
inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
|
||||||
curSelected--;
|
curSelected--;
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_RIGHT ||
|
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||||
inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
|
||||||
curSelected++;
|
curSelected++;
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||||
if (optionsEnumPtr != nullptr) {
|
if (optionsEnumPtr != nullptr) {
|
||||||
@@ -495,135 +491,6 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
|||||||
// count lines
|
// count lines
|
||||||
|
|
||||||
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
uint16_t boxWidth = hPadding * 2 + maxWidth;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
if (needs_bell) {
|
|
||||||
if (isHighResolution && boxWidth <= 150)
|
|
||||||
boxWidth += 26;
|
|
||||||
if (!isHighResolution && boxWidth <= 100)
|
|
||||||
boxWidth += 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t screenHeight = display->height();
|
|
||||||
uint8_t effectiveLineHeight = FONT_HEIGHT_SMALL - 3;
|
|
||||||
uint8_t visibleTotalLines = std::min<uint8_t>(lineCount, (screenHeight - vPadding * 2) / effectiveLineHeight);
|
|
||||||
uint16_t contentHeight = visibleTotalLines * effectiveLineHeight;
|
|
||||||
uint16_t boxHeight = contentHeight + vPadding * 2;
|
|
||||||
if (visibleTotalLines == 1)
|
|
||||||
boxHeight += (isHighResolution ? 4 : 3);
|
|
||||||
|
|
||||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
|
||||||
if (totalLines > visibleTotalLines)
|
|
||||||
boxWidth += (isHighResolution ? 4 : 2);
|
|
||||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
|
||||||
|
|
||||||
if (visibleTotalLines == 1) {
|
|
||||||
boxTop += 25;
|
|
||||||
}
|
|
||||||
if (alertBannerOptions < 3) {
|
|
||||||
int missingLines = 3 - alertBannerOptions;
|
|
||||||
int moveUp = missingLines * (effectiveLineHeight / 2);
|
|
||||||
boxTop -= moveUp;
|
|
||||||
if (boxTop < 0)
|
|
||||||
boxTop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Draw Box ===
|
|
||||||
display->setColor(BLACK);
|
|
||||||
display->fillRect(boxLeft, boxTop, boxWidth, boxHeight);
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight);
|
|
||||||
display->fillRect(boxLeft, boxTop - 2, boxWidth, 1);
|
|
||||||
display->fillRect(boxLeft - 2, boxTop, 1, boxHeight);
|
|
||||||
display->fillRect(boxLeft + boxWidth + 1, boxTop, 1, boxHeight);
|
|
||||||
display->setColor(BLACK);
|
|
||||||
display->fillRect(boxLeft, boxTop, 1, 1);
|
|
||||||
display->fillRect(boxLeft + boxWidth - 1, boxTop, 1, 1);
|
|
||||||
display->fillRect(boxLeft, boxTop + boxHeight - 1, 1, 1);
|
|
||||||
display->fillRect(boxLeft + boxWidth - 1, boxTop + boxHeight - 1, 1, 1);
|
|
||||||
display->setColor(WHITE);
|
|
||||||
int16_t lineY = boxTop + vPadding;
|
|
||||||
int swingRange = 8;
|
|
||||||
static int swingOffset = 0;
|
|
||||||
static bool swingRight = true;
|
|
||||||
static unsigned long lastSwingTime = 0;
|
|
||||||
unsigned long now = millis();
|
|
||||||
int swingSpeedMs = 10 / (swingRange * 2);
|
|
||||||
if (now - lastSwingTime >= (unsigned long)swingSpeedMs) {
|
|
||||||
lastSwingTime = now;
|
|
||||||
if (swingRight) {
|
|
||||||
swingOffset++;
|
|
||||||
if (swingOffset >= swingRange)
|
|
||||||
swingRight = false;
|
|
||||||
} else {
|
|
||||||
swingOffset--;
|
|
||||||
if (swingOffset <= 0)
|
|
||||||
swingRight = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < lineCount; i++) {
|
|
||||||
bool isTitle = (i == 0);
|
|
||||||
int globalOptionIndex = (i - 1) + firstOptionToShow;
|
|
||||||
bool isSelectedOption = (!isTitle && globalOptionIndex >= 0 && globalOptionIndex == curSelected);
|
|
||||||
|
|
||||||
uint16_t visibleWidth = 64 - hPadding * 2;
|
|
||||||
if (totalLines > visibleTotalLines)
|
|
||||||
visibleWidth -= 6;
|
|
||||||
char lineBuffer[lineLengths[i] + 1];
|
|
||||||
strncpy(lineBuffer, lines[i], lineLengths[i]);
|
|
||||||
lineBuffer[lineLengths[i]] = '\0';
|
|
||||||
|
|
||||||
if (isTitle) {
|
|
||||||
if (visibleTotalLines == 1) {
|
|
||||||
display->setColor(BLACK);
|
|
||||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
|
||||||
} else {
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
|
|
||||||
display->setColor(BLACK);
|
|
||||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
|
|
||||||
display->setColor(WHITE);
|
|
||||||
if (needs_bell) {
|
|
||||||
int bellY = boxTop + (FONT_HEIGHT_SMALL - 8) / 2;
|
|
||||||
display->drawXbm(boxLeft + (boxWidth - lineWidths[i]) / 2 - 10, bellY, 8, 8, bell_alert);
|
|
||||||
display->drawXbm(boxLeft + (boxWidth + lineWidths[i]) / 2 + 2, bellY, 8, 8, bell_alert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lineY = boxTop + effectiveLineHeight + 1;
|
|
||||||
} else if (isSelectedOption) {
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
|
||||||
display->setColor(BLACK);
|
|
||||||
if (lineLengths[i] > 15 && lineWidths[i] > visibleWidth) {
|
|
||||||
int textX = boxLeft + hPadding + swingOffset;
|
|
||||||
display->drawString(textX, lineY - 1, lineBuffer);
|
|
||||||
} else {
|
|
||||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY - 1, lineBuffer);
|
|
||||||
}
|
|
||||||
display->setColor(WHITE);
|
|
||||||
lineY += effectiveLineHeight;
|
|
||||||
} else {
|
|
||||||
display->setColor(BLACK);
|
|
||||||
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
|
|
||||||
display->setColor(WHITE);
|
|
||||||
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY, lineBuffer);
|
|
||||||
lineY += effectiveLineHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (totalLines > visibleTotalLines) {
|
|
||||||
const uint8_t scrollBarWidth = 5;
|
|
||||||
int16_t scrollBarX = boxLeft + boxWidth - scrollBarWidth - 2;
|
|
||||||
int16_t scrollBarY = boxTop + vPadding + effectiveLineHeight;
|
|
||||||
uint16_t scrollBarHeight = boxHeight - vPadding * 2 - effectiveLineHeight;
|
|
||||||
float ratio = (float)visibleTotalLines / totalLines;
|
|
||||||
uint16_t indicatorHeight = std::max((int)(scrollBarHeight * ratio), 4);
|
|
||||||
float scrollRatio = (float)(firstOptionToShow + lineCount - visibleTotalLines) / (totalLines - visibleTotalLines);
|
|
||||||
uint16_t indicatorY = scrollBarY + scrollRatio * (scrollBarHeight - indicatorHeight);
|
|
||||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
|
||||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (needs_bell) {
|
if (needs_bell) {
|
||||||
if (isHighResolution && boxWidth <= 150)
|
if (isHighResolution && boxWidth <= 150)
|
||||||
boxWidth += 26;
|
boxWidth += 26;
|
||||||
@@ -712,7 +579,6 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
|||||||
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
display->drawRect(scrollBarX, scrollBarY, scrollBarWidth, scrollBarHeight);
|
||||||
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
display->fillRect(scrollBarX + 1, indicatorY, scrollBarWidth - 2, indicatorHeight);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the last text message we received
|
/// Draw the last text message we received
|
||||||
@@ -795,8 +661,10 @@ void NotificationRenderer::drawTextInput(OLEDDisplay *display, OLEDDisplayUiStat
|
|||||||
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN_LONG) {
|
||||||
virtualKeyboard->moveCursorDown();
|
virtualKeyboard->moveCursorDown();
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
|
||||||
|
// Long press UP = move left
|
||||||
virtualKeyboard->moveCursorLeft();
|
virtualKeyboard->moveCursorLeft();
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
|
||||||
|
// Long press DOWN = move right
|
||||||
virtualKeyboard->moveCursorRight();
|
virtualKeyboard->moveCursorRight();
|
||||||
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
|
||||||
virtualKeyboard->handlePress();
|
virtualKeyboard->handlePress();
|
||||||
@@ -825,7 +693,6 @@ void NotificationRenderer::drawTextInput(OLEDDisplay *display, OLEDDisplayUiStat
|
|||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
display->fillRect(0, 0, display->getWidth(), display->getHeight());
|
display->fillRect(0, 0, display->getWidth(), display->getHeight());
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
// Draw the virtual keyboard
|
|
||||||
virtualKeyboard->draw(display, 0, 0);
|
virtualKeyboard->draw(display, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
// If virtualKeyboard is null, reset the banner to avoid getting stuck
|
// If virtualKeyboard is null, reset the banner to avoid getting stuck
|
||||||
|
|||||||
@@ -20,9 +20,7 @@
|
|||||||
|
|
||||||
// External variables
|
// External variables
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
static uint32_t lastSwitchTime = 0;
|
|
||||||
#endif
|
|
||||||
namespace graphics
|
namespace graphics
|
||||||
{
|
{
|
||||||
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
NodeNum UIRenderer::currentFavoriteNodeNum = 0;
|
||||||
@@ -118,122 +116,64 @@ void UIRenderer::drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw GPS status coordinates
|
// Draw GPS status coordinates
|
||||||
void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps,
|
void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gps)
|
||||||
const char *mode)
|
|
||||||
{
|
{
|
||||||
auto gpsFormat = uiconfig.gps_format;
|
auto gpsFormat = config.display.gps_format;
|
||||||
char displayLine[32];
|
char displayLine[32];
|
||||||
|
|
||||||
if (!gps->getIsConnected() && !config.position.fixed_position) {
|
if (!gps->getIsConnected() && !config.position.fixed_position) {
|
||||||
strcpy(displayLine, "No GPS present");
|
strcpy(displayLine, "No GPS present");
|
||||||
display->drawString(x, y, displayLine);
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||||
} else if (!gps->getHasLock() && !config.position.fixed_position) {
|
} else if (!gps->getHasLock() && !config.position.fixed_position) {
|
||||||
if (strcmp(mode, "line1") == 0) {
|
strcpy(displayLine, "No GPS Lock");
|
||||||
strcpy(displayLine, "No GPS Lock");
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||||
display->drawString(x, y, displayLine);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
|
||||||
|
|
||||||
if (gpsFormat != meshtastic_DeviceUIConfig_GpsCoordinateFormat_DMS) {
|
if (gpsFormat != meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) {
|
||||||
char coordinateLine_1[22];
|
char coordinateLine[22];
|
||||||
char coordinateLine_2[22];
|
if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
|
||||||
if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
|
snprintf(coordinateLine, sizeof(coordinateLine), "%f %f", geoCoord.getLatitude() * 1e-7,
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "Lat: %f", geoCoord.getLatitude() * 1e-7);
|
geoCoord.getLongitude() * 1e-7);
|
||||||
snprintf(coordinateLine_2, sizeof(coordinateLine_2), "Lon: %f", geoCoord.getLongitude() * 1e-7);
|
} else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
|
||||||
} else if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
|
snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%2i%1c %06u E", geoCoord.getUTMZone(),
|
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
|
||||||
geoCoord.getUTMBand(), geoCoord.getUTMEasting());
|
} else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System
|
||||||
snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%07u N", geoCoord.getUTMNorthing());
|
snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(),
|
||||||
} else if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System
|
geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(),
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%2i%1c %1c%1c", geoCoord.getMGRSZone(),
|
geoCoord.getMGRSEasting(), geoCoord.getMGRSNorthing());
|
||||||
geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k());
|
} else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC) { // Open Location Code
|
||||||
snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%05u E %05u N", geoCoord.getMGRSEasting(),
|
geoCoord.getOLCCode(coordinateLine);
|
||||||
geoCoord.getMGRSNorthing());
|
} else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference
|
||||||
} else if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC) { // Open Location Code
|
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
|
||||||
geoCoord.getOLCCode(coordinateLine_1);
|
snprintf(coordinateLine, sizeof(coordinateLine), "%s", "Out of Boundary");
|
||||||
coordinateLine_2[0] = '\0';
|
else
|
||||||
} else if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference
|
snprintf(coordinateLine, sizeof(coordinateLine), "%1c%1c %05u %05u", geoCoord.getOSGRE100k(),
|
||||||
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') { // OSGR is only valid around the UK region
|
geoCoord.getOSGRN100k(), geoCoord.getOSGREasting(), geoCoord.getOSGRNorthing());
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%s", "Out of Boundary");
|
}
|
||||||
coordinateLine_2[0] = '\0';
|
|
||||||
|
// If fixed position, display text "Fixed GPS" alternating with the coordinates.
|
||||||
|
if (config.position.fixed_position) {
|
||||||
|
if ((millis() / 10000) % 2) {
|
||||||
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(coordinateLine))) / 2, y,
|
||||||
|
coordinateLine);
|
||||||
} else {
|
} else {
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "%1c%1c", geoCoord.getOSGRE100k(),
|
display->drawString(x + (display->getWidth() - (display->getStringWidth("Fixed GPS"))) / 2, y, "Fixed GPS");
|
||||||
geoCoord.getOSGRN100k());
|
|
||||||
snprintf(coordinateLine_2, sizeof(coordinateLine_2), "%05u E %05u N", geoCoord.getOSGREasting(),
|
|
||||||
geoCoord.getOSGRNorthing());
|
|
||||||
}
|
}
|
||||||
} else if (gpsFormat == meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS) { // Maidenhead Locator System
|
} else {
|
||||||
double lat = geoCoord.getLatitude() * 1e-7;
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
|
||||||
double lon = geoCoord.getLongitude() * 1e-7;
|
|
||||||
|
|
||||||
// Normalize
|
|
||||||
if (lat > 90.0)
|
|
||||||
lat = 90.0;
|
|
||||||
if (lat < -90.0)
|
|
||||||
lat = -90.0;
|
|
||||||
while (lon < -180.0)
|
|
||||||
lon += 360.0;
|
|
||||||
while (lon >= 180.0)
|
|
||||||
lon -= 360.0;
|
|
||||||
|
|
||||||
double adjLon = lon + 180.0;
|
|
||||||
double adjLat = lat + 90.0;
|
|
||||||
|
|
||||||
char maiden[10]; // enough for 8-char + null
|
|
||||||
|
|
||||||
// Field (2 letters)
|
|
||||||
int lonField = int(adjLon / 20.0);
|
|
||||||
int latField = int(adjLat / 10.0);
|
|
||||||
adjLon -= lonField * 20.0;
|
|
||||||
adjLat -= latField * 10.0;
|
|
||||||
|
|
||||||
// Square (2 digits)
|
|
||||||
int lonSquare = int(adjLon / 2.0);
|
|
||||||
int latSquare = int(adjLat / 1.0);
|
|
||||||
adjLon -= lonSquare * 2.0;
|
|
||||||
adjLat -= latSquare * 1.0;
|
|
||||||
|
|
||||||
// Subsquare (2 letters)
|
|
||||||
double lonUnit = 2.0 / 24.0;
|
|
||||||
double latUnit = 1.0 / 24.0;
|
|
||||||
int lonSub = int(adjLon / lonUnit);
|
|
||||||
int latSub = int(adjLat / latUnit);
|
|
||||||
|
|
||||||
snprintf(maiden, sizeof(maiden), "%c%c%c%c%c%c", 'A' + lonField, 'A' + latField, '0' + lonSquare, '0' + latSquare,
|
|
||||||
'A' + lonSub, 'A' + latSub);
|
|
||||||
|
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "MH: %s", maiden);
|
|
||||||
coordinateLine_2[0] = '\0'; // only need one line
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(mode, "line1") == 0) {
|
|
||||||
display->drawString(x, y, coordinateLine_1);
|
|
||||||
} else if (strcmp(mode, "line2") == 0) {
|
|
||||||
display->drawString(x, y, coordinateLine_2);
|
|
||||||
} else if (strcmp(mode, "combined") == 0) {
|
|
||||||
display->drawString(x, y, coordinateLine_1);
|
|
||||||
if (coordinateLine_2[0] != '\0') {
|
|
||||||
display->drawString(x + display->getStringWidth(coordinateLine_1), y, coordinateLine_2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
char coordinateLine_1[22];
|
char latLine[22];
|
||||||
char coordinateLine_2[22];
|
char lonLine[22];
|
||||||
snprintf(coordinateLine_1, sizeof(coordinateLine_1), "Lat: %2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(),
|
snprintf(latLine, sizeof(latLine), "%2i° %2i' %2u\" %1c", geoCoord.getDMSLatDeg(), geoCoord.getDMSLatMin(),
|
||||||
geoCoord.getDMSLatMin(), geoCoord.getDMSLatSec(), geoCoord.getDMSLatCP());
|
geoCoord.getDMSLatSec(), geoCoord.getDMSLatCP());
|
||||||
snprintf(coordinateLine_2, sizeof(coordinateLine_2), "Lon: %3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(),
|
snprintf(lonLine, sizeof(lonLine), "%3i° %2i' %2u\" %1c", geoCoord.getDMSLonDeg(), geoCoord.getDMSLonMin(),
|
||||||
geoCoord.getDMSLonMin(), geoCoord.getDMSLonSec(), geoCoord.getDMSLonCP());
|
geoCoord.getDMSLonSec(), geoCoord.getDMSLonCP());
|
||||||
if (strcmp(mode, "line1") == 0) {
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(latLine))) / 2, y - FONT_HEIGHT_SMALL * 1,
|
||||||
display->drawString(x, y, coordinateLine_1);
|
latLine);
|
||||||
} else if (strcmp(mode, "line2") == 0) {
|
display->drawString(x + (display->getWidth() - (display->getStringWidth(lonLine))) / 2, y, lonLine);
|
||||||
display->drawString(x, y, coordinateLine_2);
|
|
||||||
} else { // both
|
|
||||||
display->drawString(x, y, coordinateLine_1);
|
|
||||||
display->drawString(x, y + 10, coordinateLine_2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +194,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
|
|
||||||
if (isHighResolution) {
|
if (isHighResolution) {
|
||||||
@@ -278,6 +218,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
|||||||
// **********************
|
// **********************
|
||||||
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (favoritedNodes.empty())
|
if (favoritedNodes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -289,15 +230,8 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
meshtastic_NodeInfoLite *node = favoritedNodes[nodeIndex];
|
meshtastic_NodeInfoLite *node = favoritedNodes[nodeIndex];
|
||||||
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
display->clear();
|
display->clear();
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
uint32_t now = millis();
|
|
||||||
if (now - lastSwitchTime >= 10000) // 10000 ms = 10 秒
|
|
||||||
{
|
|
||||||
display->display();
|
|
||||||
lastSwitchTime = now;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
currentFavoriteNodeNum = node->num;
|
currentFavoriteNodeNum = node->num;
|
||||||
// === Create the shortName and title string ===
|
// === Create the shortName and title string ===
|
||||||
const char *shortName = (node->has_user && haveGlyphs(node->user.short_name)) ? node->user.short_name : "Node";
|
const char *shortName = (node->has_user && haveGlyphs(node->user.short_name)) ? node->user.short_name : "Node";
|
||||||
@@ -316,13 +250,9 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
// List of available macro Y positions in order, from top to bottom.
|
// List of available macro Y positions in order, from top to bottom.
|
||||||
int line = 1; // which slot to use next
|
int line = 1; // which slot to use next
|
||||||
std::string usernameStr;
|
std::string usernameStr;
|
||||||
// === 1. Long Name (always try to show first) ===
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.short_name : nullptr;
|
|
||||||
#else
|
|
||||||
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// === 1. Long Name (always try to show first) ===
|
||||||
|
const char *username = (node->has_user && node->user.long_name[0]) ? node->user.long_name : nullptr;
|
||||||
if (username) {
|
if (username) {
|
||||||
usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case
|
usernameStr = sanitizeString(username); // Sanitize the incoming long_name just in case
|
||||||
// Print node's long name (e.g. "Backpack Node")
|
// Print node's long name (e.g. "Backpack Node")
|
||||||
@@ -377,7 +307,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
if (seenStr[0] && line < 5) {
|
if (seenStr[0] && line < 5) {
|
||||||
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
||||||
}
|
}
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
// === 4. Uptime (only show if metric is present) ===
|
// === 4. Uptime (only show if metric is present) ===
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||||
@@ -549,7 +479,6 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st
|
|||||||
}
|
}
|
||||||
// else show nothing
|
// else show nothing
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************
|
// ****************************
|
||||||
@@ -563,11 +492,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
int line = 1;
|
int line = 1;
|
||||||
|
|
||||||
// === Header ===
|
// === Header ===
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
graphics::drawCommonHeader(display, x, y, "Home");
|
|
||||||
#else
|
|
||||||
graphics::drawCommonHeader(display, x, y, "");
|
graphics::drawCommonHeader(display, x, y, "");
|
||||||
#endif
|
|
||||||
|
|
||||||
// === Content below header ===
|
// === Content below header ===
|
||||||
|
|
||||||
@@ -582,25 +507,20 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
config.display.heading_bold = false;
|
config.display.heading_bold = false;
|
||||||
|
|
||||||
// Display Region and Channel Utilization
|
// Display Region and Channel Utilization
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
drawNodes(display, x, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
|
||||||
#else
|
|
||||||
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
drawNodes(display, x + 1, getTextPositions(display)[line] + 2, nodeStatus, -1, false, "online");
|
||||||
#endif
|
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
uint32_t uptime = millis() / 1000;
|
uint32_t uptime = millis() / 1000;
|
||||||
uint32_t days = uptime / 86400;
|
uint32_t days = uptime / 86400;
|
||||||
uint32_t hours = (uptime % 86400) / 3600;
|
uint32_t hours = (uptime % 86400) / 3600;
|
||||||
uint32_t mins = (uptime % 3600) / 60;
|
uint32_t mins = (uptime % 3600) / 60;
|
||||||
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
// Show as "Up: 2d 3h", "Up: 5h 14m", or "Up: 37m"
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
if (days)
|
if (days)
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %ud %uh", days, hours);
|
||||||
else if (hours)
|
else if (hours)
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %uh %um", hours, mins);
|
||||||
else
|
else
|
||||||
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
snprintf(uptimeStr, sizeof(uptimeStr), "Up: %um", mins);
|
||||||
#endif
|
|
||||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
display->drawString(SCREEN_WIDTH - display->getStringWidth(uptimeStr), getTextPositions(display)[line++], uptimeStr);
|
||||||
|
|
||||||
// === Second Row: Satellites and Voltage ===
|
// === Second Row: Satellites and Voltage ===
|
||||||
@@ -629,21 +549,6 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
line += 1;
|
|
||||||
|
|
||||||
// === Node Identity ===
|
|
||||||
int textWidth = 0;
|
|
||||||
int nameX = 0;
|
|
||||||
char shortnameble[35];
|
|
||||||
snprintf(shortnameble, sizeof(shortnameble), "%s",
|
|
||||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
|
||||||
|
|
||||||
// === ShortName Centered ===
|
|
||||||
textWidth = display->getStringWidth(shortnameble);
|
|
||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
|
||||||
#else
|
|
||||||
if (powerStatus->getHasBattery()) {
|
if (powerStatus->getHasBattery()) {
|
||||||
char batStr[20];
|
char batStr[20];
|
||||||
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||||||
@@ -736,6 +641,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
int textWidth = 0;
|
int textWidth = 0;
|
||||||
int nameX = 0;
|
int nameX = 0;
|
||||||
int yOffset = (isHighResolution) ? 0 : 5;
|
int yOffset = (isHighResolution) ? 0 : 5;
|
||||||
|
const char *longName = nullptr;
|
||||||
std::string longNameStr;
|
std::string longNameStr;
|
||||||
|
|
||||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||||
@@ -768,7 +674,6 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Functions to write date/time to the screen
|
// Start Functions to write date/time to the screen
|
||||||
@@ -927,28 +832,6 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
|||||||
// needs to be drawn relative to x and y
|
// needs to be drawn relative to x and y
|
||||||
|
|
||||||
// draw centered icon left to right and centered above the one line of app text
|
// draw centered icon left to right and centered above the one line of app text
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
display->drawXbm(x + (SCREEN_WIDTH - 50) / 2, y + (SCREEN_HEIGHT - 28) / 2, icon_width, icon_height, icon_bits);
|
|
||||||
display->setFont(FONT_MEDIUM);
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
// Draw region in upper left
|
|
||||||
if (upperMsg) {
|
|
||||||
int msgWidth = display->getStringWidth(upperMsg);
|
|
||||||
int msgX = x + (SCREEN_WIDTH - msgWidth) / 2;
|
|
||||||
int msgY = y;
|
|
||||||
display->drawString(msgX, msgY, upperMsg);
|
|
||||||
}
|
|
||||||
// Draw version and short name in bottom middle
|
|
||||||
char buf[25];
|
|
||||||
snprintf(buf, sizeof(buf), "%s %s", xstr(APP_VERSION_SHORT),
|
|
||||||
graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : "");
|
|
||||||
|
|
||||||
display->drawString(x + getStringCenteredX(buf), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, buf);
|
|
||||||
screen->forceDisplay();
|
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
|
||||||
#else
|
|
||||||
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
|
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
|
||||||
icon_width, icon_height, icon_bits);
|
icon_width, icon_height, icon_bits);
|
||||||
|
|
||||||
@@ -957,6 +840,7 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
|||||||
const char *title = "meshtastic.org";
|
const char *title = "meshtastic.org";
|
||||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// Draw region in upper left
|
// Draw region in upper left
|
||||||
if (upperMsg)
|
if (upperMsg)
|
||||||
display->drawString(x + 0, y + 0, upperMsg);
|
display->drawString(x + 0, y + 0, upperMsg);
|
||||||
@@ -971,7 +855,6 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
|||||||
screen->forceDisplay();
|
screen->forceDisplay();
|
||||||
|
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************
|
// ****************************
|
||||||
@@ -996,26 +879,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
config.display.heading_bold = false;
|
config.display.heading_bold = false;
|
||||||
|
|
||||||
const char *displayLine = ""; // Initialize to empty string by default
|
const char *displayLine = ""; // Initialize to empty string by default
|
||||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||||
|
|
||||||
bool usePhoneGPS = (ourNode && nodeDB->hasValidPosition(ourNode) &&
|
|
||||||
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED);
|
|
||||||
|
|
||||||
if (usePhoneGPS) {
|
|
||||||
// Phone-provided GPS is active
|
|
||||||
displayLine = "Phone GPS";
|
|
||||||
int yOffset = (isHighResolution) ? 3 : 1;
|
|
||||||
if (isHighResolution) {
|
|
||||||
NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width,
|
|
||||||
imgSatellite_height, imgSatellite, display);
|
|
||||||
} else {
|
|
||||||
display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height,
|
|
||||||
imgSatellite);
|
|
||||||
}
|
|
||||||
int xOffset = (isHighResolution) ? 6 : 0;
|
|
||||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
|
||||||
} else if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
|
||||||
// GPS disabled / not present
|
|
||||||
if (config.position.fixed_position) {
|
if (config.position.fixed_position) {
|
||||||
displayLine = "Fixed GPS";
|
displayLine = "Fixed GPS";
|
||||||
} else {
|
} else {
|
||||||
@@ -1032,7 +896,6 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
int xOffset = (isHighResolution) ? 6 : 0;
|
int xOffset = (isHighResolution) ? 6 : 0;
|
||||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
||||||
} else {
|
} else {
|
||||||
// Onboard GPS
|
|
||||||
UIRenderer::drawGps(display, 0, getTextPositions(display)[line++], gpsStatus);
|
UIRenderer::drawGps(display, 0, getTextPositions(display)[line++], gpsStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,52 +922,36 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
|
|
||||||
// If GPS is off, no need to display these parts
|
// If GPS is off, no need to display these parts
|
||||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||||
// === Second Row: Last GPS Fix ===
|
|
||||||
if (gpsStatus->getLastFixMillis() > 0) {
|
|
||||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
|
||||||
uint32_t days = delta / 86400;
|
|
||||||
uint32_t hours = (delta % 86400) / 3600;
|
|
||||||
uint32_t mins = (delta % 3600) / 60;
|
|
||||||
uint32_t secs = delta % 60;
|
|
||||||
|
|
||||||
char buf[32];
|
// === Second Row: Date ===
|
||||||
#if defined(USE_EINK)
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||||
// E-Ink: skip seconds, show only days/hours/mins
|
char datetimeStr[25];
|
||||||
if (days > 0) {
|
bool showTime = false; // set to true for full datetime
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||||
} else if (hours > 0) {
|
char fullLine[40];
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
|
||||||
} else {
|
display->drawString(0, getTextPositions(display)[line++], fullLine);
|
||||||
snprintf(buf, sizeof(buf), "Last: %um", mins);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Non E-Ink: include seconds where useful
|
|
||||||
if (days > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
|
||||||
} else if (mins > 0) {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
// === Third Row: Latitude ===
|
||||||
|
char latStr[32];
|
||||||
|
snprintf(latStr, sizeof(latStr), " Lat: %.5f", geoCoord.getLatitude() * 1e-7);
|
||||||
|
display->drawString(x, getTextPositions(display)[line++], latStr);
|
||||||
|
|
||||||
|
// === Fourth Row: Longitude ===
|
||||||
|
char lonStr[32];
|
||||||
|
snprintf(lonStr, sizeof(lonStr), " Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||||
|
display->drawString(x, getTextPositions(display)[line++], lonStr);
|
||||||
|
|
||||||
|
// === Fifth Row: Altitude ===
|
||||||
|
char DisplayLineTwo[32] = {0};
|
||||||
|
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||||
|
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0fft", geoCoord.getAltitude() * METERS_TO_FEET);
|
||||||
} else {
|
} else {
|
||||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0im", geoCoord.getAltitude());
|
||||||
}
|
|
||||||
|
|
||||||
// === Third Row: Line 1 GPS Info ===
|
|
||||||
UIRenderer::drawGpsCoordinates(display, x, getTextPositions(display)[line++], gpsStatus, "line1");
|
|
||||||
|
|
||||||
if (uiconfig.gps_format != meshtastic_DeviceUIConfig_GpsCoordinateFormat_OLC &&
|
|
||||||
uiconfig.gps_format != meshtastic_DeviceUIConfig_GpsCoordinateFormat_MLS) {
|
|
||||||
// === Fourth Row: Line 2 GPS Info ===
|
|
||||||
UIRenderer::drawGpsCoordinates(display, x, getTextPositions(display)[line++], gpsStatus, "line2");
|
|
||||||
}
|
}
|
||||||
|
display->drawString(x, getTextPositions(display)[line++], DisplayLineTwo);
|
||||||
}
|
}
|
||||||
#if !defined(M5STACK_UNITC6L)
|
|
||||||
// === Draw Compass if heading is valid ===
|
// === Draw Compass if heading is valid ===
|
||||||
if (validHeading) {
|
if (validHeading) {
|
||||||
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
||||||
@@ -1187,7 +1034,6 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif // HAS_GPS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USERPREFS_OEM_TEXT
|
#ifdef USERPREFS_OEM_TEXT
|
||||||
@@ -1280,13 +1126,14 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
const int totalWidth = (pageEnd - pageStart) * iconSize + (pageEnd - pageStart - 1) * spacing;
|
const int totalWidth = (pageEnd - pageStart) * iconSize + (pageEnd - pageStart - 1) * spacing;
|
||||||
const int xStart = (SCREEN_WIDTH - totalWidth) / 2;
|
const int xStart = (SCREEN_WIDTH - totalWidth) / 2;
|
||||||
|
|
||||||
|
// Only show bar briefly after switching frames
|
||||||
|
static uint32_t navBarLastShown = 0;
|
||||||
|
static bool cosmeticRefreshDone = false;
|
||||||
|
|
||||||
bool navBarVisible = millis() - lastFrameChangeTime <= ICON_DISPLAY_DURATION_MS;
|
bool navBarVisible = millis() - lastFrameChangeTime <= ICON_DISPLAY_DURATION_MS;
|
||||||
int y = navBarVisible ? (SCREEN_HEIGHT - iconSize - 1) : SCREEN_HEIGHT;
|
int y = navBarVisible ? (SCREEN_HEIGHT - iconSize - 1) : SCREEN_HEIGHT;
|
||||||
|
|
||||||
#if defined(USE_EINK)
|
#if defined(USE_EINK)
|
||||||
// Only show bar briefly after switching frames
|
|
||||||
static uint32_t navBarLastShown = 0;
|
|
||||||
static bool cosmeticRefreshDone = false;
|
|
||||||
static bool navBarPrevVisible = false;
|
static bool navBarPrevVisible = false;
|
||||||
|
|
||||||
if (navBarVisible && !navBarPrevVisible) {
|
if (navBarVisible && !navBarPrevVisible) {
|
||||||
@@ -1343,6 +1190,7 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Knock the corners off the square
|
// Knock the corners off the square
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
display->drawRect(rectX, y - 2, 1, 1);
|
display->drawRect(rectX, y - 2, 1, 1);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "graphics/emotes.h"
|
#include "graphics/emotes.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
@@ -38,8 +37,7 @@ class UIRenderer
|
|||||||
|
|
||||||
// GPS status functions
|
// GPS status functions
|
||||||
static void drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
static void drawGps(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
||||||
static void drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus,
|
static void drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
||||||
const char *mode = "line1");
|
|
||||||
static void drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
static void drawGpsAltitude(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
||||||
static void drawGpsPowerStatus(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
static void drawGpsPowerStatus(OLEDDisplay *display, int16_t x, int16_t y, const meshtastic::GPSStatus *gpsStatus);
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
|
|||||||
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
|
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \
|
||||||
ARCH_PORTDUINO) && \
|
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||||
@@ -118,8 +117,8 @@ const uint8_t icon_radio[] PROGMEM = {
|
|||||||
0xA9 // Row 7: #..#.#.#
|
0xA9 // Row 7: #..#.#.#
|
||||||
};
|
};
|
||||||
|
|
||||||
// 🪙 System Icon
|
// 🪙 Memory Icon
|
||||||
const uint8_t icon_system[] PROGMEM = {
|
const uint8_t icon_memory[] PROGMEM = {
|
||||||
0x24, // Row 0: ..#..#..
|
0x24, // Row 0: ..#..#..
|
||||||
0x3C, // Row 1: ..####..
|
0x3C, // Row 1: ..####..
|
||||||
0xC3, // Row 2: ##....##
|
0xC3, // Row 2: ##....##
|
||||||
@@ -288,81 +287,5 @@ const uint8_t digital_icon_clock[] PROGMEM = {0b00111100, 0b01000010, 0b10000101
|
|||||||
const uint8_t analog_icon_clock[] PROGMEM = {0b11111111, 0b01000010, 0b00100100, 0b00011000,
|
const uint8_t analog_icon_clock[] PROGMEM = {0b11111111, 0b01000010, 0b00100100, 0b00011000,
|
||||||
0b00100100, 0b01000010, 0b01000010, 0b11111111};
|
0b00100100, 0b01000010, 0b01000010, 0b11111111};
|
||||||
|
|
||||||
#define chirpy_width 38
|
|
||||||
#define chirpy_height 50
|
|
||||||
const uint8_t chirpy[] = {
|
|
||||||
0xfe, 0xff, 0xff, 0xff, 0xdf, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x80, 0xe3, 0x01,
|
|
||||||
0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0x80, 0xe3, 0x01, 0x00,
|
|
||||||
0x00, 0x00, 0xe0, 0x81, 0xff, 0xff, 0x7f, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xcf, 0x7f,
|
|
||||||
0xfe, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc,
|
|
||||||
0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0,
|
|
||||||
0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1,
|
|
||||||
0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0xcf, 0x7f, 0xfe, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0x81, 0xff,
|
|
||||||
0xff, 0x7f, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xc3, 0x00, 0xe0, 0x01, 0x00, 0xc3,
|
|
||||||
0x00, 0xe0, 0x01, 0x80, 0xe1, 0x01, 0xe0, 0x01, 0x80, 0xe1, 0x01, 0xe0, 0x01, 0xc0, 0x30, 0x03, 0xe0, 0x01, 0xc0, 0x30, 0x03,
|
|
||||||
0xe0, 0x01, 0x60, 0x18, 0x06, 0xe0, 0x01, 0x60, 0x18, 0x06, 0xe0, 0x01, 0x30, 0x0c, 0x0c, 0xe0, 0x01, 0x30, 0x0c, 0x0c, 0xe0,
|
|
||||||
0x01, 0x18, 0x06, 0x18, 0xe0, 0x01, 0x18, 0x06, 0x18, 0xe0, 0x01, 0x0c, 0x03, 0x30, 0xe0, 0x01, 0x0c, 0x03, 0x30, 0xe0, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xdf};
|
|
||||||
|
|
||||||
#define chirpy_width_hirez 76
|
|
||||||
#define chirpy_height_hirez 100
|
|
||||||
const uint8_t chirpy_hirez[] = {
|
|
||||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x03,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
|
|
||||||
0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc,
|
|
||||||
0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03,
|
|
||||||
0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0,
|
|
||||||
0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f,
|
|
||||||
0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0,
|
|
||||||
0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff,
|
|
||||||
0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f,
|
|
||||||
0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0,
|
|
||||||
0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff,
|
|
||||||
0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00,
|
|
||||||
0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc,
|
|
||||||
0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03,
|
|
||||||
0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0,
|
|
||||||
0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f,
|
|
||||||
0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0,
|
|
||||||
0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff,
|
|
||||||
0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
|
||||||
0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03,
|
|
||||||
0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00,
|
|
||||||
0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
|
|
||||||
0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0,
|
|
||||||
0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00,
|
|
||||||
0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f,
|
|
||||||
0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c,
|
|
||||||
0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00,
|
|
||||||
0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00,
|
|
||||||
0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc,
|
|
||||||
0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03,
|
|
||||||
0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00,
|
|
||||||
0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0,
|
|
||||||
0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xf3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3};
|
|
||||||
|
|
||||||
#define chirpy_small_image_width 8
|
|
||||||
#define chirpy_small_image_height 8
|
|
||||||
const uint8_t chirpy_small[] = {0x7f, 0x41, 0x55, 0x55, 0x55, 0x55, 0x41, 0x7f};
|
|
||||||
|
|
||||||
#ifdef M5STACK_UNITC6L
|
|
||||||
#include "img/icon_small.xbm"
|
|
||||||
#else
|
|
||||||
#include "img/icon.xbm"
|
#include "img/icon.xbm"
|
||||||
#endif
|
|
||||||
static_assert(sizeof(icon_bits) >= 0, "Silence unused variable warning");
|
static_assert(sizeof(icon_bits) >= 0, "Silence unused variable warning");
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#ifndef USERPREFS_HAS_SPLASH
|
|
||||||
#define icon_width 50
|
|
||||||
#define icon_height 20
|
|
||||||
static uint8_t icon_bits[] = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80,
|
|
||||||
0x07, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xc0, 0x0f,
|
|
||||||
0xc0, 0x0f, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xe0,
|
|
||||||
0x0f, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x1f,
|
|
||||||
0x00, 0x00, 0x00, 0xf0, 0x03, 0xf0, 0x3f, 0x00,
|
|
||||||
0x00, 0x00, 0xf8, 0x03, 0xf8, 0x7f, 0x00, 0x00,
|
|
||||||
0x00, 0xf8, 0x01, 0xfc, 0x7e, 0x00, 0x00, 0x00,
|
|
||||||
0xfc, 0x00, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0xfe,
|
|
||||||
0x00, 0x7e, 0xf8, 0x00, 0x00, 0x00, 0x7e, 0x00,
|
|
||||||
0x3f, 0xf8, 0x01, 0x00, 0x00, 0x3f, 0x00, 0x1f,
|
|
||||||
0xf0, 0x01, 0x00, 0x00, 0x1f, 0x80, 0x1f, 0xe0,
|
|
||||||
0x03, 0x00, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x03,
|
|
||||||
0x00, 0x80, 0x0f, 0xc0, 0x07, 0xc0, 0x07, 0x00,
|
|
||||||
0xc0, 0x0f, 0xe0, 0x07, 0x80, 0x0f, 0x00, 0xe0,
|
|
||||||
0x07, 0xf0, 0x03, 0x80, 0x1f, 0x00, 0xe0, 0x03,
|
|
||||||
0xf8, 0x03, 0x00, 0x1f, 0x00, 0xf0, 0x03, 0xf8,
|
|
||||||
0x01, 0x00, 0x3f, 0x00, 0xf8, 0x01, 0xfc, 0x00,
|
|
||||||
0x00, 0x7e, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x00,
|
|
||||||
0x7e, 0x00, 0xfc, 0x00, 0x7e, 0x00, 0x00, 0xfc,
|
|
||||||
0x00, 0x7e, 0x00, 0x3f, 0x00, 0x00, 0xf8, 0x00,
|
|
||||||
0x7e, 0x00, 0x3e, 0x00, 0x00, 0xf8, 0x00, 0x38,
|
|
||||||
0x00, 0x1c, 0x00, 0x00, 0x70, 0x00, 0x10, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00 };
|
|
||||||
#endif
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#include "./ZJY122250_0213BAAMFGN.h"
|
|
||||||
|
|
||||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
||||||
|
|
||||||
using namespace NicheGraphics::Drivers;
|
|
||||||
|
|
||||||
// Map the display controller IC's output to the connected panel
|
|
||||||
void ZJY122250_0213BAAMFGN::configScanning()
|
|
||||||
{
|
|
||||||
// "Driver output control"
|
|
||||||
// Scan gates from 0 to 249 (vertical resolution 250px)
|
|
||||||
sendCommand(0x01);
|
|
||||||
sendData(0xF9);
|
|
||||||
sendData(0x00);
|
|
||||||
sendData(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
|
||||||
// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from
|
|
||||||
// the controller IC's OTP memory, when the update procedure begins.
|
|
||||||
void ZJY122250_0213BAAMFGN::configWaveform()
|
|
||||||
{
|
|
||||||
switch (updateType) {
|
|
||||||
case FAST:
|
|
||||||
sendCommand(0x3C); // Border waveform:
|
|
||||||
sendData(0x80); // VCOM
|
|
||||||
break;
|
|
||||||
case FULL:
|
|
||||||
default:
|
|
||||||
sendCommand(0x3C); // Border waveform:
|
|
||||||
sendData(0x01); // Follow LUT 1 (blink same as white pixels)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendCommand(0x18); // Temperature sensor:
|
|
||||||
sendData(0x80); // Use internal temperature sensor to select an appropriate refresh waveform
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZJY122250_0213BAAMFGN::configUpdateSequence()
|
|
||||||
{
|
|
||||||
switch (updateType) {
|
|
||||||
case FAST:
|
|
||||||
sendCommand(0x22); // Set "update sequence"
|
|
||||||
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FULL:
|
|
||||||
default:
|
|
||||||
sendCommand(0x22); // Set "update sequence"
|
|
||||||
sendData(0xF7); // Will load LUT from OTP memory
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once the refresh operation has been started,
|
|
||||||
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
|
|
||||||
// Only used when refresh is "async"
|
|
||||||
void ZJY122250_0213BAAMFGN::detachFromUpdate()
|
|
||||||
{
|
|
||||||
switch (updateType) {
|
|
||||||
case FAST:
|
|
||||||
return beginPolling(50, 500); // At least 500ms for fast refresh
|
|
||||||
case FULL:
|
|
||||||
default:
|
|
||||||
return beginPolling(100, 2000); // At least 2 seconds for full refresh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
E-Ink display driver
|
|
||||||
- ZJY122250_0213BAAMFGN
|
|
||||||
- Manufacturer: Zhongjingyuan
|
|
||||||
- Size: 2.13 inch
|
|
||||||
- Resolution: 250px x 122px
|
|
||||||
- Flex connector marking (not a unique identifier): FPC-A002
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#include "./SSD16XX.h"
|
|
||||||
|
|
||||||
namespace NicheGraphics::Drivers
|
|
||||||
{
|
|
||||||
class ZJY122250_0213BAAMFGN : public SSD16XX
|
|
||||||
{
|
|
||||||
// Display properties
|
|
||||||
private:
|
|
||||||
static constexpr uint32_t width = 122;
|
|
||||||
static constexpr uint32_t height = 250;
|
|
||||||
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
|
||||||
|
|
||||||
public:
|
|
||||||
ZJY122250_0213BAAMFGN() : SSD16XX(width, height, supported) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void configScanning() override;
|
|
||||||
virtual void configWaveform() override;
|
|
||||||
virtual void configUpdateSequence() override;
|
|
||||||
void detachFromUpdate() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace NicheGraphics::Drivers
|
|
||||||
|
|
||||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
||||||
@@ -7,7 +7,12 @@ using namespace NicheGraphics;
|
|||||||
|
|
||||||
// Timing for "maintenance"
|
// Timing for "maintenance"
|
||||||
// Paying off full-refresh debt with unprovoked updates, if the display is not very active
|
// Paying off full-refresh debt with unprovoked updates, if the display is not very active
|
||||||
|
|
||||||
|
#ifdef SEEED_WIO_TRACKER_L1
|
||||||
|
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 5 * 1000UL;
|
||||||
|
#else
|
||||||
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 60 * 1000UL;
|
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 60 * 1000UL;
|
||||||
|
#endif
|
||||||
static constexpr uint32_t MAINTENANCE_MS = 60 * 60 * 1000UL;
|
static constexpr uint32_t MAINTENANCE_MS = 60 * 60 * 1000UL;
|
||||||
|
|
||||||
InkHUD::DisplayHealth::DisplayHealth() : concurrency::OSThread("Mediator")
|
InkHUD::DisplayHealth::DisplayHealth() : concurrency::OSThread("Mediator")
|
||||||
|
|||||||
@@ -41,78 +41,78 @@ void tftSetup(void)
|
|||||||
PacketAPI::create(PacketServer::init());
|
PacketAPI::create(PacketServer::init());
|
||||||
deviceScreen->init(new PacketClient);
|
deviceScreen->init(new PacketClient);
|
||||||
#else
|
#else
|
||||||
if (portduino_config.displayPanel != no_screen) {
|
if (settingsMap[displayPanel] != no_screen) {
|
||||||
DisplayDriverConfig displayConfig;
|
DisplayDriverConfig displayConfig;
|
||||||
static char *panels[] = {"NOSCREEN", "X11", "FB", "ST7789", "ST7735", "ST7735S",
|
static char *panels[] = {"NOSCREEN", "X11", "FB", "ST7789", "ST7735", "ST7735S",
|
||||||
"ST7796", "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D"};
|
"ST7796", "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D"};
|
||||||
static char *touch[] = {"NOTOUCH", "XPT2046", "STMPE610", "GT911", "FT5x06"};
|
static char *touch[] = {"NOTOUCH", "XPT2046", "STMPE610", "GT911", "FT5x06"};
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
if (portduino_config.displayPanel == x11) {
|
if (settingsMap[displayPanel] == x11) {
|
||||||
if (portduino_config.displayWidth && portduino_config.displayHeight)
|
if (settingsMap[displayWidth] && settingsMap[displayHeight])
|
||||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)portduino_config.displayWidth,
|
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)settingsMap[displayWidth],
|
||||||
(uint16_t)portduino_config.displayHeight);
|
(uint16_t)settingsMap[displayHeight]);
|
||||||
else
|
else
|
||||||
displayConfig.device(DisplayDriverConfig::device_t::X11);
|
displayConfig.device(DisplayDriverConfig::device_t::X11);
|
||||||
} else
|
} else
|
||||||
#elif defined(USE_FRAMEBUFFER)
|
#elif defined(USE_FRAMEBUFFER)
|
||||||
if (portduino_config.displayPanel == fb) {
|
if (settingsMap[displayPanel] == fb) {
|
||||||
if (portduino_config.displayWidth && portduino_config.displayHeight)
|
if (settingsMap[displayWidth] && settingsMap[displayHeight])
|
||||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)portduino_config.displayWidth,
|
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)settingsMap[displayWidth],
|
||||||
(uint16_t)portduino_config.displayHeight);
|
(uint16_t)settingsMap[displayHeight]);
|
||||||
else
|
else
|
||||||
displayConfig.device(DisplayDriverConfig::device_t::FB);
|
displayConfig.device(DisplayDriverConfig::device_t::FB);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
displayConfig.device(DisplayDriverConfig::device_t::CUSTOM_TFT)
|
displayConfig.device(DisplayDriverConfig::device_t::CUSTOM_TFT)
|
||||||
.panel(DisplayDriverConfig::panel_config_t{.type = panels[portduino_config.displayPanel],
|
.panel(DisplayDriverConfig::panel_config_t{.type = panels[settingsMap[displayPanel]],
|
||||||
.panel_width = (uint16_t)portduino_config.displayWidth,
|
.panel_width = (uint16_t)settingsMap[displayWidth],
|
||||||
.panel_height = (uint16_t)portduino_config.displayHeight,
|
.panel_height = (uint16_t)settingsMap[displayHeight],
|
||||||
.rotation = (bool)portduino_config.displayRotate,
|
.rotation = (bool)settingsMap[displayRotate],
|
||||||
.pin_cs = (int16_t)portduino_config.displayCS.pin,
|
.pin_cs = (int16_t)settingsMap[displayCS],
|
||||||
.pin_rst = (int16_t)portduino_config.displayReset.pin,
|
.pin_rst = (int16_t)settingsMap[displayReset],
|
||||||
.offset_x = (uint16_t)portduino_config.displayOffsetX,
|
.offset_x = (uint16_t)settingsMap[displayOffsetX],
|
||||||
.offset_y = (uint16_t)portduino_config.displayOffsetY,
|
.offset_y = (uint16_t)settingsMap[displayOffsetY],
|
||||||
.offset_rotation = (uint8_t)portduino_config.displayOffsetRotate,
|
.offset_rotation = (uint8_t)settingsMap[displayOffsetRotate],
|
||||||
.invert = portduino_config.displayInvert ? true : false,
|
.invert = settingsMap[displayInvert] ? true : false,
|
||||||
.rgb_order = (bool)portduino_config.displayRGBOrder,
|
.rgb_order = (bool)settingsMap[displayRGBOrder],
|
||||||
.dlen_16bit = portduino_config.displayPanel == ili9486 ||
|
.dlen_16bit = settingsMap[displayPanel] == ili9486 ||
|
||||||
portduino_config.displayPanel == ili9488})
|
settingsMap[displayPanel] == ili9488})
|
||||||
.bus(DisplayDriverConfig::bus_config_t{.freq_write = (uint32_t)portduino_config.displayBusFrequency,
|
.bus(DisplayDriverConfig::bus_config_t{.freq_write = (uint32_t)settingsMap[displayBusFrequency],
|
||||||
.freq_read = 16000000,
|
.freq_read = 16000000,
|
||||||
.spi{.pin_dc = (int8_t)portduino_config.displayDC.pin,
|
.spi{.pin_dc = (int8_t)settingsMap[displayDC],
|
||||||
.use_lock = true,
|
.use_lock = true,
|
||||||
.spi_host = (uint16_t)portduino_config.display_spi_dev_int}})
|
.spi_host = (uint16_t)settingsMap[displayspidev]}})
|
||||||
.input(DisplayDriverConfig::input_config_t{.keyboardDevice = portduino_config.keyboardDevice,
|
.input(DisplayDriverConfig::input_config_t{.keyboardDevice = settingsStrings[keyboardDevice],
|
||||||
.pointerDevice = portduino_config.pointerDevice})
|
.pointerDevice = settingsStrings[pointerDevice]})
|
||||||
.light(DisplayDriverConfig::light_config_t{.pin_bl = (int16_t)portduino_config.displayBacklight.pin,
|
.light(DisplayDriverConfig::light_config_t{.pin_bl = (int16_t)settingsMap[displayBacklight],
|
||||||
.pwm_channel = (int8_t)portduino_config.displayBacklightPWMChannel.pin,
|
.pwm_channel = (int8_t)settingsMap[displayBacklightPWMChannel],
|
||||||
.invert = (bool)portduino_config.displayBacklightInvert});
|
.invert = (bool)settingsMap[displayBacklightInvert]});
|
||||||
if (portduino_config.touchscreenI2CAddr == -1) {
|
if (settingsMap[touchscreenI2CAddr] == -1) {
|
||||||
displayConfig.touch(
|
displayConfig.touch(
|
||||||
DisplayDriverConfig::touch_config_t{.type = touch[portduino_config.touchscreenModule],
|
DisplayDriverConfig::touch_config_t{.type = touch[settingsMap[touchscreenModule]],
|
||||||
.freq = (uint32_t)portduino_config.touchscreenBusFrequency,
|
.freq = (uint32_t)settingsMap[touchscreenBusFrequency],
|
||||||
.pin_int = (int16_t)portduino_config.touchscreenIRQ.pin,
|
.pin_int = (int16_t)settingsMap[touchscreenIRQ],
|
||||||
.offset_rotation = (uint8_t)portduino_config.touchscreenRotate,
|
.offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
|
||||||
.spi{
|
.spi{
|
||||||
.spi_host = (int8_t)portduino_config.touchscreen_spi_dev_int,
|
.spi_host = (int8_t)settingsMap[touchscreenspidev],
|
||||||
},
|
},
|
||||||
.pin_cs = (int16_t)portduino_config.touchscreenCS.pin});
|
.pin_cs = (int16_t)settingsMap[touchscreenCS]});
|
||||||
} else {
|
} else {
|
||||||
displayConfig.touch(DisplayDriverConfig::touch_config_t{
|
displayConfig.touch(DisplayDriverConfig::touch_config_t{
|
||||||
.type = touch[portduino_config.touchscreenModule],
|
.type = touch[settingsMap[touchscreenModule]],
|
||||||
.freq = (uint32_t)portduino_config.touchscreenBusFrequency,
|
.freq = (uint32_t)settingsMap[touchscreenBusFrequency],
|
||||||
.x_min = 0,
|
.x_min = 0,
|
||||||
.x_max = (int16_t)((portduino_config.touchscreenRotate & 1 ? portduino_config.displayWidth
|
.x_max =
|
||||||
: portduino_config.displayHeight) -
|
(int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayWidth] : settingsMap[displayHeight]) -
|
||||||
1),
|
1),
|
||||||
.y_min = 0,
|
.y_min = 0,
|
||||||
.y_max = (int16_t)((portduino_config.touchscreenRotate & 1 ? portduino_config.displayHeight
|
.y_max =
|
||||||
: portduino_config.displayWidth) -
|
(int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayHeight] : settingsMap[displayWidth]) -
|
||||||
1),
|
1),
|
||||||
.pin_int = (int16_t)portduino_config.touchscreenIRQ.pin,
|
.pin_int = (int16_t)settingsMap[touchscreenIRQ],
|
||||||
.offset_rotation = (uint8_t)portduino_config.touchscreenRotate,
|
.offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
|
||||||
.i2c{.i2c_addr = (uint8_t)portduino_config.touchscreenI2CAddr}});
|
.i2c{.i2c_addr = (uint8_t)settingsMap[touchscreenI2CAddr]}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deviceScreen = &DeviceScreen::create(&displayConfig);
|
deviceScreen = &DeviceScreen::create(&displayConfig);
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ void ExpressLRSFiveWay::determineAction(KeyType key, PressLength length)
|
|||||||
// Feed input to the canned messages module
|
// Feed input to the canned messages module
|
||||||
void ExpressLRSFiveWay::sendKey(input_broker_event key)
|
void ExpressLRSFiveWay::sendKey(input_broker_event key)
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.source = inputSourceName;
|
e.source = inputSourceName;
|
||||||
e.inputEvent = key;
|
e.inputEvent = key;
|
||||||
notifyObservers(&e);
|
notifyObservers(&e);
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ int32_t LinuxInput::runOnce()
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
if (portduino_config.keyboardDevice == "")
|
if (settingsStrings[keyboardDevice] == "")
|
||||||
return disable();
|
return disable();
|
||||||
fd = open(portduino_config.keyboardDevice.c_str(), O_RDWR);
|
fd = open(settingsStrings[keyboardDevice].c_str(), O_RDWR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return disable();
|
return disable();
|
||||||
ret = ioctl(fd, EVIOCGRAB, (void *)1);
|
ret = ioctl(fd, EVIOCGRAB, (void *)1);
|
||||||
@@ -73,7 +73,7 @@ int32_t LinuxInput::runOnce()
|
|||||||
int rd = read(events[i].data.fd, ev, sizeof(ev));
|
int rd = read(events[i].data.fd, ev, sizeof(ev));
|
||||||
assert(rd > ((signed int)sizeof(struct input_event)));
|
assert(rd > ((signed int)sizeof(struct input_event)));
|
||||||
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
|
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
e.kbchar = 0;
|
e.kbchar = 0;
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
#ifdef T_LORA_PAGER
|
|
||||||
|
|
||||||
#include "RotaryEncoderImpl.h"
|
|
||||||
#include "InputBroker.h"
|
|
||||||
#include "RotaryEncoder.h"
|
|
||||||
|
|
||||||
#define ORIGIN_NAME "RotaryEncoder"
|
|
||||||
|
|
||||||
RotaryEncoderImpl *rotaryEncoderImpl;
|
|
||||||
|
|
||||||
RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME)
|
|
||||||
{
|
|
||||||
rotary = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RotaryEncoderImpl::init()
|
|
||||||
{
|
|
||||||
if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 ||
|
|
||||||
moduleConfig.canned_message.inputbroker_pin_b == 0) {
|
|
||||||
// Input device is disabled.
|
|
||||||
disable();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
eventCw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_cw);
|
|
||||||
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
|
||||||
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
|
||||||
|
|
||||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
|
||||||
moduleConfig.canned_message.inputbroker_pin_press);
|
|
||||||
rotary->resetButton();
|
|
||||||
|
|
||||||
inputBroker->registerSource(this);
|
|
||||||
|
|
||||||
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
|
||||||
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
|
||||||
eventPressed);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t RotaryEncoderImpl::runOnce()
|
|
||||||
{
|
|
||||||
InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0};
|
|
||||||
static uint32_t lastPressed = millis();
|
|
||||||
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
|
||||||
if (lastPressed + 200 < millis()) {
|
|
||||||
LOG_DEBUG("Rotary event Press");
|
|
||||||
lastPressed = millis();
|
|
||||||
e.inputEvent = this->eventPressed;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (rotary->process()) {
|
|
||||||
case RotaryEncoder::DIRECTION_CW:
|
|
||||||
LOG_DEBUG("Rotary event CW");
|
|
||||||
e.inputEvent = this->eventCw;
|
|
||||||
break;
|
|
||||||
case RotaryEncoder::DIRECTION_CCW:
|
|
||||||
LOG_DEBUG("Rotary event CCW");
|
|
||||||
e.inputEvent = this->eventCcw;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.inputEvent != INPUT_BROKER_NONE) {
|
|
||||||
this->notifyObservers(&e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// This is a non-interrupt version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library)
|
|
||||||
|
|
||||||
#include "InputBroker.h"
|
|
||||||
#include "concurrency/OSThread.h"
|
|
||||||
#include "mesh/NodeDB.h"
|
|
||||||
|
|
||||||
class RotaryEncoder;
|
|
||||||
|
|
||||||
class RotaryEncoderImpl : public Observable<const InputEvent *>, public concurrency::OSThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RotaryEncoderImpl();
|
|
||||||
bool init(void);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual int32_t runOnce() override;
|
|
||||||
|
|
||||||
input_broker_event eventCw = INPUT_BROKER_NONE;
|
|
||||||
input_broker_event eventCcw = INPUT_BROKER_NONE;
|
|
||||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
|
||||||
|
|
||||||
RotaryEncoder *rotary;
|
|
||||||
const char *originName;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
|
||||||
@@ -20,23 +20,14 @@ void RotaryEncoderInterruptBase::init(
|
|||||||
this->_eventPressed = eventPressed;
|
this->_eventPressed = eventPressed;
|
||||||
this->_eventPressedLong = eventPressedLong;
|
this->_eventPressedLong = eventPressedLong;
|
||||||
|
|
||||||
bool isRAK = false;
|
pinMode(pinPress, INPUT_PULLUP);
|
||||||
#ifdef RAK_4631
|
pinMode(this->_pinA, INPUT_PULLUP);
|
||||||
isRAK = true;
|
pinMode(this->_pinB, INPUT_PULLUP);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!isRAK || pinPress != 0) {
|
// Use FALLING edge for active-low press button to start long-press timing immediately
|
||||||
pinMode(pinPress, INPUT_PULLUP);
|
attachInterrupt(pinPress, onIntPress, FALLING);
|
||||||
attachInterrupt(pinPress, onIntPress, CHANGE);
|
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
||||||
}
|
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
||||||
if (!isRAK || this->_pinA != 0) {
|
|
||||||
pinMode(this->_pinA, INPUT_PULLUP);
|
|
||||||
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
|
||||||
}
|
|
||||||
if (!isRAK || this->_pinA != 0) {
|
|
||||||
pinMode(this->_pinB, INPUT_PULLUP);
|
|
||||||
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->rotaryLevelA = digitalRead(this->_pinA);
|
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||||
this->rotaryLevelB = digitalRead(this->_pinB);
|
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||||
@@ -45,7 +36,7 @@ void RotaryEncoderInterruptBase::init(
|
|||||||
|
|
||||||
int32_t RotaryEncoderInterruptBase::runOnce()
|
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
@@ -151,7 +142,7 @@ RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(bool
|
|||||||
// Logic to prevent bouncing.
|
// Logic to prevent bouncing.
|
||||||
newState = ROTARY_EVENT_CLEARED;
|
newState = ROTARY_EVENT_CLEARED;
|
||||||
}
|
}
|
||||||
setIntervalFromNow(ROTARY_DELAY); // TODO: this modifies a non-volatile variable!
|
setIntervalFromNow(50); // TODO: this modifies a non-volatile variable!
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ bool SeesawRotary::init()
|
|||||||
|
|
||||||
int32_t SeesawRotary::runOnce()
|
int32_t SeesawRotary::runOnce()
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
bool currentlyPressed = !ss.digitalRead(SS_SWITCH);
|
bool currentlyPressed = !ss.digitalRead(SS_SWITCH);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ SerialKeyboard::SerialKeyboard(const char *name) : concurrency::OSThread(name)
|
|||||||
|
|
||||||
void SerialKeyboard::erase()
|
void SerialKeyboard::erase()
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_BACK;
|
e.inputEvent = INPUT_BROKER_BACK;
|
||||||
e.kbchar = 0x08;
|
e.kbchar = 0x08;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
@@ -80,7 +80,7 @@ int32_t SerialKeyboard::runOnce()
|
|||||||
|
|
||||||
if (keys < prevKeys) { // a new key has been pressed (and not released), doesn't works for multiple presses at once but
|
if (keys < prevKeys) { // a new key has been pressed (and not released), doesn't works for multiple presses at once but
|
||||||
// shouldn't be a limitation
|
// shouldn't be a limitation
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
// SELECT OR SEND OR CANCEL EVENT
|
// SELECT OR SEND OR CANCEL EVENT
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
#if defined(T_LORA_PAGER)
|
|
||||||
|
|
||||||
#include "TLoraPagerKeyboard.h"
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
#ifndef LEDC_BACKLIGHT_CHANNEL
|
|
||||||
#define LEDC_BACKLIGHT_CHANNEL 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LEDC_BACKLIGHT_BIT_WIDTH
|
|
||||||
#define LEDC_BACKLIGHT_BIT_WIDTH 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LEDC_BACKLIGHT_FREQ
|
|
||||||
#define LEDC_BACKLIGHT_FREQ 1000 // Hz
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define _TCA8418_COLS 10
|
|
||||||
#define _TCA8418_ROWS 4
|
|
||||||
#define _TCA8418_NUM_KEYS 31
|
|
||||||
|
|
||||||
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
|
||||||
|
|
||||||
using Key = TCA8418KeyboardBase::TCA8418Key;
|
|
||||||
|
|
||||||
constexpr uint8_t modifierRightShiftKey = 29 - 1; // keynum -1
|
|
||||||
constexpr uint8_t modifierRightShift = 0b0001;
|
|
||||||
constexpr uint8_t modifierSymKey = 21 - 1;
|
|
||||||
constexpr uint8_t modifierSym = 0b0010;
|
|
||||||
|
|
||||||
// Num chars per key, Modulus for rotating through characters
|
|
||||||
static uint8_t TLoraPagerTapMod[_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};
|
|
||||||
|
|
||||||
static unsigned char TLoraPagerTapMap[_TCA8418_NUM_KEYS][3] = {{'q', 'Q', '1'},
|
|
||||||
{'w', 'W', '2'},
|
|
||||||
{'e', 'E', '3'},
|
|
||||||
{'r', 'R', '4'},
|
|
||||||
{'t', 'T', '5'},
|
|
||||||
{'y', 'Y', '6'},
|
|
||||||
{'u', 'U', '7'},
|
|
||||||
{'i', 'I', '8'},
|
|
||||||
{'o', 'O', '9'},
|
|
||||||
{'p', 'P', '0'},
|
|
||||||
{'a', 'A', '*'},
|
|
||||||
{'s', 'S', '/'},
|
|
||||||
{'d', 'D', '+'},
|
|
||||||
{'f', 'F', '-'},
|
|
||||||
{'g', 'G', '='},
|
|
||||||
{'h', 'H', ':'},
|
|
||||||
{'j', 'J', '\''},
|
|
||||||
{'k', 'K', '"'},
|
|
||||||
{'l', 'L', '@'},
|
|
||||||
{Key::SELECT, 0x00, Key::TAB},
|
|
||||||
{0x00, 0x00, 0x00},
|
|
||||||
{'z', 'Z', '_'},
|
|
||||||
{'x', 'X', '$'},
|
|
||||||
{'c', 'C', ';'},
|
|
||||||
{'v', 'V', '?'},
|
|
||||||
{'b', 'B', '!'},
|
|
||||||
{'n', 'N', ','},
|
|
||||||
{'m', 'M', '.'},
|
|
||||||
{0x00, 0x00, 0x00},
|
|
||||||
{Key::BSP, 0x00, Key::ESC},
|
|
||||||
{' ', 0x00, Key::BL_TOGGLE}};
|
|
||||||
|
|
||||||
TLoraPagerKeyboard::TLoraPagerKeyboard()
|
|
||||||
: 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)
|
|
||||||
{
|
|
||||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
|
||||||
ledcAttach(KB_BL_PIN, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
|
||||||
#else
|
|
||||||
ledcSetup(LEDC_BACKLIGHT_CHANNEL, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
|
||||||
ledcAttachPin(KB_BL_PIN, LEDC_BACKLIGHT_CHANNEL);
|
|
||||||
#endif
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TLoraPagerKeyboard::reset(void)
|
|
||||||
{
|
|
||||||
TCA8418KeyboardBase::reset();
|
|
||||||
pinMode(KB_BL_PIN, OUTPUT);
|
|
||||||
digitalWrite(KB_BL_PIN, LOW);
|
|
||||||
setBacklight(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle multi-key presses (shift and alt)
|
|
||||||
void TLoraPagerKeyboard::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 TLoraPagerKeyboard::setBacklight(bool on)
|
|
||||||
{
|
|
||||||
toggleBacklight(!on);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TLoraPagerKeyboard::pressed(uint8_t key)
|
|
||||||
{
|
|
||||||
if (state == Init || state == Busy) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED ||
|
|
||||||
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY) {
|
|
||||||
hapticFeedback();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 TLoraPagerKeyboard::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 (TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]] == Key::BL_TOGGLE) {
|
|
||||||
toggleBacklight();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
queueEvent(TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]]);
|
|
||||||
if (isModifierKey(last_key) == false)
|
|
||||||
modifierFlag = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TLoraPagerKeyboard::hapticFeedback()
|
|
||||||
{
|
|
||||||
drv.setWaveform(0, 14); // strong buzz 100%
|
|
||||||
drv.setWaveform(1, 0); // end waveform
|
|
||||||
drv.go();
|
|
||||||
}
|
|
||||||
|
|
||||||
// toggle brightness of the backlight in three steps
|
|
||||||
void TLoraPagerKeyboard::toggleBacklight(bool off)
|
|
||||||
{
|
|
||||||
static uint32_t brightness = 0;
|
|
||||||
if (off) {
|
|
||||||
brightness = 0;
|
|
||||||
} else {
|
|
||||||
if (brightness == 0) {
|
|
||||||
brightness = 40;
|
|
||||||
} else if (brightness == 40) {
|
|
||||||
brightness = 127;
|
|
||||||
} else if (brightness >= 127) {
|
|
||||||
brightness = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Toggle backlight: %d", brightness);
|
|
||||||
|
|
||||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
|
||||||
ledcWrite(KB_BL_PIN, brightness);
|
|
||||||
#else
|
|
||||||
ledcWrite(LEDC_BACKLIGHT_CHANNEL, brightness);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void TLoraPagerKeyboard::updateModifierFlag(uint8_t key)
|
|
||||||
{
|
|
||||||
if (key == modifierRightShiftKey) {
|
|
||||||
modifierFlag ^= modifierRightShift;
|
|
||||||
} else if (key == modifierSymKey) {
|
|
||||||
modifierFlag ^= modifierSym;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TLoraPagerKeyboard::isModifierKey(uint8_t key)
|
|
||||||
{
|
|
||||||
return (key == modifierRightShiftKey || key == modifierSymKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -4,26 +4,9 @@ class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TLoraPagerKeyboard();
|
TLoraPagerKeyboard();
|
||||||
void reset(void);
|
void setBacklight(bool on) override{};
|
||||||
void trigger(void) override;
|
|
||||||
void setBacklight(bool on) override;
|
|
||||||
virtual ~TLoraPagerKeyboard() {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void pressed(uint8_t key) override;
|
void pressed(uint8_t key) override{};
|
||||||
void released(void) override;
|
void released(void) override{};
|
||||||
void hapticFeedback(void);
|
|
||||||
|
|
||||||
void updateModifierFlag(uint8_t key);
|
|
||||||
bool isModifierKey(uint8_t key);
|
|
||||||
void toggleBacklight(bool off = false);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
|
||||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
|
||||||
int8_t last_key;
|
|
||||||
int8_t next_key;
|
|
||||||
uint32_t last_tap;
|
|
||||||
uint8_t char_idx;
|
|
||||||
int32_t tap_interval;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTo
|
|||||||
void TouchScreenImpl1::init()
|
void TouchScreenImpl1::init()
|
||||||
{
|
{
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (portduino_config.touchscreenModule) {
|
if (settingsMap[touchscreenModule]) {
|
||||||
TouchScreenBase::init(true);
|
TouchScreenBase::init(true);
|
||||||
inputBroker->registerSource(this);
|
inputBroker->registerSource(this);
|
||||||
} else {
|
} else {
|
||||||
@@ -47,7 +47,7 @@ bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
|
|||||||
*/
|
*/
|
||||||
void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.source = event.source;
|
e.source = event.source;
|
||||||
e.kbchar = 0;
|
e.kbchar = 0;
|
||||||
e.touchX = event.x;
|
e.touchX = event.x;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
|
|||||||
|
|
||||||
int32_t TrackballInterruptBase::runOnce()
|
int32_t TrackballInterruptBase::runOnce()
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
|
|
||||||
// Handle long press detection for press button
|
// Handle long press detection for press button
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#ifndef TB_DIRECTION
|
#ifndef TB_DIRECTION
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
#include "PortduinoGlue.h"
|
#include "PortduinoGlue.h"
|
||||||
#define TB_DIRECTION (PinStatus) portduino_config.lora_usb_vid
|
#define TB_DIRECTION (PinStatus) settingsMap[tbDirection]
|
||||||
#else
|
#else
|
||||||
#define TB_DIRECTION RISING
|
#define TB_DIRECTION RISING
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,23 +23,16 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
|
|||||||
|
|
||||||
// Store debounce configuration passed by caller
|
// Store debounce configuration passed by caller
|
||||||
this->updownDebounceMs = updownDebounceMs;
|
this->updownDebounceMs = updownDebounceMs;
|
||||||
bool isRAK = false;
|
|
||||||
#ifdef RAK_4631
|
|
||||||
isRAK = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!isRAK || pinPress != 0) {
|
pinMode(pinPress, INPUT_PULLUP);
|
||||||
pinMode(pinPress, INPUT_PULLUP);
|
pinMode(this->_pinDown, INPUT_PULLUP);
|
||||||
attachInterrupt(pinPress, onIntPress, FALLING);
|
pinMode(this->_pinUp, INPUT_PULLUP);
|
||||||
}
|
|
||||||
if (!isRAK || this->_pinDown != 0) {
|
// Use FALLING edge for active-low buttons so we detect press at the moment of pressing
|
||||||
pinMode(this->_pinDown, INPUT_PULLUP);
|
// This enables long-press timing to start immediately instead of waiting for release.
|
||||||
attachInterrupt(this->_pinDown, onIntDown, FALLING);
|
attachInterrupt(pinPress, onIntPress, FALLING);
|
||||||
}
|
attachInterrupt(this->_pinDown, onIntDown, FALLING);
|
||||||
if (!isRAK || this->_pinUp != 0) {
|
attachInterrupt(this->_pinUp, onIntUp, FALLING);
|
||||||
pinMode(this->_pinUp, INPUT_PULLUP);
|
|
||||||
attachInterrupt(this->_pinUp, onIntUp, FALLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
|
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
|
||||||
|
|
||||||
@@ -48,7 +41,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
|
|||||||
|
|
||||||
int32_t UpDownInterruptBase::runOnce()
|
int32_t UpDownInterruptBase::runOnce()
|
||||||
{
|
{
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ bool UpDownInterruptImpl1::init()
|
|||||||
uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b;
|
uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b;
|
||||||
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
|
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
|
||||||
|
|
||||||
input_broker_event eventDown = INPUT_BROKER_USER_PRESS; // acts like RIGHT/DOWN
|
input_broker_event eventDown = INPUT_BROKER_DOWN;
|
||||||
input_broker_event eventUp = INPUT_BROKER_ALT_PRESS; // acts like LEFT/UP
|
input_broker_event eventUp = INPUT_BROKER_UP;
|
||||||
input_broker_event eventPressed = INPUT_BROKER_SELECT;
|
input_broker_event eventPressed = INPUT_BROKER_SELECT;
|
||||||
input_broker_event eventPressedLong = INPUT_BROKER_SELECT_LONG;
|
input_broker_event eventPressedLong = INPUT_BROKER_SELECT_LONG;
|
||||||
input_broker_event eventUpLong = INPUT_BROKER_UP_LONG;
|
input_broker_event eventUpLong = INPUT_BROKER_UP_LONG;
|
||||||
|
|||||||
@@ -12,12 +12,8 @@ void CardKbI2cImpl::init()
|
|||||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
||||||
if (cardkb_found.address == 0x00) {
|
if (cardkb_found.address == 0x00) {
|
||||||
LOG_DEBUG("Rescan for I2C keyboard");
|
LOG_DEBUG("Rescan for I2C keyboard");
|
||||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, TCA8418_KB_ADDR};
|
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, XPOWERS_AXP192_AXP2101_ADDRESS};
|
||||||
#if defined(T_LORA_PAGER)
|
|
||||||
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
|
|
||||||
#else
|
|
||||||
uint8_t i2caddr_asize = 5;
|
uint8_t i2caddr_asize = 5;
|
||||||
#endif
|
|
||||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||||
|
|
||||||
#if WIRE_INTERFACES_COUNT == 2
|
#if WIRE_INTERFACES_COUNT == 2
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
#include "i2cButton.h"
|
|
||||||
#include "meshUtils.h"
|
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
|
|
||||||
#include "MeshService.h"
|
|
||||||
#include "RadioLibInterface.h"
|
|
||||||
#include "buzz.h"
|
|
||||||
#include "input/InputBroker.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "modules/CannedMessageModule.h"
|
|
||||||
#include "modules/ExternalNotificationModule.h"
|
|
||||||
#include "power.h"
|
|
||||||
#include "sleep.h"
|
|
||||||
#ifdef ARCH_PORTDUINO
|
|
||||||
#include "platform/portduino/PortduinoGlue.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
i2cButtonThread *i2cButton;
|
|
||||||
|
|
||||||
using namespace concurrency;
|
|
||||||
|
|
||||||
extern void i2c_read_byte(uint8_t addr, uint8_t reg, uint8_t *value);
|
|
||||||
|
|
||||||
extern void i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t value);
|
|
||||||
|
|
||||||
#define PI4IO_M_ADDR 0x43
|
|
||||||
#define getbit(x, y) ((x) >> (y)&0x01)
|
|
||||||
#define PI4IO_REG_IRQ_STA 0x13
|
|
||||||
#define PI4IO_REG_IN_STA 0x0F
|
|
||||||
#define PI4IO_REG_CHIP_RESET 0x01
|
|
||||||
|
|
||||||
i2cButtonThread::i2cButtonThread(const char *name) : OSThread(name)
|
|
||||||
{
|
|
||||||
_originName = name;
|
|
||||||
if (inputBroker)
|
|
||||||
inputBroker->registerSource(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t i2cButtonThread::runOnce()
|
|
||||||
{
|
|
||||||
static bool btn1_pressed = false;
|
|
||||||
static uint32_t press_start_time = 0;
|
|
||||||
const uint32_t LONG_PRESS_TIME = 1000;
|
|
||||||
static bool long_press_triggered = false;
|
|
||||||
|
|
||||||
uint8_t in_data;
|
|
||||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, &in_data);
|
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, in_data);
|
|
||||||
if (getbit(in_data, 0)) {
|
|
||||||
uint8_t input_state;
|
|
||||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IN_STA, &input_state);
|
|
||||||
|
|
||||||
if (!getbit(input_state, 0)) {
|
|
||||||
if (!btn1_pressed) {
|
|
||||||
btn1_pressed = true;
|
|
||||||
press_start_time = millis();
|
|
||||||
long_press_triggered = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (btn1_pressed) {
|
|
||||||
btn1_pressed = false;
|
|
||||||
uint32_t press_duration = millis() - press_start_time;
|
|
||||||
if (long_press_triggered) {
|
|
||||||
long_press_triggered = false;
|
|
||||||
return 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (press_duration < LONG_PRESS_TIME) {
|
|
||||||
InputEvent evt;
|
|
||||||
evt.source = "UserButton";
|
|
||||||
evt.inputEvent = INPUT_BROKER_USER_PRESS;
|
|
||||||
evt.kbchar = 0;
|
|
||||||
evt.touchX = 0;
|
|
||||||
evt.touchY = 0;
|
|
||||||
this->notifyObservers(&evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btn1_pressed && !long_press_triggered && (millis() - press_start_time >= LONG_PRESS_TIME)) {
|
|
||||||
long_press_triggered = true;
|
|
||||||
InputEvent evt;
|
|
||||||
evt.source = "UserButton";
|
|
||||||
evt.inputEvent = INPUT_BROKER_SELECT;
|
|
||||||
evt.kbchar = 0;
|
|
||||||
evt.touchX = 0;
|
|
||||||
evt.touchY = 0;
|
|
||||||
this->notifyObservers(&evt);
|
|
||||||
}
|
|
||||||
return 50;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "InputBroker.h"
|
|
||||||
#include "OneButton.h"
|
|
||||||
#include "concurrency/OSThread.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
|
|
||||||
class i2cButtonThread : public Observable<const InputEvent *>, public concurrency::OSThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const char *_originName;
|
|
||||||
explicit i2cButtonThread(const char *name);
|
|
||||||
int32_t runOnce() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern i2cButtonThread *i2cButton;
|
|
||||||
#endif
|
|
||||||
@@ -90,7 +90,7 @@ int32_t KbI2cBase::runOnce()
|
|||||||
while (keyCount--) {
|
while (keyCount--) {
|
||||||
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
|
const BBQ10Keyboard::KeyEvent key = Q10keyboard.keyEvent();
|
||||||
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
|
if ((key.key != 0x00) && (key.state == BBQ10Keyboard::StateRelease)) {
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
switch (key.key) {
|
switch (key.key) {
|
||||||
@@ -187,7 +187,7 @@ int32_t KbI2cBase::runOnce()
|
|||||||
}
|
}
|
||||||
case 0x37: { // MPR121
|
case 0x37: { // MPR121
|
||||||
MPRkeyboard.trigger();
|
MPRkeyboard.trigger();
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
|
|
||||||
while (MPRkeyboard.hasEvent()) {
|
while (MPRkeyboard.hasEvent()) {
|
||||||
char nextEvent = MPRkeyboard.dequeueEvent();
|
char nextEvent = MPRkeyboard.dequeueEvent();
|
||||||
@@ -250,7 +250,7 @@ int32_t KbI2cBase::runOnce()
|
|||||||
}
|
}
|
||||||
case 0x84: { // Adafruit TCA8418
|
case 0x84: { // Adafruit TCA8418
|
||||||
TCAKeyboard.trigger();
|
TCAKeyboard.trigger();
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
while (TCAKeyboard.hasEvent()) {
|
while (TCAKeyboard.hasEvent()) {
|
||||||
char nextEvent = TCAKeyboard.dequeueEvent();
|
char nextEvent = TCAKeyboard.dequeueEvent();
|
||||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||||
@@ -350,7 +350,7 @@ int32_t KbI2cBase::runOnce()
|
|||||||
}
|
}
|
||||||
if (PrintDataBuf != 0) {
|
if (PrintDataBuf != 0) {
|
||||||
LOG_DEBUG("RAK14004 key 0x%x pressed", PrintDataBuf);
|
LOG_DEBUG("RAK14004 key 0x%x pressed", PrintDataBuf);
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_MATRIXKEY;
|
e.inputEvent = INPUT_BROKER_MATRIXKEY;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
e.kbchar = PrintDataBuf;
|
e.kbchar = PrintDataBuf;
|
||||||
@@ -365,7 +365,7 @@ int32_t KbI2cBase::runOnce()
|
|||||||
|
|
||||||
if (i2cBus->available()) {
|
if (i2cBus->available()) {
|
||||||
char c = i2cBus->read();
|
char c = i2cBus->read();
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ int32_t KbMatrixBase::runOnce()
|
|||||||
if (key != 0) {
|
if (key != 0) {
|
||||||
LOG_DEBUG("Key 0x%x pressed", key);
|
LOG_DEBUG("Key 0x%x pressed", key);
|
||||||
// reset shift now that we have a keypress
|
// reset shift now that we have a keypress
|
||||||
InputEvent e = {};
|
InputEvent e;
|
||||||
e.inputEvent = INPUT_BROKER_NONE;
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
|||||||
151
src/main.cpp
151
src/main.cpp
@@ -135,9 +135,8 @@ AccelerometerThread *accelerometerThread = nullptr;
|
|||||||
AudioThread *audioThread = nullptr;
|
AudioThread *audioThread = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_XL9555
|
#ifdef USE_PCA9557
|
||||||
#include "ExtensionIOXL9555.hpp"
|
PCA9557 IOEXP;
|
||||||
ExtensionIOXL9555 io;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_TFT
|
#if HAS_TFT
|
||||||
@@ -204,7 +203,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
|
|||||||
/// The I2C address of our Air Quality Indicator (if found)
|
/// The I2C address of our Air Quality Indicator (if found)
|
||||||
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
||||||
|
|
||||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
#ifdef T_WATCH_S3
|
||||||
Adafruit_DRV2605 drv;
|
Adafruit_DRV2605 drv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -362,34 +361,11 @@ void setup()
|
|||||||
digitalWrite(SDCARD_CS, HIGH);
|
digitalWrite(SDCARD_CS, HIGH);
|
||||||
pinMode(PIN_EINK_CS, OUTPUT);
|
pinMode(PIN_EINK_CS, OUTPUT);
|
||||||
digitalWrite(PIN_EINK_CS, HIGH);
|
digitalWrite(PIN_EINK_CS, HIGH);
|
||||||
#elif defined(T_LORA_PAGER)
|
|
||||||
pinMode(LORA_CS, OUTPUT);
|
|
||||||
digitalWrite(LORA_CS, HIGH);
|
|
||||||
pinMode(SDCARD_CS, OUTPUT);
|
|
||||||
digitalWrite(SDCARD_CS, HIGH);
|
|
||||||
pinMode(TFT_CS, OUTPUT);
|
|
||||||
digitalWrite(TFT_CS, HIGH);
|
|
||||||
// io expander
|
|
||||||
io.begin(Wire, XL9555_SLAVE_ADDRESS0, SDA, SCL);
|
|
||||||
io.pinMode(EXPANDS_DRV_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_AMP_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_LORA_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_LORA_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_GPS_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_GPS_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_KB_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_KB_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_SD_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_SD_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_GPIO_EN, OUTPUT);
|
|
||||||
io.digitalWrite(EXPANDS_GPIO_EN, HIGH);
|
|
||||||
io.pinMode(EXPANDS_SD_PULLEN, INPUT);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
concurrency::hasBeenSetup = true;
|
concurrency::hasBeenSetup = true;
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
SPISettings spiSettings(portduino_config.spiSpeed, MSBFIRST, SPI_MODE0);
|
SPISettings spiSettings(settingsMap[spiSpeed], MSBFIRST, SPI_MODE0);
|
||||||
#else
|
#else
|
||||||
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||||
#endif
|
#endif
|
||||||
@@ -420,7 +396,7 @@ void setup()
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = time(NULL);
|
tv.tv_sec = time(NULL);
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
perhapsSetRTC(RTCQualityDevice, &tv);
|
perhapsSetRTC(RTCQualityNTP, &tv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
powerMonInit();
|
powerMonInit();
|
||||||
@@ -430,16 +406,6 @@ void setup()
|
|||||||
|
|
||||||
initDeepSleep();
|
initDeepSleep();
|
||||||
|
|
||||||
#if defined(MODEM_POWER_EN)
|
|
||||||
pinMode(MODEM_POWER_EN, OUTPUT);
|
|
||||||
digitalWrite(MODEM_POWER_EN, LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MODEM_PWRKEY)
|
|
||||||
pinMode(MODEM_PWRKEY, OUTPUT);
|
|
||||||
digitalWrite(MODEM_PWRKEY, LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(LORA_TCXO_GPIO)
|
#if defined(LORA_TCXO_GPIO)
|
||||||
pinMode(LORA_TCXO_GPIO, OUTPUT);
|
pinMode(LORA_TCXO_GPIO, OUTPUT);
|
||||||
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
||||||
@@ -534,9 +500,9 @@ void setup()
|
|||||||
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
||||||
Wire.begin(I2C_SDA, I2C_SCL);
|
Wire.begin(I2C_SDA, I2C_SCL);
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
if (portduino_config.i2cdev != "") {
|
if (settingsStrings[i2cdev] != "") {
|
||||||
LOG_INFO("Use %s as I2C device", portduino_config.i2cdev.c_str());
|
LOG_INFO("Use %s as I2C device", settingsStrings[i2cdev].c_str());
|
||||||
Wire.begin(portduino_config.i2cdev.c_str());
|
Wire.begin(settingsStrings[i2cdev].c_str());
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("No I2C device configured, Skip");
|
LOG_INFO("No I2C device configured, Skip");
|
||||||
}
|
}
|
||||||
@@ -545,12 +511,6 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
pinMode(LORA_CS, OUTPUT);
|
|
||||||
digitalWrite(LORA_CS, 1);
|
|
||||||
c6l_init();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PIN_LCD_RESET
|
#ifdef PIN_LCD_RESET
|
||||||
// FIXME - move this someplace better, LCD is at address 0x3F
|
// FIXME - move this someplace better, LCD is at address 0x3F
|
||||||
pinMode(PIN_LCD_RESET, OUTPUT);
|
pinMode(PIN_LCD_RESET, OUTPUT);
|
||||||
@@ -588,7 +548,7 @@ void setup()
|
|||||||
#if defined(I2C_SDA)
|
#if defined(I2C_SDA)
|
||||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
if (portduino_config.i2cdev != "") {
|
if (settingsStrings[i2cdev] != "") {
|
||||||
LOG_INFO("Scan for i2c devices");
|
LOG_INFO("Scan for i2c devices");
|
||||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||||
}
|
}
|
||||||
@@ -748,7 +708,6 @@ void setup()
|
|||||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
||||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2561, meshtastic_TelemetrySensorType_TSL2561);
|
|
||||||
|
|
||||||
i2cScanner.reset();
|
i2cScanner.reset();
|
||||||
#endif
|
#endif
|
||||||
@@ -838,7 +797,7 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
#ifdef T_WATCH_S3
|
||||||
drv.begin();
|
drv.begin();
|
||||||
drv.selectLibrary(1);
|
drv.selectLibrary(1);
|
||||||
// I2C trigger by sending 'go' command
|
// I2C trigger by sending 'go' command
|
||||||
@@ -861,7 +820,7 @@ void setup()
|
|||||||
SPI.begin(false);
|
SPI.begin(false);
|
||||||
#endif // HW_SPI1_DEVICE
|
#endif // HW_SPI1_DEVICE
|
||||||
#elif ARCH_PORTDUINO
|
#elif ARCH_PORTDUINO
|
||||||
if (portduino_config.lora_spi_dev != "ch341") {
|
if (settingsStrings[spidev] != "ch341") {
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
}
|
}
|
||||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||||
@@ -884,11 +843,10 @@ void setup()
|
|||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
|
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
||||||
defined(USE_SPISSD1306)
|
|
||||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || portduino_config.displayPanel) &&
|
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||||
}
|
}
|
||||||
@@ -989,13 +947,13 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#if defined(ARCH_PORTDUINO)
|
#if defined(ARCH_PORTDUINO)
|
||||||
|
|
||||||
if (portduino_config.userButtonPin.enabled) {
|
if (settingsMap.count(userButtonPin) != 0 && settingsMap[userButtonPin] != RADIOLIB_NC) {
|
||||||
|
|
||||||
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
|
LOG_DEBUG("Use GPIO%02d for button", settingsMap[userButtonPin]);
|
||||||
UserButtonThread = new ButtonThread("UserButton");
|
UserButtonThread = new ButtonThread("UserButton");
|
||||||
if (screen) {
|
if (screen) {
|
||||||
ButtonConfig config;
|
ButtonConfig config;
|
||||||
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
|
config.pinNumber = (uint8_t)settingsMap[userButtonPin];
|
||||||
config.activeLow = true;
|
config.activeLow = true;
|
||||||
config.activePullup = true;
|
config.activePullup = true;
|
||||||
config.pullupSense = INPUT_PULLUP;
|
config.pullupSense = INPUT_PULLUP;
|
||||||
@@ -1148,12 +1106,11 @@ void setup()
|
|||||||
// Don't call screen setup until after nodedb is setup (because we need
|
// Don't call screen setup until after nodedb is setup (because we need
|
||||||
// the current region name)
|
// the current region name)
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
||||||
defined(USE_SPISSD1306)
|
|
||||||
if (screen)
|
if (screen)
|
||||||
screen->setup();
|
screen->setup();
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || portduino_config.displayPanel) &&
|
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
screen->setup();
|
screen->setup();
|
||||||
}
|
}
|
||||||
@@ -1169,10 +1126,15 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
|
const struct {
|
||||||
|
configNames cfgName;
|
||||||
|
std::string strName;
|
||||||
|
} loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
|
||||||
|
{use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||||
// as one can't use a function pointer to the class constructor:
|
// as one can't use a function pointer to the class constructor:
|
||||||
auto loraModuleInterface = [](LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
|
auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||||
RADIOLIB_PIN_TYPE busy) {
|
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) {
|
||||||
switch (portduino_config.lora_module) {
|
switch (cfgName) {
|
||||||
case use_rf95:
|
case use_rf95:
|
||||||
return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy);
|
return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy);
|
||||||
case use_sx1262:
|
case use_sx1262:
|
||||||
@@ -1189,34 +1151,31 @@ void setup()
|
|||||||
return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy);
|
return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy);
|
||||||
case use_llcc68:
|
case use_llcc68:
|
||||||
return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy);
|
return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy);
|
||||||
case use_simradio:
|
|
||||||
return (RadioInterface *)new SimRadio;
|
|
||||||
default:
|
default:
|
||||||
assert(0); // shouldn't happen
|
assert(0); // shouldn't happen
|
||||||
return (RadioInterface *)nullptr;
|
return (RadioInterface *)nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
for (auto &loraModule : loraModules) {
|
||||||
LOG_DEBUG("Activate %s radio on SPI port %s", portduino_config.loraModules[portduino_config.lora_module].c_str(),
|
if (settingsMap[loraModule.cfgName] && !rIf) {
|
||||||
portduino_config.lora_spi_dev.c_str());
|
LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str());
|
||||||
if (portduino_config.lora_spi_dev == "ch341") {
|
if (settingsStrings[spidev] == "ch341") {
|
||||||
RadioLibHAL = ch341Hal;
|
RadioLibHAL = ch341Hal;
|
||||||
} else {
|
} else {
|
||||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||||
|
}
|
||||||
|
rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin],
|
||||||
|
settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]);
|
||||||
|
if (!rIf->init()) {
|
||||||
|
LOG_WARN("No %s radio", loraModule.strName.c_str());
|
||||||
|
delete rIf;
|
||||||
|
rIf = NULL;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
LOG_INFO("%s init success", loraModule.strName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rIf =
|
|
||||||
loraModuleInterface((LockingArduinoHal *)RadioLibHAL, portduino_config.lora_cs_pin.pin, portduino_config.lora_irq_pin.pin,
|
|
||||||
portduino_config.lora_reset_pin.pin, portduino_config.lora_busy_pin.pin);
|
|
||||||
|
|
||||||
if (!rIf->init()) {
|
|
||||||
LOG_WARN("No %s radio", portduino_config.loraModules[portduino_config.lora_module].c_str());
|
|
||||||
delete rIf;
|
|
||||||
rIf = NULL;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
LOG_INFO("%s init success", portduino_config.loraModules[portduino_config.lora_module].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(HW_SPI1_DEVICE)
|
#elif defined(HW_SPI1_DEVICE)
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
||||||
#else // HW_SPI1_DEVICE
|
#else // HW_SPI1_DEVICE
|
||||||
@@ -1238,6 +1197,20 @@ void setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCH_PORTDUINO)
|
||||||
|
if (!rIf) {
|
||||||
|
rIf = new SimRadio;
|
||||||
|
if (!rIf->init()) {
|
||||||
|
LOG_WARN("No simulated radio");
|
||||||
|
delete rIf;
|
||||||
|
rIf = NULL;
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Use SIMULATED radio!");
|
||||||
|
radioType = SIM_RADIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(RF95_IRQ) && RADIOLIB_EXCLUDE_SX127X != 1
|
#if defined(RF95_IRQ) && RADIOLIB_EXCLUDE_SX127X != 1
|
||||||
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
||||||
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
||||||
@@ -1452,7 +1425,7 @@ void setup()
|
|||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
#if __has_include(<ulfius.h>)
|
#if __has_include(<ulfius.h>)
|
||||||
if (portduino_config.webserverport != -1) {
|
if (settingsMap[webserverport] != -1) {
|
||||||
piwebServerThread = new PiWebServerThread();
|
piwebServerThread = new PiWebServerThread();
|
||||||
std::atexit([] { delete piwebServerThread; });
|
std::atexit([] { delete piwebServerThread; });
|
||||||
}
|
}
|
||||||
@@ -1523,7 +1496,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
|||||||
#if ((!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
|
#if ((!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
|
||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
#if NO_EXT_GPIO || MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
#if NO_EXT_GPIO
|
||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user