diff --git a/.github/actions/build-variant/action.yml b/.github/actions/build-variant/action.yml
index 2f0883fad..67d002eea 100644
--- a/.github/actions/build-variant/action.yml
+++ b/.github/actions/build-variant/action.yml
@@ -43,6 +43,13 @@ runs:
id: base
uses: ./.github/actions/setup-base
+ - name: Get web ui version
+ if: inputs.include-web-ui == 'true'
+ id: webver
+ shell: bash
+ run: |
+ echo "ver=$(cat bin/web.version)" >> $GITHUB_OUTPUT
+
- name: Pull web ui
if: inputs.include-web-ui == 'true'
uses: dsaltares/fetch-gh-release-asset@master
@@ -51,7 +58,7 @@ runs:
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
- version: tags/v2.5.3
+ version: tags/v${{ steps.webver.outputs.ver }}
- name: Unpack web ui
if: inputs.include-web-ui == 'true'
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index b14290be2..000000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-#trunk-ignore-all(yamllint/quoted-strings): required by dependabot syntax check
-version: 2
-updates:
- - package-ecosystem: docker
- directory: /.devcontainer
- schedule:
- interval: daily
- time: "05:00"
- timezone: US/Pacific
- - package-ecosystem: docker
- directory: /
- schedule:
- interval: daily
- time: "05:00"
- timezone: US/Pacific
- - package-ecosystem: gitsubmodule
- directory: /
- schedule:
- interval: daily
- time: "05:00"
- timezone: US/Pacific
- ignore:
- - dependency-name: protobufs
- - package-ecosystem: github-actions
- directory: /.github/workflows
- schedule:
- interval: daily
- time: "05:00"
- timezone: US/Pacific
diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml
index db308c9f5..d7eef29b4 100644
--- a/.github/workflows/sec_sast_semgrep_cron.yml
+++ b/.github/workflows/sec_sast_semgrep_cron.yml
@@ -13,7 +13,7 @@ permissions:
jobs:
semgrep-full:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
container:
image: semgrep/semgrep
diff --git a/.github/workflows/sec_sast_semgrep_pull.yml b/.github/workflows/sec_sast_semgrep_pull.yml
index 527a5c076..3707c91b8 100644
--- a/.github/workflows/sec_sast_semgrep_pull.yml
+++ b/.github/workflows/sec_sast_semgrep_pull.yml
@@ -6,7 +6,7 @@ permissions: read-all
jobs:
semgrep-diff:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
container:
image: semgrep/semgrep
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index aeb0a1b43..e74c1a362 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -8,15 +8,15 @@ plugins:
uri: https://github.com/trunk-io/plugins
lint:
enabled:
+ - renovate@39.235.2
- prettier@3.5.3
- - trufflehog@3.88.20
+ - trufflehog@3.88.23
- yamllint@1.37.0
- bandit@1.8.3
- - checkov@3.2.396
- terrascan@1.19.9
- trivy@0.61.0
- taplo@0.9.3
- - ruff@0.11.2
+ - ruff@0.11.4
- isort@6.0.1
- markdownlint@0.44.0
- oxipng@9.1.4
diff --git a/Dockerfile b/Dockerfile
index 733a46325..55580c579 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@ ENV TZ=Etc/UTC
# Install Dependencies
ENV PIP_ROOT_USER_ACTION=ignore
RUN apt-get update && apt-get install --no-install-recommends -y \
- wget g++ zip git ca-certificates \
+ curl wget g++ zip git ca-certificates \
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
@@ -27,6 +27,12 @@ COPY . /tmp/firmware
RUN bash ./bin/build-native.sh && \
cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
+# Fetch web assets
+RUN curl -L "https://github.com/meshtastic/web/releases/download/v$(cat /tmp/firmware/bin/web.version)/build.tar" -o /tmp/web.tar \
+ && mkdir -p /tmp/web \
+ && tar -xf /tmp/web.tar -C /tmp/web/ \
+ && gzip -dr /tmp/web \
+ && rm /tmp/web.tar
##### PRODUCTION BUILD #############
@@ -46,6 +52,7 @@ RUN apt-get update && apt-get --no-install-recommends -y install \
# Fetch compiled binary from the builder
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/
+COPY --from=builder /tmp/web /usr/share/meshtasticd/
# Copy config templates
COPY ./bin/config.d /etc/meshtasticd/available.d
@@ -54,7 +61,9 @@ VOLUME /var/lib/meshtasticd
# Expose Meshtastic TCP API port from the host
EXPOSE 4403
+# Expose Meshtastic Web UI port from the host
+EXPOSE 443
CMD [ "sh", "-cx", "meshtasticd -d /var/lib/meshtasticd" ]
-HEALTHCHECK NONE
\ No newline at end of file
+HEALTHCHECK NONE
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index df3778002..5e15cb451 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -2,7 +2,9 @@
[esp32_base]
extends = arduino_base
custom_esp32_kind = esp32
-platform = platformio/espressif32@6.10.0
+platform =
+ # renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
+ platformio/espressif32@6.10.0
build_src_filter =
${arduino_base.build_src_filter} - - - - -
@@ -45,11 +47,17 @@ lib_deps =
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
- https://github.com/meshtastic/esp32_https_server/archive/23665b3adc080a311dcbb586ed5941b5f94d6ea2.zip
+ # renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
+ https://github.com/meshtastic/esp32_https_server/archive/896f1771ceb5979987a0b41028bf1b4e7aad419b.zip
+ # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
h2zero/NimBLE-Arduino@^1.4.3
+ # renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
+ # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
lewisxhe/XPowersLib@^0.2.7
+ # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
+ # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
rweather/Crypto@^0.4.0
lib_ignore =
diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini
index dba3bac08..e1cf955e8 100644
--- a/arch/esp32/esp32c6.ini
+++ b/arch/esp32/esp32c6.ini
@@ -1,6 +1,8 @@
[esp32c6_base]
extends = esp32_base
-platform = https://github.com/Jason2866/platform-espressif32/archive/22faa566df8c789000f8136cd8d0aca49617af55.zip
+platform =
+ # renovate: datasource=git-refs depName=ESP32c6 platform-espressif32 packageName=https://github.com/Jason2866/platform-espressif32 gitBranch=Arduino/IDF5
+ https://github.com/Jason2866/platform-espressif32/archive/22faa566df8c789000f8136cd8d0aca49617af55.zip
build_flags =
${arduino_base.build_flags}
-Wall
@@ -24,8 +26,11 @@ lib_deps =
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
+ # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
lewisxhe/XPowersLib@^0.2.7
+ # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
+ # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
rweather/Crypto@^0.4.0
build_src_filter =
diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini
index 40fdc461a..0f97408b8 100644
--- a/arch/esp32/esp32s2.ini
+++ b/arch/esp32/esp32s2.ini
@@ -16,4 +16,4 @@ build_flags =
lib_ignore =
${esp32_base.lib_ignore}
NimBLE-Arduino
- libpax
\ No newline at end of file
+ libpax
diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini
index 1cd0e2033..8d8b6899e 100644
--- a/arch/esp32/esp32s3.ini
+++ b/arch/esp32/esp32s3.ini
@@ -3,4 +3,3 @@ extends = esp32_base
custom_esp32_kind = esp32s3
monitor_speed = 115200
-
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index ca12be6b1..127f46183 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -1,10 +1,14 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
-platform = platformio/nordicnrf52@^10.8.0
+platform =
+ # renovate: datasource=custom.pio depName=platformio/nordicnrf52 packageName=platformio/platform/nordicnrf52
+ platformio/nordicnrf52@^10.8.0
extends = arduino_base
platform_packages =
; our custom Git version until they merge our PR
+ # TODO renovate
platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino#e13f5820002a4fb2a5e6754b42ace185277e5adf
+ # renovate: datasource=custom.pio depName=platformio/toolchain-gccarmnoneeabi packageName=platformio/tool/toolchain-gccarmnoneeabi
platformio/toolchain-gccarmnoneeabi@~1.90301.0
build_type = debug
@@ -28,4 +32,4 @@ lib_deps=
lib_ignore =
BluetoothOTA
- lvgl
\ No newline at end of file
+ lvgl
diff --git a/arch/nrf52/nrf52840.ini b/arch/nrf52/nrf52840.ini
index 0dab5d9ba..fb5ba9960 100644
--- a/arch/nrf52/nrf52840.ini
+++ b/arch/nrf52/nrf52840.ini
@@ -6,6 +6,7 @@ build_flags = ${nrf52_base.build_flags}
lib_deps =
${nrf52_base.lib_deps}
${environmental_base.lib_deps}
+ # renovate: datasource=git-refs depName=Kongduino-Adafruit_nRFCrypto packageName=https://github.com/Kongduino/Adafruit_nRFCrypto gitBranch=master
https://github.com/Kongduino/Adafruit_nRFCrypto/archive/e31a8825ea3300b163a0a3c1ddd5de34e10e1371.zip
; Common NRF52 debugging settings follow. See the Meshtastic developer docs for how to connect SWD debugging probes to your board.
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index e0488aeff..6df3854f4 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -1,6 +1,8 @@
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
[portduino_base]
-platform = https://github.com/meshtastic/platform-native/archive/c5bd469ab9b5a6966321e09557b27d906961da63.zip
+platform =
+ # renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
+ https://github.com/meshtastic/platform-native/archive/46f509b96ddce22d1bf38efc93319dfb3e4f5acf.zip
framework = arduino
build_src_filter =
@@ -24,9 +26,12 @@ lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
${radiolib_base.lib_deps}
+ # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
rweather/Crypto@^0.4.0
+ # renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@^1.2.0
- https://github.com/pine64/libch341-spi-userspace/archive/a9b17e3452f7fb747000d9b4ad4409155b39f6ef.zip
+ # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main
+ https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip
build_flags =
${arduino_base.build_flags}
diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini
index 33fcfb211..cd7e684b4 100644
--- a/arch/rp2xx0/rp2040.ini
+++ b/arch/rp2xx0/rp2040.ini
@@ -1,8 +1,13 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
+platform =
+ # TODO renovate
+ https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5
+ ; For arduino-pico >= 4.4.3
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
+platform_packages =
+ # TODO renovate
+ framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@@ -24,4 +29,5 @@ lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
- rweather/Crypto
\ No newline at end of file
+ # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
+ rweather/Crypto@0.4.0
diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini
index 841035c80..1c7af8be4 100644
--- a/arch/rp2xx0/rp2350.ini
+++ b/arch/rp2xx0/rp2350.ini
@@ -1,8 +1,13 @@
-; Common settings for rp2040 Processor based targets
+; Common settings for rp2350 Processor based targets
[rp2350_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
+platform =
+ # TODO renovate
+ https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5
+ ; For arduino-pico >= 4.4.3
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
+platform_packages =
+ # TODO renovate
+ framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@@ -21,4 +26,5 @@ lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
- rweather/Crypto
\ No newline at end of file
+ # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
+ rweather/Crypto@0.4.0
diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini
index c1b58bb82..dd190c9d4 100644
--- a/arch/stm32/stm32.ini
+++ b/arch/stm32/stm32.ini
@@ -1,7 +1,11 @@
[stm32_base]
extends = arduino_base
-platform = ststm32
-platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
+platform =
+ # renovate: datasource=custom.pio depName=platformio/ststm32 packageName=platformio/platform/ststm32
+ platformio/ststm32@19.1.0
+platform_packages =
+ # TODO renovate
+ platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
extra_scripts =
${env.extra_scripts}
post:extra_scripts/extra_stm32.py
@@ -35,6 +39,7 @@ debug_tool = stlink
lib_deps =
${env.lib_deps}
${radiolib_base.lib_deps}
+ # renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main
https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip
lib_ignore =
diff --git a/bin/device-install.sh b/bin/device-install.sh
index bacf48f69..796626a9d 100755
--- a/bin/device-install.sh
+++ b/bin/device-install.sh
@@ -138,7 +138,7 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
# littlefs* offset for BigDB 8mb and OTA OFFSET.
for variant in "${BIGDB_8MB[@]}"; do
- if [ -n "${FILENAME##*"$variant"*}" ]; then
+ if [ -z "${FILENAME##*"$variant"*}" ]; then
OFFSET=0x670000
OTA_OFFSET=0x340000
fi
@@ -146,7 +146,7 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
# littlefs* offset for BigDB 16mb and OTA OFFSET.
for variant in "${BIGDB_16MB[@]}"; do
- if [ -n "${FILENAME##*"$variant"*}" ]; then
+ if [ -z "${FILENAME##*"$variant"*}" ]; then
OFFSET=0xc90000
OTA_OFFSET=0x650000
fi
@@ -155,7 +155,7 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
# Account for S3 board's different OTA partition
# FIXME: Use PlatformIO info to determine MCU type, this is unmaintainable
for variant in "${S3_VARIANTS[@]}"; do
- if [ -n "${FILENAME##*"$variant"*}" ]; then
+ if [ -z "${FILENAME##*"$variant"*}" ]; then
MCU="esp32s3"
fi
done
diff --git a/bin/rpkg.macros b/bin/rpkg.macros
index 2bbb203de..aa036fc33 100644
--- a/bin/rpkg.macros
+++ b/bin/rpkg.macros
@@ -2,6 +2,10 @@ function meshtastic_version {
meshtastic_version=$(python3 bin/buildinfo.py short)
echo -n "$meshtastic_version"
}
+function web_version {
+ web_version=$(cat bin/web.version)
+ echo -n "$web_version"
+}
function git_commits_num {
total_commits=$(git rev-list --all --count)
echo -n "$total_commits"
diff --git a/bin/web.version b/bin/web.version
new file mode 100644
index 000000000..914ec9671
--- /dev/null
+++ b/bin/web.version
@@ -0,0 +1 @@
+2.6.0
\ No newline at end of file
diff --git a/boards/heltec_vision_master_e213.json b/boards/heltec_vision_master_e213.json
index bf5fe15ad..152515cf3 100644
--- a/boards/heltec_vision_master_e213.json
+++ b/boards/heltec_vision_master_e213.json
@@ -2,7 +2,8 @@
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
- "partitions": "default_8MB.csv"
+ "partitions": "default_8MB.csv",
+ "memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
@@ -15,6 +16,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [
["0x303A", "0x1001"],
["0x303A", "0x0002"]
diff --git a/boards/heltec_vision_master_e290.json b/boards/heltec_vision_master_e290.json
index 70f7d5f02..b7cbac878 100644
--- a/boards/heltec_vision_master_e290.json
+++ b/boards/heltec_vision_master_e290.json
@@ -2,7 +2,8 @@
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
- "partitions": "default_8MB.csv"
+ "partitions": "default_8MB.csv",
+ "memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
@@ -15,6 +16,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [
["0x303A", "0x1001"],
["0x303A", "0x0002"]
diff --git a/boards/heltec_vision_master_t190.json b/boards/heltec_vision_master_t190.json
index 341e70218..440f76ad0 100644
--- a/boards/heltec_vision_master_t190.json
+++ b/boards/heltec_vision_master_t190.json
@@ -2,7 +2,8 @@
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
- "partitions": "default_8MB.csv"
+ "partitions": "default_8MB.csv",
+ "memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
@@ -15,6 +16,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [
["0x303A", "0x1001"],
["0x303A", "0x0002"]
diff --git a/boards/seeed-sensecap-indicator.json b/boards/seeed-sensecap-indicator.json
index 0a02fc882..03bff35b5 100644
--- a/boards/seeed-sensecap-indicator.json
+++ b/boards/seeed-sensecap-indicator.json
@@ -18,6 +18,7 @@
"f_boot": "120000000L",
"boot": "qio",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [["0x1A86", "0x7523"]],
"mcu": "esp32s3",
"variant": "esp32s3"
diff --git a/boards/seeed-xiao-s3.json b/boards/seeed-xiao-s3.json
index 0b7b432a0..6981085dd 100644
--- a/boards/seeed-xiao-s3.json
+++ b/boards/seeed-xiao-s3.json
@@ -15,6 +15,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [["0x2886", "0x0059"]],
"mcu": "esp32s3",
"variant": "seeed-xiao-s3"
diff --git a/boards/t-watch-s3.json b/boards/t-watch-s3.json
index 5d4afd322..51bb7cf4b 100644
--- a/boards/t-watch-s3.json
+++ b/boards/t-watch-s3.json
@@ -16,6 +16,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "psram_type": "opi",
"hwids": [
["0x303A", "0x1001"],
["0x303A", "0x0002"]
diff --git a/debian/ci_pack_sdeb.sh b/debian/ci_pack_sdeb.sh
index a8b2252ae..c0cea0010 100755
--- a/debian/ci_pack_sdeb.sh
+++ b/debian/ci_pack_sdeb.sh
@@ -10,8 +10,9 @@ platformio pkg install -e native -t platformio/tool-scons@4.40502.0
# Compress `pio` directory to prevent dh_clean from sanitizing it
tar -cf pio.tar pio/
rm -rf pio
-# Download the latest meshtastic/web release build.tar to `web.tar`
-curl -L https://github.com/meshtastic/web/releases/latest/download/build.tar -o web.tar
+# Download the meshtastic/web release build.tar to `web.tar`
+web_ver=$(cat bin/web.version)
+curl -L "https://github.com/meshtastic/web/releases/download/v$web_ver/build.tar" -o web.tar
package=$(dpkg-parsechangelog --show-field Source)
diff --git a/meshtasticd.spec.rpkg b/meshtasticd.spec.rpkg
index a09261056..4d6c9d6f5 100644
--- a/meshtasticd.spec.rpkg
+++ b/meshtasticd.spec.rpkg
@@ -21,7 +21,7 @@ Summary: Meshtastic daemon for communicating with Meshtastic devices
License: GPL-3.0
URL: https://github.com/meshtastic/firmware
Source0: {{{ git_dir_pack }}}
-Source1: https://github.com/meshtastic/web/releases/latest/download/build.tar
+Source1: https://github.com/meshtastic/web/releases/download/v{{{ web_version }}}/build.tar
BuildRequires: systemd-rpm-macros
BuildRequires: python3-devel
diff --git a/platformio.ini b/platformio.ini
index 377635873..3c052e6ad 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -56,12 +56,19 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200
monitor_filters = direct
lib_deps =
+ # renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/0119501e9983bd894830b02f545c377ee08d66fe.zip
+ # renovate: datasource=custom.pio depName=OneButton packageName=mathertel/library/OneButton
mathertel/OneButton@2.6.1
+ # renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
https://github.com/meshtastic/arduino-fsm/archive/7db3702bf0cfe97b783d6c72595e3f38e0b19159.zip
+ # renovate: datasource=git-refs depName=meshtastic-TinyGPSPlus packageName=https://github.com/meshtastic/TinyGPSPlus gitBranch=master
https://github.com/meshtastic/TinyGPSPlus/archive/71a82db35f3b973440044c476d4bcdc673b104f4.zip
+ # renovate: datasource=git-refs depName=meshtastic-ArduinoThread packageName=https://github.com/meshtastic/ArduinoThread gitBranch=master
https://github.com/meshtastic/ArduinoThread/archive/7c3ee9e1951551b949763b1f5280f8db1fa4068d.zip
+ # renovate: datasource=custom.pio depName=Nanopb packageName=nanopb/library/Nanopb
nanopb/Nanopb@0.4.91
+ # renovate: datasource=custom.pio depName=ErriezCRC32 packageName=erriez/library/ErriezCRC32
erriez/ErriezCRC32@1.0.1
; Used for the code analysis in PIO Home / Inspect
@@ -77,6 +84,7 @@ check_flags =
framework = arduino
lib_deps =
${env.lib_deps}
+ # renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=end2endzone/library/NonBlockingRTTTL
end2endzone/NonBlockingRTTTL@1.3.0
build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} - -
@@ -84,57 +92,98 @@ build_src_filter = ${env.build_src_filter} - -.+)$"],
+ "datasourceTemplate": "github-releases",
+ "depNameTemplate": "meshtastic/web",
+ "versioningTemplate": "semver-coerced"
+ },
+ {
+ "customType": "regex",
+ "description": "Match normal PIO dependencies",
+ "fileMatch": [".*\\.ini$"],
+ "matchStrings": [
+ "# renovate: datasource=(?.*?)(?: depName=(?.+?))? packageName=(?.+?)(?: versioning=(?[a-z-]+?))?\\s+?.+?@(?.+?)\\s"
+ ],
+ "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver-coerced{{/if}}"
+ },
+ {
+ "customType": "regex",
+ "description": "Match PIO zipped dependencies with github tag ref",
+ "fileMatch": [".*\\.ini$"],
+ "matchStrings": [
+ "# renovate: datasource=github-tags(?: depName=(?.+?))? packageName=(?.+?)(?: versioning=(?[a-z-]+?))?\\s+?https:\/\/.+?archive\/(?.+?).zip\\s"
+ ],
+ "datasourceTemplate": "github-tags",
+ "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver-coerced{{/if}}"
+ },
+ {
+ "customType": "regex",
+ "description": "Match PIO zipped dependencies with git commit ref",
+ "fileMatch": [".*\\.ini$"],
+ "matchStrings": [
+ "# renovate: datasource=git-refs(?: depName=(?.+?))? packageName=(?.+?)(?: versioning=(?[a-z-]+?))?\\sgitBranch=(?.+?)\\s+?https:\/\/.+?archive\/(?.+?).zip\\s"
+ ],
+ "datasourceTemplate": "git-refs",
+ "currentValueTemplate": "{{{gitBranch}}}",
+ "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}git{{/if}}"
+ }
+ ],
+ "packageRules": []
+}
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index 2363f804c..04200a7df 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -116,46 +116,55 @@ ButtonThread::ButtonThread() : OSThread("Button")
#endif
}
+void ButtonThread::switchPage()
+{
+#ifdef BUTTON_PIN
+#if !defined(USERPREFS_BUTTON_PIN)
+ if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
+ moduleConfig.canned_message.inputbroker_pin_press) ||
+ !(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
+ !moduleConfig.canned_message.enabled) {
+ powerFSM.trigger(EVENT_PRESS);
+ }
+#endif
+#if defined(USERPREFS_BUTTON_PIN)
+ if (((config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN) !=
+ moduleConfig.canned_message.inputbroker_pin_press) ||
+ !(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
+ !moduleConfig.canned_message.enabled) {
+ powerFSM.trigger(EVENT_PRESS);
+ }
+#endif
+
+#endif
+#if defined(ARCH_PORTDUINO)
+ if ((settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) &&
+ (settingsMap[user] != moduleConfig.canned_message.inputbroker_pin_press) ||
+ !moduleConfig.canned_message.enabled) {
+ powerFSM.trigger(EVENT_PRESS);
+ }
+#endif
+}
+
+void ButtonThread::sendAdHocPosition()
+{
+ service->refreshLocalMeshNode();
+ auto sentPosition = service->trySendPosition(NODENUM_BROADCAST, true);
+ if (screen) {
+ if (sentPosition)
+ screen->print("Sent ad-hoc position\n");
+ else
+ screen->print("Sent ad-hoc nodeinfo\n");
+ screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
+ }
+}
+
int32_t ButtonThread::runOnce()
{
// If the button is pressed we suppress CPU sleep until release
canSleep = true; // Assume we should not keep the board awake
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
- // #if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
- // buzzer_updata();
- // if (buttonPressed) {
- // buttonPressed = false; // 清除标志
- // LOG_INFO("PIN_BUTTON2 pressed!"); // 串口打印信息
- // // off_currentTime = millis();
- // while (digitalRead(PIN_BUTTON2) == HIGH) {
- // if (cont < 40) {
- // // unsigned long currentTime = millis(); // 获取当前时间
- // // if (currentTime - off_currentTime >= 1000) {
- // cont++;
- // // off_currentTime = currentTime;
- // // }
- // delay(100);
- // } else {
-
- // currentState = OFF;
- // isBuzzing = false;
- // cont = 0;
- // BEEP_STATE = false;
- // analogWrite(M2_buzzer, 0);
- // pinMode(M2_buzzer, INPUT);
- // screen->setOn(false);
- // cont = 0;
- // LOG_INFO("GGGGGGGGGGGGGGGGGGGGGGGGG");
- // pinMode(1, OUTPUT);
- // digitalWrite(1, LOW);
- // pinMode(6, OUTPUT);
- // digitalWrite(6, LOW);
- // }
- // }
- // }
-
- // #endif
userButton.tick();
canSleep &= userButton.isIdle();
#elif defined(ARCH_PORTDUINO)
@@ -180,32 +189,27 @@ int32_t ButtonThread::runOnce()
// If a nag notification is running, stop it and prevent other actions
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
- return 50;
- }
-#ifdef BUTTON_PIN
-#if !defined(USERPREFS_BUTTON_PIN)
- if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
-#endif
-#if defined(USERPREFS_BUTTON_PIN)
- if (((config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN) !=
-#endif
- moduleConfig.canned_message.inputbroker_pin_press) ||
- !(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
- !moduleConfig.canned_message.enabled) {
- powerFSM.trigger(EVENT_PRESS);
- }
-#endif
-#if defined(ARCH_PORTDUINO)
- if ((settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) &&
- (settingsMap[user] != moduleConfig.canned_message.inputbroker_pin_press) ||
- !moduleConfig.canned_message.enabled) {
- powerFSM.trigger(EVENT_PRESS);
+ break;
}
+#ifdef ELECROW_ThinkNode_M1
+ sendAdHocPosition();
+ break;
#endif
+ switchPage();
break;
}
case BUTTON_EVENT_PRESSED_SCREEN: {
+ LOG_BUTTON("AltPress!");
+#ifdef ELECROW_ThinkNode_M1
+ // If a nag notification is running, stop it and prevent other actions
+ if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
+ externalNotificationModule->stopNow();
+ break;
+ }
+ switchPage();
+ break;
+#endif
// turn screen on or off
screen_flag = !screen_flag;
if (screen)
@@ -215,22 +219,18 @@ int32_t ButtonThread::runOnce()
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!");
- service->refreshLocalMeshNode();
- auto sentPosition = service->trySendPosition(NODENUM_BROADCAST, true);
- if (screen) {
- if (sentPosition)
- screen->print("Sent ad-hoc position\n");
- else
- screen->print("Sent ad-hoc nodeinfo\n");
- screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
- }
+#ifdef ELECROW_ThinkNode_M1
+ digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
+ break;
+#endif
+ sendAdHocPosition();
break;
}
case BUTTON_EVENT_MULTI_PRESSED: {
LOG_BUTTON("Mulitipress! %hux", multipressClickCount);
switch (multipressClickCount) {
-#if HAS_GPS
+#if HAS_GPS && !defined(ELECROW_ThinkNode_M1)
// 3 clicks: toggle GPS
case 3:
if (!config.device.disable_triple_click && (gps != nullptr)) {
@@ -239,17 +239,17 @@ int32_t ButtonThread::runOnce()
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;
-#elif defined(ELECROW_ThinkNode_M2)
+#elif defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
case 3:
LOG_INFO("3 clicks: toggle buzzer");
buzzer_flag = !buzzer_flag;
- if (buzzer_flag) {
- playBeep();
- }
+ if (!buzzer_flag)
+ noTone(PIN_BUZZER);
break;
+
#endif
-#if defined(USE_EINK) && defined(PIN_EINK_EN) // i.e. T-Echo
+#if defined(USE_EINK) && defined(PIN_EINK_EN) && !defined(ELECROW_ThinkNode_M1) // i.e. T-Echo
// 4 clicks: toggle backlight
case 4:
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
@@ -349,8 +349,12 @@ void ButtonThread::attachButtonInterrupts()
#endif
#ifdef BUTTON_PIN_ALT
+#ifdef ELECROW_ThinkNode_M2
+ wakeOnIrq(BUTTON_PIN_ALT, RISING);
+#else
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
+#endif
#ifdef BUTTON_PIN_TOUCH
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
diff --git a/src/ButtonThread.h b/src/ButtonThread.h
index a8f1f77c3..3af700dd0 100644
--- a/src/ButtonThread.h
+++ b/src/ButtonThread.h
@@ -37,6 +37,9 @@ class ButtonThread : public concurrency::OSThread
void attachButtonInterrupts();
void detachButtonInterrupts();
void storeClickCount();
+ bool isBuzzing() { return buzzer_flag; }
+ void setScreenFlag(bool flag) { screen_flag = flag; }
+ bool getScreenFlag() { return screen_flag; }
// Disconnect and reconnect interrupts for light sleep
#ifdef ARCH_ESP32
@@ -72,14 +75,12 @@ class ButtonThread : public concurrency::OSThread
static void wakeOnIrq(int irq, int mode);
+ static void sendAdHocPosition();
+ static void switchPage();
+
// IRQ callbacks
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
- static void userButtonPressedScreen()
- {
- if (millis() > c_holdOffTime) {
- btnEvent = BUTTON_EVENT_PRESSED_SCREEN;
- }
- }
+ static void userButtonPressedScreen() { btnEvent = BUTTON_EVENT_PRESSED_SCREEN; }
static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_PRESSED; }
static void userButtonMultiPressed(void *callerThread); // Retrieve click count from non-static Onebutton while still valid
static void userButtonPressedLongStart();
diff --git a/src/Power.cpp b/src/Power.cpp
index 0dec0fc21..f11f8eac3 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -380,6 +380,20 @@ class AnalogBatteryLevel : public HasBatteryLevel
// if we have a integrated device with a battery, we can assume that the battery is always connected
#ifdef BATTERY_IMMUTABLE
virtual bool isBatteryConnect() override { return true; }
+#elif defined(ADC_V)
+ virtual bool isBatteryConnect() override
+ {
+ int lastReading = digitalRead(ADC_V);
+ // 判断值是否变化
+ for (int i = 2; i < 500; i++) {
+ int reading = digitalRead(ADC_V);
+ if (reading != lastReading) {
+ return false; // 有变化,USB供电, 没接电池
+ }
+ }
+
+ return true;
+ }
#else
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
#endif
@@ -533,9 +547,6 @@ Power::Power() : OSThread("Power")
{
statusHandler = {};
low_voltage_counter = 0;
-#if defined(ELECROW_ThinkNode_M1) || defined(POWER_CFG)
- low_voltage_counter_led3 = 0;
-#endif
#ifdef DEBUG_HEAP
lastheap = memGet.getFreeHeap();
#endif
@@ -716,9 +727,6 @@ void Power::readPowerStatus()
const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isChargingNow, batteryVoltageMv, batteryChargePercent);
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(),
powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
-#if defined(ELECROW_ThinkNode_M1) || defined(POWER_CFG)
- power_num = powerStatus2.getBatteryVoltageMv();
-#endif
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != memGet.getFreeHeap()) {
@@ -766,9 +774,6 @@ void Power::readPowerStatus()
if (batteryLevel && powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS - 1]) {
low_voltage_counter++;
-#if defined(ELECROW_ThinkNode_M1)
- low_voltage_counter_led3 = low_voltage_counter;
-#endif
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
@@ -781,13 +786,7 @@ void Power::readPowerStatus()
}
} else {
low_voltage_counter = 0;
-#if defined(ELECROW_ThinkNode_M1)
- low_voltage_counter_led3 = low_voltage_counter;
-#endif
}
-#ifdef POWER_CFG
- low_voltage_counter_led3 = low_voltage_counter;
-#endif
}
}
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 41a2ff980..689f5e204 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -12,6 +12,7 @@
#include "RTC.h"
#include "Throttle.h"
#include "buzz.h"
+#include "concurrency/Periodic.h"
#include "meshUtils.h"
#include "main.h" // pmu_found
@@ -89,6 +90,45 @@ static const char *getGPSPowerStateString(GPSPowerState state)
}
}
+#ifdef PIN_GPS_SWITCH
+// If we have a hardware switch, define a periodic watcher outside of the GPS runOnce thread, since this can be sleeping
+// idefinitely
+
+int lastState = LOW;
+bool firstrun = true;
+
+static int32_t gpsSwitch()
+{
+ if (gps) {
+ int currentState = digitalRead(PIN_GPS_SWITCH);
+
+ // if the switch is set to zero, disable the GPS Thread
+ if (firstrun)
+ if (currentState == LOW)
+ lastState = HIGH;
+
+ if (currentState != lastState) {
+ if (currentState == LOW) {
+ config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
+ if (!firstrun)
+ playGPSDisableBeep();
+ gps->disable();
+ } else {
+ config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
+ if (!firstrun)
+ playGPSEnableBeep();
+ gps->enable();
+ }
+ lastState = currentState;
+ }
+ firstrun = false;
+ }
+ return 1000;
+}
+
+static concurrency::Periodic *gpsPeriodic;
+#endif
+
static void UBXChecksum(uint8_t *message, size_t length)
{
uint8_t CK_A = 0, CK_B = 0;
@@ -1206,7 +1246,8 @@ GnssModel_t GPS::probe(int serialSpeed)
delay(20);
std::vector mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B},
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S},
- {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B}};
+ {"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B},
+ {"L96", "Quectel-L96", GNSS_MODEL_MTK_L76B}};
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
@@ -1389,6 +1430,12 @@ GPS *GPS::createGps()
pinMode(PIN_GPS_PPS, INPUT);
#endif
+#ifdef PIN_GPS_SWITCH
+ // toggle GPS via external GPIO switch
+ pinMode(PIN_GPS_SWITCH, INPUT);
+ gpsPeriodic = new concurrency::Periodic("GPSSwitch", gpsSwitch);
+#endif
+
// Currently disabled per issue #525 (TinyGPS++ crash bug)
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
diff --git a/src/gps/ubx.h b/src/gps/ubx.h
index d674bed51..0fe2f01fb 100644
--- a/src/gps/ubx.h
+++ b/src/gps/ubx.h
@@ -224,7 +224,7 @@ static const uint8_t _message_GSA[] = {
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
- 0x00, // Rate for USB usefull for native linux
+ 0x00, // Rate for USB useful for native linux
0x00, // Rate for SPI
0x00 // Reserved
};
@@ -258,7 +258,7 @@ static const uint8_t _message_RMC[] = {
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
- 0x01, // Rate for USB usefull for native linux
+ 0x01, // Rate for USB useful for native linux
0x00, // Rate for SPI
0x00 // Reserved
};
@@ -269,7 +269,7 @@ static const uint8_t _message_GGA[] = {
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
- 0x01, // Rate for USB, usefull for native linux
+ 0x01, // Rate for USB, useful for native linux
0x00, // Rate for SPI
0x00 // Reserved
};
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 9aae3efec..4feaefd75 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include "GPS.h"
#endif
#include "FSCommon.h"
+#include "ButtonThread.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "error.h"
@@ -2924,6 +2925,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
if (on != screenOn) {
if (on) {
LOG_INFO("Turn on screen");
+ buttonThread->setScreenFlag(true);
powerMon->setState(meshtastic_PowerMon_State_Screen_On);
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
@@ -2959,6 +2961,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
setScreensaverFrames(einkScreensaver);
#endif
LOG_INFO("Turn off screen");
+ buttonThread->setScreenFlag(false);
#ifdef ELECROW_ThinkNode_M1
if (digitalRead(PIN_EINK_EN) == HIGH) {
digitalWrite(PIN_EINK_EN, LOW);
diff --git a/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.cpp b/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.cpp
deleted file mode 100644
index b8715ed1d..000000000
--- a/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "./DEPG0154BNS800.h"
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.h b/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.h
deleted file mode 100644
index 62d42ef57..000000000
--- a/src/graphics/niche/Drivers/EInk/DEPG0154BNS800.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-
-E-Ink display driver
- - DEPG0154BNS800
- - Manufacturer: DKE
- - Size: 1.54 inch
- - Resolution: 152px x 152px
- - Flex connector marking: FPC7525
-
-*/
-
-#pragma once
-
-#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
-#include "configuration.h"
-
-#include "./SSD16XX.h"
-
-namespace NicheGraphics::Drivers
-{
-class DEPG0154BNS800 : public SSD16XX
-{
- // Display properties
- private:
- static constexpr uint32_t width = 152;
- static constexpr uint32_t height = 152;
- static constexpr UpdateTypes supported = (UpdateTypes)(FULL);
-
- public:
- DEPG0154BNS800() : SSD16XX(width, height, supported, 1) {} // Note: left edge of this display is offset by 1 byte
-};
-
-} // namespace NicheGraphics::Drivers
-#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.cpp b/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.cpp
new file mode 100644
index 000000000..2c8df96ed
--- /dev/null
+++ b/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.cpp
@@ -0,0 +1,132 @@
+#include "./DEPG0213BNS800.h"
+
+#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
+
+using namespace NicheGraphics::Drivers;
+
+// Describes the operation performed when a "fast refresh" is performed
+// Source: Modified from GxEPD2 (GxEPD2_213_BN)
+static const uint8_t LUT_FAST[] = {
+ // 1 2 3
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B2B (Existing black pixels)
+ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B2W (New white pixels)
+ 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // W2B (New black pixels)
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // W2W (Existing white pixels)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VCOM
+
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // 1. Any pixels changing W2B or B2W. Two medium taps.
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2. All pixels. One short tap.
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3. Cooldown
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, //
+};
+
+// How strongly the pixels are pulled and pushed
+void DEPG0213BNS800::configVoltages()
+{
+ switch (updateType) {
+ case FAST:
+ // Reference: display datasheet, GxEPD1
+ sendCommand(0x03); // Gate voltage
+ sendData(0x17); // VGH: 20V
+
+ // Reference: display datasheet, GxEPD1
+ sendCommand(0x04); // Source voltage
+ sendData(0x41); // VSH1: 15V
+ sendData(0x00); // VSH2: NA
+ sendData(0x32); // VSL: -15V
+
+ // GxEPD1 sets this at -1.2V, but that seems to be drive the pixels very hard
+ sendCommand(0x2C); // VCOM voltage
+ sendData(0x08); // VCOM: -0.2V
+ break;
+
+ case FULL:
+ default:
+ // From OTP memory
+ break;
+ }
+}
+
+// Load settings about how the pixels are moved from old state to new state during a refresh
+// - manually specified,
+// - or with stored values from displays OTP memory
+void DEPG0213BNS800::configWaveform()
+{
+ switch (updateType) {
+ case FAST:
+ sendCommand(0x3C); // Border waveform:
+ sendData(0x80); // VSS
+
+ sendCommand(0x32); // Write LUT register from MCU:
+ sendData(LUT_FAST, sizeof(LUT_FAST)); // (describes operation for a FAST refresh)
+ break;
+
+ case FULL:
+ default:
+ // From OTP memory
+ break;
+ }
+}
+
+// Describes the sequence of events performed by the displays controller IC during a refresh
+// Includes "power up", "load settings from memory", "update the pixels", etc
+void DEPG0213BNS800::configUpdateSequence()
+{
+ switch (updateType) {
+ case FAST:
+ sendCommand(0x22); // Set "update sequence"
+ sendData(0xCF); // Differential, use manually loaded waveform
+ break;
+
+ case FULL:
+ default:
+ sendCommand(0x22); // Set "update sequence"
+ sendData(0xF7); // Non-differential, load waveform from OTP
+ 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 DEPG0213BNS800::detachFromUpdate()
+{
+ switch (updateType) {
+ case FAST:
+ return beginPolling(50, 500); // At least 500ms, then poll every 50ms
+ case FULL:
+ default:
+ return beginPolling(100, 3500); // At least 3500ms, then poll every 100ms
+ }
+}
+
+// For this display, we do not need to re-write the new image.
+// We're overriding SSD16XX::finalizeUpdate to make this small optimization.
+// The display does also work just fine with the generic SSD16XX method, though.
+void DEPG0213BNS800::finalizeUpdate()
+{
+ // Put a copy of the image into the "old memory".
+ // Used with differential refreshes (e.g. FAST update), to determine which px need to move, and which can remain in place
+ // We need to keep the "old memory" up to date, because don't know whether next refresh will be FULL or FAST etc.
+ if (updateType != FULL) {
+ // writeNewImage(); // Not required for this display
+ writeOldImage();
+ sendCommand(0x7F); // Terminate image write without update
+ wait();
+ }
+
+ // Enter deep-sleep to save a few µA
+ // Waking from this requires that display's reset pin is broken out
+ if (pin_rst != 0xFF)
+ deepSleep();
+}
+#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.h b/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.h
new file mode 100644
index 000000000..e1bb96450
--- /dev/null
+++ b/src/graphics/niche/Drivers/EInk/DEPG0213BNS800.h
@@ -0,0 +1,44 @@
+/*
+
+E-Ink display driver
+ - DEPG0213BNS800
+ - Manufacturer: DKE
+ - Size: 2.13 inch
+ - Resolution: 122px x 250px
+ - Flex connector marking: FPC-7528B
+
+ Note: this is from an older generation of DKE panels, which still used Solomon Systech controller ICs.
+ DKE's website suggests that the latest DEPG0213BN displays may use Fitipower controllers instead.
+*/
+
+#pragma once
+
+#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
+
+#include "configuration.h"
+
+#include "./SSD16XX.h"
+
+namespace NicheGraphics::Drivers
+{
+class DEPG0213BNS800 : 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:
+ DEPG0213BNS800() : SSD16XX(width, height, supported, 1) {} // Note: left edge of this display is offset by 1 byte
+
+ protected:
+ void configVoltages() override;
+ void configWaveform() override;
+ void configUpdateSequence() override;
+ void detachFromUpdate() override;
+ void finalizeUpdate() override; // Only overriden for a slight optimization
+};
+
+} // namespace NicheGraphics::Drivers
+#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/DEPG0290BNS800.cpp b/src/graphics/niche/Drivers/EInk/DEPG0290BNS800.cpp
index 5f3a05670..15134d5ad 100644
--- a/src/graphics/niche/Drivers/EInk/DEPG0290BNS800.cpp
+++ b/src/graphics/niche/Drivers/EInk/DEPG0290BNS800.cpp
@@ -116,5 +116,10 @@ void DEPG0290BNS800::finalizeUpdate()
sendCommand(0x7F); // Terminate image write without update
wait();
}
+
+ // Enter deep-sleep to save a few µA
+ // Waking from this requires that display's reset pin is broken out
+ if (pin_rst != 0xFF)
+ deepSleep();
}
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/SSD16XX.cpp b/src/graphics/niche/Drivers/EInk/SSD16XX.cpp
index 5a5397dbd..a2357a80b 100644
--- a/src/graphics/niche/Drivers/EInk/SSD16XX.cpp
+++ b/src/graphics/niche/Drivers/EInk/SSD16XX.cpp
@@ -242,5 +242,18 @@ void SSD16XX::finalizeUpdate()
sendCommand(0x7F); // Terminate image write without update
wait();
}
+
+ // Enter deep-sleep to save a few µA
+ // Waking from this requires that display's reset pin is broken out
+ if (pin_rst != 0xFF)
+ deepSleep();
+}
+
+// Enter a lower-power state
+// May only save a few µA..
+void SSD16XX::deepSleep()
+{
+ sendCommand(0x10); // Enter deep sleep
+ sendData(0x01); // Mode 1: preserve image RAM
}
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
\ No newline at end of file
diff --git a/src/graphics/niche/Drivers/EInk/SSD16XX.h b/src/graphics/niche/Drivers/EInk/SSD16XX.h
index 799a378c0..3f92818ce 100644
--- a/src/graphics/niche/Drivers/EInk/SSD16XX.h
+++ b/src/graphics/niche/Drivers/EInk/SSD16XX.h
@@ -44,6 +44,7 @@ class SSD16XX : public EInk
virtual void detachFromUpdate();
virtual bool isUpdateDone() override;
virtual void finalizeUpdate() override;
+ virtual void deepSleep();
protected:
uint8_t bufferOffsetX = 0; // In bytes. Panel x=0 does not always align with controller x=0. Quirky internal wiring?
diff --git a/src/graphics/niche/Inputs/TwoButton.cpp b/src/graphics/niche/Inputs/TwoButton.cpp
index b270d56cf..1e91d9080 100644
--- a/src/graphics/niche/Inputs/TwoButton.cpp
+++ b/src/graphics/niche/Inputs/TwoButton.cpp
@@ -98,9 +98,8 @@ void TwoButton::setWiring(uint8_t whichButton, uint8_t pin, bool internalPullup)
assert(whichButton < 2);
buttons[whichButton].pin = pin;
buttons[whichButton].activeLogic = LOW; // Unimplemented
- buttons[whichButton].mode = internalPullup ? INPUT_PULLUP : INPUT;
- pinMode(buttons[whichButton].pin, buttons[whichButton].mode);
+ pinMode(buttons[whichButton].pin, internalPullup ? INPUT_PULLUP : INPUT);
}
void TwoButton::setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs)
@@ -299,7 +298,9 @@ int TwoButton::afterLightSleep(esp_sleep_wakeup_cause_t cause)
// Manually trigger the button-down ISR
// - during light sleep, our ISR is disabled
// - if light sleep ends by button press, pretend our own ISR caught it
- if (cause == ESP_SLEEP_WAKEUP_GPIO)
+ // - need to manually confirm by reading pin ourselves, to avoid occasional false positives
+ // (false positive only when using internal pullup resistors?)
+ if (cause == ESP_SLEEP_WAKEUP_GPIO && digitalRead(buttons[0].pin) == buttons[0].activeLogic)
isrPrimary();
return 0; // Indicates success
diff --git a/src/graphics/niche/Inputs/TwoButton.h b/src/graphics/niche/Inputs/TwoButton.h
index f1e18dd89..ae66adf96 100644
--- a/src/graphics/niche/Inputs/TwoButton.h
+++ b/src/graphics/niche/Inputs/TwoButton.h
@@ -35,7 +35,7 @@ class TwoButton : protected concurrency::OSThread
static TwoButton *getInstance(); // Create or get the singleton instance
void start(); // Start handling button input
void stop(); // Stop handling button input (disconnect ISRs for sleep)
- void setWiring(uint8_t whichButton, uint8_t pin, bool internalPulldown = false);
+ void setWiring(uint8_t whichButton, uint8_t pin, bool internalPullup = false);
void setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs);
void setHandlerDown(uint8_t whichButton, Callback onDown);
void setHandlerUp(uint8_t whichButton, Callback onUp);
@@ -65,7 +65,6 @@ class TwoButton : protected concurrency::OSThread
// Per-button config
uint8_t pin = 0xFF; // 0xFF: unset
bool activeLogic = LOW; // Active LOW by default. Currently unimplemented.
- uint8_t mode = INPUT; // Whether to use internal pull up / pull down resistors
uint32_t debounceLength = 50; // Minimum length for shortpress, in ms
uint32_t longpressLength = 500; // How long after button down to fire longpress, in ms
volatile State state = State::REST; // Internal state
diff --git a/src/main.cpp b/src/main.cpp
index fd65830ef..bfbd73a43 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -212,6 +212,64 @@ const char *getDeviceName()
return name;
}
+#if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
+static int32_t ledBlinkCount = 0;
+
+static int32_t elecrowLedBlinker()
+{
+ // are we in alert buzzer mode?
+#if HAS_BUTTON
+ if (buttonThread->isBuzzing()) {
+ // blink LED three times for 3 seconds, then 3 times for a second, with one second pause
+ if (ledBlinkCount % 2) { // odd means LED OFF
+ ledBlink.set(false);
+ ledBlinkCount++;
+ if (ledBlinkCount >= 12)
+ ledBlinkCount = 0;
+ noTone(PIN_BUZZER);
+ return 1000;
+ } else {
+ if (ledBlinkCount < 6) {
+ ledBlink.set(true);
+ tone(PIN_BUZZER, 4000, 3000);
+ ledBlinkCount++;
+ return 3000;
+ } else {
+ ledBlink.set(true);
+ tone(PIN_BUZZER, 4000, 1000);
+ ledBlinkCount++;
+ return 1000;
+ }
+ }
+ } else {
+#endif
+ ledBlinkCount = 0;
+ if (config.device.led_heartbeat_disabled)
+ return 1000;
+
+ static bool ledOn;
+ // remain on when fully charged or discharging above 10%
+ if ((powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() >= 100) ||
+ (!powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() >= 10)) {
+ ledOn = true;
+ } else {
+ ledOn ^= 1;
+ }
+ ledBlink.set(ledOn);
+ // when charging, blink 0.5Hz square wave rate to indicate that
+ if (powerStatus->getIsCharging()) {
+ return 500;
+ }
+ // Blink rapidly when almost empty or if battery is not connected
+ if ((!powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() < 10) || !powerStatus->getHasBattery()) {
+ return 250;
+ }
+#if HAS_BUTTON
+ }
+#endif
+ return 1000;
+}
+#else
static int32_t ledBlinker()
{
// Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if
@@ -227,6 +285,7 @@ static int32_t ledBlinker()
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
}
+#endif
uint32_t timeLastPowered = 0;
@@ -263,11 +322,6 @@ void printInfo()
void setup()
{
-#ifdef POWER_CHRG
- pinMode(POWER_CHRG, OUTPUT);
- digitalWrite(POWER_CHRG, HIGH);
-#endif
-
#if defined(PIN_POWER_EN)
pinMode(PIN_POWER_EN, OUTPUT);
digitalWrite(PIN_POWER_EN, HIGH);
@@ -278,11 +332,6 @@ void setup()
digitalWrite(LED_POWER, HIGH);
#endif
-#ifdef POWER_LED
- pinMode(POWER_LED, OUTPUT);
- digitalWrite(POWER_LED, HIGH);
-#endif
-
#ifdef USER_LED
pinMode(USER_LED, OUTPUT);
digitalWrite(USER_LED, LOW);
@@ -414,7 +463,12 @@ void setup()
OSThread::setup();
+#if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
+ // The ThinkNodes have their own blink logic
+ ledPeriodic = new Periodic("Blink", elecrowLedBlinker);
+#else
ledPeriodic = new Periodic("Blink", ledBlinker);
+#endif
fsInit();
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 9bb63652a..c89abbe74 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -743,6 +743,15 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.external_notification.output_ms = 100;
moduleConfig.external_notification.active = true;
#endif
+#ifdef ELECROW_ThinkNode_M1
+ // Default to Elecrow USER_LED (blue)
+ moduleConfig.external_notification.enabled = true;
+ moduleConfig.external_notification.output = USER_LED;
+ moduleConfig.external_notification.active = true;
+ moduleConfig.external_notification.alert_message = true;
+ moduleConfig.external_notification.output_ms = 1000;
+ moduleConfig.external_notification.nag_timeout = 60;
+#endif
#ifdef BUTTON_SECONDARY_CANNEDMESSAGES
// Use a board's second built-in button as input source for canned messages
moduleConfig.canned_message.enabled = true;
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index b8b7ee610..2cc3007a2 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -283,11 +283,6 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
abortSendAndNak(encodeResult, p);
return encodeResult; // FIXME - this isn't a valid ErrorCode
}
-#if HAS_UDP_MULTICAST
- if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
- udpThread->onSend(const_cast(p));
- }
-#endif
#if !MESHTASTIC_EXCLUDE_MQTT
// Only publish to MQTT if we're the original transmitter of the packet
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
@@ -297,6 +292,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
packetPool.release(p_decoded);
}
+#if HAS_UDP_MULTICAST
+ if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
+ udpThread->onSend(const_cast(p));
+ }
+#endif
+
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
return iface->send(p);
}
diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h
index 848f8df86..edcd7b41c 100644
--- a/src/mesh/generated/meshtastic/config.pb.h
+++ b/src/mesh/generated/meshtastic/config.pb.h
@@ -180,14 +180,16 @@ typedef enum _meshtastic_Config_DisplayConfig_DisplayUnits {
/* Override OLED outo detect with this if it fails. */
typedef enum _meshtastic_Config_DisplayConfig_OledType {
- /* Default / Auto */
+ /* Default / Autodetect */
meshtastic_Config_DisplayConfig_OledType_OLED_AUTO = 0,
- /* Default / Auto */
+ /* Default / Autodetect */
meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306 = 1,
- /* Default / Auto */
+ /* Default / Autodetect */
meshtastic_Config_DisplayConfig_OledType_OLED_SH1106 = 2,
/* Can not be auto detected but set by proto. Used for 128x128 screens */
- meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3
+ meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3,
+ /* Can not be auto detected but set by proto. Used for 128x64 screens */
+ meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64 = 4
} meshtastic_Config_DisplayConfig_OledType;
typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
@@ -639,8 +641,8 @@ extern "C" {
#define _meshtastic_Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayUnits)(meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
#define _meshtastic_Config_DisplayConfig_OledType_MIN meshtastic_Config_DisplayConfig_OledType_OLED_AUTO
-#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107
-#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107+1))
+#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64
+#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64+1))
#define _meshtastic_Config_DisplayConfig_DisplayMode_MIN meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h
index 69cdd33fe..dcc511ea6 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.h
+++ b/src/mesh/generated/meshtastic/telemetry.pb.h
@@ -242,7 +242,7 @@ typedef struct _meshtastic_AirQualityMetrics {
/* 10.0um Particle Count */
bool has_particles_100um;
uint32_t particles_100um;
- /* 10.0um Particle Count */
+ /* CO2 concentration in ppm */
bool has_co2;
uint32_t co2;
} meshtastic_AirQualityMetrics;
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index ab1e5c922..3c4faac3e 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -109,9 +109,8 @@ void esp32Setup()
randomSeed(seed);
*/
-#ifdef POWER_FULL
- pinMode(POWER_FULL, INPUT);
- pinMode(7, INPUT);
+#ifdef ADC_V
+ pinMode(ADC_V, INPUT);
#endif
LOG_DEBUG("Total heap: %d", ESP.getHeapSize());
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index 53971e95a..9accd2a02 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -235,10 +235,6 @@ void nrf52InitSemiHosting()
void nrf52Setup()
{
-#ifdef USB_CHECK
- pinMode(USB_CHECK, INPUT);
-#endif
-
#ifdef ADC_V
pinMode(ADC_V, INPUT);
#endif
@@ -288,7 +284,7 @@ void cpuDeepSleep(uint32_t msecToWake)
#endif
// This may cause crashes as debug messages continue to flow.
Serial.end();
-#ifdef PIN_SERIAL_RX1
+#ifdef PIN_SERIAL1_RX
Serial1.end();
#endif
setBluetoothEnable(false);
diff --git a/src/power.h b/src/power.h
index 97944fef7..e9c0deb7c 100644
--- a/src/power.h
+++ b/src/power.h
@@ -84,11 +84,6 @@ class Power : private concurrency::OSThread
void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
const uint16_t OCV[11] = {OCV_ARRAY};
-#if defined(ELECROW_ThinkNode_M1) || defined(POWER_CFG)
- uint8_t low_voltage_counter_led3;
- int power_num = 0;
-#endif
-
protected:
meshtastic::PowerStatus *statusHandler;
diff --git a/variants/ELECROW-ThinkNode-M1/variant.h b/variants/ELECROW-ThinkNode-M1/variant.h
index fc2fddbdf..2e91e378d 100644
--- a/variants/ELECROW-ThinkNode-M1/variant.h
+++ b/variants/ELECROW-ThinkNode-M1/variant.h
@@ -41,16 +41,15 @@ extern "C" {
#define NUM_ANALOG_INPUTS (1)
#define NUM_ANALOG_OUTPUTS (0)
-#define PIN_LED1 -1
#define PIN_LED2 -1
#define PIN_LED3 -1
// LED
-#define POWER_LED (32 + 6) // red
+#define PIN_LED1 (32 + 6) // red
#define LED_POWER (32 + 4)
#define USER_LED (0 + 13) // green
// USB_CHECK
-#define USB_CHECK (32 + 3)
+#define EXT_PWR_DETECT (32 + 3)
#define ADC_V (0 + 8)
#define LED_RED PIN_LED3
@@ -59,7 +58,7 @@ extern "C" {
#define LED_BUILTIN LED_BLUE
#define LED_CONN PIN_GREEN
#define LED_STATE_ON 0 // State when LED is lit // LED灯亮时的状态
-#define M1_buzzer (0 + 6)
+#define PIN_BUZZER (0 + 6)
/*
* Buttons
*/
@@ -82,6 +81,7 @@ extern "C" {
static const uint8_t A0 = PIN_A0;
#define ADC_RESOLUTION 14
+#define BATTERY_SENSE_SAMPLES 30
#define PIN_NFC1 (9)
#define PIN_NFC2 (10)
@@ -159,7 +159,7 @@ External serial flash WP25R1635FZUIL0
#define GPS_THREAD_INTERVAL 50
-#define PIN_GPS_PPS (32 + 1) // GPS开关判断
+#define PIN_GPS_SWITCH (32 + 1) // GPS开关判断
#define PIN_SERIAL1_RX GPS_TX_PIN
#define PIN_SERIAL1_TX GPS_RX_PIN
diff --git a/variants/ELECROW-ThinkNode-M2/variant.h b/variants/ELECROW-ThinkNode-M2/variant.h
index 801d5606f..a6bb40f1a 100644
--- a/variants/ELECROW-ThinkNode-M2/variant.h
+++ b/variants/ELECROW-ThinkNode-M2/variant.h
@@ -1,14 +1,13 @@
// Status
-#define LED_PIN_POWER 1
-#define BIAS_T_ENABLE LED_PIN_POWER
-#define BIAS_T_VALUE HIGH
+#define LED_PIN 1
#define PIN_BUTTON1 47 // 功能键
#define PIN_BUTTON2 4 // 电源键
-#define POWER_CFG
-#define POWER_CHRG 6
-#define POWER_FULL 42
+#define LED_POWER 6
+#define ADC_V 42
+// USB_CHECK
+#define EXT_PWR_DETECT 7
#define PIN_BUZZER 5
diff --git a/variants/crowpanel-esp32s3-5-epaper/platformio.ini b/variants/crowpanel-esp32s3-5-epaper/platformio.ini
index f1257a979..ebf013f64 100644
--- a/variants/crowpanel-esp32s3-5-epaper/platformio.ini
+++ b/variants/crowpanel-esp32s3-5-epaper/platformio.ini
@@ -11,7 +11,7 @@ board = esp32-s3-devkitc-1
board_level = extra
upload_protocol = esptool
build_flags =
- ${esp32_base.build_flags} -D CROWPANEL_ESP32S3_5_EPAPER -I variants/crowpanel-esp32s3-5-epaper
+ ${esp32s3_base.build_flags} -D CROWPANEL_ESP32S3_5_EPAPER -I variants/crowpanel-esp32s3-5-epaper
-D PRIVATE_HW
-DBOARD_HAS_PSRAM
-DGPS_POWER_TOGGLE
@@ -39,7 +39,7 @@ board = esp32-s3-devkitc-1
board_level = extra
upload_protocol = esptool
build_flags =
- ${esp32_base.build_flags} -D CROWPANEL_ESP32S3_4_EPAPER -I variants/crowpanel-esp32s3-5-epaper
+ ${esp32s3_base.build_flags} -D CROWPANEL_ESP32S3_4_EPAPER -I variants/crowpanel-esp32s3-5-epaper
-D PRIVATE_HW
-DBOARD_HAS_PSRAM
-DGPS_POWER_TOGGLE
@@ -67,7 +67,7 @@ board = esp32-s3-devkitc-1
board_level = extra
upload_protocol = esptool
build_flags =
- ${esp32_base.build_flags} -D CROWPANEL_ESP32S3_2_EPAPER -I variants/crowpanel-esp32s3-5-epaper
+ ${esp32s3_base.build_flags} -D CROWPANEL_ESP32S3_2_EPAPER -I variants/crowpanel-esp32s3-5-epaper
-D PRIVATE_HW
-DBOARD_HAS_PSRAM
-DGPS_POWER_TOGGLE
diff --git a/variants/diy/v1/variant.h b/variants/diy/v1/variant.h
index 4802dbe89..8a2df3f2b 100644
--- a/variants/diy/v1/variant.h
+++ b/variants/diy/v1/variant.h
@@ -53,4 +53,5 @@
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
// (which is the default for the sx1262interface code)
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define TCXO_OPTIONAL // make it so that the firmware can try both TCXO and XTAL
#endif
diff --git a/variants/diy/v1_1/variant.h b/variants/diy/v1_1/variant.h
index 8a006d0d2..1c8110301 100644
--- a/variants/diy/v1_1/variant.h
+++ b/variants/diy/v1_1/variant.h
@@ -54,4 +54,5 @@
// Internally the TTGO module hooks the SX126x-DIO2 in to control the TX/RX switch
// (which is the default for the sx1262interface code)
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define TCXO_OPTIONAL // make it so that the firmware can try both TCXO and XTAL
#endif
diff --git a/variants/t-echo/nicheGraphics.h b/variants/t-echo/nicheGraphics.h
index f5dde6b19..5862dcdfb 100644
--- a/variants/t-echo/nicheGraphics.h
+++ b/variants/t-echo/nicheGraphics.h
@@ -112,7 +112,7 @@ void setupNicheGraphics()
// Setup the capacitive touch button
// - short: momentary backlight
// - long: latch backlight on
- buttons->setWiring(TOUCH_BUTTON, PIN_BUTTON_TOUCH, LOW);
+ buttons->setWiring(TOUCH_BUTTON, PIN_BUTTON_TOUCH);
buttons->setTiming(TOUCH_BUTTON, 50, 5000); // 5 seconds before latch - limited by T-Echo's capacitive touch IC
buttons->setHandlerDown(TOUCH_BUTTON, [backlight]() {
backlight->peek();
diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini
index 85e66c2dd..9049836a3 100644
--- a/variants/tbeam/platformio.ini
+++ b/variants/tbeam/platformio.ini
@@ -8,4 +8,6 @@ lib_deps =
build_flags =
${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam
-DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely.
+ -DBOARD_HAS_PSRAM
+ -mfix-esp32-psram-cache-issue
upload_speed = 921600
\ No newline at end of file
diff --git a/variants/tlora_t3s3_epaper/nicheGraphics.h b/variants/tlora_t3s3_epaper/nicheGraphics.h
new file mode 100644
index 000000000..55bb9a203
--- /dev/null
+++ b/variants/tlora_t3s3_epaper/nicheGraphics.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "configuration.h"
+
+#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
+
+// InkHUD-specific components
+// ---------------------------
+#include "graphics/niche/InkHUD/InkHUD.h"
+
+// Applets
+#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h"
+#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h"
+#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h"
+#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h"
+#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h"
+#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h"
+
+// #include "graphics/niche/InkHUD/Applets/Examples/BasicExample/BasicExampleApplet.h"
+// #include "graphics/niche/InkHUD/Applets/Examples/NewMsgExample/NewMsgExampleApplet.h"
+
+// Shared NicheGraphics components
+// --------------------------------
+#include "graphics/niche/Drivers/EInk/DEPG0213BNS800.h"
+#include "graphics/niche/Inputs/TwoButton.h"
+
+#include "graphics/niche/Fonts/FreeSans6pt7b.h"
+#include "graphics/niche/Fonts/FreeSans6pt8bCyrillic.h"
+#include
+
+void setupNicheGraphics()
+{
+ using namespace NicheGraphics;
+
+ // SPI
+ // -----------------------------
+
+ // Display is connected to HSPI
+ SPIClass *hspi = new SPIClass(HSPI);
+ hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS);
+
+ // E-Ink Driver
+ // -----------------------------
+
+ // Use E-Ink driver
+ Drivers::EInk *driver = new Drivers::DEPG0213BNS800;
+ driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
+
+ // InkHUD
+ // ----------------------------
+
+ InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance();
+
+ // Set the driver
+ inkhud->setDriver(driver);
+
+ // Set how many FAST updates per FULL update
+ // Set how unhealthy additional FAST updates beyond this number are
+ inkhud->setDisplayResilience(15, 1.5);
+
+ // Prepare fonts
+ InkHUD::Applet::fontLarge = InkHUD::AppletFont(FreeSans9pt7b);
+ InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt7b);
+ /*
+ // Font localization demo: Cyrillic
+ InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt8bCyrillic);
+ InkHUD::Applet::fontSmall.addSubstitutionsWin1251();
+ */
+
+ // Customize default settings
+ inkhud->persistence->settings.userTiles.maxCount = 2; // How many tiles can the display handle?
+ inkhud->persistence->settings.rotation = 3; // 270 degrees clockwise
+ inkhud->persistence->settings.userTiles.count = 1; // One tile only by default, keep things simple for new users
+
+ // Pick applets
+ inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); // Activated, autoshown
+ inkhud->addApplet("DMs", new InkHUD::DMApplet); // Inactive
+ inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); // Inactive
+ inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); // Inactive
+ inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); // Activated
+ inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // Inactive
+ inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, not autoshown, default on tile 0
+ // inkhud->addApplet("Basic", new InkHUD::BasicExampleApplet);
+ // inkhud->addApplet("NewMsg", new InkHUD::NewMsgExampleApplet);
+
+ // Start running InkHUD
+ inkhud->begin();
+
+ // Buttons
+ // --------------------------
+
+ Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); // Shared NicheGraphics component
+
+ // Setup the main user button
+ buttons->setWiring(0, Inputs::TwoButton::getUserButtonPin(), true);
+ buttons->setHandlerShortPress(0, []() { InkHUD::InkHUD::getInstance()->shortpress(); });
+ buttons->setHandlerLongPress(0, []() { InkHUD::InkHUD::getInstance()->longpress(); });
+
+ buttons->start();
+}
+
+#endif
\ No newline at end of file
diff --git a/variants/tlora_t3s3_epaper/platformio.ini b/variants/tlora_t3s3_epaper/platformio.ini
index 87351e586..957c37b95 100644
--- a/variants/tlora_t3s3_epaper/platformio.ini
+++ b/variants/tlora_t3s3_epaper/platformio.ini
@@ -7,6 +7,7 @@ upload_protocol = esptool
build_flags =
${esp32_base.build_flags} -D TLORA_T3S3_EPAPER -I variants/tlora_t3s3_epaper
-DGPS_POWER_TOGGLE
+ -DUSE_EINK
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
@@ -16,3 +17,21 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip
+
+[env:tlora-t3s3-epaper-inkhud]
+extends = esp32s3_base, inkhud
+board = tlora-t3s3-v1
+board_check = true
+upload_protocol = esptool
+build_src_filter =
+ ${esp32_base.build_src_filter}
+ ${inkhud.build_src_filter}
+build_flags =
+ ${esp32s3_base.build_flags}
+ ${inkhud.build_flags}
+ -I variants/tlora_t3s3_epaper
+ -D TLORA_T3S3_EPAPER
+ -D MAX_THREADS=40 ; Required if used with WiFi
+lib_deps =
+ ${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX
+ ${esp32s3_base.lib_deps}
\ No newline at end of file
diff --git a/variants/tlora_t3s3_epaper/variant.h b/variants/tlora_t3s3_epaper/variant.h
index 732869b20..1ed505420 100644
--- a/variants/tlora_t3s3_epaper/variant.h
+++ b/variants/tlora_t3s3_epaper/variant.h
@@ -2,7 +2,6 @@
#define SDCARD_USE_SPI1
// Display (E-Ink)
-#define USE_EINK
#define PIN_EINK_CS 15
#define PIN_EINK_BUSY 48
#define PIN_EINK_DC 16