Files
wadamesh/platformio.ini
T
Kaj SchittecatandClaude Fable 5 a38ea1e3bb touch: Elecrow ThinkNode M9 port (ESP32-S3 + LR1110 + I2C QWERTY) — bring-up builds 1-9
New board: ThinkNode_M9_companion_radio_touch env, variants/thinknode_m9/
(board glue, LR1110 target, keyboard driver, partitions, M9_PORT.md pin
reference), boards/thinknode_m9.json, device_caps HAS_THINKNODE_M9 block,
HAS_M9_KEYBOARD input path in the touch UI (d-pad focus nav, tab jump keys,
QWERTY typing).

Based on a contributed bring-up patch by ded (SalishMesh), who also remote-
tested every build on a preproduction unit. Hard-won fixes on top of the
patch, each verified on hardware:

- LR1110 radio init -706: preprod chips run transceiver FW 0x0303, which
  rejects DriveDiosInSleepMode (0x012A, added in FW 0x0308) that RadioLib
  7.x sends unconditionally during begin(). New build-time patch
  scripts/build/patch_radiolib_lr11x0.py tolerates it on old FW;
  radio_init() prints the chip's device/FW/errors either way.
- TCXO: DIO3 at 3.3 V (the patch's active-oscillator/tcxo=0 theory gave
  -707 on hardware).
- Display: rotation 1 (not 3), plus the missing landscape s_ui_rotation
  override so LVGL renders 320x240 instead of portrait-into-landscape.
- Keyboard: the controller is a separate ESP32-S2 I2C slave (0x6C) with
  addressed registers - reads select register 0x01 first (bare reads
  return the HW-version register forever). Boot probe logs the
  controller's HW/FW; backlight duty register wired.
- USB pad release: the keyboard bus lives on GPIO20/21 = the S3's native
  USB D-/D+ pads, owned from reset by the ROM USB-Serial-JTAG (D+ pullup
  on SDA). M9Board::begin() releases them before any bus init.
- GPIO35-37 are octal-PSRAM pins on the S3R8 - never drive them (the
  patch's "SD CS = 36" misread package pin 36 = GPIO48; SD is on the
  shared SPI bus, support returns with PIN_SD_CS=48 later).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:49:25 +02:00

627 lines
22 KiB
INI

