diff --git a/variants/thinknode_g3/ThinkNodeG3Board.h b/variants/thinknode_g3/ThinkNodeG3Board.h new file mode 100644 index 0000000000..8d99ff49c4 --- /dev/null +++ b/variants/thinknode_g3/ThinkNodeG3Board.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +// G3 LoRa LED on GPIO 6 is active-low. ESP32Board drives the TX LED +// high for on, which leaves this board's LED lit at idle. +class ThinkNodeG3Board : public ESP32Board { +public: + void begin() { + ESP32Board::begin(); +#ifdef P_LORA_TX_LED + digitalWrite(P_LORA_TX_LED, HIGH); // idle = off +#endif + } + +#ifdef P_LORA_TX_LED + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); + } + + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH); + } +#endif +}; diff --git a/variants/thinknode_g3/pins_arduino.h b/variants/thinknode_g3/pins_arduino.h new file mode 100644 index 0000000000..91b44f5b20 --- /dev/null +++ b/variants/thinknode_g3/pins_arduino.h @@ -0,0 +1,18 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +static const uint8_t SDA = 17; +static const uint8_t SCL = 18; + +// Default SPI is the SX1262, not the CH390. +static const uint8_t SS = 39; +static const uint8_t MOSI = 40; +static const uint8_t MISO = 41; +static const uint8_t SCK = 42; + +#endif diff --git a/variants/thinknode_g3/platformio.ini b/variants/thinknode_g3/platformio.ini new file mode 100644 index 0000000000..4bc0fed953 --- /dev/null +++ b/variants/thinknode_g3/platformio.ini @@ -0,0 +1,126 @@ +; Elecrow ThinkNode G3 (ILM13103D) — ESP32-S3-WROOM-1-N8R8 + LR1262 (SX1262) +; +; Drop this directory in as variants/thinknode_g3/ of a MeshCore checkout. +; MeshCore loads every variants/*/platformio.ini automatically. +; +; Radio map recovered from a stock Elecrow US915 flash dump (nsbradley88, +; meshtastic/firmware discussion #9434, 2026-09-23), then confirmed on air +; as a Meshtastic node with TCXO at 3.0 V. Not yet confirmed under MeshCore. +; +; Do not copy ThinkNode M7 pins. M7 is an LR1110 + different PCB. +; Ethernet is intentionally omitted: the CH390 SPI pins are not confirmed, +; and M7's ETH pins collide with this radio (BUSY is GPIO 47 here). + +[ThinkNode_G3] +extends = esp32_base +board = esp32-s3-devkitc-1 +board_build.flash_size = 8MB +board_upload.flash_size = 8MB +board_build.partitions = default_8MB.csv +board_build.arduino.memory_type = qio_opi +board_build.flash_mode = qio +board_build.psram_type = opi +upload_speed = 115200 +; CH340 USB-UART, no auto-reset wiring. Hold BOOT, tap RST, release BOOT. +upload_flags = + --before=no_reset + --no-stub +build_flags = ${esp32_base.build_flags} + -I variants/thinknode_g3 + -D THINKNODE_G3 + -D BOARD_HAS_PSRAM + ; Radio — stock firmware tables @ 0x38244 / 0x3826c + -D USE_SX1262 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D P_LORA_NSS=39 + -D P_LORA_SCLK=42 + -D P_LORA_MOSI=40 + -D P_LORA_MISO=41 + -D P_LORA_RESET=21 + -D P_LORA_BUSY=47 + -D P_LORA_DIO_1=15 + -D P_LORA_EN=45 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=3.0 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + ; Front panel. Reload = GPIO 4, LINK LED = 5, LoRa LED = 6. + -D PIN_USER_BTN=4 + -D PIN_STATUS_LED=5 + -D P_LORA_TX_LED=6 + -D LED_STATE_ON=HIGH + ; I2C brought out in the early Meshtastic variant; unused by stock firmware. + -D PIN_BOARD_SDA=17 + -D PIN_BOARD_SCL=18 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/thinknode_g3> + +[env:ThinkNode_G3_repeater] +extends = ThinkNode_G3 +build_src_filter = ${ThinkNode_G3.build_src_filter} + +<../examples/simple_repeater/*.cpp> +build_flags = + ${ThinkNode_G3.build_flags} + -D ADVERT_NAME='"ThinkNode G3 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +lib_deps = + ${esp32_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:ThinkNode_G3_room_server] +extends = ThinkNode_G3 +build_src_filter = ${ThinkNode_G3.build_src_filter} + +<../examples/simple_room_server> +build_flags = + ${ThinkNode_G3.build_flags} + -D ADVERT_NAME='"ThinkNode G3 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +lib_deps = + ${esp32_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:ThinkNode_G3_companion_radio_ble] +extends = ThinkNode_G3 +build_flags = + ${ThinkNode_G3.build_flags} + -I examples/companion_radio/ui-orig + -D DISPLAY_CLASS=NullDisplayDriver + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${ThinkNode_G3.build_src_filter} + + + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-orig/*.cpp> +lib_deps = + ${esp32_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:ThinkNode_G3_companion_radio_usb] +extends = ThinkNode_G3 +build_flags = + ${ThinkNode_G3.build_flags} + -I examples/companion_radio/ui-orig + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D OFFLINE_QUEUE_SIZE=256 + -D ENABLE_USB_INTERFACE +build_src_filter = ${ThinkNode_G3.build_src_filter} + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-orig/*.cpp> +lib_deps = + ${esp32_base.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/thinknode_g3/target.cpp b/variants/thinknode_g3/target.cpp new file mode 100644 index 0000000000..b7ab438aa3 --- /dev/null +++ b/variants/thinknode_g3/target.cpp @@ -0,0 +1,30 @@ +#include +#include "target.h" + +ThinkNodeG3Board board; + +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +bool radio_init() { + // Stock firmware drives GPIO 45 high once at init (antenna switch / PE_EN). + // ESP32Board does not know about P_LORA_EN, so do it here before radio begin. +#ifdef P_LORA_EN + pinMode(P_LORA_EN, OUTPUT); + digitalWrite(P_LORA_EN, HIGH); +#endif + + fallback_clock.begin(); + rtc_clock.begin(Wire); + return radio.std_init(&spi); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); +} diff --git a/variants/thinknode_g3/target.h b/variants/thinknode_g3/target.h new file mode 100644 index 0000000000..7eb9db62cc --- /dev/null +++ b/variants/thinknode_g3/target.h @@ -0,0 +1,17 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include + +extern ThinkNodeG3Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/thinknode_g3/variant.h b/variants/thinknode_g3/variant.h new file mode 100644 index 0000000000..1afe9c0148 --- /dev/null +++ b/variants/thinknode_g3/variant.h @@ -0,0 +1,28 @@ +#pragma once + +// Elecrow ThinkNode G3 (ILM13103D) +// ESP32-S3-WROOM-1-N8R8, LR1262 module (SX1262 + TCXO + RF switch) +// +// Pin values recovered from stock Elecrow firmware constants, not from a +// published schematic. Confirm against your own flash dump before flashing. + +#define P_LORA_NSS 39 +#define P_LORA_SCLK 42 +#define P_LORA_MOSI 40 +#define P_LORA_MISO 41 +#define P_LORA_RESET 21 +#define P_LORA_BUSY 47 +#define P_LORA_DIO_1 15 + +// Stock firmware drives this high once at init (antenna_sw / PE_EN). +#define P_LORA_EN 45 + +#define PIN_USER_BTN 4 // Reload, silk K2 +#define PIN_STATUS_LED 5 // LINK, green +#define P_LORA_TX_LED 6 // LoRa LED + +#define PIN_BOARD_SDA 17 +#define PIN_BOARD_SCL 18 + +// USB D-/D+ are GPIO 19/20. Do not reuse. +// BOOT is WROOM IO0. Do not use as a radio pin.