diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml
index f6c1fd80c..80f5c6855 100644
--- a/.github/actions/setup-base/action.yml
+++ b/.github/actions/setup-base/action.yml
@@ -5,7 +5,7 @@ runs:
using: composite
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
diff --git a/.github/workflows/build_debian_src.yml b/.github/workflows/build_debian_src.yml
index d36e7fea1..d7d26f0e8 100644
--- a/.github/workflows/build_debian_src.yml
+++ b/.github/workflows/build_debian_src.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml
index 57c1e72c7..9ac84c23e 100644
--- a/.github/workflows/build_firmware.yml
+++ b/.github/workflows/build_firmware.yml
@@ -22,7 +22,7 @@ jobs:
outputs:
artifact-id: ${{ steps.upload.outputs.artifact-id }}
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
diff --git a/.github/workflows/build_one_arch.yml b/.github/workflows/build_one_arch.yml
index 6d5462c93..5673f8cb6 100644
--- a/.github/workflows/build_one_arch.yml
+++ b/.github/workflows/build_one_arch.yml
@@ -26,7 +26,7 @@ jobs:
setup:
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
@@ -44,7 +44,7 @@ jobs:
version:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -108,7 +108,7 @@ jobs:
needs: [version, build]
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml
index 46362a629..343e5be64 100644
--- a/.github/workflows/build_one_target.yml
+++ b/.github/workflows/build_one_target.yml
@@ -45,7 +45,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
@@ -66,7 +66,7 @@ jobs:
if: ${{ inputs.target != '' }}
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -114,7 +114,7 @@ jobs:
needs: [version, build]
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml
index 26a9cff18..8d19af894 100644
--- a/.github/workflows/docker_build.yml
+++ b/.github/workflows/docker_build.yml
@@ -47,7 +47,7 @@ jobs:
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
diff --git a/.github/workflows/docker_manifest.yml b/.github/workflows/docker_manifest.yml
index 20b9ceee6..396ddb68e 100644
--- a/.github/workflows/docker_manifest.yml
+++ b/.github/workflows/docker_manifest.yml
@@ -83,7 +83,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
diff --git a/.github/workflows/hook_copr.yml b/.github/workflows/hook_copr.yml
index 2204cc02c..eb4ebc57b 100644
--- a/.github/workflows/hook_copr.yml
+++ b/.github/workflows/hook_copr.yml
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{ github.ref }}
diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index 7ea033d55..38373a2fc 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -35,7 +35,7 @@ jobs:
- check
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
@@ -59,7 +59,7 @@ jobs:
version:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -81,7 +81,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Build base
id: base
uses: ./.github/actions/setup-base
@@ -163,7 +163,7 @@ jobs:
needs: [version, build]
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -242,7 +242,7 @@ jobs:
- package-pio-deps-native-tft
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
@@ -311,7 +311,7 @@ jobs:
needs: [release-artifacts, version]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
@@ -366,7 +366,7 @@ jobs:
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
diff --git a/.github/workflows/merge_queue.yml b/.github/workflows/merge_queue.yml
index 6d69258c9..154b230c7 100644
--- a/.github/workflows/merge_queue.yml
+++ b/.github/workflows/merge_queue.yml
@@ -17,7 +17,7 @@ jobs:
- check
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
@@ -40,7 +40,7 @@ jobs:
version:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
@@ -62,7 +62,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Build base
id: base
uses: ./.github/actions/setup-base
@@ -142,7 +142,7 @@ jobs:
needs: [version, build]
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -221,7 +221,7 @@ jobs:
- package-pio-deps-native-tft
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
@@ -290,7 +290,7 @@ jobs:
needs: [release-artifacts, version]
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
@@ -345,7 +345,7 @@ jobs:
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index f26073ec4..045e94895 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Trunk Check
uses: trunk-io/trunk-action@v1
@@ -31,7 +31,7 @@ jobs:
pull-requests: write # For trunk to create PRs
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Trunk Upgrade
uses: trunk-io/trunk-action/upgrade@v1
diff --git a/.github/workflows/package_obs.yml b/.github/workflows/package_obs.yml
index b8a829d9a..2b202ed95 100644
--- a/.github/workflows/package_obs.yml
+++ b/.github/workflows/package_obs.yml
@@ -34,7 +34,7 @@ jobs:
needs: build-debian-src
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
diff --git a/.github/workflows/package_pio_deps.yml b/.github/workflows/package_pio_deps.yml
index c52dfe348..cb10a79f3 100644
--- a/.github/workflows/package_pio_deps.yml
+++ b/.github/workflows/package_pio_deps.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
diff --git a/.github/workflows/package_ppa.yml b/.github/workflows/package_ppa.yml
index 2d6c257e6..2e3278041 100644
--- a/.github/workflows/package_ppa.yml
+++ b/.github/workflows/package_ppa.yml
@@ -32,7 +32,7 @@ jobs:
needs: build-debian-src
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml
index c3a964e04..048186538 100644
--- a/.github/workflows/pr_tests.yml
+++ b/.github/workflows/pr_tests.yml
@@ -40,7 +40,7 @@ jobs:
checks: write
pull-requests: write
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
submodules: recursive
diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml
index 4e5a48dfe..f21b13ee1 100644
--- a/.github/workflows/release_channels.yml
+++ b/.github/workflows/release_channels.yml
@@ -60,7 +60,7 @@ jobs:
shell: bash
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
# Always use master branch for version bumps
ref: master
diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml
index dfb828bf6..d044f9038 100644
--- a/.github/workflows/sec_sast_semgrep_cron.yml
+++ b/.github/workflows/sec_sast_semgrep_cron.yml
@@ -21,7 +21,7 @@ jobs:
steps:
# step 1
- name: clone application source code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
# step 2
- name: full scan
diff --git a/.github/workflows/sec_sast_semgrep_pull.yml b/.github/workflows/sec_sast_semgrep_pull.yml
index e93b2ae8b..e9b4108a1 100644
--- a/.github/workflows/sec_sast_semgrep_pull.yml
+++ b/.github/workflows/sec_sast_semgrep_pull.yml
@@ -13,7 +13,7 @@ jobs:
steps:
# step 1
- name: clone application source code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
fetch-depth: 0
diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml
index 591d52bd0..a2328022e 100644
--- a/.github/workflows/test_native.yml
+++ b/.github/workflows/test_native.yml
@@ -14,7 +14,7 @@ jobs:
name: Native Simulator Tests
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -70,7 +70,7 @@ jobs:
name: Native PlatformIO Tests
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -127,7 +127,7 @@ jobs:
- platformio-tests
if: always()
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 1ec435512..4a97853e2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: test-runner
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
# - uses: actions/setup-python@v5
# with:
diff --git a/.github/workflows/trunk_annotate_pr.yml b/.github/workflows/trunk_annotate_pr.yml
index 23dcf8d09..59ab25c28 100644
--- a/.github/workflows/trunk_annotate_pr.yml
+++ b/.github/workflows/trunk_annotate_pr.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Trunk Check
uses: trunk-io/trunk-action@v1
diff --git a/.github/workflows/trunk_check.yml b/.github/workflows/trunk_check.yml
index 41731d491..874374fe0 100644
--- a/.github/workflows/trunk_check.yml
+++ b/.github/workflows/trunk_check.yml
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Trunk Check
uses: trunk-io/trunk-action@v1
diff --git a/.github/workflows/trunk_format_pr.yml b/.github/workflows/trunk_format_pr.yml
index 51082fc5f..8fa0cc1eb 100644
--- a/.github/workflows/trunk_format_pr.yml
+++ b/.github/workflows/trunk_format_pr.yml
@@ -15,7 +15,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml
index c06e06b0a..af0557fda 100644
--- a/.github/workflows/update_protobufs.yml
+++ b/.github/workflows/update_protobufs.yml
@@ -11,7 +11,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
submodules: true
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index 1fd8790f2..ccb426745 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -4,31 +4,31 @@ cli:
plugins:
sources:
- id: trunk
- ref: v1.7.3
+ ref: v1.7.4
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- - checkov@3.2.492
- - renovate@42.5.4
+ - checkov@3.2.495
+ - renovate@42.24.1
- prettier@3.6.2
- - trufflehog@3.90.13
+ - trufflehog@3.91.1
- yamllint@1.37.1
- - bandit@1.8.6
+ - bandit@1.9.2
- trivy@0.67.2
- taplo@0.10.0
- - ruff@0.14.4
+ - ruff@0.14.6
- isort@7.0.0
- - markdownlint@0.45.0
+ - markdownlint@0.46.0
- oxipng@9.1.5
- svgo@4.0.0
- - actionlint@1.7.8
+ - actionlint@1.7.9
- flake8@7.3.0
- hadolint@2.14.0
- shfmt@3.6.0
- shellcheck@0.11.0
- black@25.11.0
- git-diff-check
- - gitleaks@8.29.0
+ - gitleaks@8.30.0
- clang-format@16.0.3
ignore:
- linters: [ALL]
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 36effe017..e60d47ce7 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -7,7 +7,7 @@ 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
+ platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino#c770c8a16a351b55b86e347a3d9d7b74ad0bbf39
; Don't renovate toolchain-gccarmnoneeabi
platformio/toolchain-gccarmnoneeabi@~1.90301.0
diff --git a/arch/nrf52/nrf52840.ini b/arch/nrf52/nrf52840.ini
index 5e846b3b7..e13443152 100644
--- a/arch/nrf52/nrf52840.ini
+++ b/arch/nrf52/nrf52840.ini
@@ -8,7 +8,7 @@ lib_deps =
${environmental_base.lib_deps}
${environmental_extra.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/5f838d2709461a2c981f642917aa50254a25c14c.zip
+ https://github.com/Kongduino/Adafruit_nRFCrypto/archive/8cde7189b5ead9dcd49f72601b43b969c0bbc06e.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/stm32/stm32.ini b/arch/stm32/stm32.ini
index 7732533c9..1a9fd10ce 100644
--- a/arch/stm32/stm32.ini
+++ b/arch/stm32/stm32.ini
@@ -2,7 +2,7 @@
extends = arduino_base
platform =
# renovate: datasource=custom.pio depName=platformio/ststm32 packageName=platformio/platform/ststm32
- platformio/ststm32@19.3.0
+ platformio/ststm32@19.4.0
platform_packages =
# TODO renovate
platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
diff --git a/boards/ThinkNode-M3.json b/boards/ThinkNode-M3.json
new file mode 100644
index 000000000..ff21e046a
--- /dev/null
+++ b/boards/ThinkNode-M3.json
@@ -0,0 +1,53 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x4405"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"]
+ ],
+ "usb_product": "elecrow_eink",
+ "mcu": "nrf52840",
+ "variant": "ELECROW-ThinkNode-M3",
+ "variants_dir": "variants",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "onboard_tools": ["jlink"],
+ "svd_path": "nrf52840.svd",
+ "openocd_target": "nrf52840-mdk-rs"
+ },
+ "frameworks": ["arduino"],
+ "name": "elecrow nrf",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ },
+ "url": "",
+ "vendor": "ELECROW"
+}
diff --git a/boards/ThinkNode-M6.json b/boards/ThinkNode-M6.json
new file mode 100644
index 000000000..9fe324ec2
--- /dev/null
+++ b/boards/ThinkNode-M6.json
@@ -0,0 +1,53 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_NRF52840_ELECROW_M6 -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x4405"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"]
+ ],
+ "usb_product": "elecrow_thinknode_m6",
+ "mcu": "nrf52840",
+ "variant": "ELECROW-ThinkNode-M6",
+ "variants_dir": "variants",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "onboard_tools": ["jlink"],
+ "svd_path": "nrf52840.svd",
+ "openocd_target": "nrf52840-mdk-rs"
+ },
+ "frameworks": ["arduino"],
+ "name": "ELECROW ThinkNode M6",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ },
+ "url": "https://www.elecrow.com/thinknode-m6-outdoor-solar-power-for-lora-powered-by-nrf52840-supports-gps.html",
+ "vendor": "ELECROW"
+}
diff --git a/boards/muzi-base.json b/boards/muzi-base.json
new file mode 100644
index 000000000..5f65c0dc8
--- /dev/null
+++ b/boards/muzi-base.json
@@ -0,0 +1,56 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_NRF52840_MUZI_BASE -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [["0x239A", "0xcafe"]],
+ "mcu": "nrf52840",
+ "variant": "muzi-base",
+ "variants_dir": "variants",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "onboard_tools": ["jlink"],
+ "svd_path": "nrf52840.svd",
+ "openocd_target": "nrf52840-mdk-rs"
+ },
+ "frameworks": ["arduino"],
+ "name": "Muzi Base",
+ "url": "https://muzi.works/",
+ "vendor": "MuziWorks",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": [
+ "jlink",
+ "nrfjprog",
+ "nrfutil",
+ "blackmagic",
+ "cmsis-dap",
+ "mbed",
+ "stlink"
+ ],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ }
+}
diff --git a/platformio.ini b/platformio.ini
index d6ff155e4..1363a63fc 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -90,7 +90,7 @@ framework = arduino
lib_deps =
${env.lib_deps}
# renovate: datasource=custom.pio depName=NonBlockingRTTTL packageName=end2endzone/library/NonBlockingRTTTL
- end2endzone/NonBlockingRTTTL@1.3.0
+ end2endzone/NonBlockingRTTTL@1.4.0
build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} - -
@@ -169,7 +169,7 @@ lib_deps =
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
# renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226
- robtillaart/INA226@0.6.4
+ robtillaart/INA226@0.6.5
# renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
# renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library
@@ -213,6 +213,6 @@ lib_deps =
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
- sensirion/Sensirion Core@0.7.1
+ sensirion/Sensirion Core@0.7.2
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C SCD4x@1.1.0
diff --git a/protobufs b/protobufs
index 7654db2e2..52fa252f1 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 7654db2e2d1834aebde40090a9b74162ad1048ae
+Subproject commit 52fa252f1e01be87ad2f7ab17ceef7882b2a4a93
diff --git a/src/Power.cpp b/src/Power.cpp
index fa8661d01..a2c559d91 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -278,6 +278,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
break;
}
}
+#if defined(BATTERY_CHARGING_INV)
+ // bit of trickery to show 99% up until the charge finishes
+ if (!digitalRead(BATTERY_CHARGING_INV) && battery_SOC > 99)
+ battery_SOC = 99;
+#endif
return clamp((int)(battery_SOC), 0, 100);
}
@@ -455,6 +460,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
// if it's not HIGH - check the battery
#endif
+#elif defined(MUZI_BASE)
+ return NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk;
#endif
return getBattVoltage() > chargingVolt;
}
@@ -470,6 +477,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
#endif
#ifdef EXT_CHRG_DETECT
return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value;
+#elif defined(BATTERY_CHARGING_INV)
+ return !digitalRead(BATTERY_CHARGING_INV);
#else
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
if (hasINA()) {
@@ -698,11 +707,18 @@ bool Power::setup()
[]() {
power->setIntervalFromNow(0);
runASAP = true;
- BaseType_t higherWake = 0;
},
CHANGE);
#endif
-
+#ifdef BATTERY_CHARGING_INV
+ attachInterrupt(
+ BATTERY_CHARGING_INV,
+ []() {
+ power->setIntervalFromNow(0);
+ runASAP = true;
+ },
+ CHANGE);
+#endif
enabled = found;
low_voltage_counter = 0;
@@ -759,6 +775,8 @@ void Power::shutdown()
if (screen) {
#ifdef T_DECK_PRO
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
+#elif defined(USE_EINK)
+ screen->showSimpleBanner("Shutting Down...", 2250); // dismiss after 3 seconds to avoid the banner on the sleep screen
#else
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
#endif
diff --git a/src/configuration.h b/src/configuration.h
index 8ec3b2211..d30280d8b 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -250,8 +250,9 @@ along with this program. If not, see .
// Touchscreen
// -----------------------------------------------------------------------------
#define FT6336U_ADDR 0x48
-#define CST328_ADDR 0x1A
+#define CST328_ADDR 0x1A // same address as CST226SE
#define CHSC6X_ADDR 0x2E
+#define CST226SE_ADDR_ALT 0x5A
// -----------------------------------------------------------------------------
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
@@ -396,6 +397,13 @@ along with this program. If not, see .
#define HAS_RGB_LED
#endif
+#ifndef LED_STATE_OFF
+#define LED_STATE_OFF 0
+#endif
+#ifndef LED_STATE_ON
+#define LED_STATE_ON 1
+#endif
+
// default mapping of pins
#if defined(PIN_BUTTON2) && !defined(CANCEL_BUTTON_PIN)
#define ALT_BUTTON_PIN PIN_BUTTON2
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 55980face..cced980a6 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -85,7 +85,8 @@ class ScanI2C
DRV2605,
BH1750,
DA217,
- CHSC6X
+ CHSC6X,
+ CST226SE
} DeviceType;
// typedef uint8_t DeviceAddress;
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 167728ad3..db269ac64 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -499,7 +499,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address);
- SCAN_SIMPLE_CASE(CST328_ADDR, CST328, "CST328", (uint8_t)addr.address);
+ case CST328_ADDR:
+ // Do we have the CST328 or the CST226SE
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xAB), 1);
+ if (registerValue == 0xA9) {
+ type = CST226SE;
+ logFoundDevice("CST226SE", (uint8_t)addr.address);
+ } else {
+ type = CST328;
+ logFoundDevice("CST328", (uint8_t)addr.address);
+ }
+ break;
+
SCAN_SIMPLE_CASE(CHSC6X_ADDR, CHSC6X, "CHSC6X", (uint8_t)addr.address);
case LTR553ALS_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x86), 1); // Part ID register
@@ -528,8 +539,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#endif
case MLX90614_ADDR_DEF:
- registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
- if (registerValue == 0x5a) {
+ // Do we have the MLX90614 or the MPR121KB or the CST226SE
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x06), 1);
+ if (registerValue == 0xAB) {
+ type = CST226SE;
+ logFoundDevice("CST226SE", (uint8_t)addr.address);
+ } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1) == 0x5a) {
type = MLX90614;
logFoundDevice("MLX90614", (uint8_t)addr.address);
} else {
@@ -547,6 +562,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
+#ifdef HAS_ICM20948
+ type = ICM20948;
+ logFoundDevice("ICM20948", (uint8_t)addr.address);
+ break;
+#endif
if (registerValue == 0xEA) {
type = ICM20948;
logFoundDevice("ICM20948", (uint8_t)addr.address);
diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp
index 692f3c2d2..1122f0a51 100644
--- a/src/gps/RTC.cpp
+++ b/src/gps/RTC.cpp
@@ -112,7 +112,11 @@ RTCSetResult readFromRTC()
#elif defined(RX8130CE_RTC)
if (rtc_found.address == RX8130CE_RTC) {
uint32_t now = millis();
+#ifdef MUZI_BASE
+ ArtronShop_RX8130CE rtc(&Wire1);
+#else
ArtronShop_RX8130CE rtc(&Wire);
+#endif
tm t;
if (rtc.getTime(&t)) {
tv.tv_sec = gm_mktime(&t);
@@ -245,7 +249,11 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
}
#elif defined(RX8130CE_RTC)
if (rtc_found.address == RX8130CE_RTC) {
+#ifdef MUZI_BASE
+ ArtronShop_RX8130CE rtc(&Wire1);
+#else
ArtronShop_RX8130CE rtc(&Wire);
+#endif
tm *t = gmtime(&tv->tv_sec);
if (rtc.setTime(*t)) {
LOG_DEBUG("RX8130CE setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1,
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 4da96026c..12ea21e3c 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -325,7 +325,7 @@ static int8_t prevFrame = -1;
// Combined dynamic node list frame cycling through LastHeard, HopSignal, and Distance modes
// Uses a single frame and changes data every few seconds (E-Ink variant is separate)
-#if defined(ESP_PLATFORM) && defined(USE_ST7789)
+#if defined(ESP_PLATFORM) && (defined(USE_ST7789) || defined(USE_ST7796))
SPIClass SPI1(HSPI);
#endif
@@ -357,7 +357,18 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
#else
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
#endif
+#elif defined(USE_ST7796)
+#ifdef ESP_PLATFORM
+ dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7796_SDA,
+ ST7796_MISO, ST7796_SCK, TFT_SPI_FREQUENCY);
+#else
+ dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
+#endif
+#if defined(USE_ST7789)
static_cast(dispdev)->setRGB(TFT_MESH);
+#elif defined(USE_ST7796)
+ static_cast(dispdev)->setRGB(TFT_MESH);
+#endif
#elif defined(USE_SSD1306)
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
@@ -438,6 +449,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
PMU->enablePowerOutput(XPOWERS_ALDO2);
#endif
+#if defined(MUZI_BASE)
+ dispdev->init();
+ dispdev->setBrightness(brightness);
+ dispdev->flipScreenVertically();
+ dispdev->resetDisplay();
+ digitalWrite(SCREEN_12V_ENABLE, HIGH);
+ delay(100);
+#endif
#if !ARCH_PORTDUINO
dispdev->displayOn();
#endif
@@ -469,6 +488,15 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
pinMode(VTFT_LEDA, OUTPUT);
digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON);
#endif
+#endif
+#ifdef USE_ST7796
+ ui->init();
+#ifdef ESP_PLATFORM
+ analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT);
+#else
+ pinMode(VTFT_LEDA, OUTPUT);
+ digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON);
+#endif
#endif
enabled = true;
setInterval(0); // Draw ASAP
@@ -487,6 +515,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
#endif
dispdev->displayOff();
+
+#ifdef SCREEN_12V_ENABLE
+ digitalWrite(SCREEN_12V_ENABLE, LOW);
+#endif
#ifdef USE_ST7789
SPI1.end();
#if defined(ARCH_ESP32)
@@ -503,6 +535,21 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
nrf_gpio_cfg_default(ST7789_NSS);
#endif
#endif
+#ifdef USE_ST7796
+ SPI1.end();
+#if defined(ARCH_ESP32)
+ pinMode(VTFT_LEDA, OUTPUT);
+ digitalWrite(VTFT_LEDA, LOW);
+ pinMode(ST7796_RESET, ANALOG);
+ pinMode(ST7796_RS, ANALOG);
+ pinMode(ST7796_NSS, ANALOG);
+#else
+ nrf_gpio_cfg_default(VTFT_LEDA);
+ nrf_gpio_cfg_default(ST7796_RESET);
+ nrf_gpio_cfg_default(ST7796_RS);
+ nrf_gpio_cfg_default(ST7796_NSS);
+#endif
+#endif
#ifdef T_WATCH_S3
PMU->disablePowerOutput(XPOWERS_ALDO2);
@@ -537,7 +584,7 @@ void Screen::setup()
static_cast(dispdev)->setDetected(model);
#endif
-#ifdef USE_SH1107_128_64
+#if defined(USE_SH1107_128_64) || defined(USE_SH1107)
static_cast(dispdev)->setSubtype(7);
#endif
@@ -545,6 +592,13 @@ void Screen::setup()
// Apply custom RGB color (e.g. Heltec T114/T190)
static_cast(dispdev)->setRGB(TFT_MESH);
#endif
+#if defined(MUZI_BASE)
+ dispdev->delayPoweron = true;
+#endif
+#if defined(USE_ST7796) && defined(TFT_MESH)
+ // Custom text color, if defined in variant.h
+ static_cast(dispdev)->setRGB(TFT_MESH);
+#endif
// === Initialize display and UI system ===
ui->init();
@@ -608,6 +662,8 @@ void Screen::setup()
static_cast(dispdev)->flipScreenVertically();
#elif defined(USE_ST7789)
static_cast(dispdev)->flipScreenVertically();
+#elif defined(USE_ST7796)
+ static_cast(dispdev)->mirrorScreen();
#elif !defined(M5STACK_UNITC6L)
dispdev->flipScreenVertically();
#endif
@@ -640,7 +696,7 @@ void Screen::setup()
touchScreenImpl1->init();
}
}
-#elif HAS_TOUCHSCREEN && !defined(USE_EINK) && !defined(USE_EPD)
+#elif HAS_TOUCHSCREEN && !defined(USE_EINK) && !defined(USE_EPD) && !HAS_CST226SE
touchScreenImpl1 =
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch);
touchScreenImpl1->init();
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index 0477e5af1..5fa2d013f 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -83,6 +83,8 @@ class Screen
#include
#elif defined(USE_SPISSD1306)
#include
+#elif defined(USE_ST7796)
+#include
#else
// the SH1106/SSD1306 variant is auto-detected
#include
@@ -249,6 +251,8 @@ class Screen : public concurrency::OSThread
bool isOverlayBannerShowing();
+ bool isScreenOn() { return screenOn; }
+
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
// FIXME: Needs refactoring and getMacAddr needs to be moved to a utility class
char ourId[5];
diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h
index 49a857598..10d7527fb 100644
--- a/src/graphics/ScreenFonts.h
+++ b/src/graphics/ScreenFonts.h
@@ -73,7 +73,7 @@
#endif
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
- defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)) && \
+ defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_ST7796)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
diff --git a/src/graphics/VirtualKeyboard.cpp b/src/graphics/VirtualKeyboard.cpp
index 8062a0338..a332aad9a 100644
--- a/src/graphics/VirtualKeyboard.cpp
+++ b/src/graphics/VirtualKeyboard.cpp
@@ -506,6 +506,9 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
centeredTextY -= 1;
}
}
+#ifdef MUZI_BASE // Correct issue with character vertical position on MUZI_BASE
+ centeredTextY -= 2;
+#endif
display->drawString(textX, centeredTextY, keyText.c_str());
}
diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp
index 79c1e7e61..6bccb1653 100644
--- a/src/graphics/draw/DebugRenderer.cpp
+++ b/src/graphics/draw/DebugRenderer.cpp
@@ -97,7 +97,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
- ARCH_PORTDUINO) && \
+ defined(USE_ST7796) || \
+ ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
8, imgQuestionL1);
@@ -109,7 +110,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
#endif
} else {
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
- defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
+ defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || defined(USE_ST7796)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
8, imgSFL1);
@@ -125,7 +126,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
// TODO: Raspberry Pi supports more than just the one screen size
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
- ARCH_PORTDUINO) && \
+ defined(USE_ST7796) || \
+ ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgInfoL1);
diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp
index c22ff23f9..bd647c3d8 100644
--- a/src/graphics/draw/MenuHandler.cpp
+++ b/src/graphics/draw/MenuHandler.cpp
@@ -119,6 +119,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
auto changes = SEGMENT_CONFIG;
// This is needed as we wait til picking the LoRa region to generate keys for the first time.
+#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
if (!owner.is_licensed) {
bool keygenSuccess = false;
if (config.security.private_key.size == 32) {
@@ -139,6 +140,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
}
}
+#endif
config.lora.tx_enabled = true;
initRegion();
if (myRegion->dutyCycle < 100) {
@@ -1750,4 +1752,4 @@ void menuHandler::saveUIConfig()
} // namespace graphics
-#endif
\ No newline at end of file
+#endif
diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp
index 9262074fb..ef4239dae 100644
--- a/src/graphics/draw/UIRenderer.cpp
+++ b/src/graphics/draw/UIRenderer.cpp
@@ -257,7 +257,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
}
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
- defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
+ defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || defined(USE_ST7796)) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
if (isHighResolution) {
diff --git a/src/graphics/images.h b/src/graphics/images.h
index 8670d78d9..998fe8e2a 100644
--- a/src/graphics/images.h
+++ b/src/graphics/images.h
@@ -27,8 +27,7 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
- defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
- ARCH_PORTDUINO) && \
+ defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(USE_ST7796) || defined(ST7796_CS) || ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
diff --git a/src/main.cpp b/src/main.cpp
index ea1e6472f..2087d7c87 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -887,7 +887,7 @@ void setup()
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
- defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
+ defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_ST7796) || \
defined(USE_SPISSD1306) || defined(USE_EPD)
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
#elif defined(ARCH_PORTDUINO)
@@ -973,6 +973,7 @@ void setup()
i2cScanner.reset();
#endif
+#if !defined(MESHTASTIC_EXCLUDE_PKI)
// warn the user about a low entropy key
if (nodeDB->keyIsLowEntropy && !nodeDB->hasWarned) {
LOG_WARN(LOW_ENTROPY_WARNING);
@@ -983,6 +984,7 @@ void setup()
service->sendClientNotification(cn);
nodeDB->hasWarned = true;
}
+#endif
// buttons are now inputBroker, so have to come after setupModules
#if HAS_BUTTON
@@ -1168,7 +1170,7 @@ void setup()
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
- defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || \
+ defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_ST7796) || \
defined(USE_SPISSD1306) || defined(USE_EPD)
if (screen)
screen->setup();
diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp
index 3831a384d..af6dd92e9 100644
--- a/src/mesh/LR11x0Interface.cpp
+++ b/src/mesh/LR11x0Interface.cpp
@@ -244,6 +244,8 @@ template void LR11x0Interface::startReceive()
// We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
int err =
lora.startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, MESHTASTIC_RADIOLIB_IRQ_RX_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0);
+ if (err)
+ LOG_ERROR("StartReceive error: %d", err);
assert(err == RADIOLIB_ERR_NONE);
RadioLibInterface::startReceive();
@@ -304,4 +306,4 @@ template bool LR11x0Interface::sleep()
return true;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index d8146c4a3..4e99a22ef 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -664,7 +664,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.bluetooth.fixed_pin = defaultBLEPin;
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
- defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_SPISSD1306)
+ defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS) || defined(USE_SPISSD1306) || defined(USE_ST7796)
bool hasScreen = true;
#ifdef HELTEC_MESH_NODE_T114
uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET);
@@ -734,6 +734,9 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.display.screen_on_secs = 30;
config.display.wake_on_tap_or_motion = true;
#endif
+#ifdef COMPASS_ORIENTATION
+ config.display.compass_orientation = COMPASS_ORIENTATION;
+#endif
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
if (WiFiOTA::isUpdated()) {
WiFiOTA::recoverConfig(&config.network);
@@ -2008,6 +2011,7 @@ UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum)
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
}
+#if !defined(MESHTASTIC_EXCLUDE_PKI)
bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest)
{
if (keyToTest.size == 32) {
@@ -2022,6 +2026,7 @@ bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_pub
}
return false;
}
+#endif
bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location)
{
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index 444ac13e4..306acc0a5 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -283,7 +283,9 @@ class NodeDB
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
+#if !defined(MESHTASTIC_EXCLUDE_PKI)
bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest);
+#endif
bool backupPreferences(meshtastic_AdminMessage_BackupLocation location);
bool restorePreferences(meshtastic_AdminMessage_BackupLocation location,
@@ -373,4 +375,4 @@ extern uint32_t error_address;
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
-// Please do not remove this comment, it makes trunk and compiler happy at the same time.
\ No newline at end of file
+// Please do not remove this comment, it makes trunk and compiler happy at the same time.
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index 0da44cce0..46de1dee0 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -288,6 +288,12 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_WISMESH_TAP_V2 = 116,
/* RAK3401 */
meshtastic_HardwareModel_RAK3401 = 117,
+ /* RAK6421 Hat+ */
+ meshtastic_HardwareModel_RAK6421 = 118,
+ /* Elecrow ThinkNode M4 */
+ meshtastic_HardwareModel_THINKNODE_M4 = 119,
+ /* Elecrow ThinkNode M6 */
+ meshtastic_HardwareModel_THINKNODE_M6 = 120,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -825,7 +831,11 @@ typedef struct _meshtastic_MeshPacket {
Note: Our crypto implementation uses this field as well.
See [crypto](/docs/overview/encryption) for details. */
uint32_t from;
- /* The (immediate) destination for this packet */
+ /* The (immediate) destination for this packet
+ If the value is 4,294,967,295 (maximum value of an unsigned 32bit integer), this indicates that the packet was
+ not destined for a specific node, but for a channel as indicated by the value of `channel` below.
+ If the value is another, this indicates that the packet was destined for a specific
+ node (i.e. a kind of "Direct Message" to this node) and not broadcast on a channel. */
uint32_t to;
/* (Usually) If set, this indicates the index in the secondary_channels table that this packet was sent/received on.
If unset, packet was on the primary channel.
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index a98515059..aa510a86d 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -773,6 +773,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
config.lora = validatedLora;
// If we're setting region for the first time, init the region and regenerate the keys
if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
+#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
if (!owner.is_licensed) {
bool keygenSuccess = false;
if (config.security.private_key.size == 32) {
@@ -791,6 +792,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32);
}
}
+#endif
config.lora.tx_enabled = true;
initRegion();
if (myRegion->dutyCycle < 100) {
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index f435f6060..9cbacc877 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -836,6 +836,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
if (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() > 0) {
payload = 0x08;
lastTouchMillis = millis();
+ requestFocus();
runOnce();
return true;
}
@@ -844,6 +845,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
if (event->inputEvent == INPUT_BROKER_LEFT) {
payload = INPUT_BROKER_LEFT;
lastTouchMillis = millis();
+ requestFocus();
runOnce();
return true;
}
@@ -851,6 +853,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
if (event->inputEvent == INPUT_BROKER_RIGHT) {
payload = INPUT_BROKER_RIGHT;
lastTouchMillis = millis();
+ requestFocus();
runOnce();
return true;
}
diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp
index 4fe49cc1b..91e96b8d4 100644
--- a/src/modules/ExternalNotificationModule.cpp
+++ b/src/modules/ExternalNotificationModule.cpp
@@ -314,11 +314,10 @@ void ExternalNotificationModule::stopNow()
audioThread->stop();
#endif
// Turn off all outputs
- LOG_INFO("Turning off setExternalStates: ");
+ LOG_INFO("Turning off setExternalStates");
for (int i = 0; i < 3; i++) {
setExternalState(i, false);
externalTurnedOn[i] = 0;
- LOG_INFO("%d ", i);
}
setIntervalFromNow(0);
#ifdef T_WATCH_S3
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index e477574dd..827524fc3 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -13,6 +13,8 @@
#include "input/TrackballInterruptImpl1.h"
#endif
+#include "modules/StatusLEDModule.h"
+
#if !MESHTASTIC_EXCLUDE_I2C
#include "input/cardKbI2cImpl.h"
#endif
@@ -119,6 +121,10 @@ void setupModules()
buzzerFeedbackThread = new BuzzerFeedbackThread();
}
#endif
+#if defined(LED_CHARGE) || defined(LED_PAIRING)
+ statusLEDModule = new StatusLEDModule();
+#endif
+
#if !MESHTASTIC_EXCLUDE_ADMIN
adminModule = new AdminModule();
#endif
@@ -175,12 +181,13 @@ void setupModules()
// new ReplyModule();
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
+#ifndef T_LORA_PAGER
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
-#ifdef T_LORA_PAGER
+#elif defined(T_LORA_PAGER)
// use a special FSM based rotary encoder version for T-LoRa Pager
rotaryEncoderImpl = new RotaryEncoderImpl();
if (!rotaryEncoderImpl->init()) {
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 575e9fa96..719e342b1 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -64,7 +64,8 @@ SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio;
#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
- defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
+ defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || \
+ defined(MUZI_BASE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
@@ -204,7 +205,7 @@ int32_t SerialModule::runOnce()
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
}
#elif !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
- !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
+ !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
#ifdef ARCH_RP2040
Serial2.setFIFOSize(RX_BUFFER);
@@ -261,7 +262,7 @@ int32_t SerialModule::runOnce()
}
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
- !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
+ !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
processWXSerial();
@@ -536,7 +537,8 @@ ParsedLine parseLine(const char *line)
void SerialModule::processWXSerial()
{
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
- !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL)
+ !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
+ !defined(ARCH_STM32WL) && !defined(MUZI_BASE)
static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
static double dir_sum_sin = 0;
diff --git a/src/modules/StatusLEDModule.cpp b/src/modules/StatusLEDModule.cpp
new file mode 100644
index 000000000..fc9ed310e
--- /dev/null
+++ b/src/modules/StatusLEDModule.cpp
@@ -0,0 +1,94 @@
+#include "StatusLEDModule.h"
+#include "MeshService.h"
+#include "configuration.h"
+#include
+
+/*
+StatusLEDModule manages the device's status LEDs, updating their states based on power and Bluetooth status.
+It reflects charging, charged, discharging, and Bluetooth connection states using the appropriate LEDs.
+*/
+StatusLEDModule *statusLEDModule;
+
+StatusLEDModule::StatusLEDModule() : concurrency::OSThread("StatusLEDModule")
+{
+ bluetoothStatusObserver.observe(&bluetoothStatus->onNewStatus);
+ powerStatusObserver.observe(&powerStatus->onNewStatus);
+}
+
+int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
+{
+ switch (arg->getStatusType()) {
+ case STATUS_TYPE_POWER: {
+ meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
+ if (powerStatus->getHasUSB()) {
+ power_state = charging;
+ if (powerStatus->getBatteryChargePercent() >= 100) {
+ power_state = charged;
+ }
+ } else {
+ power_state = discharging;
+ }
+ break;
+ }
+ case STATUS_TYPE_BLUETOOTH: {
+ meshtastic::BluetoothStatus *bluetoothStatus = (meshtastic::BluetoothStatus *)arg;
+ switch (bluetoothStatus->getConnectionState()) {
+ case meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED: {
+ ble_state = unpaired;
+ PAIRING_LED_starttime = millis();
+ break;
+ }
+ case meshtastic::BluetoothStatus::ConnectionState::PAIRING: {
+ ble_state = pairing;
+ PAIRING_LED_starttime = millis();
+ break;
+ }
+ case meshtastic::BluetoothStatus::ConnectionState::CONNECTED: {
+ ble_state = connected;
+ PAIRING_LED_starttime = millis();
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ return 0;
+};
+
+int32_t StatusLEDModule::runOnce()
+{
+
+ if (power_state == charging) {
+ CHARGE_LED_state = !CHARGE_LED_state;
+ } else if (power_state == charged) {
+ CHARGE_LED_state = LED_STATE_ON;
+ } else {
+ CHARGE_LED_state = LED_STATE_OFF;
+ }
+
+ if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis()) {
+ PAIRING_LED_state = LED_STATE_OFF;
+ } else if (ble_state == unpaired) {
+ if (slowTrack) {
+ PAIRING_LED_state = !PAIRING_LED_state;
+ slowTrack = false;
+ } else {
+ slowTrack = true;
+ }
+ } else if (ble_state == pairing) {
+ PAIRING_LED_state = !PAIRING_LED_state;
+ } else {
+ PAIRING_LED_state = LED_STATE_ON;
+ }
+
+#ifdef LED_CHARGE
+ digitalWrite(LED_CHARGE, CHARGE_LED_state);
+#endif
+ // digitalWrite(green_LED_PIN, LED_STATE_OFF);
+#ifdef LED_PAIRING
+ digitalWrite(LED_PAIRING, PAIRING_LED_state);
+#endif
+
+ return (my_interval);
+}
diff --git a/src/modules/StatusLEDModule.h b/src/modules/StatusLEDModule.h
new file mode 100644
index 000000000..d9e3a4f33
--- /dev/null
+++ b/src/modules/StatusLEDModule.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "BluetoothStatus.h"
+#include "MeshModule.h"
+#include "PowerStatus.h"
+#include "concurrency/OSThread.h"
+#include "configuration.h"
+#include
+#include
+
+class StatusLEDModule : private concurrency::OSThread
+{
+ bool slowTrack = false;
+
+ public:
+ StatusLEDModule();
+
+ int handleStatusUpdate(const meshtastic::Status *);
+
+ protected:
+ unsigned int my_interval = 1000; // interval in millisconds
+ virtual int32_t runOnce() override;
+
+ CallbackObserver bluetoothStatusObserver =
+ CallbackObserver(this, &StatusLEDModule::handleStatusUpdate);
+ CallbackObserver powerStatusObserver =
+ CallbackObserver(this, &StatusLEDModule::handleStatusUpdate);
+
+ private:
+ bool CHARGE_LED_state = LED_STATE_OFF;
+ bool PAIRING_LED_state = LED_STATE_OFF;
+
+ uint32_t PAIRING_LED_starttime = 0;
+
+ enum PowerState { discharging, charging, charged };
+
+ PowerState power_state = discharging;
+
+ enum BLEState { unpaired, pairing, connected };
+
+ BLEState ble_state = unpaired;
+};
+
+extern StatusLEDModule *statusLEDModule;
diff --git a/src/modules/Telemetry/Sensor/AHT10.cpp b/src/modules/Telemetry/Sensor/AHT10.cpp
index 52fdc05c0..c38fd2a92 100644
--- a/src/modules/Telemetry/Sensor/AHT10.cpp
+++ b/src/modules/Telemetry/Sensor/AHT10.cpp
@@ -35,7 +35,7 @@ bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement)
// prefer other sensors like bmp280, bmp3xx
if (!measurement->variant.environment_metrics.has_temperature) {
measurement->variant.environment_metrics.has_temperature = true;
- measurement->variant.environment_metrics.temperature = temp.temperature;
+ measurement->variant.environment_metrics.temperature = temp.temperature + AHT10_TEMP_OFFSET;
}
if (!measurement->variant.environment_metrics.has_relative_humidity) {
diff --git a/src/modules/Telemetry/Sensor/AHT10.h b/src/modules/Telemetry/Sensor/AHT10.h
index ab3f5806c..f85f04aa0 100644
--- a/src/modules/Telemetry/Sensor/AHT10.h
+++ b/src/modules/Telemetry/Sensor/AHT10.h
@@ -6,6 +6,10 @@
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include()
+#ifndef AHT10_TEMP_OFFSET
+#define AHT10_TEMP_OFFSET 0
+#endif
+
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include
diff --git a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp
index 59a98e291..101b01f8f 100644
--- a/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp
+++ b/src/modules/Telemetry/Sensor/DFRobotGravitySensor.cpp
@@ -13,7 +13,10 @@ DFRobotGravitySensor::DFRobotGravitySensor() : TelemetrySensor(meshtastic_Teleme
DFRobotGravitySensor::~DFRobotGravitySensor()
{
if (gravity) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
delete gravity;
+#pragma GCC diagnostic pop
gravity = nullptr;
}
}
diff --git a/src/motion/BMX160Sensor.cpp b/src/motion/BMX160Sensor.cpp
index 56f794306..5888c20be 100755
--- a/src/motion/BMX160Sensor.cpp
+++ b/src/motion/BMX160Sensor.cpp
@@ -115,8 +115,13 @@ int32_t BMX160Sensor::runOnce()
void BMX160Sensor::calibrate(uint16_t forSeconds)
{
#if !defined(MESHTASTIC_EXCLUDE_SCREEN)
+ sBmx160SensorData_t magAccel;
+ sBmx160SensorData_t gAccel;
LOG_DEBUG("BMX160 calibration started for %is", forSeconds);
- highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
+ sensor.getAllData(&magAccel, NULL, &gAccel);
+ highestX = magAccel.x, lowestX = magAccel.x;
+ highestY = magAccel.y, lowestY = magAccel.y;
+ highestZ = magAccel.z, lowestZ = magAccel.z;
doCalibration = true;
uint16_t calibrateFor = forSeconds * 1000; // calibrate for seconds provided
diff --git a/src/motion/ICM20948Sensor.cpp b/src/motion/ICM20948Sensor.cpp
index ebb0f7b66..9455eafe0 100755
--- a/src/motion/ICM20948Sensor.cpp
+++ b/src/motion/ICM20948Sensor.cpp
@@ -47,6 +47,21 @@ int32_t ICM20948Sensor::runOnce()
int32_t ICM20948Sensor::runOnce()
{
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) && HAS_SCREEN
+#if defined(MUZI_BASE) // temporarily gated to single device due to feature freeze
+ if (screen && !screen->isScreenOn() && !config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) {
+ if (!isAsleep) {
+ LOG_DEBUG("sleeping IMU");
+ sensor->sleep(true);
+ isAsleep = true;
+ }
+ return MOTION_SENSOR_CHECK_INTERVAL_MS;
+ }
+ if (isAsleep) {
+ sensor->sleep(false);
+ isAsleep = false;
+ }
+#endif
+
float magX = 0, magY = 0, magZ = 0;
if (sensor->dataReady()) {
sensor->getAGMT();
@@ -156,8 +171,20 @@ int32_t ICM20948Sensor::runOnce()
void ICM20948Sensor::calibrate(uint16_t forSeconds)
{
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) && HAS_SCREEN
+ LOG_DEBUG("Old calibration data: highestX = %f, lowestX = %f, highestY = %f, lowestY = %f, highestZ = %f, lowestZ = %f",
+ highestX, lowestX, highestY, lowestY, highestZ, lowestZ);
LOG_DEBUG("BMX160 calibration started for %is", forSeconds);
- highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
+ if (sensor->dataReady()) {
+ sensor->getAGMT();
+ highestX = sensor->agmt.mag.axes.x;
+ lowestX = sensor->agmt.mag.axes.x;
+ highestY = sensor->agmt.mag.axes.y;
+ lowestY = sensor->agmt.mag.axes.y;
+ highestZ = sensor->agmt.mag.axes.z;
+ lowestZ = sensor->agmt.mag.axes.z;
+ } else {
+ highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
+ }
doCalibration = true;
uint16_t calibrateFor = forSeconds * 1000; // calibrate for seconds provided
diff --git a/src/motion/ICM20948Sensor.h b/src/motion/ICM20948Sensor.h
index 27ce4f451..a9b7b69d0 100755
--- a/src/motion/ICM20948Sensor.h
+++ b/src/motion/ICM20948Sensor.h
@@ -82,7 +82,13 @@ class ICM20948Sensor : public MotionSensor
private:
ICM20948Singleton *sensor = nullptr;
bool showingScreen = false;
+#ifdef MUZI_BASE
+ bool isAsleep = false;
+ float highestX = 449.000000, lowestX = -140.000000, highestY = 422.000000, lowestY = -232.000000, highestZ = 749.000000,
+ lowestZ = 98.000000;
+#else
float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
+#endif
public:
explicit ICM20948Sensor(ScanI2C::FoundDevice foundDevice);
diff --git a/src/platform/extra_variants/tbeam_displayshield/variant.cpp b/src/platform/extra_variants/tbeam_displayshield/variant.cpp
new file mode 100644
index 000000000..7beac2293
--- /dev/null
+++ b/src/platform/extra_variants/tbeam_displayshield/variant.cpp
@@ -0,0 +1,43 @@
+#include "configuration.h"
+
+#ifdef HAS_CST226SE
+
+#include "TouchDrvCSTXXX.hpp"
+#include "input/TouchScreenImpl1.h"
+#include
+
+TouchDrvCSTXXX tsPanel;
+static constexpr uint8_t PossibleAddresses[2] = {CST328_ADDR, CST226SE_ADDR_ALT};
+uint8_t i2cAddress = 0;
+
+bool readTouch(int16_t *x, int16_t *y)
+{
+ int16_t x_array[1], y_array[1];
+ uint8_t touched = tsPanel.getPoint(x_array, y_array, 1);
+ if (touched > 0) {
+ *y = x_array[0];
+ *x = (TFT_WIDTH - y_array[0]);
+ // Check bounds
+ if (*x < 0 || *x >= TFT_WIDTH || *y < 0 || *y >= TFT_HEIGHT) {
+ return false;
+ }
+ return true; // Valid touch detected
+ }
+ return false; // No valid touch data
+}
+
+void lateInitVariant()
+{
+ tsPanel.setTouchDrvModel(TouchDrv_CST226);
+ for (uint8_t addr : PossibleAddresses) {
+ if (tsPanel.begin(Wire, addr, I2C_SDA, I2C_SCL)) {
+ i2cAddress = addr;
+ LOG_DEBUG("CST226SE init OK at address 0x%02X", addr);
+ touchScreenImpl1 = new TouchScreenImpl1(TFT_WIDTH, TFT_HEIGHT, readTouch);
+ touchScreenImpl1->init();
+ return;
+ }
+ }
+ LOG_ERROR("CST226SE init failed at all known addresses");
+}
+#endif
diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h
index c74f02c44..1568e1790 100644
--- a/src/platform/nrf52/architecture.h
+++ b/src/platform/nrf52/architecture.h
@@ -57,17 +57,21 @@
#define HW_VENDOR meshtastic_HardwareModel_NOMADSTAR_METEOR_PRO
#elif defined(R1_NEO)
#define HW_VENDOR meshtastic_HardwareModel_MUZI_R1_NEO
+#elif defined(RAK3401)
+#define HW_VENDOR meshtastic_HardwareModel_RAK3401
// MAke sure all custom RAK4630 boards are defined before the generic RAK4630
#elif defined(RAK4630)
#define HW_VENDOR meshtastic_HardwareModel_RAK4631
-#elif defined(RAK3401)
-#define HW_VENDOR meshtastic_HardwareModel_RAK3401
#elif defined(TTGO_T_ECHO)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
#elif defined(T_ECHO_LITE)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
#elif defined(ELECROW_ThinkNode_M1)
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
+#elif defined(ELECROW_ThinkNode_M3)
+#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M3
+#elif defined(ELECROW_ThinkNode_M6)
+#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M6
#elif defined(NANO_G2_ULTRA)
#define HW_VENDOR meshtastic_HardwareModel_NANO_G2_ULTRA
#elif defined(CANARYONE)
@@ -104,6 +108,8 @@
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1
#elif defined(HELTEC_MESH_SOLAR)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR
+#elif defined(MUZI_BASE)
+#define HW_VENDOR meshtastic_HardwareModel_RESERVED_FRIED_CHICKEN
#else
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
#endif
@@ -128,7 +134,9 @@
#endif
+#ifdef PIN_LED1
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
+#endif
#ifdef PIN_BUTTON1
#define BUTTON_PIN PIN_BUTTON1
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index f29def72e..c03cc4454 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -4,6 +4,14 @@
#include
#include
#include
+
+#define APP_WATCHDOG_SECS 90
+#define NRFX_WDT_ENABLED 1
+#define NRFX_WDT0_ENABLED 1
+#define NRFX_WDT_CONFIG_NO_IRQ 1
+#include
+#include
+
#include
#include
#include
@@ -22,6 +30,14 @@
#include "BQ25713.h"
#endif
+// Weak empty variant initialization function.
+// May be redefined by variant files.
+void variant_shutdown() __attribute__((weak));
+void variant_shutdown() {}
+
+static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
+static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
+
static inline void debugger_break(void)
{
__asm volatile("bkpt #0x01\n\t"
@@ -205,6 +221,15 @@ void checkSDEvents()
void nrf52Loop()
{
+ {
+ static bool watchdog_running = false;
+ if (!watchdog_running) {
+ nrfx_wdt_enable(&nrfx_wdt);
+ watchdog_running = true;
+ }
+ }
+ nrfx_wdt_channel_feed(&nrfx_wdt, nrfx_wdt_channel_id_nrf52_main);
+
checkSDEvents();
reportLittleFSCorruptionOnce();
}
@@ -272,6 +297,22 @@ void nrf52Setup()
LOG_DEBUG("Set random seed %u", seed.seed32);
randomSeed(seed.seed32);
nRFCrypto.end();
+
+ // Set up nrfx watchdog. Do not enable the watchdog yet (we do that
+ // the first time through the main loop), so that other threads can
+ // allocate their own wdt channel to protect themselves from hangs.
+ nrfx_wdt_config_t wdt0_config = {
+ .behaviour = NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT, .reload_value = APP_WATCHDOG_SECS * 1000,
+ // Note: Not using wdt interrupts.
+ // .interrupt_priority = NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY
+ };
+ nrfx_err_t r = nrfx_wdt_init(&nrfx_wdt, &wdt0_config,
+ nullptr // Watchdog event handler, not used, we just reset.
+ );
+ assert(r == NRFX_SUCCESS);
+
+ r = nrfx_wdt_channel_alloc(&nrfx_wdt, &nrfx_wdt_channel_id_nrf52_main);
+ assert(r == NRFX_SUCCESS);
}
void cpuDeepSleep(uint32_t msecToWake)
@@ -355,6 +396,7 @@ void cpuDeepSleep(uint32_t msecToWake)
NRF_GPIO->DIRCLR = (1 << pin);
}
#endif
+ variant_shutdown();
// Sleepy trackers or sensors can low power "sleep"
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
diff --git a/src/power.h b/src/power.h
index f9ccb08aa..3f28dedb2 100644
--- a/src/power.h
+++ b/src/power.h
@@ -34,8 +34,8 @@
#define OCV_ARRAY 4200, 3876, 3826, 3763, 3713, 3660, 3573, 3485, 3422, 3359, 3300
#elif defined(SEEED_SOLAR_NODE)
#define OCV_ARRAY 4200, 3986, 3922, 3812, 3734, 3645, 3527, 3420, 3281, 3087, 2786
-#elif defined(R1_NEO)
-#define OCV_ARRAY 4330, 4292, 4254, 4216, 4178, 4140, 4102, 4064, 4026, 3988, 3950
+#elif defined(WISMESH_TAG)
+#define OCV_ARRAY 4240, 4112, 4029, 3970, 3906, 3846, 3824, 3802, 3776, 3650, 3072
#else // LiIon
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
#endif
@@ -138,7 +138,7 @@ class Power : private concurrency::OSThread
void reboot();
// open circuit voltage lookup table
uint8_t low_voltage_counter;
- int32_t lastLogTime = 0;
+ uint32_t lastLogTime = 0;
#ifdef DEBUG_HEAP
uint32_t lastheap;
#endif
diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini
index e53f22d30..c635081ff 100644
--- a/variants/esp32/tbeam/platformio.ini
+++ b/variants/esp32/tbeam/platformio.ini
@@ -4,12 +4,22 @@ extends = esp32_base
board = ttgo-t-beam
board_level = pr
board_check = true
-lib_deps =
- ${esp32_base.lib_deps}
-build_flags =
- ${esp32_base.build_flags}
+lib_deps = ${esp32_base.lib_deps}
+build_flags = ${esp32_base.build_flags}
-D TBEAM_V10
-I variants/esp32/tbeam
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
upload_speed = 921600
+
+[env:tbeam-displayshield]
+extends = env:tbeam
+
+build_flags =
+ ${env:tbeam.build_flags}
+ -D USE_ST7796
+
+lib_deps =
+ ${env:tbeam.lib_deps}
+ https://github.com/meshtastic/st7796/archive/refs/tags/1.0.5.zip ; display addon
+ lewisxhe/SensorLib@0.3.1 ; touchscreen addon
\ No newline at end of file
diff --git a/variants/esp32/tbeam/variant.h b/variants/esp32/tbeam/variant.h
index 5b521a2de..2d144a888 100644
--- a/variants/esp32/tbeam/variant.h
+++ b/variants/esp32/tbeam/variant.h
@@ -42,4 +42,35 @@
#define GPS_UBLOX
#define GPS_RX_PIN 34
#define GPS_TX_PIN 12
-// #define GPS_DEBUG
\ No newline at end of file
+// #define GPS_DEBUG
+
+// Used when the display shield is chosen
+#ifdef USE_ST7796
+
+#undef EXT_NOTIFY_OUT
+#undef LED_STATE_ON
+#undef LED_PIN
+
+#define HAS_CST226SE 1
+#define HAS_TOUCHSCREEN 1
+// #define TOUCH_IRQ 35 // broken in this version of the lib 0.3.1
+#ifndef TOUCH_IRQ
+#define TOUCH_IRQ -1
+#endif
+#define CANNED_MESSAGE_MODULE_ENABLE 1
+#define USE_VIRTUAL_KEYBOARD 1
+
+#define ST7796_NSS 25
+#define ST7796_RS 13 // DC
+#define ST7796_SDA 14 // MOSI
+#define ST7796_SCK 15
+#define ST7796_RESET 2
+#define ST7796_MISO -1
+#define ST7796_BUSY -1
+#define VTFT_LEDA 4
+#define TFT_SPI_FREQUENCY 60000000
+#define TFT_HEIGHT 222
+#define TFT_WIDTH 480
+#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightness
+#define SCREEN_TRANSITION_FRAMERATE 5 // fps
+#endif
\ No newline at end of file
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini
new file mode 100644
index 000000000..958e48e48
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini
@@ -0,0 +1,17 @@
+[env:thinknode_m3]
+extends = nrf52840_base
+board = ThinkNode-M3
+board_check = true
+debug_tool = jlink
+build_flags =
+ ${nrf52840_base.build_flags}
+ -Ivariants/nrf52840/ELECROW-ThinkNode-M3
+ -DELECROW_ThinkNode_M3
+ -DGPS_POWER_TOGGLE
+ -D CONFIG_NFCT_PINS_AS_GPIOS=1
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ELECROW-ThinkNode-M3>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+ khoih-prog/nRF52_PWM@^1.0.1
+ lewisxhe/PCF8563_Library@^1.0.1
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M3/rfswitch.h b/variants/nrf52840/ELECROW-ThinkNode-M3/rfswitch.h
new file mode 100644
index 000000000..77ae9ef73
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M3/rfswitch.h
@@ -0,0 +1,15 @@
+#include "RadioLib.h"
+#include "nrf.h"
+
+// set RF switch configuration for ELECROW ThinkNode M3
+// ELECROW ThinkNode M3 uses DIO5 and DIO6 for RF switching
+
+static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
+
+static const Module::RfSwitchMode_t rfswitch_table[] = {
+ // mode DIO5 DIO6
+ {LR11x0::MODE_STBY, {LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW}},
+ {LR11x0::MODE_TX, {HIGH, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH}},
+ {LR11x0::MODE_TX_HF, {LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW}},
+ {LR11x0::MODE_WIFI, {LOW, LOW}}, END_OF_MODE_TABLE,
+};
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M3/variant.cpp b/variants/nrf52840/ELECROW-ThinkNode-M3/variant.cpp
new file mode 100644
index 000000000..b7a7b7342
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M3/variant.cpp
@@ -0,0 +1,93 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "variant.h"
+#include "meshUtils.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+ // P1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+
+void initVariant()
+{
+ pinMode(KEY_POWER, OUTPUT);
+ digitalWrite(KEY_POWER, HIGH);
+ pinMode(RGB_POWER, OUTPUT);
+ digitalWrite(RGB_POWER, HIGH);
+ pinMode(green_LED_PIN, OUTPUT);
+ digitalWrite(green_LED_PIN, LED_STATE_OFF);
+ pinMode(LED_BLUE, OUTPUT);
+ pinMode(PIN_POWER_USB, INPUT);
+ pinMode(PIN_POWER_DONE, INPUT);
+ pinMode(PIN_POWER_CHRG, INPUT);
+ pinMode(BUTTON_PIN, INPUT_PULLUP);
+ pinMode(EEPROM_POWER, OUTPUT);
+ digitalWrite(EEPROM_POWER, HIGH);
+ pinMode(PIN_EN1, OUTPUT);
+ digitalWrite(PIN_EN1, HIGH);
+ pinMode(PIN_EN2, OUTPUT);
+ digitalWrite(PIN_EN2, HIGH);
+ pinMode(ACC_POWER, OUTPUT);
+ digitalWrite(ACC_POWER, LOW);
+ pinMode(DHT_POWER, OUTPUT);
+ digitalWrite(DHT_POWER, HIGH);
+ pinMode(Battery_POWER, OUTPUT);
+ digitalWrite(Battery_POWER, HIGH);
+ pinMode(GPS_POWER, OUTPUT);
+ digitalWrite(GPS_POWER, HIGH);
+}
+
+// called from main-nrf52.cpp during the cpuDeepSleep() function
+void variant_shutdown()
+{
+ digitalWrite(EEPROM_POWER, LOW);
+ digitalWrite(KEY_POWER, LOW);
+
+ for (int pin = 0; pin < 48; pin++) {
+ if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
+ pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN ||
+ pin == LR1110_SPI_MOSI_PIN || pin == LR1110_SPI_SCK_PIN || pin == LR1110_SPI_NSS_PIN || pin == LR1110_BUSY_PIN ||
+ pin == LR1110_NRESET_PIN || pin == LR1110_IRQ_PIN || pin == GPS_TX_PIN || pin == GPS_RX_PIN || pin == green_LED_PIN ||
+ pin == red_LED_PIN || pin == LED_BLUE) {
+ continue;
+ }
+ pinMode(pin, OUTPUT);
+ digitalWrite(pin, LOW);
+ if (pin >= 32) {
+ NRF_P1->DIRCLR = (1 << (pin - 32));
+ } else {
+ NRF_GPIO->DIRCLR = (1 << pin);
+ }
+ }
+
+ nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
+ nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
+ nrf_gpio_cfg_sense_set(BUTTON_PIN, sense1);
+
+ nrf_gpio_cfg_input(PIN_POWER_USB, NRF_GPIO_PIN_PULLDOWN); // Configure the pin to be woken up as an input
+ nrf_gpio_pin_sense_t sense2 = NRF_GPIO_PIN_SENSE_HIGH;
+ nrf_gpio_cfg_sense_set(PIN_POWER_USB, sense2);
+}
\ No newline at end of file
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M3/variant.h b/variants/nrf52840/ELECROW-ThinkNode-M3/variant.h
new file mode 100644
index 000000000..cf940172b
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M3/variant.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _VARIANT_ELECROW_EINK_V1_0_
+#define _VARIANT_ELECROW_EINK_V1_0_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include "WVariant.h"
+
+#define VARIANT_MCK (64000000ul)
+#define USE_LFXO // Board uses 32khz crystal for LF
+
+#define ELECROW_ThinkNode_M3 1
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (1)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// Power Pin
+#define NRF_APM
+#define GPS_POWER 14
+#define PIN_POWER_USB 31
+#define EXT_PWR_DETECT PIN_POWER_USB
+#define PIN_POWER_DONE 24
+#define PIN_POWER_CHRG 32
+#define KEY_POWER 16
+#define ACC_POWER 2
+#define DHT_POWER 3
+#define Battery_POWER 17
+#define RGB_POWER 29
+#define EEPROM_POWER 7
+
+// LED
+#define red_LED_PIN 33
+#define LED_POWER red_LED_PIN
+#define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED
+#define green_LED_PIN 35
+#define LED_BLUE 37
+#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
+
+#define LED_BUILTIN -1
+#define LED_STATE_ON LOW
+#define LED_STATE_OFF HIGH
+
+// BUZZER
+#define PIN_BUZZER 23
+#define PIN_EN1 36
+#define PIN_EN2 34
+/*Wire Interfaces*/
+#define WIRE_INTERFACES_COUNT 1
+#define PIN_WIRE_SDA 26
+#define PIN_WIRE_SCL 27
+
+// Temperature correction for sensor
+#define AHT10_TEMP_OFFSET -5.0
+
+/*GPS pins*/
+#define HAS_GPS 1
+#define GPS_BAUDRATE 9600
+#define PIN_GPS_RESET 25
+#define PIN_GPS_STANDBY 21
+#define GPS_TX_PIN 20
+#define GPS_RX_PIN 22
+#define GPS_THREAD_INTERVAL 50
+#define PIN_SERIAL1_RX GPS_TX_PIN
+#define PIN_SERIAL1_TX GPS_RX_PIN
+// Button
+#define BUTTON_PIN 12
+#define BUTTON_PIN_ALT (0 + 12)
+// Battery
+#define BATTERY_PIN 5
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 2.4
+#define VBAT_AR_INTERNAL AR_INTERNAL_2_4
+#define ADC_MULTIPLIER (1.75)
+/*SPI Interfaces*/
+#define SPI_INTERFACES_COUNT 1
+#define PIN_SPI_MISO (32 + 15) // P1.15 47
+#define PIN_SPI_MOSI (32 + 14) // P1.14 46
+#define PIN_SPI_SCK (32 + 13) // P1.13 45
+#define PIN_SPI_NSS (32 + 12) // P1.12 44
+/*LORA Interfaces*/
+#define USE_LR1110
+#define LR1110_IRQ_PIN 40
+#define LR1110_NRESET_PIN 42
+#define LR1110_BUSY_PIN 43
+#define LR1110_SPI_NSS_PIN 44
+#define LR1110_SPI_SCK_PIN 45
+#define LR1110_SPI_MOSI_PIN 46
+#define LR1110_SPI_MISO_PIN 47
+#define LR11X0_DIO3_TCXO_VOLTAGE 3.3
+#define LR11X0_DIO_AS_RF_SWITCH
+
+// PCF8563 RTC Module
+#define PCF8563_RTC 0x51
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini
new file mode 100644
index 000000000..2bf227791
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini
@@ -0,0 +1,15 @@
+; ThinkNode M6 - Outdoor Solar Power nrf52840/sx1262 device
+[env:thinknode_m6]
+extends = nrf52840_base
+board = ThinkNode-M6
+board_check = true
+debug_tool = jlink
+
+build_flags = ${nrf52840_base.build_flags}
+ -Ivariants/nrf52840/ELECROW-ThinkNode-M6
+ -DELECROW_ThinkNode_M6
+
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ELECROW-ThinkNode-M6>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+ lewisxhe/PCF8563_Library@^1.0.1
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M6/variant.cpp b/variants/nrf52840/ELECROW-ThinkNode-M6/variant.cpp
new file mode 100644
index 000000000..09872d409
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M6/variant.cpp
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "variant.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
+ 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+ // P1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+
+void initVariant()
+{
+ pinMode(LED_CHARGE, OUTPUT);
+ ledOff(LED_CHARGE);
+
+ pinMode(LED_PAIRING, OUTPUT);
+ ledOff(LED_PAIRING);
+
+ pinMode(VDD_FLASH_EN, OUTPUT);
+ digitalWrite(VDD_FLASH_EN, HIGH);
+}
diff --git a/variants/nrf52840/ELECROW-ThinkNode-M6/variant.h b/variants/nrf52840/ELECROW-ThinkNode-M6/variant.h
new file mode 100644
index 000000000..5e543b21f
--- /dev/null
+++ b/variants/nrf52840/ELECROW-ThinkNode-M6/variant.h
@@ -0,0 +1,144 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef _VARIANT_ELECROW_THINKNODE_M6_
+#define _VARIANT_ELECROW_THINKNODE_M6_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+#define USE_LFXO
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (1)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// LEDs
+#define LED_BUILTIN -1
+#define LED_BLUE -1
+#define LED_CHARGE (12)
+#define LED_PAIRING (7)
+
+#define LED_STATE_ON 1
+
+// USB power detection
+#define EXT_PWR_DETECT (13)
+
+// Button
+#define PIN_BUTTON1 (17)
+
+// Battery ADC
+#define PIN_A0 (28)
+#define BATTERY_PIN PIN_A0
+#define ADC_CTRL (11)
+#define ADC_CTRL_ENABLED 1
+
+static const uint8_t A0 = PIN_A0;
+
+#define ADC_RESOLUTION 14
+#define BATTERY_SENSE_SAMPLES 30
+
+#define PIN_NFC1 (9)
+#define PIN_NFC2 (10)
+
+// I2C
+#define WIRE_INTERFACES_COUNT 1
+#define PIN_WIRE_SDA (32 + 9)
+#define PIN_WIRE_SCL (8)
+
+// Peripheral power enable
+#define PIN_POWER_EN (27)
+
+// Solar charger status
+#define EXT_CHRG_DETECT (15)
+#define EXT_CHRG_DETECT_VALUE LOW
+
+// QSPI Flash
+#define PIN_QSPI_SCK (32 + 3)
+#define PIN_QSPI_CS (23)
+#define PIN_QSPI_IO0 (32 + 1)
+#define PIN_QSPI_IO1 (32 + 2)
+#define PIN_QSPI_IO2 (32 + 4)
+#define PIN_QSPI_IO3 (32 + 5)
+
+#define EXTERNAL_FLASH_DEVICES MX25R1635F
+#define EXTERNAL_FLASH_USE_QSPI
+#define VDD_FLASH_EN (21)
+
+// LoRa SX1262
+#define USE_SX1262
+#define SX126X_CS (32 + 12)
+#define SX126X_DIO1 (32 + 6)
+#define SX126X_BUSY (32 + 11)
+#define SX126X_RESET (32 + 10)
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 3.3
+
+// GPS L76K
+#define GPS_L76K
+#define GPS_BAUDRATE 9600
+#define PIN_GPS_EN (6)
+#define PIN_GPS_REINIT (29)
+#define PIN_GPS_STANDBY (30)
+#define PIN_GPS_PPS (31)
+#define GPS_TX_PIN (3)
+#define GPS_RX_PIN (2)
+#define GPS_THREAD_INTERVAL 50
+
+#define PIN_SERIAL1_RX GPS_TX_PIN
+#define PIN_SERIAL1_TX GPS_RX_PIN
+
+// Secondary UART
+#define PIN_SERIAL2_RX (22)
+#define PIN_SERIAL2_TX (24)
+
+// PCF8563 RTC Module
+#define PCF8563_RTC 0x51
+
+// SPI
+#define SPI_INTERFACES_COUNT 1
+#define PIN_SPI_MISO (32 + 15)
+#define PIN_SPI_MOSI (32 + 14)
+#define PIN_SPI_SCK (32 + 13)
+
+// Battery
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 3.0
+#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
+#define ADC_MULTIPLIER (1.75F)
+
+#define HAS_SOLAR
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/variants/nrf52840/muzi_base/platformio.ini b/variants/nrf52840/muzi_base/platformio.ini
new file mode 100644
index 000000000..49393f4e0
--- /dev/null
+++ b/variants/nrf52840/muzi_base/platformio.ini
@@ -0,0 +1,15 @@
+[env:muzi-base]
+extends = nrf52840_base
+board = muzi-base
+build_flags = ${nrf52840_base.build_flags}
+ -I variants/nrf52840/muzi_base
+ -D MUZI_BASE
+ -D CONFIG_NFCT_PINS_AS_GPIOS=1
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
+
+build_src_filter = ${nrf52840_base.build_src_filter} +<../variants/nrf52840/muzi_base>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+ artronshop/ArtronShop_RX8130CE@1.0.0
+
+
diff --git a/variants/nrf52840/muzi_base/rfswitch.h b/variants/nrf52840/muzi_base/rfswitch.h
new file mode 100644
index 000000000..589f24767
--- /dev/null
+++ b/variants/nrf52840/muzi_base/rfswitch.h
@@ -0,0 +1,11 @@
+#include "RadioLib.h"
+
+static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
+
+static const Module::RfSwitchMode_t rfswitch_table[] = {
+ // mode DIO5 DIO6
+ {LR11x0::MODE_STBY, {LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW}},
+ {LR11x0::MODE_TX, {LOW, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH}},
+ {LR11x0::MODE_TX_HF, {LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW}},
+ {LR11x0::MODE_WIFI, {LOW, LOW}}, END_OF_MODE_TABLE,
+};
diff --git a/variants/nrf52840/muzi_base/variant.cpp b/variants/nrf52840/muzi_base/variant.cpp
new file mode 100644
index 000000000..da01de974
--- /dev/null
+++ b/variants/nrf52840/muzi_base/variant.cpp
@@ -0,0 +1,83 @@
+#include "variant.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+
+ // P1
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+};
+
+void initVariant()
+{
+ // Initialize the digital pins as inputs or outputs
+ pinMode(PIN_LED1, OUTPUT);
+ digitalWrite(PIN_LED1, HIGH);
+
+ pinMode(PIN_LED2, OUTPUT);
+ digitalWrite(PIN_LED2, HIGH);
+
+ // Initialize LoRa pins
+ pinMode(SX126X_RESET, OUTPUT);
+ digitalWrite(SX126X_RESET, HIGH);
+
+ pinMode(SX126X_CS, OUTPUT);
+ digitalWrite(SX126X_CS, HIGH);
+
+ pinMode(GPS_EN_GPIO, OUTPUT);
+ digitalWrite(GPS_EN_GPIO, HIGH); // GPS on initially
+
+ pinMode(SCREEN_12V_ENABLE, OUTPUT);
+ digitalWrite(SCREEN_12V_ENABLE, LOW); //
+
+ pinMode(BATTERY_CHARGING_INV, INPUT);
+}
diff --git a/variants/nrf52840/muzi_base/variant.h b/variants/nrf52840/muzi_base/variant.h
new file mode 100644
index 000000000..d3e315f8b
--- /dev/null
+++ b/variants/nrf52840/muzi_base/variant.h
@@ -0,0 +1,192 @@
+#pragma once
+
+#ifndef _VARIANT_MUZI_BASE_
+#define _VARIANT_MUZI_BASE_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+#define USE_LFXO // Board uses 32khz crystal for LF
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (6)
+#define NUM_ANALOG_OUTPUTS (0)
+
+// Define I2C Peripherals
+#define WIRE_INTERFACES_COUNT 2
+
+// this is the OLED bus
+#define PIN_WIRE_SDA (0 + 24) // P0.24
+#define PIN_WIRE_SCL (0 + 25) // P0.25
+
+// IMU bus
+#define PIN_WIRE1_SDA (0 + 04) // P0.04
+#define PIN_WIRE1_SCL (0 + 06) // P0.06
+
+#define COMPASS_ORIENTATION meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270
+#define HAS_ICM20948 // forces the i2c address to be seen as this sensor
+
+#define HAS_RTC 1
+#define RX8130CE_RTC 0x32
+
+// LEDs
+#define PIN_LED1 (32 + 3) // P1.03, Green
+#define PIN_LED2 (32 + 4) // P1.04, Blue
+
+#define LED_BUILTIN -1 // PIN_LED1
+#define LED_BLUE PIN_LED2
+#define LED_STATE_ON 0 // State when LED is lit
+
+// Buttons
+#define HAS_TRACKBALL 1
+#define TB_UP (0 + 21)
+#define TB_DOWN (0 + 17)
+#define TB_LEFT (32 + 05)
+#define TB_RIGHT (0 + 16)
+#define TB_PRESS (0 + 10)
+#define TB_DIRECTION FALLING
+
+#define CANCEL_BUTTON_PIN (0 + 15) // P0.15
+#define CANCEL_BUTTON_ACTIVE_LOW true
+#define CANCEL_BUTTON_ACTIVE_PULLUP false
+
+// Switch
+#define SWITCH_MODE1 (32 + 9) // P1.09, Top Position
+#define SWITCH_MODE2 (0 + 12) // P0.12, Middle Position
+#define PIN_GPS_SWITCH SWITCH_MODE2
+
+/*
+ * SPI Interfaces
+ */
+
+#define SPI_INTERFACES_COUNT 1
+
+// For LORA, spi 0
+#define PIN_SPI_MISO (32 + 15) // P1.15
+#define PIN_SPI_MOSI (32 + 14) // P1.14
+#define PIN_SPI_SCK (32 + 13) // P1.13
+
+#define LORA_SCK PIN_SPI_SCK
+#define LORA_MISO PIN_SPI_MISO
+#define LORA_MOSI PIN_SPI_MOSI
+#define LORA_CS (32 + 12) // P1.12
+
+#define USE_SX1262
+#define SX126X_CS LORA_CS
+#define SX126X_DIO1 (32 + 6) // P1.06
+#define SX126X_BUSY (32 + 11) // P1.11
+#define SX126X_RESET (32 + 10) // P1.10
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 3.3
+
+#define USE_LR1121
+#define LR1121_IRQ_PIN (32 + 8) // P1.08
+#define LR1121_NRESET_PIN (32 + 10) // P1.10
+#define LR1121_BUSY_PIN (32 + 11) // P1.11
+#define LR1121_SPI_NSS_PIN LORA_CS
+#define LR1121_SPI_SCK_PIN LORA_SCK
+#define LR1121_SPI_MOSI_PIN LORA_MOSI
+#define LR1121_SPI_MISO_PIN LORA_MISO
+#define LR11X0_DIO3_TCXO_VOLTAGE 3.0
+#define LR11X0_DIO_AS_RF_SWITCH
+
+// GPS
+#define GPS_RX_PIN (0 + 19) // P0.19
+#define GPS_TX_PIN (0 + 20) // P0.20
+#define GPS_EN_GPIO (32 + 1) // P1.01
+
+#define PIN_SERIAL1_RX GPS_TX_PIN
+#define PIN_SERIAL1_TX GPS_RX_PIN
+
+#define PIN_BUZZER (0 + 22) // P0.22
+
+// Battery monitoring
+#define BATTERY_PIN (0 + 31) // P0.31
+
+// #define CHARGER_FAULT (0 + 27) // P0.27
+#define BATTERY_CHARGING_INV (32 + 02) // P1.02
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+#define ADC_MULTIPLIER 1.537
+
+#define OCV_ARRAY 4050, 4010, 3990, 3930, 3870, 3820, 3740, 3630, 3550, 3450, 3100
+
+// Display - I2C display
+#define HAS_SCREEN 1
+#define SCREEN_12V_ENABLE (0 + 23) // P0.23
+#define USE_SH1107
+
+#define USERPREFS_OEM_TEXT "muzi_works_logo"
+#define USERPREFS_OEM_FONT_SIZE 0
+#define USERPREFS_OEM_IMAGE_WIDTH 88 // 11 bytes wide
+#define USERPREFS_OEM_IMAGE_HEIGHT 47 // 517 bytes total
+#define USERPREFS_OEM_IMAGE_DATA \
+ { \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, \
+ 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x7F, 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, 0xC0, 0x03, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0xF7, 0x0F, 0xFF, 0x00, 0xF0, 0xFF, 0x0F, 0xC0, 0xFF, 0x07, 0x78, 0xFF, 0x9F, 0xFF, 0x01, 0xF0, 0xFF, 0x0F, 0xC0, \
+ 0xFF, 0x03, 0x78, 0x3F, 0xFE, 0xF3, 0x01, 0xF0, 0xFF, 0x0F, 0x00, 0xE0, 0x03, 0x78, 0x1F, 0xFC, 0xC0, 0x03, 0xF0, \
+ 0xFF, 0x0F, 0x00, 0xE0, 0x01, 0x78, 0x0F, 0xF8, 0x80, 0x03, 0xF0, 0xFF, 0x0F, 0x00, 0xF0, 0x00, 0x78, 0x0F, 0x78, \
+ 0x80, 0x03, 0xF0, 0xFF, 0x0F, 0x00, 0x70, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, 0xF0, 0xFF, 0x0F, 0x00, 0x78, 0x00, \
+ 0x78, 0x07, 0x70, 0x80, 0x03, 0xF0, 0xFF, 0x0F, 0x00, 0x3C, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, 0xF0, 0xFF, 0x0F, \
+ 0x00, 0x1C, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, 0xF0, 0xFF, 0x0F, 0x00, 0x1E, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, \
+ 0xE0, 0xFF, 0x0F, 0x00, 0x0F, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, 0xE0, 0xFF, 0x07, 0x80, 0x07, 0x00, 0x78, 0x07, \
+ 0x70, 0x80, 0x03, 0xC0, 0xFF, 0x07, 0x80, 0x07, 0x00, 0x78, 0x07, 0x70, 0x80, 0x03, 0xC0, 0xFF, 0x03, 0xC0, 0xFF, \
+ 0x07, 0x78, 0x07, 0x70, 0x80, 0x03, 0x00, 0xFF, 0x01, 0xE0, 0xFF, 0x07, 0x78, 0x07, 0x70, 0x80, 0x03, 0x00, 0x7C, \
+ 0x00, 0xF0, 0xFF, 0x07, 0x78, 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xE3, 0xE7, 0xC7, 0x1F, 0xF8, 0x0F, 0xF0, 0xE7, 0xE3, 0x07, 0x7C, 0xC7, 0xE7, \
+ 0xC3, 0x0F, 0xE0, 0x07, 0xE0, 0xC7, 0xE1, 0x03, 0x70, 0xC7, 0xC3, 0xE3, 0x87, 0xC1, 0x07, 0xC0, 0xC7, 0xF8, 0xE3, \
+ 0x71, 0xC7, 0xC3, 0xE3, 0xE3, 0xC7, 0xC7, 0xC7, 0x47, 0xF8, 0xF3, 0x7F, 0x8F, 0xC3, 0xF1, 0xE3, 0x8F, 0xC7, 0x8F, \
+ 0x27, 0xFC, 0xE3, 0x7F, 0x8F, 0x81, 0xF1, 0xF1, 0x8F, 0xC7, 0xCF, 0x07, 0xFE, 0x03, 0x7E, 0x8F, 0x99, 0xF1, 0xF1, \
+ 0x8F, 0x07, 0xC0, 0x07, 0xFF, 0x07, 0x78, 0x9F, 0x99, 0xF9, 0xF1, 0x8F, 0x07, 0xE0, 0x07, 0xFE, 0x3F, 0x70, 0x1F, \
+ 0x18, 0xF8, 0xF3, 0x8F, 0x07, 0xF0, 0x27, 0xFC, 0xFF, 0x71, 0x3F, 0x18, 0xF8, 0xE3, 0xC7, 0xC7, 0xF1, 0x47, 0xF8, \
+ 0xF3, 0x63, 0x3F, 0x3C, 0xFC, 0xC3, 0xC3, 0xC7, 0xE3, 0xC7, 0xF0, 0xE1, 0x71, 0x3F, 0x3C, 0xFC, 0x07, 0xE0, 0xC7, \
+ 0xC7, 0xC7, 0xE1, 0x03, 0x70, 0x7F, 0x7E, 0xFE, 0x0F, 0xF0, 0xC7, 0x87, 0xC7, 0xC3, 0x07, 0x78, 0xFF, 0xFF, 0xFF, \
+ 0x7F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0x7F \
+ }
+
+// QSPI Pins
+#define PIN_QSPI_SCK (0 + 3)
+#define PIN_QSPI_CS (0 + 26)
+#define PIN_QSPI_IO0 (0 + 30)
+#define PIN_QSPI_IO1 (0 + 29)
+#define PIN_QSPI_IO2 (0 + 28)
+#define PIN_QSPI_IO3 (0 + 2)
+
+// On-board QSPI Flash
+#define EXTERNAL_FLASH_DEVICES W25Q32JVSS
+#define EXTERNAL_FLASH_USE_QSPI
+
+// NFC is disabled via CONFIG_NFCT_PINS_AS_GPIOS=1 build flag
+// This configures P0.09 and P0.10 as regular GPIO pins instead of NFC pins
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+#ifdef __cplusplus
+#endif
+
+#endif // _VARIANT_MUZI_BASE_
\ No newline at end of file
diff --git a/variants/nrf52840/r1-neo/variant.h b/variants/nrf52840/r1-neo/variant.h
index 901e993e3..b1d96ebd0 100644
--- a/variants/nrf52840/r1-neo/variant.h
+++ b/variants/nrf52840/r1-neo/variant.h
@@ -132,7 +132,8 @@ static const uint8_t SCK = PIN_SPI_SCK;
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
-#define ADC_MULTIPLIER 1.73
+#define ADC_MULTIPLIER 1.667
+#define OCV_ARRAY 4120, 4020, 4000, 3940, 3870, 3820, 3750, 3630, 3550, 3450, 3100
#define HAS_RTC 1