; wadamesh — Heltec V4 TFT touch firmware.
; Standalone PlatformIO project: the MeshCore core is consumed as a library
; (lib/MeshCore here; a git-tagged fork once published). This env is the flattened
; equivalent of meshcomod's heltec_v4_tft_companion_radio_usb_tcp_touch.
[platformio]
default_envs =
heltec_v4_tft_companion_radio_usb_tcp_touch
LilyGo_TDeck_companion_radio_touch
ThinkNode_M9_companion_radio_touch
[env:heltec_v4_tft_companion_radio_usb_tcp_touch]
platform = platformio/espressif32@6.11.0
framework = arduino
board = heltec_v4
monitor_speed = 115200
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/inject_wifi_env.py, merge-bin.py
build_flags =
-Wno-deprecated-declarations -Wno-unused-parameter -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D MC_VENDORED_TOUCH_APP
; NOTE: tried -D ARDUINO_USB_MODE=1 (HW-CDC, drops unused TinyUSB MSC/DFU ≈ 12 KB internal
; DRAM) — but on the real V4 the binary companion link regressed: small per-message frames
; arrived yet the larger device-profile frame (node name + keys) dropped bytes over HW-CDC's
; smaller TX FIFO. Reverted to the board JSON's TinyUSB CDC. Revisit only with an HW-CDC TX
; buffer/DTR-wait fix verified on hardware. (T-Deck ships MODE=1 and is fine — board-specific.)
-D LORA_FREQ=869.618
-D LORA_BW=62.5
-D LORA_SF=8
-D ENABLE_PRIVATE_KEY_IMPORT=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
-D RADIOLIB_EXCLUDE_CC1101=1
-D RADIOLIB_EXCLUDE_RF69=1
-D RADIOLIB_EXCLUDE_SX1231=1
-D RADIOLIB_EXCLUDE_SI443X=1
-D RADIOLIB_EXCLUDE_RFM2X=1
-D RADIOLIB_EXCLUDE_SX128X=1
-D RADIOLIB_EXCLUDE_AFSK=1
-D RADIOLIB_EXCLUDE_AX25=1
-D RADIOLIB_EXCLUDE_HELLSCHREIBER=1
-D RADIOLIB_EXCLUDE_MORSE=1
-D RADIOLIB_EXCLUDE_APRS=1
-D RADIOLIB_EXCLUDE_BELL=1
-D RADIOLIB_EXCLUDE_RTTY=1
-D RADIOLIB_EXCLUDE_SSTV=1
-D ESP32_PLATFORM
; --- sensors ---
-D ENV_INCLUDE_GPS=1
-D ENV_INCLUDE_AHTX0=1
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_BMP280=1
-D ENV_INCLUDE_SHTC3=1
-D ENV_INCLUDE_SHT4X=1
-D ENV_INCLUDE_LPS22HB=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
-D ENV_INCLUDE_INA226=1
-D ENV_INCLUDE_INA260=1
-D ENV_INCLUDE_MLX90614=1
-D ENV_INCLUDE_VL53L0X=1
-D ENV_INCLUDE_BME680=1
-D ENV_INCLUDE_BMP085=1
; --- Heltec LoRa32 V4 board ---
-I variants/heltec_v4
-D HELTEC_LORA_V4
-D USE_SX1262
-D ESP32_CPU_FREQ=80
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D P_LORA_TX_LED=35
-D P_LORA_DIO_1=14
-D P_LORA_NSS=8
-D P_LORA_RESET=12
-D P_LORA_BUSY=13
-D P_LORA_SCLK=9
-D P_LORA_MISO=11
-D P_LORA_MOSI=10
-D P_LORA_PA_POWER=7
-D P_LORA_PA_EN=2
-D P_LORA_PA_TX_EN=46
-D P_LORA_GC1109_PA_EN=2
-D P_LORA_GC1109_PA_TX_EN=46
-D P_LORA_KCT8103L_PA_CSD=2
-D P_LORA_KCT8103L_PA_CTX=5
-D PIN_USER_BTN=0
-D PIN_VEXT_EN=36
-D PIN_VEXT_EN_ACTIVE=HIGH
-D LORA_TX_POWER=10
-D MAX_LORA_TX_POWER=22
-D SX126X_REGISTER_PATCH=1
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D PIN_GPS_RX=38
-D PIN_GPS_TX=39
-D PIN_GPS_RESET=42
-D PIN_GPS_RESET_ACTIVE=LOW
-D PIN_GPS_EN=34
-D PIN_GPS_EN_ACTIVE=LOW
-D PIN_ADC_CTRL=37
-D PIN_VBAT_READ=1
; --- TFT ---
-D HELTEC_LORA_V4_TFT
-D PIN_BOARD_SDA=4
-D PIN_BOARD_SCL=3
-D DISPLAY_ROTATION=2
-D DISPLAY_SCALE_X=1.0
-D DISPLAY_SCALE_Y=1.0
-D PIN_TFT_RST=18
-D PIN_TFT_VDD_CTL=-1
-D PIN_TFT_LEDA_CTL=21
-D PIN_TFT_LEDA_CTL_ACTIVE=HIGH
-D PIN_TFT_CS=15
-D PIN_TFT_DC=16
-D PIN_TFT_SCL=17
-D PIN_TFT_SDA=33
; --- CHSC6x cap touch ---
-D HAS_HELTEC_V4_CAP_TOUCH=1
-D PIN_TOUCH_SDA=47
-D PIN_TOUCH_SCL=48
-D PIN_TOUCH_RST=44
-D HELTEC_V4_BUZZER_PIN=6
; --- touch UI / companion stack ---
-I include
-I src
-I src/ui-touch
-D UI_LVGL=1
-D HAS_TOUCH_UI=1
; Heltec V4 Expansion Kit: local environment sensors UI (Sensors tab, Home env
; widget, Local-Sensors page). Board-gated — only this env compiles it.
-D HAS_EXPANSION_KIT=1
-D FIRMWARE_OTA_ENV='"heltec_v4_tft_companion_radio_usb_tcp_touch"'
-D ENABLE_ADVERT_ON_BOOT=0
-D LV_CONF_PATH=lv_conf.h
-D LV_CONF_INCLUDE_SIMPLE=1
; Smoother scroll: lower deceleration than LVGL's default (10) so flicks glide
; longer instead of stopping abruptly. lv_conf leaves this unset, so this -D wins.
-D LV_INDEV_DEF_SCROLL_THROW=7
-D USER_SETUP_LOADED=1
-D ST7789_DRIVER=1
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
-D TFT_MOSI=33
-D TFT_SCLK=17
-D TFT_CS=15
-D TFT_DC=16
-D TFT_RST=18
-D TFT_MISO=-1
-D SPI_FREQUENCY=80000000
-D TFT_RGB_ORDER=TFT_RGB
-D TFT_INVERSION_ON=1
-D TFT_BL=21
-D TFT_BACKLIGHT_ON=1
-D MAX_CONTACTS=2000
-D MAX_GROUP_CHANNELS=40
-D DISPLAY_CLASS=ST7789LCDDisplay
-D ADMIN_PASSWORD='"password"'
-D MULTI_TRANSPORT_COMPANION=1
-D WADAMESH_FORK_BUILD=1
-D TCP_PORT=5000
-D WS_PORT=8765
-D BLE_PIN_CODE=123456
-D CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=1
-D CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
-D CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
build_src_filter =
+<*.cpp>
+<*.c>
+<helpers/*.cpp>
+<helpers/esp32/*.cpp>
+<helpers/input/*.cpp>
+<ui-touch/*.cpp>
+<ui-touch/*.c>
+<../variants/heltec_v4/*.cpp>
lib_deps =
; MeshCore core = the meshcomod monorepo built as a lib, pinned by tag.
; Touch-app files (TouchPrefsStore, WifiRuntimeStore, transports, ...) are
; vendored in this app's src/ and dropped from the lib via -DMC_VENDORED_TOUCH_APP.
https://github.com/ALLFATHER-BV/meshcomod.git#core-v1.16.5
SPI
Wire
jgromes/RadioLib @ ^7.6.0
rweather/Crypto @ ^0.4.0
adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0
electroniccats/CayenneLPP @ 1.6.1
h2zero/NimBLE-Arduino @ 1.4.3
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
robtillaart/INA226 @ ^0.6.4
adafruit/Adafruit INA260 Library @ ^1.5.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library @ ^2.6.8
adafruit/Adafruit SHTC3 Library @ ^1.0.1
sensirion/Sensirion I2C SHT4x @ ^1.1.2
arduino-libraries/Arduino_LPS22HB @ ^1.0.2
adafruit/Adafruit MLX90614 Library @ ^2.1.5
adafruit/Adafruit_VL53L0X @ ^1.2.4
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME680 Library @ ^2.0.4
adafruit/Adafruit BMP085 Library @ ^1.2.4
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
https://github.com/Quency-D/chsc6x/archive/5cbead829d6b432a8d621ed1aafd4eb474fd4f27.zip
ESP32Async/ESPAsyncWebServer @ 3.10.3
file://arch/esp32/AsyncElegantOTA
lvgl/lvgl @ ^8.3.11
bodmer/TFT_eSPI @ ^2.5.43
densaugeo/base64 @ ~1.4.0
knolleary/PubSubClient @ ^2.8.0
; ======================================================================
; LilyGo T-Deck / T-Deck Plus — flattened equivalent of meshcomod's
; LilyGo_TDeck_companion_radio_touch. ST7789 via Adafruit (not TFT_eSPI);
; GT911 touch + matrix keyboard + trackball; sensors off except GPS.
; ======================================================================
[env:LilyGo_TDeck_companion_radio_touch]
platform = platformio/espressif32@6.11.0
framework = arduino
board = t-deck
monitor_speed = 115200
board_build.partitions = variants/lilygo_tdeck/partitions_tdeck_touch.csv
extra_scripts = pre:scripts/inject_wifi_env.py, merge-bin.py
build_flags =
-Wno-deprecated-declarations -Wno-unused-parameter -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D MC_VENDORED_TOUCH_APP
-D LORA_FREQ=869.618
-D LORA_BW=62.5
-D LORA_SF=8
-D ENABLE_PRIVATE_KEY_IMPORT=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
-D RADIOLIB_EXCLUDE_CC1101=1
-D RADIOLIB_EXCLUDE_RF69=1
-D RADIOLIB_EXCLUDE_SX1231=1
-D RADIOLIB_EXCLUDE_SI443X=1
-D RADIOLIB_EXCLUDE_RFM2X=1
-D RADIOLIB_EXCLUDE_SX128X=1
-D RADIOLIB_EXCLUDE_AFSK=1
-D RADIOLIB_EXCLUDE_AX25=1
-D RADIOLIB_EXCLUDE_HELLSCHREIBER=1
-D RADIOLIB_EXCLUDE_MORSE=1
-D RADIOLIB_EXCLUDE_APRS=1
-D RADIOLIB_EXCLUDE_BELL=1
-D RADIOLIB_EXCLUDE_RTTY=1
-D RADIOLIB_EXCLUDE_SSTV=1
-D ESP32_PLATFORM
; --- T-Deck board ---
-I variants/lilygo_tdeck
-D LILYGO_TDECK
-D BOARD_HAS_PSRAM=1
; 0 = silence ARDUHAL [E] spam (benign vfs_api cache-miss "no permits for
; creation" + Preferences nvs_open NOT_FOUND on first-namespace-access) that
; also pollutes the USB-CDC companion stream. Our own Serial.printf logs stay.
-D CORE_DEBUG_LEVEL=0
-D ARDUINO_USB_CDC_ON_BOOT=1
-D PIN_USER_BTN=0
-D PIN_PERF_POWERON=10
-D USE_SX1262
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
; The T-Deck's SX1262 antenna (TX/RX) switch is driven by DIO2 — this MUST be
; true. With it false, setDio2AsRfSwitch(false) leaves the switch uncontrolled,
; so on TX the +22 dBm PA is never routed to the antenna (~16 dB loss -> ~4 mW).
; That was issue #6. (Meshtastic's T-Deck + the Heltec V4 here + every other
; MeshCore SX1262 variant use true; the T-Deck was the lone outlier.)
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D SX126X_DIO3_TCXO_VOLTAGE=1.8f
-D P_LORA_DIO_1=45
-D P_LORA_NSS=9
-D P_LORA_RESET=17
-D P_LORA_BUSY=13
-D P_LORA_SCLK=40
-D P_LORA_MISO=38
-D P_LORA_MOSI=41
-D ENV_INCLUDE_GPS=1
-D ENV_SKIP_GPS_DETECT=1
-D ENV_INCLUDE_AHTX0=0
-D ENV_INCLUDE_BME280=0
-D ENV_INCLUDE_BMP280=0
-D ENV_INCLUDE_SHTC3=0
-D ENV_INCLUDE_SHT4X=0
-D ENV_INCLUDE_LPS22HB=0
-D ENV_INCLUDE_INA3221=0
-D ENV_INCLUDE_INA219=0
-D ENV_INCLUDE_INA226=0
-D ENV_INCLUDE_INA260=0
-D ENV_INCLUDE_MLX90614=0
-D ENV_INCLUDE_VL53L0X=0
-D ENV_INCLUDE_BME680=0
-D ENV_INCLUDE_BMP085=0
-D DISPLAY_SCALE_X=1.0
-D DISPLAY_SCALE_Y=1.0
-D PIN_TFT_RST=-1
-D PIN_TFT_VDD_CTL=-1
-D PIN_TFT_LEDA_CTL=42
-D PIN_TFT_CS=12
-D PIN_TFT_DC=11
-D PIN_TFT_SCL=40
-D PIN_TFT_SDA=41
-D PIN_GPS_RX=43
-D PIN_GPS_TX=44
-D GPS_BAUD_RATE=38400
; --- touch UI / companion stack ---
-I include
-I src
-I src/ui-touch
-D UI_LVGL=1
-D HAS_TOUCH_UI=1
-D FIRMWARE_OTA_ENV='"LilyGo_TDeck_companion_radio_touch"'
-D HAS_TDECK_GT911=1
-D HAS_TDECK_TRACKBALL=1
-D HAS_TDECK_KEYBOARD=1
-D ENABLE_ADVERT_ON_BOOT=0
-D PIN_TB_UP=15
-D PIN_TB_DOWN=3
-D PIN_TB_LEFT=2
-D PIN_TB_RIGHT=1
-D LV_CONF_PATH=lv_conf.h
-D LV_CONF_INCLUDE_SIMPLE=1
; Smoother scroll: lower deceleration than LVGL's default (10) so flicks glide
; longer instead of stopping abruptly. lv_conf leaves this unset, so this -D wins.
-D LV_INDEV_DEF_SCROLL_THROW=7
-D MAX_CONTACTS=2000
-D MAX_GROUP_CHANNELS=40
-D DISPLAY_CLASS=ST7789LCDDisplay
-D ADMIN_PASSWORD='"password"'
-D MULTI_TRANSPORT_COMPANION=1
-D WADAMESH_FORK_BUILD=1
-D TCP_PORT=5000
-D WS_PORT=8765
-D BLE_PIN_CODE=123456
-D CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=1
-D CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
-D CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
build_src_filter =
+<*.cpp>
+<*.c>
+<helpers/*.cpp>
+<helpers/esp32/*.cpp>
+<helpers/input/*.cpp>
+<ui-touch/*.cpp>
+<ui-touch/*.c>
+<../variants/lilygo_tdeck/*.cpp>
lib_deps =
https://github.com/ALLFATHER-BV/meshcomod.git#core-v1.16.5
SPI
Wire
jgromes/RadioLib @ ^7.6.0
rweather/Crypto @ ^0.4.0
adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0
electroniccats/CayenneLPP @ 1.6.1
h2zero/NimBLE-Arduino @ 1.4.3
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
robtillaart/INA226 @ ^0.6.4
adafruit/Adafruit INA260 Library @ ^1.5.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library @ ^2.6.8
adafruit/Adafruit SHTC3 Library @ ^1.0.1
sensirion/Sensirion I2C SHT4x @ ^1.1.2
arduino-libraries/Arduino_LPS22HB @ ^1.0.2
adafruit/Adafruit MLX90614 Library @ ^2.1.5
adafruit/Adafruit_VL53L0X @ ^1.2.4
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME680 Library @ ^2.0.4
adafruit/Adafruit BMP085 Library @ ^1.2.4
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
ESP32Async/ESPAsyncWebServer @ 3.10.3
file://arch/esp32/AsyncElegantOTA
lvgl/lvgl @ ^8.3.11
densaugeo/base64 @ ~1.4.0
knolleary/PubSubClient @ ^2.8.0
; ======================================================================
; Elecrow ThinkNode M9 — ESP32-S3R8 / LR1110 / 2.4" 240x320 ST7789 / QWERTY
; keyboard + d-pad (no touchscreen). Pin map verified against the V1.0
; schematic + Meshtastic boot log during Specter (ESP-IDF) bring-up; the
; panel IC, TCXO voltage, battery divider, and LR1110 RF-switch DIO mapping
; below are all schematic/manufacturer-confirmed (NOT the earlier ILI9341 /
; 2:1-divider / unverified-RF-switch state from a prior attempt). See
; variants/thinknode_m9/M9_PORT.md for the full pin table and the remaining
; hardware-verify checklist (GPS EN polarity/baud, display rotation, RF-switch
; truth-table polarity, SD mount-timing margins) — those items are
; deliberately left unset/unconfirmed below.
; ======================================================================
[env:ThinkNode_M9_companion_radio_touch]
platform = platformio/espressif32@6.11.0
framework = arduino
board = thinknode_m9
monitor_speed = 115200
board_build.partitions = variants/thinknode_m9/partitions_m9_touch.csv
; patch_radiolib_lr11x0: preprod M9 LR1110s run old transceiver FW that rejects
; DriveDiosInSleepMode (0x012A, FW 0x0308+) with CMD_PERR -> begin() = -706.
; The pre-script makes RadioLib's config() skip it on old FW (idempotent,
; per-env libdeps copy). See scripts/build/patch_radiolib_lr11x0.py.
extra_scripts = pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_radiolib_lr11x0.py, merge-bin.py
build_flags =
-Wno-deprecated-declarations -Wno-unused-parameter -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D MC_VENDORED_TOUCH_APP
-D LORA_FREQ=869.618
-D LORA_BW=62.5
-D LORA_SF=8
-D ENABLE_PRIVATE_KEY_IMPORT=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
-D RADIOLIB_EXCLUDE_CC1101=1
-D RADIOLIB_EXCLUDE_RF69=1
-D RADIOLIB_EXCLUDE_SX1231=1
-D RADIOLIB_EXCLUDE_SI443X=1
-D RADIOLIB_EXCLUDE_RFM2X=1
-D RADIOLIB_EXCLUDE_SX128X=1
-D RADIOLIB_EXCLUDE_AFSK=1
-D RADIOLIB_EXCLUDE_AX25=1
-D RADIOLIB_EXCLUDE_HELLSCHREIBER=1
-D RADIOLIB_EXCLUDE_MORSE=1
-D RADIOLIB_EXCLUDE_APRS=1
-D RADIOLIB_EXCLUDE_BELL=1
-D RADIOLIB_EXCLUDE_RTTY=1
-D RADIOLIB_EXCLUDE_SSTV=1
-D ESP32_PLATFORM
; --- ThinkNode M9 board ---
-I variants/thinknode_m9
-D HAS_THINKNODE_M9
-D BOARD_HAS_PSRAM=1
; M9 uses the UART bridge (ttyUSB0), not native USB-CDC — confirmed during
; Specter bring-up. With ARDUINO_USB_CDC_ON_BOOT=1 (the T-Deck's setting)
; app Serial logs go to a ttyACM* port this board doesn't expose and
; appear completely silent.
-D ARDUINO_USB_CDC_ON_BOOT=0
-D PIN_USER_BTN=0
-D RADIO_CLASS=CustomLR1110
-D WRAPPER_CLASS=CustomLR1110Wrapper
-D LORA_TX_POWER=22
; LR1110 clock: TCXO mode at 3.3 V — EMPIRICALLY CONFIRMED on the tester's
; preproduction unit: Meshtastic's thinknode_m9 variant logs "using DIO3 as
; TCXO reference voltage at 3.300000 V" followed by "LR1110 init result 0".
; The earlier theory here (Y1 = self-powered active oscillator -> tcxo must
; be 0) was disproven on hardware: with 0 the chip boots on its internal RC
; (SPI alive, no -2) but the first command needing the real 32 MHz clock is
; rejected -> radio init failed -707 (bring-up build #1, 2026-07-06). The
; schematic's "VTCXO rail" feeding Y1 is evidently the LR1110's own
; TCXO-supply output, so the chip must drive it.
-D LR11X0_DIO3_TCXO_VOLTAGE=3.3
; Bring-up only: RadioLib's own boot prints (found-chip line with the
; transceiver/WiFi/GNSS FW versions, calibration errors). Goes to Serial =
; UART0 on this board. Low volume; drop once the radio is proven.
-D RADIOLIB_DEBUG_BASIC=1
-D RX_BOOSTED_GAIN=true
; DIO5/DIO6 -> RFSW0_V1/RFSW1_V2 confirmed against the V1.0 schematic (LR1110
; block, U7 pins 19/20 -> R19/R20 -> U8 V1/V2) — see target.cpp for the table
; and M9_PORT.md for the crop. The per-mode polarity is the conventional
; 2-pin table every other MeshCore LR1110 board uses, not independently
; re-derived from U8's datasheet (part number isn't printed on the schematic).
-D RF_SWITCH_TABLE
; --- LR1110 SPI / control pins (verified: V1.0 schematic + boot log) ---
-D P_LORA_NSS=39
-D P_LORA_DIO_1=42
-D P_LORA_RESET=45
-D P_LORA_BUSY=41
-D P_LORA_SCLK=40
-D P_LORA_MISO=38
-D P_LORA_MOSI=47
; --- Peripheral I2C bus 0 (Wire): RTC PCF8563 0x51 / IMU QMI8658 0x6b /
; compass QMC6309 0x7c. Brought up by ESP32Board::begin(). ---
-D PIN_BOARD_SDA=7
-D PIN_BOARD_SCL=6
; --- Battery: 1:1 divider, manufacturer-confirmed (M9Board::getBattMilliVolts()
; overrides the ESP32Board base class's hardcoded 2:1 assumption). ---
-D PIN_VBAT_READ=13
; --- GPS (CC1167Q, UART1) ---
-D ENV_INCLUDE_GPS=1
-D PIN_GPS_RX=2
-D PIN_GPS_TX=3
-D PIN_GPS_EN=11
-D PIN_GPS_RESET=5
; GPS_BAUD_RATE / PIN_GPS_EN_ACTIVE intentionally left at library defaults
; (9600 / HIGH) — UNVERIFIED for this module, see M9_PORT.md.
; GPIO10 (GPS ON_OFF) and GPIO4 (1PPS) exist on the schematic but have no
; consumer in this driver yet — reserved, not wired.
-D ENV_INCLUDE_AHTX0=0
-D ENV_INCLUDE_BME280=0
-D ENV_INCLUDE_BMP280=0
-D ENV_INCLUDE_SHTC3=0
-D ENV_INCLUDE_SHT4X=0
-D ENV_INCLUDE_LPS22HB=0
-D ENV_INCLUDE_INA3221=0
-D ENV_INCLUDE_INA219=0
-D ENV_INCLUDE_INA226=0
-D ENV_INCLUDE_INA260=0
-D ENV_INCLUDE_MLX90614=0
-D ENV_INCLUDE_VL53L0X=0
-D ENV_INCLUDE_BME680=0
-D ENV_INCLUDE_BMP085=0
; --- ST7789 panel (manufacturer-confirmed; NOT ILI9341) ---
; No LILYGO_TDECK / HELTEC_LORA_V4_TFT macro is defined, so ST7789LCDDisplay
; uses its default branch (Adafruit_ST7789 over the global `SPI`, the same
; instance the radio uses) — matches the LR1110 reference variants, which
; also share one SPI peripheral across radio + display + (on the M9) SD.
-D DISPLAY_SCALE_X=1.0
-D DISPLAY_SCALE_Y=1.0
; HARDWARE-VERIFIED (bring-up #6, 2026-07-06): rotation 3 rendered the UI
; 180 degrees off on the tester's unit; 1 is the correct landscape
; orientation (keyboard below screen). Adafruit rotations 1/3 are the two
; landscape options, 180 degrees apart.
-D DISPLAY_ROTATION=1
; PIN_TFT_LEDA_CTL is set to -1, NOT left undefined: the installed ST7789LCDDisplay
; references it unconditionally (`if (PIN_TFT_LEDA_CTL != -1)`, no #ifdef guard around
; the macro itself — leaving it undefined is a compile error, not a no-op). -1 makes
; that check skip the pin entirely, since the vendored class always drives it
; active-HIGH, but the M9's backlight is a PNP transistor (active-LOW) — so
; ThinkNodeM9Board owns BL_EN (GPIO17) directly instead (see M9Board.h/.cpp).
; PIN_PERIPH_POWER is the OTHER (also active-low) rail, gating the LCD/GPS/sensors,
; and IS passed through ST7789LCDDisplay's RefCountedDigitalPin constructor arg in
; target.cpp.
-D PIN_TFT_LEDA_CTL=-1
-D PIN_PERIPH_POWER=18
-D PIN_TFT_BL_EN=17
-D PIN_TFT_RST=14
-D PIN_TFT_DC=15
-D PIN_TFT_CS=16
; PIN_TFT_SCL / PIN_TFT_SDA intentionally NOT defined: only the
; USE_PIN_TFT / LILYGO_TDECK / HELTEC_LORA_V4_TFT branches of
; ST7789LCDDisplay's constructor consume them, and M9 uses none of those —
; it takes the default `display(&SPI, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST)`
; branch (global SPI, same instance the radio uses).
;
; NOTE: a software-SPI (USE_PIN_TFT) diagnostic build was tried here to test
; whether the class's hardcoded 80MHz hardware SPI clock was corrupting the
; boot-splash write. It wasn't — software SPI reproduced the EXACT same
; freeze-then-TG1WDT_SYS_RST at the exact same point, just slower, which
; rules out the SPI clock/signal-integrity theory entirely. See
; M9_PORT.md / git history if revisiting that path.
; microSD: on SD_MMC per the Meshtastic boot log (SDMMC peripheral, no SPI
; CS). The earlier "CS=36" reading is an octal-PSRAM-reserved pin (GPIO35-37,
; S3R8) — never drive it. SD support deferred until the SDMMC pins are known.
; --- Keyboard controller (own bus, Wire1) — full QWERTY + d-pad + function
; keys, all over one I2C device. See M9Keyboard.h for the confirmed
; keycode table. ---
-D HAS_M9_KEYBOARD=1
; Keyboard bus SCHEMATIC-VERIFIED (V1.0 sheet, bring-up #9): S3 GPIO20 =
; net ESP32-2_SDA, GPIO21 = ESP32-2_SCL, to the keyboard ESP32-S2 (its
; GPIO7/6) through R2/R1 series resistors, pullups R73/R72, S2 powered from
; always-on 3V3 via R3. GPIO19/20 are also the S3's native USB D-/D+ pads —
; M9Board::begin() must release the USB-Serial-JTAG pad claim first.
-D PIN_KB_SDA=20
-D PIN_KB_SCL=21
-D PIN_KB_ADDR=0x6c
; --- touch UI / companion stack (M9 has no touch — keyboard + d-pad text
; entry only; keypad-nav focus traversal is NOT wired yet, see
; M9_PORT.md) ---
-I include
-I src
-I src/ui-touch
-D UI_LVGL=1
-D HAS_TOUCH_UI=1
-D FIRMWARE_OTA_ENV='"ThinkNode_M9_companion_radio_touch"'
-D ENABLE_ADVERT_ON_BOOT=0
-D LV_CONF_PATH=lv_conf.h
-D LV_CONF_INCLUDE_SIMPLE=1
-D LV_INDEV_DEF_SCROLL_THROW=7
-D MAX_CONTACTS=2000
-D MAX_GROUP_CHANNELS=40
-D DISPLAY_CLASS=ST7789LCDDisplay
-D ADMIN_PASSWORD='"password"'
-D MULTI_TRANSPORT_COMPANION=1
-D WADAMESH_FORK_BUILD=1
-D TCP_PORT=5000
-D WS_PORT=8765
-D BLE_PIN_CODE=123456
-D CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=1
-D CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
-D CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
build_src_filter =
+<*.cpp>
+<*.c>
+<helpers/*.cpp>
+<helpers/esp32/*.cpp>
+<helpers/input/*.cpp>
+<ui-touch/*.cpp>
+<ui-touch/*.c>
+<../variants/thinknode_m9/*.cpp>
lib_deps =
https://github.com/ALLFATHER-BV/meshcomod.git#core-v1.16.5
SPI
Wire
jgromes/RadioLib @ ^7.6.0
rweather/Crypto @ ^0.4.0
adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0
electroniccats/CayenneLPP @ 1.6.1
h2zero/NimBLE-Arduino @ 1.4.3
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
robtillaart/INA226 @ ^0.6.4
adafruit/Adafruit INA260 Library @ ^1.5.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library @ ^2.6.8
adafruit/Adafruit SHTC3 Library @ ^1.0.1
sensirion/Sensirion I2C SHT4x @ ^1.1.2
arduino-libraries/Arduino_LPS22HB @ ^1.0.2
adafruit/Adafruit MLX90614 Library @ ^2.1.5
adafruit/Adafruit_VL53L0X @ ^1.2.4
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME680 Library @ ^2.0.4
adafruit/Adafruit BMP085 Library @ ^1.2.4
adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0
ESP32Async/ESPAsyncWebServer @ 3.10.3
file://arch/esp32/AsyncElegantOTA
lvgl/lvgl @ ^8.3.11
densaugeo/base64 @ ~1.4.0
knolleary/PubSubClient @ ^2.8.0