Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
089ad58
thinknode-m9 variant
mverch67 Apr 21, 2026
7960144
move lora to SPI1 device
mverch67 Apr 27, 2026
c85f2a2
enable SDcard
mverch67 Apr 27, 2026
9009bbd
use HSPI
mverch67 Apr 27, 2026
86a0d94
BaseUI tft -> HSPI
mverch67 Apr 27, 2026
d71a380
buzzer, webdav lib
mverch67 May 20, 2026
7088470
Merge branch 'develop' into thinknode-m9
mverch67 May 20, 2026
9d885ad
fix build issues
mverch67 May 21, 2026
d4d4b2c
M9 default to MUI, no BT, short ringtone
mverch67 May 21, 2026
8e6df32
add keyboard long-press config
mverch67 Jun 10, 2026
12ca206
update variant
mverch67 Jun 10, 2026
affbf05
add ThingNode-M9 GPS string
mverch67 Jun 11, 2026
813c990
GPS 115200 baud
mverch67 Jun 11, 2026
3d0b2ca
Merge branch 'develop' into thinknode-m9
mverch67 Jun 30, 2026
d56d5db
Merge branch 'develop' into thinknode-m9
jp-bennett Jul 1, 2026
ae34cce
Basic BaseUI support
jp-bennett Jul 1, 2026
8e75a76
Fixup power detection
jp-bennett Jul 1, 2026
071d7e1
Merge remote-tracking branch 'refs/remotes/origin/thinknode-m9' into …
mverch67 Jul 1, 2026
280a701
Compass and KB fixes for M9
jp-bennett Jul 2, 2026
2c23a2a
Merge remote-tracking branch 'refs/remotes/origin/thinknode-m9' into …
mverch67 Jul 6, 2026
fa5ff1e
add timed Lock::lock()
mverch67 Jul 6, 2026
7886e55
add SD card
mverch67 Jul 6, 2026
25c055a
Merge branch 'develop' into thinknode-m9
mverch67 Jul 6, 2026
000120f
point device-ui to thinknode m9 draft branch
mverch67 Jul 6, 2026
402c6f0
Merge branch 'develop' into thinknode-m9
thebentern Jul 6, 2026
8f18dce
Merge branch 'develop' into thinknode-m9
mverch67 Jul 7, 2026
a0c9736
trunk fmt
mverch67 Jul 7, 2026
c4e50c8
fix FusionCompass
mverch67 Jul 7, 2026
36a6b27
Fix t-deck-tft linker arg list overflow in CI
Copilot Jul 7, 2026
0d0aa7d
Merge branch 'develop' into thinknode-m9
mverch67 Jul 7, 2026
79ab3eb
Merge branch 'develop' into thinknode-m9
mverch67 Jul 8, 2026
fefb268
SDcard/lora fix: SPI1 must not be declared twice in arduino 3.x -> re…
mverch67 Jul 10, 2026
bbbd963
Merge branch 'develop' into thinknode-m9
mverch67 Jul 10, 2026
9fe9c31
Merge branch 'develop' into thinknode-m9
mverch67 Jul 13, 2026
5352260
Merge branch 'develop' into thinknode-m9
mverch67 Jul 14, 2026
2fc1d87
update battery parameters
mverch67 Jul 15, 2026
79ffa5c
reinit SD card when updating; fix PSRAM size
mverch67 Jul 15, 2026
269f21b
Merge branch 'develop' into thinknode-m9
mverch67 Jul 16, 2026
7b62dd3
Merge branch 'develop' into thinknode-m9
mverch67 Jul 22, 2026
58b6f8e
update lib versions
mverch67 Jul 22, 2026
e384f28
fix wakeup on key press (KB_INT)
mverch67 Jul 22, 2026
fd9bb08
fix default nag_timeout for TFT/MUI devices with buzzer
mverch67 Jul 22, 2026
4e96f7d
increase PSRAM and SD freq
mverch67 Jul 23, 2026
a3b0d2d
Merge branch 'develop' into thinknode-m9
mverch67 Jul 23, 2026
37ad16b
trunk fmt
mverch67 Jul 23, 2026
ddc4fb5
update lovyanGFX 1.2.26
mverch67 Jul 23, 2026
f0ec12b
update device-ui commit reference
mverch67 Jul 23, 2026
6024804
Merge branch 'develop' into thinknode-m9
mverch67 Jul 24, 2026
4dbd3a6
Merge branch 'develop' into thinknode-m9
mverch67 Jul 24, 2026
363b642
Merge branch 'develop' into thinknode-m9
mverch67 Jul 24, 2026
e33cc4c
Merge branch 'develop' into thinknode-m9
mverch67 Jul 27, 2026
fc7cae7
fix screen definition
mverch67 Jul 27, 2026
c831343
Merge branch 'develop' into thinknode-m9
mverch67 Jul 28, 2026
8df1ab1
remove DONE; maybe a keyword or other used identifier
mverch67 Jul 28, 2026
336097e
fixed CI error nag_timeout
mverch67 Jul 29, 2026
3691565
Merge branch 'develop' into thinknode-m9
mverch67 Jul 29, 2026
9e39aea
Merge branch 'develop' into thinknode-m9
mverch67 Aug 3, 2026
6fbd32f
fix prepareSleep initialization
mverch67 Aug 4, 2026
c6341ea
Merge branch 'develop' into thinknode-m9
mverch67 Aug 4, 2026
f1d410e
trunk fmt
mverch67 Aug 4, 2026
e5287f3
Merge branch 'develop' into thinknode-m9
mverch67 Aug 4, 2026
76c457f
reduce SD SPI frequency
mverch67 Aug 4, 2026
5f9a69b
update device-ui
mverch67 Aug 8, 2026
61ec082
Merge branch 'develop' into thinknode-m9
mverch67 Aug 8, 2026
644f3fb
Merge branch 'develop' into thinknode-m9
mverch67 Aug 9, 2026
a020a73
Merge branch 'develop' into thinknode-m9
mverch67 Aug 10, 2026
175c651
fix SDcard issue
mverch67 Aug 11, 2026
d53a7cc
stage
mverch67 Aug 11, 2026
6cf71be
Merge branch 'develop' into thinknode-m9
mverch67 Aug 11, 2026
24e8473
fix device-ui commit reference
mverch67 Aug 11, 2026
d3f9ab2
Merge branch 'develop' into thinknode-m9
mverch67 Aug 11, 2026
f69fe2f
fix device-ui commit
mverch67 Aug 11, 2026
e1364fd
update device-ui commit (fixed keyboard lag)
mverch67 Aug 12, 2026
85b785c
Merge branch 'develop' into thinknode-m9
mverch67 Aug 12, 2026
7360dda
fix QMI8658
mverch67 Aug 12, 2026
e7207ae
trunk fmt
mverch67 Aug 12, 2026
6e0a125
update .ini meta information, align SD freq
mverch67 Aug 12, 2026
b021334
fix device-ui reference to target (ready to merge)
mverch67 Aug 13, 2026
d0d9ddc
Merge branch 'develop' into thinknode-m9
mverch67 Aug 13, 2026
565d1f0
device-ui for all other targets
mverch67 Aug 13, 2026
659e342
make the rabbit happy
mverch67 Aug 13, 2026
f4ef229
trunk fmt
mverch67 Aug 13, 2026
08efca7
Merge branch 'develop' into thinknode-m9
mverch67 Aug 13, 2026
de7a414
Merge branch 'develop' into thinknode-m9
mverch67 Aug 14, 2026
ab4ec43
Merge branch 'develop' into thinknode-m9
mverch67 Aug 14, 2026
13b2f20
fixed lock screen
mverch67 Aug 14, 2026
84da087
fix compile error
mverch67 Aug 14, 2026
11b4308
SPI lock timeout
mverch67 Aug 14, 2026
d2a4bc0
Merge branch 'develop' into thinknode-m9
mverch67 Aug 14, 2026
9928983
apply device-ui fix
mverch67 Aug 17, 2026
030884d
revert bad RadioLib commit hash in platformio.ini
Copilot Aug 17, 2026
07631be
fix wrong commit hash change
mverch67 Aug 17, 2026
775357b
Merge branch 'develop' into thinknode-m9
mverch67 Aug 17, 2026
e130f98
fix fix commit fix
mverch67 Aug 17, 2026
1bbde19
I love changing random numbers in random files
mverch67 Aug 17, 2026
44b530f
Merge branch 'develop' into thinknode-m9
mverch67 Aug 17, 2026
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
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ lib_deps =
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/e1de01e0b3c4a6b149c00e95d59cfb0cca7ad49e.zip
https://github.com/meshtastic/device-ui/archive/adfbd3811a53b6aed0649c8d8f078118c042a407.zip
custom_sdkconfig =
# CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
Expand Down
24 changes: 13 additions & 11 deletions src/PowerFSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,23 +173,25 @@ static void lsIdle()
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
break;

