diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 6ccb4a105..a15b34aae 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,7 +1,6 @@
+## 🙏 Thank you for sending in a pull request, here's some tips to get started!
+
### ❌ (Please delete all these tips and replace them with your text) ❌
-
-## Thank you for sending in a pull request, here's some tips to get started!
-
- Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first
to say "Hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
@@ -12,4 +11,17 @@
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.
- Please also enable "Allow edits by maintainers".
+- Please do not submit untested code.
+- If you do not have the affected hardware to test your code changes adequately against regressions, please indicate this, so that contributors and commnunity members can help test your changes.
- If your PR gets accepted you can request a "Contributor" role in the Meshtastic Discord
+
+
+## 🤝 Attestations
+- [ ] I have tested that my proposed changes behave as described.
+- [ ] I have tested that my proposed changes do not cause any obvious regressions on the following devices:
+ - [ ] Heltec (Lora32) V3
+ - [ ] LilyGo T-Deck
+ - [ ] LilyGo T-Beam
+ - [ ] RAK WisBlock 4631
+ - [ ] Seeed Studio T-1000E tracker card
+ - [ ] Other (please specify below)
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index b44f46a51..8f938ce9e 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -10,13 +10,13 @@ lint:
enabled:
- prettier@3.5.3
- trufflehog@3.88.18
- - yamllint@1.36.2
+ - yamllint@1.37.0
- bandit@1.8.3
- - checkov@3.2.390
+ - checkov@3.2.394
- terrascan@1.19.9
- trivy@0.60.0
- taplo@0.9.3
- - ruff@0.11.1
+ - ruff@0.11.2
- isort@6.0.1
- markdownlint@0.44.0
- oxipng@9.1.4
@@ -28,7 +28,7 @@ lint:
- shellcheck@0.10.0
- black@25.1.0
- git-diff-check
- - gitleaks@8.24.0
+ - gitleaks@8.24.2
- clang-format@16.0.3
ignore:
- linters: [ALL]
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index 256781ba1..df3778002 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -45,11 +45,11 @@ lib_deps =
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
- https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
+ https://github.com/meshtastic/esp32_https_server/archive/23665b3adc080a311dcbb586ed5941b5f94d6ea2.zip
h2zero/NimBLE-Arduino@^1.4.3
- https://github.com/dbinfrago/libpax.git#3cdc0371c375676a97967547f4065607d4c53fd1
+ https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
lewisxhe/XPowersLib@^0.2.7
- https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
+ https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
rweather/Crypto@^0.4.0
lib_ignore =
diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini
index d0425812f..dba3bac08 100644
--- a/arch/esp32/esp32c6.ini
+++ b/arch/esp32/esp32c6.ini
@@ -1,6 +1,6 @@
[esp32c6_base]
extends = esp32_base
-platform = https://github.com/Jason2866/platform-espressif32.git#22faa566df8c789000f8136cd8d0aca49617af55
+platform = https://github.com/Jason2866/platform-espressif32/archive/22faa566df8c789000f8136cd8d0aca49617af55.zip
build_flags =
${arduino_base.build_flags}
-Wall
@@ -25,7 +25,7 @@ lib_deps =
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
lewisxhe/XPowersLib@^0.2.7
- https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
+ https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
rweather/Crypto@^0.4.0
build_src_filter =
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index d4e88af1f..ca12be6b1 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -1,10 +1,10 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
-platform = platformio/nordicnrf52@^10.7.0
+platform = platformio/nordicnrf52@^10.8.0
extends = arduino_base
platform_packages =
; our custom Git version until they merge our PR
- platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino.git#e13f5820002a4fb2a5e6754b42ace185277e5adf
+ platformio/framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino#e13f5820002a4fb2a5e6754b42ace185277e5adf
platformio/toolchain-gccarmnoneeabi@~1.90301.0
build_type = debug
diff --git a/arch/nrf52/nrf52840.ini b/arch/nrf52/nrf52840.ini
index a13a600f3..0dab5d9ba 100644
--- a/arch/nrf52/nrf52840.ini
+++ b/arch/nrf52/nrf52840.ini
@@ -6,7 +6,7 @@ build_flags = ${nrf52_base.build_flags}
lib_deps =
${nrf52_base.lib_deps}
${environmental_base.lib_deps}
- https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
+ https://github.com/Kongduino/Adafruit_nRFCrypto/archive/e31a8825ea3300b163a0a3c1ddd5de34e10e1371.zip
; Common NRF52 debugging settings follow. See the Meshtastic developer docs for how to connect SWD debugging probes to your board.
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index 55234914f..e0488aeff 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -1,6 +1,6 @@
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
[portduino_base]
-platform = https://github.com/meshtastic/platform-native.git#e82ba1a19b6cd1dc55cbde29b33ea8dd0640014f
+platform = https://github.com/meshtastic/platform-native/archive/c5bd469ab9b5a6966321e09557b27d906961da63.zip
framework = arduino
build_src_filter =
@@ -26,7 +26,7 @@ lib_deps =
${radiolib_base.lib_deps}
rweather/Crypto@^0.4.0
lovyan03/LovyanGFX@^1.2.0
- https://github.com/pine64/libch341-spi-userspace#a9b17e3452f7fb747000d9b4ad4409155b39f6ef
+ https://github.com/pine64/libch341-spi-userspace/archive/a9b17e3452f7fb747000d9b4ad4409155b39f6ef.zip
build_flags =
${arduino_base.build_flags}
diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini
index 1542dbee7..33fcfb211 100644
--- a/arch/rp2xx0/rp2040.ini
+++ b/arch/rp2xx0/rp2040.ini
@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
+platform = https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.4.3
+platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini
index 6f1e4400e..841035c80 100644
--- a/arch/rp2xx0/rp2350.ini
+++ b/arch/rp2xx0/rp2350.ini
@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2350_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
+platform = https://github.com/maxgerhardt/platform-raspberrypi#76ecf3c7e9dd4503af0331154c4ca1cddc4b03e5 ; For arduino-pico >= 4.4.3
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.4.3
+platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico#4.4.3
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini
index d5e615f5f..c1b58bb82 100644
--- a/arch/stm32/stm32.ini
+++ b/arch/stm32/stm32.ini
@@ -1,7 +1,7 @@
[stm32_base]
extends = arduino_base
platform = ststm32
-platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32.git#2.9.0
+platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
extra_scripts =
${env.extra_scripts}
post:extra_scripts/extra_stm32.py
@@ -35,7 +35,7 @@ debug_tool = stlink
lib_deps =
${env.lib_deps}
${radiolib_base.lib_deps}
- https://github.com/caveman99/Crypto.git#eae9c768054118a9399690f8af202853d1ae8516
+ https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip
lib_ignore =
mathertel/OneButton@2.6.1
diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml
index da4c192c7..722f80fae 100644
--- a/bin/config-dist.yaml
+++ b/bin/config-dist.yaml
@@ -6,6 +6,12 @@
### Including the "Module:" line!
---
Lora:
+ # Default to auto-detecting the module type
+ # This will be overridden by configs from config.d
+ Module: auto
+
+# # Uncomment to enable Simulation mode, or use --sim
+# Module: sim
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
# CS: 7
diff --git a/bin/config.d/lora-Adafruit-RFM9x b/bin/config.d/lora-Adafruit-RFM9x
deleted file mode 100644
index 2d64f1f91..000000000
--- a/bin/config.d/lora-Adafruit-RFM9x
+++ /dev/null
@@ -1,5 +0,0 @@
-# Module: RF95 # Adafruit RFM9x
-# Reset: 25
-# CS: 7
-# IRQ: 22
-# Busy: 23
\ No newline at end of file
diff --git a/bin/config.d/lora-Adafruit-RFM9x.yaml b/bin/config.d/lora-Adafruit-RFM9x.yaml
new file mode 100644
index 000000000..20295dc72
--- /dev/null
+++ b/bin/config.d/lora-Adafruit-RFM9x.yaml
@@ -0,0 +1,6 @@
+Lora:
+ Module: RF95 # Adafruit RFM9x
+ Reset: 25
+ CS: 7
+ IRQ: 22
+# Busy: 23
diff --git a/bin/device-install.bat b/bin/device-install.bat
index 3ffca0b63..594d973f5 100755
--- a/bin/device-install.bat
+++ b/bin/device-install.bat
@@ -17,8 +17,8 @@ SET "LOGCOUNTER=0"
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone"
SET "C3=esp32c3"
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
-SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
-SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite t-watch-s3"
+SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core t-watch-s3 tracksenger"
+SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite"
GOTO getopts
:help
diff --git a/bin/device-install.sh b/bin/device-install.sh
index b5322b9d1..bacf48f69 100755
--- a/bin/device-install.sh
+++ b/bin/device-install.sh
@@ -22,6 +22,7 @@ BIGDB_8MB=(
"icarus"
"seeed-xiao-s3"
"tbeam-s3-core"
+ "t-watch-s3"
"tracksenger"
)
BIGDB_16MB=(
@@ -33,7 +34,6 @@ BIGDB_16MB=(
"m5stack-cores3"
"station-g2"
"t-eth-elite"
- "t-watch-s3"
)
S3_VARIANTS=(
"s3"
diff --git a/boards/ThinkNode-M1.json b/boards/ThinkNode-M1.json
new file mode 100644
index 000000000..e55da3ec7
--- /dev/null
+++ b/boards/ThinkNode-M1.json
@@ -0,0 +1,53 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x4405"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"]
+ ],
+ "usb_product": "elecrow_eink",
+ "mcu": "nrf52840",
+ "variant": "ELECROW-ThinkNode-M1",
+ "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 eink",
+ "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": "FIXME",
+ "vendor": "ELECROW"
+}
diff --git a/platformio.ini b/platformio.ini
index 3de5b715f..010aea90f 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -56,11 +56,11 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200
monitor_filters = direct
lib_deps =
- https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95
+ https://github.com/meshtastic/esp8266-oled-ssd1306/archive/e16cee124fe26490cb14880c679321ad8ac89c95.zip
mathertel/OneButton@2.6.1
- https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
- https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
- https://github.com/meshtastic/ArduinoThread.git#7c3ee9e1951551b949763b1f5280f8db1fa4068d
+ https://github.com/meshtastic/arduino-fsm/archive/7db3702bf0cfe97b783d6c72595e3f38e0b19159.zip
+ https://github.com/meshtastic/TinyGPSPlus/archive/71a82db35f3b973440044c476d4bcdc673b104f4.zip
+ https://github.com/meshtastic/ArduinoThread/archive/7c3ee9e1951551b949763b1f5280f8db1fa4068d.zip
nanopb/Nanopb@0.4.91
erriez/ErriezCRC32@1.0.1
@@ -94,18 +94,18 @@ lib_deps =
[device-ui_base]
lib_deps =
- https://github.com/meshtastic/device-ui.git#7a6ffba3c86901b0e3234b6c056aa803b4cd8854
+ https://github.com/meshtastic/device-ui/archive/99171e87a70452395b56cce713a951c1c2964370.zip
; Common libs for environmental measurements in telemetry module
; (not included in native / portduino)
[environmental_base]
lib_deps =
- adafruit/Adafruit BusIO@1.16.2
- adafruit/Adafruit Unified Sensor@1.1.14
+ adafruit/Adafruit BusIO@1.17.0
+ adafruit/Adafruit Unified Sensor@1.1.15
adafruit/Adafruit BMP280 Library@2.6.8
adafruit/Adafruit BMP085 Library@1.2.4
adafruit/Adafruit BME280 Library@2.2.4
- adafruit/Adafruit BMP3XX Library@2.1.5
+ adafruit/Adafruit BMP3XX Library@2.1.6
adafruit/Adafruit DPS310@1.1.5
adafruit/Adafruit MCP9808 Library@2.0.2
adafruit/Adafruit INA260 Library@1.5.2
@@ -114,27 +114,27 @@ lib_deps =
adafruit/Adafruit SHTC3 Library@1.0.1
adafruit/Adafruit LPS2X@2.0.6
adafruit/Adafruit SHT31 Library@2.2.2
- adafruit/Adafruit PM25 AQI Sensor@1.1.1
+ adafruit/Adafruit PM25 AQI Sensor@1.2.0
adafruit/Adafruit MPU6050@2.2.6
adafruit/Adafruit LIS3DH@1.3.0
adafruit/Adafruit AHTX0@2.0.5
- adafruit/Adafruit LSM6DS@4.7.3
+ adafruit/Adafruit LSM6DS@4.7.4
adafruit/Adafruit VEML7700 Library@2.1.6
adafruit/Adafruit SHT4x Library@1.0.5
adafruit/Adafruit TSL2591 Library@1.4.5
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
- sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13
+ sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.3.0
ClosedCube OPT3001@1.1.2
emotibit/EmotiBit MLX90632@1.0.8
adafruit/Adafruit MLX90614 Library@2.1.5
- https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
+ https://github.com/boschsensortec/Bosch-BSEC2-Library/archive/v1.7.2502.zip
boschsensortec/BME68x Sensor Library@1.1.40407
- https://github.com/KodinLanewave/INA3221@1.0.1
+ https://github.com/KodinLanewave/INA3221/archive/1.0.1.zip
mprograms/QMC5883LCompass@1.2.3
dfrobot/DFRobot_RTU@1.0.3
- https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d
- https://github.com/DFRobot/DFRobot_RainfallSensor#38fea5e02b40a5430be6dab39a99a6f6347d667e
- robtillaart/INA226@0.6.0
+ https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
+ https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
+ robtillaart/INA226@0.6.4
; Health Sensor Libraries
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
diff --git a/protobufs b/protobufs
index b4044f8f9..484d002a5 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit b4044f8f9f3681d4d20521dbe13ee42c96eae353
+Subproject commit 484d002a52bc20fa9f91ebf1b216d585c5f93a1b
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index 12f81353c..2363f804c 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -73,23 +73,28 @@ ButtonThread::ButtonThread() : OSThread("Button")
userButton.setDebounceMs(1);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed, this); // Reference to instance: get click count from non-static OneButton
-#ifndef T_DECK // T-Deck immediately wakes up after shutdown, so disable this function
+#if !defined(T_DECK) && \
+ !defined( \
+ ELECROW_ThinkNode_M2) // T-Deck immediately wakes up after shutdown, Thinknode M2 has this on the smaller ALT button
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
#endif
#endif
#ifdef BUTTON_PIN_ALT
- userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
+#if defined(ELECROW_ThinkNode_M2)
+ this->userButtonAlt = OneButton(BUTTON_PIN_ALT, false, false);
+#else
+ this->userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
+#endif
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
#endif
- userButtonAlt.attachClick(userButtonPressed);
+ userButtonAlt.attachClick(userButtonPressedScreen);
userButtonAlt.setClickMs(BUTTON_CLICK_MS);
userButtonAlt.setPressMs(BUTTON_LONGPRESS_MS);
userButtonAlt.setDebounceMs(1);
- userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
#endif
@@ -117,6 +122,40 @@ int32_t ButtonThread::runOnce()
canSleep = true; // Assume we should not keep the board awake
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
+ // #if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
+ // buzzer_updata();
+ // if (buttonPressed) {
+ // buttonPressed = false; // 清除标志
+ // LOG_INFO("PIN_BUTTON2 pressed!"); // 串口打印信息
+ // // off_currentTime = millis();
+ // while (digitalRead(PIN_BUTTON2) == HIGH) {
+ // if (cont < 40) {
+ // // unsigned long currentTime = millis(); // 获取当前时间
+ // // if (currentTime - off_currentTime >= 1000) {
+ // cont++;
+ // // off_currentTime = currentTime;
+ // // }
+ // delay(100);
+ // } else {
+
+ // currentState = OFF;
+ // isBuzzing = false;
+ // cont = 0;
+ // BEEP_STATE = false;
+ // analogWrite(M2_buzzer, 0);
+ // pinMode(M2_buzzer, INPUT);
+ // screen->setOn(false);
+ // cont = 0;
+ // LOG_INFO("GGGGGGGGGGGGGGGGGGGGGGGGG");
+ // pinMode(1, OUTPUT);
+ // digitalWrite(1, LOW);
+ // pinMode(6, OUTPUT);
+ // digitalWrite(6, LOW);
+ // }
+ // }
+ // }
+
+ // #endif
userButton.tick();
canSleep &= userButton.isIdle();
#elif defined(ARCH_PORTDUINO)
@@ -166,6 +205,14 @@ int32_t ButtonThread::runOnce()
break;
}
+ case BUTTON_EVENT_PRESSED_SCREEN: {
+ // turn screen on or off
+ screen_flag = !screen_flag;
+ if (screen)
+ screen->setOn(screen_flag);
+ break;
+ }
+
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!");
service->refreshLocalMeshNode();
@@ -192,7 +239,16 @@ int32_t ButtonThread::runOnce()
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;
+#elif defined(ELECROW_ThinkNode_M2)
+ case 3:
+ LOG_INFO("3 clicks: toggle buzzer");
+ buzzer_flag = !buzzer_flag;
+ if (buzzer_flag) {
+ playBeep();
+ }
+ break;
#endif
+
#if defined(USE_EINK) && defined(PIN_EINK_EN) // i.e. T-Echo
// 4 clicks: toggle backlight
case 4:
diff --git a/src/ButtonThread.h b/src/ButtonThread.h
index 54b833d03..a8f1f77c3 100644
--- a/src/ButtonThread.h
+++ b/src/ButtonThread.h
@@ -24,6 +24,7 @@ class ButtonThread : public concurrency::OSThread
enum ButtonEventType {
BUTTON_EVENT_NONE,
BUTTON_EVENT_PRESSED,
+ BUTTON_EVENT_PRESSED_SCREEN,
BUTTON_EVENT_DOUBLE_PRESSED,
BUTTON_EVENT_MULTI_PRESSED,
BUTTON_EVENT_LONG_PRESSED,
@@ -42,7 +43,6 @@ class ButtonThread : public concurrency::OSThread
int beforeLightSleep(void *unused);
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
#endif
-
private:
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
static OneButton userButton; // Static - accessed from an interrupt
@@ -64,6 +64,8 @@ class ButtonThread : public concurrency::OSThread
// set during IRQ
static volatile ButtonEventType btnEvent;
+ bool buzzer_flag = false;
+ bool screen_flag = true;
// Store click count during callback, for later use
volatile int multipressClickCount = 0;
@@ -72,6 +74,12 @@ class ButtonThread : public concurrency::OSThread
// IRQ callbacks
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
+ static void userButtonPressedScreen()
+ {
+ if (millis() > c_holdOffTime) {
+ btnEvent = BUTTON_EVENT_PRESSED_SCREEN;
+ }
+ }
static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_PRESSED; }
static void userButtonMultiPressed(void *callerThread); // Retrieve click count from non-static Onebutton while still valid
static void userButtonPressedLongStart();
diff --git a/src/Power.cpp b/src/Power.cpp
index 8c2ef998d..0dec0fc21 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -533,6 +533,9 @@ Power::Power() : OSThread("Power")
{
statusHandler = {};
low_voltage_counter = 0;
+#if defined(ELECROW_ThinkNode_M1) || defined(POWER_CFG)
+ low_voltage_counter_led3 = 0;
+#endif
#ifdef DEBUG_HEAP
lastheap = memGet.getFreeHeap();
#endif
@@ -668,12 +671,12 @@ void Power::readPowerStatus()
int8_t batteryChargePercent = -1;
OptionalBool usbPowered = OptUnknown;
OptionalBool hasBattery = OptUnknown; // These must be static because NRF_APM code doesn't run every time
- OptionalBool isCharging = OptUnknown;
+ OptionalBool isChargingNow = OptUnknown;
if (batteryLevel) {
hasBattery = batteryLevel->isBatteryConnect() ? OptTrue : OptFalse;
usbPowered = batteryLevel->isVbusIn() ? OptTrue : OptFalse;
- isCharging = batteryLevel->isCharging() ? OptTrue : OptFalse;
+ isChargingNow = batteryLevel->isCharging() ? OptTrue : OptFalse;
if (hasBattery) {
batteryVoltageMv = batteryLevel->getBattVoltage();
// If the AXP192 returns a valid battery percentage, use it
@@ -702,17 +705,20 @@ void Power::readPowerStatus()
// If changed to DISCONNECTED
if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED)
- isCharging = usbPowered = OptFalse;
+ isChargingNow = usbPowered = OptFalse;
// If changed to CONNECTED / READY
else
- isCharging = usbPowered = OptTrue;
+ isChargingNow = usbPowered = OptTrue;
#endif
// Notify any status instances that are observing us
- const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isCharging, batteryVoltageMv, batteryChargePercent);
+ const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isChargingNow, batteryVoltageMv, batteryChargePercent);
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(),
powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
+#if defined(ELECROW_ThinkNode_M1) || defined(POWER_CFG)
+ power_num = powerStatus2.getBatteryVoltageMv();
+#endif
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != memGet.getFreeHeap()) {
@@ -756,9 +762,13 @@ void Power::readPowerStatus()
// If we have a battery at all and it is less than 0%, force deep sleep if we have more than 10 low readings in
// a row. NOTE: min LiIon/LiPo voltage is 2.0 to 2.5V, current OCV min is set to 3100 that is large enough.
//
+
if (batteryLevel && powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS - 1]) {
low_voltage_counter++;
+#if defined(ELECROW_ThinkNode_M1)
+ low_voltage_counter_led3 = low_voltage_counter;
+#endif
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
@@ -771,7 +781,13 @@ void Power::readPowerStatus()
}
} else {
low_voltage_counter = 0;
+#if defined(ELECROW_ThinkNode_M1)
+ low_voltage_counter_led3 = low_voltage_counter;
+#endif
}
+#ifdef POWER_CFG
+ low_voltage_counter_led3 = low_voltage_counter;
+#endif
}
}
diff --git a/src/buzz/buzz.cpp b/src/buzz/buzz.cpp
index 8db9602bc..6ba2f4140 100644
--- a/src/buzz/buzz.cpp
+++ b/src/buzz/buzz.cpp
@@ -30,8 +30,11 @@ struct ToneDuration {
#define NOTE_B3 247
#define NOTE_CS4 277
-const int DURATION_1_8 = 125; // 1/8 note
-const int DURATION_1_4 = 250; // 1/4 note
+const int DURATION_1_8 = 125; // 1/8 note
+const int DURATION_1_4 = 250; // 1/4 note
+const int DURATION_1_2 = 500; // 1/2 note
+const int DURATION_3_4 = 750; // 1/4 note
+const int DURATION_1_1 = 1000; // 1/1 note
void playTones(const ToneDuration *tone_durations, int size)
{
@@ -55,6 +58,12 @@ void playBeep()
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
+void playLongBeep()
+{
+ ToneDuration melody[] = {{NOTE_B3, DURATION_1_1}};
+ playTones(melody, sizeof(melody) / sizeof(ToneDuration));
+}
+
void playGPSEnableBeep()
{
ToneDuration melody[] = {{NOTE_C3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_CS4, DURATION_1_4}};
diff --git a/src/buzz/buzz.h b/src/buzz/buzz.h
index c52c3020c..adeaca73d 100644
--- a/src/buzz/buzz.h
+++ b/src/buzz/buzz.h
@@ -1,6 +1,7 @@
#pragma once
void playBeep();
+void playLongBeep();
void playStartMelody();
void playShutdownMelody();
void playGPSEnableBeep();
diff --git a/src/configuration.h b/src/configuration.h
index 1a4dbbcc3..fd4a5b196 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -110,11 +110,6 @@ along with this program. If not, see .
// Define if screen should be mirrored left to right
// #define SCREEN_MIRROR
-// Define BUTTON_PIN to ensure button setup is always done
-#ifndef BUTTON_PIN
-#define BUTTON_PIN (-1)
-#endif
-
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index c33cb2975..41a2ff980 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -981,15 +981,16 @@ void GPS::down()
setPowerState(GPS_IDLE);
else {
- // Check whether the GPS hardware is capable of GPS_SOFTSLEEP
- // If not, fallback to GPS_HARDSLEEP instead
+// Check whether the GPS hardware is capable of GPS_SOFTSLEEP
+// If not, fallback to GPS_HARDSLEEP instead
+#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
+ bool softsleepSupported = true;
+#else
bool softsleepSupported = false;
+#endif
// U-blox is supported via PMREQ
if (IS_ONE_OF(gnssModel, GNSS_MODEL_UBLOX6, GNSS_MODEL_UBLOX7, GNSS_MODEL_UBLOX8, GNSS_MODEL_UBLOX9, GNSS_MODEL_UBLOX10))
softsleepSupported = true;
-#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin
- softsleepSupported = true;
-#endif
if (softsleepSupported) {
// How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than
diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp
index a640e3560..96c6b44c1 100644
--- a/src/graphics/EInkDisplay2.cpp
+++ b/src/graphics/EInkDisplay2.cpp
@@ -128,16 +128,24 @@ bool EInkDisplay::connect()
#ifdef PIN_EINK_EN
// backlight power, HIGH is backlight on, LOW is off
pinMode(PIN_EINK_EN, OUTPUT);
+#ifdef ELECROW_ThinkNode_M1
digitalWrite(PIN_EINK_EN, LOW);
+#else
+ digitalWrite(PIN_EINK_EN, HIGH);
+#endif
#endif
-#if defined(TTGO_T_ECHO)
+#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1)
{
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
adafruitDisplay = new GxEPD2_BW(*lowLevel);
adafruitDisplay->init();
+#ifdef ELECROW_ThinkNode_M1
+ adafruitDisplay->setRotation(4);
+#else
adafruitDisplay->setRotation(3);
+#endif
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
}
#elif defined(MESHLINK)
@@ -166,7 +174,8 @@ bool EInkDisplay::connect()
}
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \
- defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER)
+ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
+ defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
{
// Start HSPI
hspi = new SPIClass(HSPI);
@@ -182,7 +191,7 @@ bool EInkDisplay::connect()
// Init GxEPD2
adafruitDisplay->init();
adafruitDisplay->setRotation(3);
-#if defined(CROWPANEL_ESP32S3_5_EPAPER)
+#if defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER)
adafruitDisplay->setRotation(0);
#endif
}
diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h
index efbf45f0f..9c1c8d18e 100644
--- a/src/graphics/EInkDisplay2.h
+++ b/src/graphics/EInkDisplay2.h
@@ -68,7 +68,8 @@ class EInkDisplay : public OLEDDisplay
// If display uses HSPI
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
- defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER)
+ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
+ defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
SPIClass *hspi = NULL;
#endif
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index ecd1a8b1d..5d4205e8e 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -2691,6 +2691,11 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
setScreensaverFrames(einkScreensaver);
#endif
LOG_INFO("Turn off screen");
+#ifdef ELECROW_ThinkNode_M1
+ if (digitalRead(PIN_EINK_EN) == HIGH) {
+ digitalWrite(PIN_EINK_EN, LOW);
+ }
+#endif
dispdev->displayOff();
#ifdef USE_ST7789
SPI1.end();
@@ -3790,7 +3795,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
drawGPSpowerstat(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
}
#endif
- /* Display a heartbeat pixel that blinks every time the frame is redrawn */
+/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
if (heartbeat)
display->setPixel(0, 0);
diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h
index 910d1b0b9..079a3e282 100644
--- a/src/graphics/ScreenFonts.h
+++ b/src/graphics/ScreenFonts.h
@@ -16,6 +16,10 @@
#include "graphics/fonts/OLEDDisplayFontsCS.h"
#endif
+#ifdef CROWPANEL_ESP32S3_5_EPAPER
+#include "graphics/fonts/EinkDisplayFonts.h"
+#endif
+
#ifdef OLED_PL
#define FONT_SMALL_LOCAL ArialMT_Plain_10_PL
#else
@@ -74,13 +78,12 @@
#endif
#if defined(CROWPANEL_ESP32S3_5_EPAPER)
-#include "graphics/fonts/EinkDisplayFonts.h"
#undef FONT_SMALL
#undef FONT_MEDIUM
#undef FONT_LARGE
-#define FONT_SMALL FONT_LARGE_LOCAL // Height: 30
-#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 30
-#define FONT_LARGE FONT_LARGE_LOCAL // Height: 30
+#define FONT_SMALL Monospaced_plain_30
+#define FONT_MEDIUM Monospaced_plain_30
+#define FONT_LARGE Monospaced_plain_30
#endif
#define _fontHeight(font) ((font)[1] + 1) // height is position 1
diff --git a/src/main.cpp b/src/main.cpp
index e9e0c9d4b..59cd6d8e9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -262,6 +262,32 @@ void printInfo()
#ifndef PIO_UNIT_TESTING
void setup()
{
+
+#ifdef POWER_CHRG
+ pinMode(POWER_CHRG, OUTPUT);
+ digitalWrite(POWER_CHRG, HIGH);
+#endif
+
+#if defined(PIN_POWER_EN)
+ pinMode(PIN_POWER_EN, OUTPUT);
+ digitalWrite(PIN_POWER_EN, HIGH);
+#endif
+
+#ifdef LED_POWER
+ pinMode(LED_POWER, OUTPUT);
+ digitalWrite(LED_POWER, HIGH);
+#endif
+
+#ifdef POWER_LED
+ pinMode(POWER_LED, OUTPUT);
+ digitalWrite(POWER_LED, HIGH);
+#endif
+
+#ifdef USER_LED
+ pinMode(USER_LED, OUTPUT);
+ digitalWrite(USER_LED, LOW);
+#endif
+
#if defined(T_DECK)
// GPIO10 manages all peripheral power supplies
// Turn on peripheral power immediately after MUC starts.
@@ -325,13 +351,6 @@ void setup()
initDeepSleep();
- // power on peripherals
-#if defined(PIN_POWER_EN)
- pinMode(PIN_POWER_EN, OUTPUT);
- digitalWrite(PIN_POWER_EN, HIGH);
- // digitalWrite(PIN_POWER_EN1, INPUT);
-#endif
-
#if defined(LORA_TCXO_GPIO)
pinMode(LORA_TCXO_GPIO, OUTPUT);
digitalWrite(LORA_TCXO_GPIO, HIGH);
@@ -825,7 +844,9 @@ void setup()
#ifdef ARCH_PORTDUINO
// FIXME: portduino does not ever call onNetworkConnected so call it here because I don't know what happen if I call
// onNetworkConnected there
- udpThread->start();
+ if (config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
+ udpThread->start();
+ }
#endif
#endif
service = new MeshService();
@@ -1301,5 +1322,4 @@ void loop()
mainDelay.delay(delayMsec);
}
}
-
#endif
diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp
index f1d4926db..4d061f80f 100644
--- a/src/mesh/Channels.cpp
+++ b/src/mesh/Channels.cpp
@@ -347,7 +347,7 @@ bool Channels::anyMqttEnabled()
{
#if USERPREFS_EVENT_MODE
// Don't publish messages on the public MQTT broker if we are in event mode
- if (mqtt && mqtt.isUsingDefaultServer()) {
+ if (mqtt && mqtt->isUsingDefaultServer()) {
return false;
}
#endif
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index df0fbcedd..3f79d18e6 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -1061,8 +1061,8 @@ void NodeDB::loadFromDisk()
// if (state != LoadFileResult::LOAD_SUCCESS) {
// installDefaultDeviceState(); // Our in RAM copy might now be corrupt
//} else {
- if (devicestate.version < DEVICESTATE_MIN_VER) {
- LOG_WARN("Devicestate %d is old, discard", devicestate.version);
+ if ((state != LoadFileResult::LOAD_SUCCESS) || (devicestate.version < DEVICESTATE_MIN_VER)) {
+ LOG_WARN("Devicestate %d is old or invalid, discard", devicestate.version);
installDefaultDeviceState();
} else {
LOG_INFO("Loaded saved devicestate version %d", devicestate.version);
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 992f38ff4..b8b7ee610 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -188,7 +188,7 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
// don't override if a channel was requested and no need to set it when PKI is enforced
if (!p->channel && !p->pki_encrypted && !isBroadcast(p->to)) {
- meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->to);
+ meshtastic_NodeInfoLite const *node = nodeDB->getMeshNode(p->to);
if (node) {
p->channel = node->channel;
LOG_DEBUG("localSend to channel %d", p->channel);
@@ -688,7 +688,7 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
return;
}
- meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->from);
+ meshtastic_NodeInfoLite const *node = nodeDB->getMeshNode(p->from);
if (node != NULL && node->is_ignored) {
LOG_DEBUG("Ignore msg, 0x%x is ignored", p->from);
packetPool.release(p);
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index daee04f90..defaaad28 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -326,7 +326,11 @@ typedef enum _meshtastic_ExcludedModules {
/* Detection Sensor module */
meshtastic_ExcludedModules_DETECTIONSENSOR_CONFIG = 2048,
/* Paxcounter module */
- meshtastic_ExcludedModules_PAXCOUNTER_CONFIG = 4096
+ meshtastic_ExcludedModules_PAXCOUNTER_CONFIG = 4096,
+ /* Bluetooth config (not technically a module, but used to indicate bluetooth capabilities) */
+ meshtastic_ExcludedModules_BLUETOOTH_CONFIG = 8192,
+ /* Network config (not technically a module, but used to indicate network capabilities) */
+ meshtastic_ExcludedModules_NETWORK_CONFIG = 16384
} meshtastic_ExcludedModules;
/* How the location was acquired: manual, onboard GPS, external (EUD) GPS */
@@ -1122,8 +1126,8 @@ extern "C" {
#define _meshtastic_CriticalErrorCode_ARRAYSIZE ((meshtastic_CriticalErrorCode)(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE+1))
#define _meshtastic_ExcludedModules_MIN meshtastic_ExcludedModules_EXCLUDED_NONE
-#define _meshtastic_ExcludedModules_MAX meshtastic_ExcludedModules_PAXCOUNTER_CONFIG
-#define _meshtastic_ExcludedModules_ARRAYSIZE ((meshtastic_ExcludedModules)(meshtastic_ExcludedModules_PAXCOUNTER_CONFIG+1))
+#define _meshtastic_ExcludedModules_MAX meshtastic_ExcludedModules_NETWORK_CONFIG
+#define _meshtastic_ExcludedModules_ARRAYSIZE ((meshtastic_ExcludedModules)(meshtastic_ExcludedModules_NETWORK_CONFIG+1))
#define _meshtastic_Position_LocSource_MIN meshtastic_Position_LocSource_LOC_UNSET
#define _meshtastic_Position_LocSource_MAX meshtastic_Position_LocSource_LOC_EXTERNAL
diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h
index 1c86653dc..f748d295e 100644
--- a/src/mesh/mesh-pb-constants.h
+++ b/src/mesh/mesh-pb-constants.h
@@ -18,6 +18,10 @@
#define MAX_RX_TOPHONE 32
#endif
+/// Verify baseline assumption of node size. If it increases, we need to reevaluate
+/// the impact of its memory footprint, notably on MAX_NUM_NODES.
+static_assert(sizeof(meshtastic_NodeInfoLite) <= 192, "NodeInfoLite size increased. Reconsider impact on MAX_NUM_NODES.");
+
/// max number of nodes allowed in the nodeDB
#ifndef MAX_NUM_NODES
#if defined(ARCH_STM32WL)
diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp
index 92388d52a..e050c2057 100644
--- a/src/mesh/wifi/WiFiAPClient.cpp
+++ b/src/mesh/wifi/WiFiAPClient.cpp
@@ -133,7 +133,7 @@ static void onNetworkConnected()
}
#if HAS_UDP_MULTICAST
- if (udpThread) {
+ if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
udpThread->start();
}
#endif
@@ -163,7 +163,7 @@ static int32_t reconnectWiFi()
delay(5000);
if (!WiFi.isConnected()) {
-#ifdef CONFIG_IDF_TARGET_ESP32C3
+#ifdef ARCH_ESP32
WiFi.mode(WIFI_MODE_NULL);
WiFi.useStaticBuffers(true);
WiFi.mode(WIFI_STA);
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 34ece2312..e088b4612 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -60,7 +60,7 @@
SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio;
-#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK)
+#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
static Print *serialPrint = &Serial;
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
@@ -158,7 +158,7 @@ int32_t SerialModule::runOnce()
Serial.begin(baud);
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
}
-#elif !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(MESHLINK)
+#elif !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1)
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
#ifdef ARCH_RP2040
Serial2.setFIFOSize(RX_BUFFER);
@@ -214,7 +214,7 @@ int32_t SerialModule::runOnce()
}
}
-#if !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(MESHLINK)
+#if !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1)
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
processWXSerial();
@@ -408,6 +408,49 @@ uint32_t SerialModule::getBaudRate()
return BAUD;
}
+// Add this structure to help with parsing WindGust = 24.4 serial lines.
+struct ParsedLine {
+ String name;
+ String value;
+};
+
+/**
+ * Parse a line of format "Name = Value" into name/value pair
+ * @param line Input line to parse
+ * @return ParsedLine containing name and value, or empty strings if parse failed
+ */
+ParsedLine parseLine(const char *line)
+{
+ ParsedLine result = {"", ""};
+
+ // Find equals sign
+ const char *equals = strchr(line, '=');
+ if (!equals) {
+ return result;
+ }
+
+ // Extract name by copying substring
+ char nameBuf[64]; // Temporary buffer
+ size_t nameLen = equals - line;
+ if (nameLen >= sizeof(nameBuf)) {
+ nameLen = sizeof(nameBuf) - 1;
+ }
+ strncpy(nameBuf, line, nameLen);
+ nameBuf[nameLen] = '\0';
+
+ // Create trimmed name string
+ String name = String(nameBuf);
+ name.trim();
+
+ // Extract value after equals sign
+ String value = String(equals + 1);
+ value.trim();
+
+ result.name = name;
+ result.value = value;
+ return result;
+}
+
/**
* Process the received weather station serial data, extract wind, voltage, and temperature information,
* calculate averages and send telemetry data over the mesh network.
@@ -416,7 +459,8 @@ uint32_t SerialModule::getBaudRate()
*/
void SerialModule::processWXSerial()
{
-#if !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK)
+#if !defined(TTGO_T_ECHO) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && \
+ !defined(ELECROW_ThinkNode_M1)
static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
static double dir_sum_sin = 0;
@@ -452,6 +496,7 @@ void SerialModule::processWXSerial()
// WindSpeed = 0.5
// WindGust = 0.6
// GXTS04Temp = 24.4
+ // Temperature = 23.4 // WS80
// RainIntSum = 0
// Rain = 0.0
@@ -470,75 +515,48 @@ void SerialModule::processWXSerial()
memset(line, '\0', sizeof(line));
if (lineEnd - lineStart < sizeof(line) - 1) {
memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
- if (strstr(line, "Wind") != NULL) // we have a wind line
- {
- gotwind = true;
- // Find the positions of "=" signs in the line
- char *windDirPos = strstr(line, "WindDir = ");
- char *windSpeedPos = strstr(line, "WindSpeed = ");
- char *windGustPos = strstr(line, "WindGust = ");
- if (windDirPos != NULL) {
- // Extract data after "=" for WindDir
- strlcpy(windDir, windDirPos + 15, sizeof(windDir)); // Add 15 to skip "WindDir = "
+ ParsedLine parsed = parseLine(line);
+ if (parsed.name.length() > 0) {
+ if (parsed.name == "WindDir") {
+ strlcpy(windDir, parsed.value.c_str(), sizeof(windDir));
double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
dir_sum_sin += sin(radians);
dir_sum_cos += cos(radians);
dirCount++;
- } else if (windSpeedPos != NULL) {
- // Extract data after "=" for WindSpeed
- strlcpy(windVel, windSpeedPos + 15, sizeof(windVel)); // Add 15 to skip "WindSpeed = "
+ gotwind = true;
+ } else if (parsed.name == "WindSpeed") {
+ strlcpy(windVel, parsed.value.c_str(), sizeof(windVel));
float newv = strtof(windVel, nullptr);
velSum += newv;
velCount++;
- if (newv < lull || lull == -1)
+ if (newv < lull || lull == -1) {
lull = newv;
-
- } else if (windGustPos != NULL) {
- strlcpy(windGust, windGustPos + 15, sizeof(windGust)); // Add 15 to skip "WindSpeed = "
+ }
+ gotwind = true;
+ } else if (parsed.name == "WindGust") {
+ strlcpy(windGust, parsed.value.c_str(), sizeof(windGust));
float newg = strtof(windGust, nullptr);
- if (newg > gust)
+ if (newg > gust) {
gust = newg;
- }
-
- // these are also voltage data we care about possibly
- } else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
- char *batVoltagePos = strstr(line, "BatVoltage = ");
- if (batVoltagePos != NULL) {
- strlcpy(batVoltage, batVoltagePos + 17, sizeof(batVoltage)); // 18 for ws 80, 17 for ws85
+ }
+ gotwind = true;
+ } else if (parsed.name == "BatVoltage") {
+ strlcpy(batVoltage, parsed.value.c_str(), sizeof(batVoltage));
batVoltageF = strtof(batVoltage, nullptr);
break; // last possible data we want so break
- }
- } else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
- char *capVoltagePos = strstr(line, "CapVoltage = ");
- if (capVoltagePos != NULL) {
- strlcpy(capVoltage, capVoltagePos + 17, sizeof(capVoltage)); // 18 for ws 80, 17 for ws85
+ } else if (parsed.name == "CapVoltage") {
+ strlcpy(capVoltage, parsed.value.c_str(), sizeof(capVoltage));
capVoltageF = strtof(capVoltage, nullptr);
- }
- // GXTS04Temp = 24.4
- } else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
- char *tempPos = strstr(line, "GXTS04Temp = ");
- if (tempPos != NULL) {
- strlcpy(temperature, tempPos + 15, sizeof(temperature)); // 15 spaces for ws85
+ } else if (parsed.name == "GXTS04Temp" || parsed.name == "Temperature") {
+ strlcpy(temperature, parsed.value.c_str(), sizeof(temperature));
temperatureF = strtof(temperature, nullptr);
- }
-
- } else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
- // LOG_INFO(line);
- char *pos = strstr(line, "RainIntSum = ");
- if (pos != NULL) {
- strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
+ } else if (parsed.name == "RainIntSum") {
+ strlcpy(rainStr, parsed.value.c_str(), sizeof(rainStr));
rainSum = int(strtof(rainStr, nullptr));
- }
-
- } else if (strstr(line, "Rain") != NULL) { // we have a rain line
- if (strstr(line, "WaveRain") == NULL) { // skip WaveRain lines though.
- // LOG_INFO(line);
- char *pos = strstr(line, "Rain = ");
- if (pos != NULL) {
- strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
- rain = strtof(rainStr, nullptr);
- }
+ } else if (parsed.name == "Rain") {
+ strlcpy(rainStr, parsed.value.c_str(), sizeof(rainStr));
+ rain = strtof(rainStr, nullptr);
}
}
@@ -556,7 +574,7 @@ void SerialModule::processWXSerial()
}
if (gotwind) {
- LOG_INFO("WS85 : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr),
+ LOG_INFO("WS8X : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr),
strtof(windGust, nullptr), batVoltageF, capVoltageF, temperatureF, rain, rainSum);
}
if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis)) {
@@ -606,7 +624,7 @@ void SerialModule::processWXSerial()
m.variant.environment_metrics.wind_lull = lull;
m.variant.environment_metrics.has_wind_lull = true;
- LOG_INFO("WS85 Transmit speed=%fm/s, direction=%d , lull=%f, gust=%f, voltage=%f temperature=%f",
+ LOG_INFO("WS8X Transmit speed=%fm/s, direction=%d , lull=%f, gust=%f, voltage=%f temperature=%f",
m.variant.environment_metrics.wind_speed, m.variant.environment_metrics.wind_direction,
m.variant.environment_metrics.wind_lull, m.variant.environment_metrics.wind_gust,
m.variant.environment_metrics.voltage, m.variant.environment_metrics.temperature);
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index 631df0fe4..0af6d4d04 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -144,6 +144,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
#elif defined(EBYTE_ESP32_S3)
#define HW_VENDOR meshtastic_HardwareModel_EBYTE_ESP32_S3
+#elif defined(ELECROW_ThinkNode_M2)
+#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M2
#elif defined(ESP32_S3_PICO)
#define HW_VENDOR meshtastic_HardwareModel_ESP32_S3_PICO
#elif defined(SENSELORA_S3)
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index d0fe31f21..ab1e5c922 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -109,6 +109,11 @@ void esp32Setup()
randomSeed(seed);
*/
+#ifdef POWER_FULL
+ pinMode(POWER_FULL, INPUT);
+ pinMode(7, INPUT);
+#endif
+
LOG_DEBUG("Total heap: %d", ESP.getHeapSize());
LOG_DEBUG("Free heap: %d", ESP.getFreeHeap());
LOG_DEBUG("Total PSRAM: %d", ESP.getPsramSize());
diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h
index bf7fce29a..4e8823063 100644
--- a/src/platform/nrf52/architecture.h
+++ b/src/platform/nrf52/architecture.h
@@ -53,6 +53,8 @@
#define HW_VENDOR meshtastic_HardwareModel_RAK4631
#elif defined(TTGO_T_ECHO)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
+#elif defined(ELECROW_ThinkNode_M1)
+#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
#elif defined(NANO_G2_ULTRA)
#define HW_VENDOR meshtastic_HardwareModel_NANO_G2_ULTRA
#elif defined(CANARYONE)
@@ -75,6 +77,8 @@
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#elif defined(HELTEC_T114)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114
+#elif defined(MESHLINK)
+#define HW_VENDOR meshtastic_HardwareModel_MESHLINK
#elif defined(SEEED_XIAO_NRF52840_KIT)
#define HW_VENDOR meshtastic_HardwareModel_XIAO_NRF52_KIT
#else
@@ -129,4 +133,4 @@
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
-#endif
\ No newline at end of file
+#endif
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index 8483d21c6..53971e95a 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -235,6 +235,14 @@ void nrf52InitSemiHosting()
void nrf52Setup()
{
+#ifdef USB_CHECK
+ pinMode(USB_CHECK, INPUT);
+#endif
+
+#ifdef ADC_V
+ pinMode(ADC_V, INPUT);
+#endif
+
uint32_t why = NRF_POWER->RESETREAS;
// per
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html
@@ -275,9 +283,11 @@ void cpuDeepSleep(uint32_t msecToWake)
Wire.end();
#endif
SPI.end();
+#if SPI_INTERFACES_COUNT > 1
+ SPI1.end();
+#endif
// This may cause crashes as debug messages continue to flow.
Serial.end();
-
#ifdef PIN_SERIAL_RX1
Serial1.end();
#endif
@@ -315,6 +325,31 @@ void cpuDeepSleep(uint32_t msecToWake)
detachInterrupt(PIN_GPS_PPS);
detachInterrupt(PIN_BUTTON1);
#endif
+
+#ifdef ELECROW_ThinkNode_M1
+ for (int pin = 0; pin < 48; pin++) {
+ if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
+ pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
+ continue;
+ }
+ pinMode(pin, OUTPUT);
+ }
+ for (int pin = 0; pin < 48; pin++) {
+ if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
+ pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
+ continue;
+ }
+ digitalWrite(pin, LOW);
+ }
+ for (int pin = 0; pin < 48; pin++) {
+ if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
+ pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
+ continue;
+ }
+ NRF_GPIO->DIRCLR = (1 << pin);
+ }
+#endif
+
// Sleepy trackers or sensors can low power "sleep"
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
if (msecToWake != portMAX_DELAY &&
@@ -333,6 +368,17 @@ void cpuDeepSleep(uint32_t msecToWake)
// FIXME, use system off mode with ram retention for key state?
// FIXME, use non-init RAM per
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
+
+#ifdef ELECROW_ThinkNode_M1
+ nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
+ nrf_gpio_pin_sense_t sense = NRF_GPIO_PIN_SENSE_LOW;
+ nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense);
+
+ nrf_gpio_cfg_input(PIN_BUTTON2, NRF_GPIO_PIN_PULLUP);
+ nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
+ nrf_gpio_cfg_sense_set(PIN_BUTTON2, sense1);
+#endif
+
auto ok = sd_power_system_off();
if (ok != NRF_SUCCESS) {
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 9da65c92c..a4050e702 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -33,6 +33,7 @@ std::ofstream traceFile;
Ch341Hal *ch341Hal = nullptr;
char *configPath = nullptr;
char *optionMac = nullptr;
+bool forceSimulated = false;
// FIXME - move setBluetoothEnable into a HALPlatform class
void setBluetoothEnable(bool enable)
@@ -61,6 +62,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
case 'c':
configPath = arg;
break;
+ case 's':
+ forceSimulated = true;
+ break;
case 'h':
optionMac = arg;
break;
@@ -78,6 +82,7 @@ void portduinoCustomInit()
static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."},
{"config", 'c', "CONFIG_PATH", 0, "Full path of the .yaml config file to use."},
{"hwid", 'h', "HWID", 0, "The mac address to assign to this virtual machine"},
+ {"sim", 's', 0, 0, "Run in Simulated radio mode"},
{0}};
static void *childArguments;
static char doc[] = "Meshtastic native build.";
@@ -157,7 +162,9 @@ void portduinoSetup()
YAML::Node yamlConfig;
- if (configPath != nullptr) {
+ if (forceSimulated == true) {
+ settingsMap[use_simradio] = true;
+ } else if (configPath != nullptr) {
if (loadConfig(configPath)) {
std::cout << "Using " << configPath << " as config file" << std::endl;
} else {
@@ -179,7 +186,12 @@ void portduinoSetup()
exit(EXIT_FAILURE);
}
} else {
- std::cout << "No 'config.yaml' found, running simulated." << std::endl;
+ std::cout << "No 'config.yaml' found..." << std::endl;
+ settingsMap[use_simradio] = true;
+ }
+
+ if (settingsMap[use_simradio] == true) {
+ std::cout << "Running in simulated mode." << std::endl;
settingsMap[maxnodes] = 200; // Default to 200 nodes
settingsMap[logoutputlevel] = level_debug; // Default to debug
// Set the random seed equal to TCPPort to have a different seed per instance
@@ -197,6 +209,56 @@ void portduinoSetup()
}
}
}
+
+ // If LoRa `Module: auto` (default in config.yaml),
+ // attempt to auto config based on Product Strings
+ if (settingsMap[use_autoconf] == true) {
+ char autoconf_product[96] = {0};
+ // Try CH341
+ try {
+ std::cout << "autoconf: Looking for CH341 device..." << std::endl;
+ ch341Hal =
+ new Ch341Hal(0, settingsStrings[lora_usb_serial_num], settingsMap[lora_usb_vid], settingsMap[lora_usb_pid]);
+ ch341Hal->getProductString(autoconf_product, 95);
+ delete ch341Hal;
+ std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
+ } catch (...) {
+ std::cout << "autoconf: Could not locate CH341 device" << std::endl;
+ }
+ // Try Pi HAT+
+ std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
+ if (access("/proc/device-tree/hat/product", R_OK) == 0) {
+ std::ifstream hatProductFile("/proc/device-tree/hat/product");
+ if (hatProductFile.is_open()) {
+ hatProductFile.read(autoconf_product, 95);
+ hatProductFile.close();
+ }
+ std::cout << "autoconf: Found Pi HAT+ " << autoconf_product << " at /proc/device-tree/hat/product" << std::endl;
+ } else {
+ std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat/product" << std::endl;
+ }
+ // Load the config file based on the product string
+ if (strlen(autoconf_product) > 0) {
+ // From configProducts map in PortduinoGlue.h
+ std::string product_config = "";
+ try {
+ product_config = configProducts.at(autoconf_product);
+ } catch (std::out_of_range &e) {
+ std::cerr << "autoconf: Unable to find config for " << autoconf_product << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ if (loadConfig(("/etc/meshtasticd/available.d/" + product_config).c_str())) {
+ std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
+ } else {
+ std::cerr << "autoconf: Unable to use " << product_config << " as config file for " << autoconf_product
+ << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ std::cerr << "autoconf: Could not locate any devices" << std::endl;
+ }
+ }
+
// if we're using a usermode driver, we need to initialize it here, to get a serial number back for mac address
uint8_t dmac[6] = {0};
if (settingsStrings[spidev] == "ch341") {
@@ -210,7 +272,10 @@ void portduinoSetup()
}
char serial[9] = {0};
ch341Hal->getSerialString(serial, 8);
- std::cout << "Serial " << serial << std::endl;
+ std::cout << "CH341 Serial " << serial << std::endl;
+ char product_string[96] = {0};
+ ch341Hal->getProductString(product_string, 95);
+ std::cout << "CH341 Product " << product_string << std::endl;
if (strlen(serial) == 8 && settingsStrings[mac_address].length() < 12) {
uint8_t hash[32] = {0};
memcpy(hash, serial, 8);
@@ -355,8 +420,9 @@ bool loadConfig(const char *configPath)
const struct {
configNames cfgName;
std::string strName;
- } loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
- {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
+ } loraModules[] = {{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"},
+ {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"},
+ {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
for (auto &loraModule : loraModules) {
settingsMap[loraModule.cfgName] = false;
}
diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h
index a52ca88f8..a7aea1c3e 100644
--- a/src/platform/portduino/PortduinoGlue.h
+++ b/src/platform/portduino/PortduinoGlue.h
@@ -1,9 +1,18 @@
#pragma once
#include
#include