Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions variants/thinknode_g3/ThinkNodeG3Board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <helpers/ESP32Board.h>

// 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
};
18 changes: 18 additions & 0 deletions variants/thinknode_g3/pins_arduino.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <stdint.h>

#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
126 changes: 126 additions & 0 deletions variants/thinknode_g3/platformio.ini
Original file line number Diff line number Diff line change
@@ -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='"#P@$sw0rd123456"'
-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='"#P@$sw0rd123456"'
-D ROOM_PASSWORD='"hellno"'
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}
+<helpers/esp32/*.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/ui/NullDisplayDriver.cpp>
+<../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}
+<helpers/esp32/*.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps =
${esp32_base.lib_deps}
densaugeo/base64 @ ~1.4.0
30 changes: 30 additions & 0 deletions variants/thinknode_g3/target.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <Arduino.h>
#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);
}
17 changes: 17 additions & 0 deletions variants/thinknode_g3/target.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/radiolib/RadioLibWrappers.h>
#include <ThinkNodeG3Board.h>
#include <helpers/radiolib/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>

extern ThinkNodeG3Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;

bool radio_init();
mesh::LocalIdentity radio_new_identity();
28 changes: 28 additions & 0 deletions variants/thinknode_g3/variant.h
Original file line number Diff line number Diff line change
@@ -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.