default:
// We woke for some other reason (button press, device IRQ interrupt)

#ifdef BUTTON_PIN
bool pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#else
case ESP_SLEEP_WAKEUP_GPIO: {
bool pressed = false;
#if defined(BUTTON_PIN)
pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#elif defined(KB_INT)
// keyboard press (probably) triggered GPIO interrupt
pressed = true;
#endif
if (pressed) { // If we woke because of press, instead generate a PRESS event.
if (pressed) {
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
// we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
}
break;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
default:
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
// we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
break;
}
} else {
// Someone says we can't sleep now, so just save some power by sleeping the CPU for 100ms or so
delay(100);
Expand Down
10 changes: 10 additions & 0 deletions src/concurrency/Lock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ void Lock::lock()
}
}

bool Lock::lock(uint32_t timeout)
{
return xSemaphoreTake(handle, pdMS_TO_TICKS(timeout)) == pdTRUE;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

void Lock::unlock()
{
if (xSemaphoreGive(handle) == false) {
Expand All @@ -39,6 +44,11 @@ Lock::~Lock() {}

void Lock::lock() {}

bool Lock::lock(uint32_t)
{
return true;
}

void Lock::unlock() {}
#endif

Expand Down
5 changes: 5 additions & 0 deletions src/concurrency/Lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class Lock
// Must not be called from an ISR.
void lock();

/// Locks the lock with timeout.
//
// Must not be called from an ISR.
bool lock(uint32_t timeout);

// Unlocks the lock.
//
// Must not be called from an ISR.
Expand Down
2 changes: 2 additions & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BBQ10_KB_ADDR 0x1F
#define MPR121_KB_ADDR 0x5A
#define TCA8418_KB_ADDR 0x34
#define TSTC8_KB_ADDR 0x6C // STC8H companion-MCU keypad on the ThinkNode-M9

// -----------------------------------------------------------------------------
// SENSOR
Expand All @@ -270,6 +271,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define QMC5883L_ADDR 0x0D
#define HMC5883L_ADDR 0x1E
#define MMC5983MA_ADDR 0x30
#define QMC6309_ADDR 0x7C
#define SHTC3_ADDR 0x70
#define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D
Expand Down
14 changes: 7 additions & 7 deletions src/detect/ScanI2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const

ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB, TCA8418KB};
return firstOfOrNONE(6, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB, TCA8418KB, STC8HKB};
return firstOfOrNONE(7, types);
}

ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, SC7A20, BMA423, LSM6DS3, BMX160, STK8BAXX,
ICM20948, BMM150, BMI270, ICM42607P, ISM330DHCX, QMA6100P};
return firstOfOrNONE(13, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, SC7A20, BMA423, LSM6DS3, BMX160, STK8BAXX,
ICM20948, BMM150, BMI270, ICM42607P, ISM330DHCX, QMA6100P, QMI8658};
return firstOfOrNONE(14, types);
}

