mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-01 13:16:36 +00:00
Merge branch 'master' into chatter_2_fixes
This commit is contained in:
commit
fbe819cb95
35
.github/workflows/build_esp32.yml
vendored
35
.github/workflows/build_esp32.yml
vendored
@ -11,27 +11,30 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-esp32:
|
build-esp32:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build ESP32
|
- name: Build ESP32
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: esp32
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
remove-debug-flags: >-
|
pio_target: build
|
||||||
./arch/esp32/esp32.ini
|
ota_firmware_source: firmware.bin
|
||||||
./arch/esp32/esp32s2.ini
|
ota_firmware_target: release/bleota.bin
|
||||||
./arch/esp32/esp32s3.ini
|
|
||||||
./arch/esp32/esp32c3.ini
|
- name: Store binaries as an artifact
|
||||||
./arch/esp32/esp32c6.ini
|
uses: actions/upload-artifact@v4
|
||||||
build-script-path: bin/build-esp32.sh
|
with:
|
||||||
ota-firmware-source: firmware.bin
|
name: firmware-esp32-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
ota-firmware-target: release/bleota.bin
|
overwrite: true
|
||||||
artifact-paths: |
|
path: |
|
||||||
release/*.bin
|
release/*.bin
|
||||||
release/*.elf
|
release/*.elf
|
||||||
#include-web-ui: true
|
|
||||||
arch: esp32
|
|
||||||
|
35
.github/workflows/build_esp32_c3.yml
vendored
35
.github/workflows/build_esp32_c3.yml
vendored
@ -11,27 +11,30 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-esp32-c3:
|
build-esp32-c3:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build ESP32-C3
|
- name: Build ESP32-C3
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: esp32
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
remove-debug-flags: >-
|
pio_target: build
|
||||||
./arch/esp32/esp32.ini
|
ota_firmware_source: firmware-c3.bin
|
||||||
./arch/esp32/esp32s2.ini
|
ota_firmware_target: release/bleota-c3.bin
|
||||||
./arch/esp32/esp32s3.ini
|
|
||||||
./arch/esp32/esp32c3.ini
|
- name: Store binaries as an artifact
|
||||||
./arch/esp32/esp32c6.ini
|
uses: actions/upload-artifact@v4
|
||||||
build-script-path: bin/build-esp32.sh
|
with:
|
||||||
ota-firmware-source: firmware-c3.bin
|
name: firmware-esp32c3-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
ota-firmware-target: release/bleota-c3.bin
|
overwrite: true
|
||||||
artifact-paths: |
|
path: |
|
||||||
release/*.bin
|
release/*.bin
|
||||||
release/*.elf
|
release/*.elf
|
||||||
#include-web-ui: true
|
|
||||||
arch: esp32c3
|
|
||||||
|
35
.github/workflows/build_esp32_c6.yml
vendored
35
.github/workflows/build_esp32_c6.yml
vendored
@ -11,27 +11,30 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-esp32-c6:
|
build-esp32-c6:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build ESP32-C6
|
- name: Build ESP32-C6
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: esp32
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
remove-debug-flags: >-
|
pio_target: build
|
||||||
./arch/esp32/esp32.ini
|
ota_firmware_source: firmware-c3.bin
|
||||||
./arch/esp32/esp32s2.ini
|
ota_firmware_target: release/bleota-c3.bin
|
||||||
./arch/esp32/esp32s3.ini
|
|
||||||
./arch/esp32/esp32c3.ini
|
- name: Store binaries as an artifact
|
||||||
./arch/esp32/esp32c6.ini
|
uses: actions/upload-artifact@v4
|
||||||
build-script-path: bin/build-esp32.sh
|
with:
|
||||||
ota-firmware-source: firmware-c3.bin
|
name: firmware-esp32c6-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
ota-firmware-target: release/bleota-c3.bin
|
overwrite: true
|
||||||
artifact-paths: |
|
path: |
|
||||||
release/*.bin
|
release/*.bin
|
||||||
release/*.elf
|
release/*.elf
|
||||||
#include-web-ui: true
|
|
||||||
arch: esp32c6
|
|
||||||
|
35
.github/workflows/build_esp32_s3.yml
vendored
35
.github/workflows/build_esp32_s3.yml
vendored
@ -11,27 +11,30 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-esp32-s3:
|
build-esp32-s3:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build ESP32-S3
|
- name: Build ESP32-S3
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: esp32
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
remove-debug-flags: >-
|
pio_target: build
|
||||||
./arch/esp32/esp32.ini
|
ota_firmware_source: firmware-s3.bin
|
||||||
./arch/esp32/esp32s2.ini
|
ota_firmware_target: release/bleota-s3.bin
|
||||||
./arch/esp32/esp32s3.ini
|
|
||||||
./arch/esp32/esp32c3.ini
|
- name: Store binaries as an artifact
|
||||||
./arch/esp32/esp32c6.ini
|
uses: actions/upload-artifact@v4
|
||||||
build-script-path: bin/build-esp32.sh
|
with:
|
||||||
ota-firmware-source: firmware-s3.bin
|
name: firmware-esp32s3-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
ota-firmware-target: release/bleota-s3.bin
|
overwrite: true
|
||||||
artifact-paths: |
|
path: |
|
||||||
release/*.bin
|
release/*.bin
|
||||||
release/*.elf
|
release/*.elf
|
||||||
#include-web-ui: true
|
|
||||||
arch: esp32s3
|
|
||||||
|
28
.github/workflows/build_nrf52.yml
vendored
28
.github/workflows/build_nrf52.yml
vendored
@ -11,20 +11,30 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-nrf52:
|
build-nrf52:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build NRF52
|
- name: Build NRF52
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: nrf52
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
build-script-path: bin/build-nrf52.sh
|
pio_target: build
|
||||||
artifact-paths: |
|
|
||||||
release/*.hex
|
- name: Store binaries as an artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: firmware-nrf52840-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: |
|
||||||
release/*.uf2
|
release/*.uf2
|
||||||
release/*.elf
|
release/*.elf
|
||||||
release/*.zip
|
release/*.hex
|
||||||
arch: nrf52840
|
release/*-ota.zip
|
||||||
|
24
.github/workflows/build_rpi2040.yml
vendored
24
.github/workflows/build_rpi2040.yml
vendored
@ -11,18 +11,28 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-rpi2040:
|
build-rpi2040:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build Raspberry Pi 2040
|
- name: Build Raspberry Pi 2040
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: rp2xx0
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
build-script-path: bin/build-rpi2040.sh
|
pio_target: build
|
||||||
artifact-paths: |
|
|
||||||
|
- name: Store binaries as an artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: firmware-rp2040-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: |
|
||||||
release/*.uf2
|
release/*.uf2
|
||||||
release/*.elf
|
release/*.elf
|
||||||
arch: rp2040
|
|
||||||
|
24
.github/workflows/build_stm32.yml
vendored
24
.github/workflows/build_stm32.yml
vendored
@ -11,19 +11,29 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-stm32:
|
build-stm32:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
shell: bash
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
- name: Build STM32WL
|
- name: Build STM32WL
|
||||||
id: build
|
id: build
|
||||||
uses: ./.github/actions/build-variant
|
uses: meshtastic/gh-action-firmware@main
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
pio_platform: stm32wl
|
||||||
board: ${{ inputs.board }}
|
pio_env: ${{ inputs.board }}
|
||||||
build-script-path: bin/build-stm32.sh
|
pio_target: build
|
||||||
artifact-paths: |
|
|
||||||
|
- name: Store binaries as an artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: firmware-stm32-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: |
|
||||||
release/*.hex
|
release/*.hex
|
||||||
release/*.bin
|
release/*.bin
|
||||||
release/*.elf
|
release/*.elf
|
||||||
arch: stm32
|
|
||||||
|
3
.github/workflows/main_matrix.yml
vendored
3
.github/workflows/main_matrix.yml
vendored
@ -135,6 +135,7 @@ jobs:
|
|||||||
board: ${{ matrix.board }}
|
board: ${{ matrix.board }}
|
||||||
|
|
||||||
build-debian-src:
|
build-debian-src:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
uses: ./.github/workflows/build_debian_src.yml
|
uses: ./.github/workflows/build_debian_src.yml
|
||||||
with:
|
with:
|
||||||
series: UNRELEASED
|
series: UNRELEASED
|
||||||
@ -425,7 +426,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
publish-firmware:
|
publish-firmware:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
needs: [release-firmware]
|
needs: [release-firmware]
|
||||||
env:
|
env:
|
||||||
|
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@ -8,6 +8,7 @@ permissions: read-all
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
trunk_check:
|
trunk_check:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
name: Trunk Check and Upload
|
name: Trunk Check and Upload
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ jobs:
|
|||||||
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
||||||
|
|
||||||
trunk_upgrade:
|
trunk_upgrade:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
# See: https://github.com/trunk-io/trunk-action/blob/v1/readme.md#automatic-upgrades
|
# See: https://github.com/trunk-io/trunk-action/blob/v1/readme.md#automatic-upgrades
|
||||||
name: Trunk Upgrade (PR)
|
name: Trunk Upgrade (PR)
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
1
.github/workflows/sec_sast_semgrep_cron.yml
vendored
1
.github/workflows/sec_sast_semgrep_cron.yml
vendored
@ -13,6 +13,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
semgrep-full:
|
semgrep-full:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
container:
|
container:
|
||||||
image: semgrep/semgrep
|
image: semgrep/semgrep
|
||||||
|
1
.github/workflows/stale_bot.yml
vendored
1
.github/workflows/stale_bot.yml
vendored
@ -11,6 +11,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale_issues:
|
stale_issues:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
name: Close Stale Issues
|
name: Close Stale Issues
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@ -12,9 +12,11 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
native-tests:
|
native-tests:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
uses: ./.github/workflows/test_native.yml
|
uses: ./.github/workflows/test_native.yml
|
||||||
|
|
||||||
hardware-tests:
|
hardware-tests:
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
runs-on: test-runner
|
runs-on: test-runner
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
"hwids": [
|
"hwids": [
|
||||||
["0x239A", "0x4405"],
|
["0x239A", "0x4405"],
|
||||||
["0x239A", "0x0029"],
|
["0x239A", "0x0029"],
|
||||||
["0x239A", "0x002A"]
|
["0x239A", "0x002A"],
|
||||||
|
["0x2886", "0x1667"]
|
||||||
],
|
],
|
||||||
"usb_product": "HT-n5262",
|
"usb_product": "HT-n5262",
|
||||||
"mcu": "nrf52840",
|
"mcu": "nrf52840",
|
||||||
|
@ -129,7 +129,7 @@ lib_deps =
|
|||||||
# renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library
|
# renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library
|
||||||
adafruit/Adafruit MCP9808 Library@2.0.2
|
adafruit/Adafruit MCP9808 Library@2.0.2
|
||||||
# renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library
|
# renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library
|
||||||
adafruit/Adafruit INA260 Library@1.5.2
|
adafruit/Adafruit INA260 Library@1.5.3
|
||||||
# renovate: datasource=custom.pio depName=Adafruit INA219 packageName=adafruit/library/Adafruit INA219
|
# renovate: datasource=custom.pio depName=Adafruit INA219 packageName=adafruit/library/Adafruit INA219
|
||||||
adafruit/Adafruit INA219@1.2.3
|
adafruit/Adafruit INA219@1.2.3
|
||||||
# renovate: datasource=custom.pio depName=Adafruit PM25 AQI Sensor packageName=adafruit/library/Adafruit PM25 AQI Sensor
|
# renovate: datasource=custom.pio depName=Adafruit PM25 AQI Sensor packageName=adafruit/library/Adafruit PM25 AQI Sensor
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#ifdef GXEPD2_DRIVER_0
|
||||||
|
#include "einkDetect.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The macros EINK_DISPLAY_MODEL, EINK_WIDTH, and EINK_HEIGHT are defined as build_flags in a variant's platformio.ini
|
The macros EINK_DISPLAY_MODEL, EINK_WIDTH, and EINK_HEIGHT are defined as build_flags in a variant's platformio.ini
|
||||||
Previously, these macros were defined at the top of this file.
|
Previously, these macros were defined at the top of this file.
|
||||||
@ -174,9 +178,8 @@ bool EInkDisplay::connect()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \
|
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || \
|
||||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
|
||||||
{
|
{
|
||||||
// Start HSPI
|
// Start HSPI
|
||||||
hspi = new SPIClass(HSPI);
|
hspi = new SPIClass(HSPI);
|
||||||
@ -232,6 +235,23 @@ bool EInkDisplay::connect()
|
|||||||
adafruitDisplay->init();
|
adafruitDisplay->init();
|
||||||
adafruitDisplay->setRotation(3);
|
adafruitDisplay->setRotation(3);
|
||||||
}
|
}
|
||||||
|
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||||
|
|
||||||
|
// Detect display model, before starting SPI
|
||||||
|
EInkDetectionResult displayModel = detectEInk();
|
||||||
|
|
||||||
|
// Start HSPI
|
||||||
|
hspi = new SPIClass(HSPI);
|
||||||
|
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||||
|
|
||||||
|
// Create GxEPD2 object
|
||||||
|
adafruitDisplay = new GxEPD2_Multi<GXEPD2_DRIVER_0, GXEPD2_DRIVER_1>((uint8_t)displayModel, PIN_EINK_CS, PIN_EINK_DC,
|
||||||
|
PIN_EINK_RES, PIN_EINK_BUSY, *hspi);
|
||||||
|
|
||||||
|
// Init GxEPD2
|
||||||
|
adafruitDisplay->init();
|
||||||
|
adafruitDisplay->setRotation(3);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
#include "GxEPD2_BW.h"
|
#include "GxEPD2_BW.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
|
|
||||||
|
#ifdef GXEPD2_DRIVER_0 // If variant has multiple possible display models
|
||||||
|
#include "GxEPD2Multi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
* An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation.
|
||||||
*
|
*
|
||||||
@ -63,8 +67,15 @@ class EInkDisplay : public OLEDDisplay
|
|||||||
// Connect to the display
|
// Connect to the display
|
||||||
virtual bool connect() override;
|
virtual bool connect() override;
|
||||||
|
|
||||||
// AdafruitGFX display object - instantiated in connect(), variant specific
|
#ifdef GXEPD2_DRIVER_0
|
||||||
|
// AdafruitGFX display object - wrapper for multiple drivers
|
||||||
|
// Allows runtime detection of multiple displays
|
||||||
|
// Avoid this situation if possible!
|
||||||
|
GxEPD2_Multi<GXEPD2_DRIVER_0, GXEPD2_DRIVER_1> *adafruitDisplay = NULL;
|
||||||
|
#else
|
||||||
|
// AdafruitGFX display object (for single display model) - instantiated in connect(), variant specific
|
||||||
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay = NULL;
|
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
// If display uses HSPI
|
// If display uses HSPI
|
||||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||||
|
135
src/graphics/GxEPD2Multi.h
Normal file
135
src/graphics/GxEPD2Multi.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Wrapper class for GxEPD2_BW
|
||||||
|
|
||||||
|
// Generic signature at build-time, so that we can detect display model at run-time
|
||||||
|
// Workaround for issue of GxEPD2_BW objects not having a shared base class
|
||||||
|
// Only exposes methods which we are actually using
|
||||||
|
|
||||||
|
template <typename Driver0, typename Driver1> class GxEPD2_Multi
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->drawPixel(x, y, color);
|
||||||
|
else
|
||||||
|
driver1->drawPixel(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nextPage()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
return driver0->nextPage();
|
||||||
|
else
|
||||||
|
return driver1->nextPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void hibernate()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->hibernate();
|
||||||
|
else
|
||||||
|
driver1->hibernate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(uint32_t serial_diag_bitrate = 0)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->init(serial_diag_bitrate);
|
||||||
|
else
|
||||||
|
driver1->init(serial_diag_bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
|
||||||
|
else
|
||||||
|
driver1->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRotation(uint8_t x)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->setRotation(x);
|
||||||
|
else
|
||||||
|
driver1->setRotation(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->setPartialWindow(x, y, w, h);
|
||||||
|
else
|
||||||
|
driver1->setPartialWindow(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFullWindow()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->setFullWindow();
|
||||||
|
else
|
||||||
|
driver1->setFullWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t width()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
return driver0->width();
|
||||||
|
else
|
||||||
|
return driver1->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t height()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
return driver0->height();
|
||||||
|
else
|
||||||
|
return driver1->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearScreen(uint8_t value = 0xFF)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->clearScreen();
|
||||||
|
else
|
||||||
|
driver1->clearScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void endAsyncFull()
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
driver0->endAsyncFull();
|
||||||
|
else
|
||||||
|
driver1->endAsyncFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exposes methods of the GxEPD2_EPD object which is usually available as GxEPD2_BW::epd
|
||||||
|
class Epd2Wrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool isBusy() { return m_epd2->isBusy(); }
|
||||||
|
GxEPD2_EPD *m_epd2;
|
||||||
|
} epd2;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
// Select driver by passing whichDriver as 0 or 1
|
||||||
|
GxEPD2_Multi(uint8_t whichDriver, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi)
|
||||||
|
{
|
||||||
|
assert(whichDriver == 0 || whichDriver == 1);
|
||||||
|
which = whichDriver;
|
||||||
|
LOG_DEBUG("GxEPD2_Multi driver: %d", which);
|
||||||
|
|
||||||
|
if (which == 0) {
|
||||||
|
driver0 = new GxEPD2_BW<Driver0, Driver0::HEIGHT>(Driver0(cs, dc, rst, busy, spi));
|
||||||
|
epd2.m_epd2 = &(driver0->epd2);
|
||||||
|
} else if (which == 1) {
|
||||||
|
driver1 = new GxEPD2_BW<Driver1, Driver1::HEIGHT>(Driver1(cs, dc, rst, busy, spi));
|
||||||
|
epd2.m_epd2 = &(driver1->epd2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t which;
|
||||||
|
GxEPD2_BW<Driver0, Driver0::HEIGHT> *driver0;
|
||||||
|
GxEPD2_BW<Driver1, Driver1::HEIGHT> *driver1;
|
||||||
|
};
|
@ -136,6 +136,7 @@ void menuHandler::ClockFacePicker()
|
|||||||
screen->setFrames(Screen::FOCUS_CLOCK);
|
screen->setFrames(Screen::FOCUS_CLOCK);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
bannerOptions.InitialSelected = uiconfig.is_clockface_analog ? 2 : 1;
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,8 +338,8 @@ void menuHandler::homeBaseMenu()
|
|||||||
} else if (selected == Freetext) {
|
} else if (selected == Freetext) {
|
||||||
cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST);
|
cannedMessageModule->LaunchFreetextWithDestination(NODENUM_BROADCAST);
|
||||||
} else if (selected == Bluetooth) {
|
} else if (selected == Bluetooth) {
|
||||||
InputEvent event = {.inputEvent = (input_broker_event)170, .kbchar = 170, .touchX = 0, .touchY = 0};
|
menuQueue = bluetooth_toggle_menu;
|
||||||
inputBroker->injectInputEvent(&event);
|
screen->runNow();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
@ -587,6 +588,23 @@ void menuHandler::GPSToggleMenu()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void menuHandler::BluetoothToggleMenu()
|
||||||
|
{
|
||||||
|
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
|
||||||
|
BannerOverlayOptions bannerOptions;
|
||||||
|
bannerOptions.message = "Toggle Bluetooth";
|
||||||
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
|
bannerOptions.optionsCount = 3;
|
||||||
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
|
if (selected == 1 || selected == 2) {
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)170, .kbchar = 170, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bannerOptions.InitialSelected = config.bluetooth.enabled ? 1 : 2;
|
||||||
|
screen->showOverlayBanner(bannerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
void menuHandler::BuzzerModeMenu()
|
void menuHandler::BuzzerModeMenu()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"};
|
static const char *optionsArray[] = {"All Enabled", "Disabled", "Notifications", "System Only"};
|
||||||
@ -935,6 +953,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case wifi_toggle_menu:
|
case wifi_toggle_menu:
|
||||||
wifiToggleMenu();
|
wifiToggleMenu();
|
||||||
break;
|
break;
|
||||||
|
case bluetooth_toggle_menu:
|
||||||
|
BluetoothToggleMenu();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
menuQueue = menu_none;
|
menuQueue = menu_none;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ class menuHandler
|
|||||||
remove_favorite,
|
remove_favorite,
|
||||||
test_menu,
|
test_menu,
|
||||||
number_test,
|
number_test,
|
||||||
wifi_toggle_menu
|
wifi_toggle_menu,
|
||||||
|
bluetooth_toggle_menu
|
||||||
};
|
};
|
||||||
static screenMenus menuQueue;
|
static screenMenus menuQueue;
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ class menuHandler
|
|||||||
static void numberTest();
|
static void numberTest();
|
||||||
static void wifiBaseMenu();
|
static void wifiBaseMenu();
|
||||||
static void wifiToggleMenu();
|
static void wifiToggleMenu();
|
||||||
|
static void BluetoothToggleMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
84
src/graphics/niche/Drivers/EInk/E0213A367.cpp
Normal file
84
src/graphics/niche/Drivers/EInk/E0213A367.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "./E0213A367.h"
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
using namespace NicheGraphics::Drivers;
|
||||||
|
|
||||||
|
// Map the display controller IC's output to the connected panel
|
||||||
|
void E0213A367::configScanning()
|
||||||
|
{
|
||||||
|
// "Driver output control"
|
||||||
|
// Scan gates from 0 to 249 (vertical resolution 250px)
|
||||||
|
sendCommand(0x01);
|
||||||
|
sendData(0xF9);
|
||||||
|
sendData(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
||||||
|
void E0213A367::configWaveform()
|
||||||
|
{
|
||||||
|
// This command (0x37) is poorly documented
|
||||||
|
// As of July 2025, the datasheet for this display's controller IC is unavailable
|
||||||
|
// The values are supplied by Heltec, who presumably have privileged access to information from the display manufacturer
|
||||||
|
// Datasheet for the similar SSD1680 IC hints at the function of this command:
|
||||||
|
|
||||||
|
// "Spare VCOM OTP selection":
|
||||||
|
// Unclear why 0x40 is set. Sane values for related SSD1680 seem to be 0x80 or 0x00.
|
||||||
|
// Maybe value is redundant? No noticeable impact when set to 0x00.
|
||||||
|
// We'll leave it set to 0x40, following Heltec's lead, just in case.
|
||||||
|
|
||||||
|
// "Display Mode"
|
||||||
|
// Seems to specify whether a waveform stored in OTP should use display mode 1 or 2 (full refresh or differential refresh)
|
||||||
|
|
||||||
|
// Unusual that waveforms are programmed to OTP, but this meta information is not ..?
|
||||||
|
|
||||||
|
sendCommand(0x37); // "Write Register for Display Option" ?
|
||||||
|
sendData(0x40); // "Spare VCOM OTP selection" ?
|
||||||
|
sendData(0x80); // "Display Mode for WS[7:0]" ?
|
||||||
|
sendData(0x03); // "Display Mode for WS[15:8]" ?
|
||||||
|
sendData(0x0E); // "Display Mode [23:16]" ?
|
||||||
|
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
sendCommand(0x3C); // Border waveform:
|
||||||
|
sendData(0x81); // As specified by Heltec. Actually VCOM (0x80)?. Bit 0 seems redundant here.
|
||||||
|
break;
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
sendCommand(0x3C); // Border waveform:
|
||||||
|
sendData(0x01); // Follow LUT 1 (blink same as white pixels)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell controller IC which operations to run
|
||||||
|
void E0213A367::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, Display mode 1 "full refresh"
|
||||||
|
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 E0213A367::detachFromUpdate()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
return beginPolling(50, 500); // At least 500ms for fast refresh
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
return beginPolling(100, 1500); // At least 1.5 seconds for full refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
41
src/graphics/niche/Drivers/EInk/E0213A367.h
Normal file
41
src/graphics/niche/Drivers/EInk/E0213A367.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
E-Ink display driver
|
||||||
|
- SSD1682
|
||||||
|
- Manufacturer: SEEKINK
|
||||||
|
- Size: 2.13 inch
|
||||||
|
- Resolution: 122px x 255px
|
||||||
|
- Flex connector marking: HINK-E0213A162-A1 (hidden, printed on reverse)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "./SSD1682.h"
|
||||||
|
|
||||||
|
namespace NicheGraphics::Drivers
|
||||||
|
{
|
||||||
|
class E0213A367 : public SSD1682
|
||||||
|
{
|
||||||
|
// Display properties
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t width = 122;
|
||||||
|
static constexpr uint32_t height = 250;
|
||||||
|
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||||
|
|
||||||
|
public:
|
||||||
|
E0213A367() : SSD1682(width, height, supported, 0) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void configScanning() override;
|
||||||
|
void configWaveform() override;
|
||||||
|
void configUpdateSequence() override;
|
||||||
|
void detachFromUpdate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NicheGraphics::Drivers
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
41
src/graphics/niche/Drivers/EInk/SSD1682.cpp
Normal file
41
src/graphics/niche/Drivers/EInk/SSD1682.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "./SSD1682.h"
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
using namespace NicheGraphics::Drivers;
|
||||||
|
|
||||||
|
SSD1682::SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX)
|
||||||
|
: SSD16XX(width, height, supported, bufferOffsetX)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSD1682 only accepts single-byte x and y values
|
||||||
|
// This causes an incompatibility with the default SSD16XX::configFullscreen
|
||||||
|
void SSD1682::configFullscreen()
|
||||||
|
{
|
||||||
|
// Define the boundaries of the "fullscreen" region, for the controller IC
|
||||||
|
static const uint8_t sx = bufferOffsetX; // Notice the offset
|
||||||
|
static const uint8_t sy = 0;
|
||||||
|
static const uint8_t ex = bufferRowSize + bufferOffsetX - 1; // End is "max index", not "count". Minus 1 handles this
|
||||||
|
static const uint8_t ey = height;
|
||||||
|
|
||||||
|
// Data entry mode - Left to Right, Top to Bottom
|
||||||
|
sendCommand(0x11);
|
||||||
|
sendData(0x03);
|
||||||
|
|
||||||
|
// Select controller IC memory region to display a fullscreen image
|
||||||
|
sendCommand(0x44); // Memory X start - end
|
||||||
|
sendData(sx);
|
||||||
|
sendData(ex);
|
||||||
|
sendCommand(0x45); // Memory Y start - end
|
||||||
|
sendData(sy);
|
||||||
|
sendData(ey);
|
||||||
|
|
||||||
|
// Place the cursor at the start of this memory region, ready to send image data x=0 y=0
|
||||||
|
sendCommand(0x4E); // Memory cursor X
|
||||||
|
sendData(sx);
|
||||||
|
sendCommand(0x4F); // Memory cursor y
|
||||||
|
sendData(sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
31
src/graphics/niche/Drivers/EInk/SSD1682.h
Normal file
31
src/graphics/niche/Drivers/EInk/SSD1682.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
E-Ink base class for displays based on SSD1682
|
||||||
|
|
||||||
|
SSD1682 has a few quirks. We're implementing them here in a new base class,
|
||||||
|
to avoid re-implementing them every time we need to add a new SSD1682-based display.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "./SSD16XX.h"
|
||||||
|
|
||||||
|
namespace NicheGraphics::Drivers
|
||||||
|
{
|
||||||
|
|
||||||
|
class SSD1682 : public SSD16XX
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SSD1682(uint16_t width, uint16_t height, EInk::UpdateTypes supported, uint8_t bufferOffsetX = 0);
|
||||||
|
virtual void configFullscreen(); // Select memory region on controller IC
|
||||||
|
virtual void deepSleep() {} // Not usable (image memory not retained)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NicheGraphics::Drivers
|
||||||
|
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
@ -246,8 +246,10 @@ void PacketHistory::insert(PacketRecord &r)
|
|||||||
#if RECENT_WARN_AGE > 0
|
#if RECENT_WARN_AGE > 0
|
||||||
if (tu->rxTimeMsec && (OldtrxTimeMsec < RECENT_WARN_AGE)) {
|
if (tu->rxTimeMsec && (OldtrxTimeMsec < RECENT_WARN_AGE)) {
|
||||||
if (!(tu->id == r.id && tu->sender == r.sender)) {
|
if (!(tu->id == r.id && tu->sender == r.sender)) {
|
||||||
|
#if VERBOSE_PACKET_HISTORY
|
||||||
LOG_WARN("Packet History - insert: Reusing slot aged %ds < %ds RECENT_WARN_AGE", OldtrxTimeMsec / 1000,
|
LOG_WARN("Packet History - insert: Reusing slot aged %ds < %ds RECENT_WARN_AGE", OldtrxTimeMsec / 1000,
|
||||||
RECENT_WARN_AGE / 1000);
|
RECENT_WARN_AGE / 1000);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// debug only
|
// debug only
|
||||||
#if VERBOSE_PACKET_HISTORY
|
#if VERBOSE_PACKET_HISTORY
|
||||||
@ -275,7 +277,9 @@ void PacketHistory::insert(PacketRecord &r)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (r.rxTimeMsec == 0) {
|
if (r.rxTimeMsec == 0) {
|
||||||
|
#if VERBOSE_PACKET_HISTORY
|
||||||
LOG_WARN("Packet History - insert: I will not store packet with rxTimeMsec = 0.");
|
LOG_WARN("Packet History - insert: I will not store packet with rxTimeMsec = 0.");
|
||||||
|
#endif
|
||||||
return; // Return early if we can't update the history
|
return; // Return early if we can't update the history
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
variants/heltec_vision_master_e213/einkDetect.h
Normal file
35
variants/heltec_vision_master_e213/einkDetect.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
enum class EInkDetectionResult : uint8_t {
|
||||||
|
LCMEN213EFC1 = 0, // Initial version
|
||||||
|
E0213A367 = 1, // E213 PCB marked V1.1 (Mid 2025)
|
||||||
|
};
|
||||||
|
|
||||||
|
EInkDetectionResult detectEInk()
|
||||||
|
{
|
||||||
|
// Test 1: Logic of BUSY pin
|
||||||
|
|
||||||
|
// Determines controller IC manufacturer
|
||||||
|
// Fitipower: busy when LOW
|
||||||
|
// Solomon Systech: busy when HIGH
|
||||||
|
|
||||||
|
// Force display BUSY by holding reset pin active
|
||||||
|
pinMode(PIN_EINK_RES, OUTPUT);
|
||||||
|
digitalWrite(PIN_EINK_RES, LOW);
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
// Read whether pin is HIGH or LOW while busy
|
||||||
|
pinMode(PIN_EINK_BUSY, INPUT);
|
||||||
|
bool busyLogic = digitalRead(PIN_EINK_BUSY);
|
||||||
|
|
||||||
|
// Test complete. Release pin
|
||||||
|
pinMode(PIN_EINK_RES, INPUT);
|
||||||
|
|
||||||
|
if (busyLogic == LOW)
|
||||||
|
return EInkDetectionResult::LCMEN213EFC1;
|
||||||
|
else // busy HIGH
|
||||||
|
return EInkDetectionResult::E0213A367;
|
||||||
|
}
|
@ -18,16 +18,22 @@
|
|||||||
|
|
||||||
// Shared NicheGraphics components
|
// Shared NicheGraphics components
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
#include "graphics/niche/Drivers/EInk/E0213A367.h"
|
||||||
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
|
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
|
||||||
#include "graphics/niche/Inputs/TwoButton.h"
|
#include "graphics/niche/Inputs/TwoButton.h"
|
||||||
|
|
||||||
// Button feedback
|
#include "buzz.h" // Button feedback
|
||||||
#include "buzz.h"
|
#include "einkDetect.h" // Detect display model at runtime
|
||||||
|
|
||||||
void setupNicheGraphics()
|
void setupNicheGraphics()
|
||||||
{
|
{
|
||||||
using namespace NicheGraphics;
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
|
// Detect E-Ink Model
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
EInkDetectionResult displayModel = detectEInk();
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
@ -38,7 +44,13 @@ void setupNicheGraphics()
|
|||||||
// E-Ink Driver
|
// E-Ink Driver
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
Drivers::EInk *driver = new Drivers::LCMEN213EFC1;
|
Drivers::EInk *driver;
|
||||||
|
|
||||||
|
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked)
|
||||||
|
driver = new Drivers::LCMEN213EFC1;
|
||||||
|
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1
|
||||||
|
driver = new Drivers::E0213A367;
|
||||||
|
|
||||||
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
||||||
|
|
||||||
// InkHUD
|
// InkHUD
|
||||||
@ -51,7 +63,11 @@ void setupNicheGraphics()
|
|||||||
|
|
||||||
// Set how many FAST updates per FULL update
|
// Set how many FAST updates per FULL update
|
||||||
// Set how unhealthy additional FAST updates beyond this number are
|
// Set how unhealthy additional FAST updates beyond this number are
|
||||||
|
|
||||||
|
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked)
|
||||||
inkhud->setDisplayResilience(10, 1.5);
|
inkhud->setDisplayResilience(10, 1.5);
|
||||||
|
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1
|
||||||
|
inkhud->setDisplayResilience(15, 3);
|
||||||
|
|
||||||
// Select fonts
|
// Select fonts
|
||||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
||||||
|
@ -7,7 +7,8 @@ build_flags =
|
|||||||
-Ivariants/heltec_vision_master_e213
|
-Ivariants/heltec_vision_master_e213
|
||||||
-DHELTEC_VISION_MASTER_E213
|
-DHELTEC_VISION_MASTER_E213
|
||||||
-DUSE_EINK
|
-DUSE_EINK
|
||||||
-DEINK_DISPLAY_MODEL=GxEPD2_213_FC1
|
-DGXEPD2_DRIVER_0=GxEPD2_213_FC1
|
||||||
|
-DGXEPD2_DRIVER_1=GxEPD2_213_E0213A367
|
||||||
-DEINK_WIDTH=250
|
-DEINK_WIDTH=250
|
||||||
-DEINK_HEIGHT=122
|
-DEINK_HEIGHT=122
|
||||||
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
|
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
|
||||||
@ -16,7 +17,7 @@ build_flags =
|
|||||||
-DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
-DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip
|
https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip
|
||||||
lewisxhe/PCF8563_Library@^1.0.1
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
|
|
||||||
|
35
variants/heltec_wireless_paper/einkDetect.h
Normal file
35
variants/heltec_wireless_paper/einkDetect.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
enum class EInkDetectionResult : uint8_t {
|
||||||
|
LCMEN213EFC1 = 0, // V1.1
|
||||||
|
E0213A367 = 1, // V1.1.1, V1.2
|
||||||
|
};
|
||||||
|
|
||||||
|
EInkDetectionResult detectEInk()
|
||||||
|
{
|
||||||
|
// Test 1: Logic of BUSY pin
|
||||||
|
|
||||||
|
// Determines controller IC manufacturer
|
||||||
|
// Fitipower: busy when LOW
|
||||||
|
// Solomon Systech: busy when HIGH
|
||||||
|
|
||||||
|
// Force display BUSY by holding reset pin active
|
||||||
|
pinMode(PIN_EINK_RES, OUTPUT);
|
||||||
|
digitalWrite(PIN_EINK_RES, LOW);
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
// Read whether pin is HIGH or LOW while busy
|
||||||
|
pinMode(PIN_EINK_BUSY, INPUT);
|
||||||
|
bool busyLogic = digitalRead(PIN_EINK_BUSY);
|
||||||
|
|
||||||
|
// Test complete. Release pin
|
||||||
|
pinMode(PIN_EINK_RES, INPUT);
|
||||||
|
|
||||||
|
if (busyLogic == LOW)
|
||||||
|
return EInkDetectionResult::LCMEN213EFC1;
|
||||||
|
else // busy HIGH
|
||||||
|
return EInkDetectionResult::E0213A367;
|
||||||
|
}
|
@ -18,13 +18,21 @@
|
|||||||
|
|
||||||
// Shared NicheGraphics components
|
// Shared NicheGraphics components
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
#include "graphics/niche/Drivers/EInk/E0213A367.h"
|
||||||
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
|
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
|
||||||
#include "graphics/niche/Inputs/TwoButton.h"
|
#include "graphics/niche/Inputs/TwoButton.h"
|
||||||
|
|
||||||
|
#include "einkDetect.h" // Detect display model at runtime
|
||||||
|
|
||||||
void setupNicheGraphics()
|
void setupNicheGraphics()
|
||||||
{
|
{
|
||||||
using namespace NicheGraphics;
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
|
// Detect E-Ink Model
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
EInkDetectionResult displayModel = detectEInk();
|
||||||
|
|
||||||
// SPI
|
// SPI
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
@ -35,7 +43,13 @@ void setupNicheGraphics()
|
|||||||
// E-Ink Driver
|
// E-Ink Driver
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
Drivers::EInk *driver = new Drivers::LCMEN213EFC1;
|
Drivers::EInk *driver;
|
||||||
|
|
||||||
|
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1
|
||||||
|
driver = new Drivers::LCMEN213EFC1;
|
||||||
|
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2
|
||||||
|
driver = new Drivers::E0213A367;
|
||||||
|
|
||||||
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
||||||
|
|
||||||
// InkHUD
|
// InkHUD
|
||||||
@ -48,7 +62,11 @@ void setupNicheGraphics()
|
|||||||
|
|
||||||
// Set how many FAST updates per FULL update
|
// Set how many FAST updates per FULL update
|
||||||
// Set how unhealthy additional FAST updates beyond this number are
|
// Set how unhealthy additional FAST updates beyond this number are
|
||||||
|
|
||||||
|
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1 (unmarked)
|
||||||
inkhud->setDisplayResilience(10, 1.5);
|
inkhud->setDisplayResilience(10, 1.5);
|
||||||
|
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2
|
||||||
|
inkhud->setDisplayResilience(15, 3);
|
||||||
|
|
||||||
// Select fonts
|
// Select fonts
|
||||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
||||||
|
@ -7,7 +7,8 @@ build_flags =
|
|||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-I variants/heltec_wireless_paper
|
-I variants/heltec_wireless_paper
|
||||||
-D HELTEC_WIRELESS_PAPER
|
-D HELTEC_WIRELESS_PAPER
|
||||||
-D EINK_DISPLAY_MODEL=GxEPD2_213_FC1
|
-D GXEPD2_DRIVER_0=GxEPD2_213_FC1
|
||||||
|
-D GXEPD2_DRIVER_1=GxEPD2_213_E0213A367
|
||||||
-D EINK_WIDTH=250
|
-D EINK_WIDTH=250
|
||||||
-D EINK_HEIGHT=122
|
-D EINK_HEIGHT=122
|
||||||
-D USE_EINK
|
-D USE_EINK
|
||||||
@ -17,7 +18,7 @@ build_flags =
|
|||||||
-D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
-D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip
|
https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip
|
||||||
lewisxhe/PCF8563_Library@^1.0.1
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
upload_speed = 115200
|
upload_speed = 115200
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user