ScanI2C::FoundDevice ScanI2C::firstMagnetometer() const
{
ScanI2C::DeviceType types[] = {MMC5983MA, IIS2MDCTR};
return firstOfOrNONE(2, types);
ScanI2C::DeviceType types[] = {MMC5983MA, IIS2MDCTR, QMC6309};
return firstOfOrNONE(3, types);
}

ScanI2C::FoundDevice ScanI2C::firstAQI() const
Expand Down
2 changes: 2 additions & 0 deletions src/detect/ScanI2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ScanI2C
QMC5883L,
HMC5883L,
MMC5983MA,
QMC6309,
PMSA003I,
QMA6100P,
MPU6050,
Expand Down Expand Up @@ -105,6 +106,7 @@ class ScanI2C
IIS2MDCTR,
ISM330DHCX,
SPA06,
STC8HKB, // STC8H companion-MCU keypad (ThinkNode-M9)
DS248X,
HM330X
} DeviceType;
Expand Down
15 changes: 15 additions & 0 deletions src/detect/ScanI2CTwoWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
type = BBQ10KB;
logFoundDevice("BB Q10", (uint8_t)addr.address);
break;
SCAN_SIMPLE_CASE(TSTC8_KB_ADDR, STC8HKB, "STC8H KB", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address);
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address);
Expand Down Expand Up @@ -1093,6 +1094,20 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
foundDevices[addr] = type;
}
}

// The QMC6309 magnetometer sits at 0x7C, above the general scan ceiling (the loop above stops at 0x77 to
// avoid the reserved 0x78-0x7F block). Probe it explicitly. Gated on the SensorLib driver being present so
// only boards that can actually drive the chip poke this reserved address.
#if __has_include(<SensorQMC6309.hpp>)
addr.address = QMC6309_ADDR;
i2cBus->beginTransmission(addr.address);
if (i2cBus->endTransmission() == 0 &&
getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1) == 0x90 /* QMC6309 chip id */) {
deviceAddresses[QMC6309] = addr;
foundDevices[addr] = QMC6309;
logFoundDevice("QMC6309", (uint8_t)addr.address);
}
#endif
}

void ScanI2CTwoWire::scanPort(I2CPort port)
Expand Down
8 changes: 5 additions & 3 deletions src/gps/GPS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,7 @@ GnssModel_t GPS::probe(int serialSpeed)
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
{"UC6580", "UC6580", GNSS_MODEL_UC6580}
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
Expand All @@ -1713,8 +1713,10 @@ GnssModel_t GPS::probe(int serialSpeed)
case 1: {

// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
std::vector<ChipInfo> unicore = {
{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
std::vector<ChipInfo> unicore = {{"UC6580", "UC6580", GNSS_MODEL_UC6580},
{"UM600", "UM600", GNSS_MODEL_UC6580},
{"CM121", "CM121", GNSS_MODEL_CM121},
{"CC1167Q", "CC1167Q", GNSS_MODEL_CM121}};
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
currentDelay = 20;
currentStep = 2;
Expand Down
23 changes: 23 additions & 0 deletions src/graphics/draw/UIRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "graphics/images.h"
#include "main.h"
#include "target_specific.h"
#ifdef COMPASS_SENSOR_DEBUG
#include "motion/MotionSensor.h"
#endif
#include <OLEDDisplay.h>
#include <cstring>
#include <gps/RTC.h>
Expand Down Expand Up @@ -1776,6 +1779,26 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
const int *textPos = getTextPositions(display);
const bool compactPanel = graphics::isCompactPanel(display);

#ifdef COMPASS_SENSOR_DEBUG
// Optional raw IMU accel + magnetometer x/y/z readout for on-device axis/sign tuning.
{
char dbg[40];
float sx = 0, sy = 0, sz = 0;
uint32_t age = 0;
if (MotionSensor::getLatestCompassAccelSample(sx, sy, sz, age))
snprintf(dbg, sizeof(dbg), "A %.2f %.2f %.2f", sx, sy, sz);
else
snprintf(dbg, sizeof(dbg), "A ---");
display->drawString(x, textPos[line++], dbg);

if (MotionSensor::getLatestCompassMagSample(sx, sy, sz, age))
snprintf(dbg, sizeof(dbg), "M %.2f %.2f %.2f", sx, sy, sz);
else
snprintf(dbg, sizeof(dbg), "M ---");
display->drawString(x, textPos[line++], dbg);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
#endif

// === First Row: My Location ===
#if HAS_GPS
bool origBold = config.display.heading_bold;
Expand Down
29 changes: 23 additions & 6 deletions src/graphics/tftSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,8 @@ DeviceScreen *deviceScreen = nullptr;

#ifdef ARCH_ESP32
// Get notified when the system is entering light sleep
CallbackObserver<DeviceScreen, void *> tftSleepObserver =
CallbackObserver<DeviceScreen, void *>(deviceScreen, &DeviceScreen::prepareSleep);
CallbackObserver<DeviceScreen, esp_sleep_wakeup_cause_t> endSleepObserver =
CallbackObserver<DeviceScreen, esp_sleep_wakeup_cause_t>(deviceScreen, &DeviceScreen::wakeUp);
static CallbackObserver<DeviceScreen, void *> *tftSleepObserver = nullptr;
static CallbackObserver<DeviceScreen, esp_sleep_wakeup_cause_t> *endSleepObserver = nullptr;
#endif

/**
Expand Down Expand Up @@ -277,6 +275,19 @@ class ReentrantSpiLock : public ISpiLock
depth = 1;
}

bool lock(uint32_t timeout) override
{
ThreadId self = currentThread();
if (depth && owner == self) {
depth++;
return true;
}
bool result = spiLock->lock(timeout);
owner = self;
depth = 1;
return result;
}

void unlock(void) override
{
if (--depth == 0) {
Expand Down Expand Up @@ -413,8 +424,14 @@ void tftSetup(void)

if (deviceScreen) {
#ifdef ARCH_ESP32
tftSleepObserver.observe(&notifyLightSleep);
endSleepObserver.observe(&notifyLightSleepEnd);
if (!tftSleepObserver) {
tftSleepObserver = new CallbackObserver<DeviceScreen, void *>(deviceScreen, &DeviceScreen::prepareSleep);
}
if (!endSleepObserver) {
endSleepObserver = new CallbackObserver<DeviceScreen, esp_sleep_wakeup_cause_t>(deviceScreen, &DeviceScreen::wakeUp);
}
tftSleepObserver->observe(&notifyLightSleep);
endSleepObserver->observe(&notifyLightSleepEnd);
xTaskCreatePinnedToCore(tft_task_handler, "tft", TFT_TASK_STACK_SIZE, NULL, 1, NULL, 0);
#elif defined(ARCH_PORTDUINO)
std::thread *tft_task = new std::thread([] { tft_task_handler(); });
Expand Down
Loading
Loading