initial max updates - not yet working

This commit is contained in:
pelgraine
2026-06-02 18:03:09 +10:00
parent 4dfefa58ca
commit 590655016a
13 changed files with 224 additions and 51 deletions
+5
View File
@@ -292,6 +292,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
if (file.read((uint8_t *)_prefs.channel_notif, sizeof(_prefs.channel_notif)) != sizeof(_prefs.channel_notif)) {
memset(_prefs.channel_notif, 0, sizeof(_prefs.channel_notif)); // default: NOTIF_ALL
}
if (file.read((uint8_t *)&_prefs.lora_antenna, sizeof(_prefs.lora_antenna)) != sizeof(_prefs.lora_antenna)) {
_prefs.lora_antenna = 0; // default: internal antenna
}
// Clamp to valid ranges
if (_prefs.dark_mode > 1) _prefs.dark_mode = 0;
@@ -305,6 +308,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
for (int i = 0; i < (int)sizeof(_prefs.channel_notif); i++) {
if (_prefs.channel_notif[i] > 2) _prefs.channel_notif[i] = 0;
}
if (_prefs.lora_antenna > 1) _prefs.lora_antenna = 0;
// auto_lock_minutes: only accept known options (0, 2, 5, 10, 15, 30)
{
uint8_t alm = _prefs.auto_lock_minutes;
@@ -365,6 +369,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 106
file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 137
file.write((uint8_t *)_prefs.channel_notif, sizeof(_prefs.channel_notif)); // 153
file.write((uint8_t *)&_prefs.lora_antenna, sizeof(_prefs.lora_antenna)); // 174
file.close();
}
+5
View File
@@ -64,6 +64,11 @@ struct NodePrefs { // persisted to file
// Defaults to NOTIF_ALL for all channels.
uint8_t channel_notif[21]; // 20 group channels + 1 DM slot
// --- LoRa antenna selection (T-Deck Pro MAX only) ---
// 0 = internal antenna (XL9555 LORA_SEL HIGH), 1 = external (LORA_SEL LOW).
// Applied at boot in main.cpp and live on toggle in SettingsScreen.
uint8_t lora_antenna; // 0 = internal (default), 1 = external
// --- Font helpers (inline, no overhead) ---
// Returns the DisplayDriver text-size index for "small/body" text.
// T-Deck Pro: 0 = built-in 6×8 (or 7pt with custom fonts), 1 = 9pt.
+27 -1
View File
@@ -2140,6 +2140,12 @@ void setup() {
);
MESH_DEBUG_PRINTLN("setup() - the_mesh.begin() done");
#if defined(LilyGo_TDeck_Pro_Max)
// Restore saved LoRa antenna selection (XL9555 boots to internal by default)
if (the_mesh.getNodePrefs()->lora_antenna) board.loraAntennaExternal();
else board.loraAntennaInternal();
#endif
// Boot-time config import: check for /meshcore/import.json on SD
#ifdef HAS_SDCARD
if (sdCardReady) {
@@ -2540,6 +2546,17 @@ void setup() {
if (p4) free(p4); if (p10) free(p10); if (p25) free(p25);
}
MESH_DEBUG_PRINTLN("=== setup() - COMPLETE ===");
// DIAGNOSTIC: assert the frontlight at the very end of setup(), after ALL
// init has run. The factory firmware proves analogWrite(41,50) lights this
// panel. If the home screen is lit now (but the early step-12 assert was
// not), the pin was being reconfigured during init and this late assert wins.
// If it lights now and stays until a specific screen is opened, that screen's
// pinMode(41) is the thief. Watch this marker vs the screen you open.
#ifdef PIN_EINK_BL
analogWrite(PIN_EINK_BL, 50);
Serial.println(">>> BL DIAG: analogWrite(41,50) asserted at end of setup()");
#endif
}
// ---------------------------------------------------------------------------
@@ -4100,7 +4117,16 @@ void handleKeyboardInput() {
// Defer contact saves while user is actively pressing keys
the_mesh.notifyUserInput();
#if defined(LilyGo_TDeck_Pro_Max)
// Alt+B toggles the e-ink frontlight (MAX only -- working backlight on IO41)
if (key == KB_KEY_BACKLIGHT) {
if (board.isBacklightOn()) board.backlightOff();
else board.backlightOn();
return;
}
#endif
// Alarm ringing: ANY key dismisses (highest priority after lock screen)
#ifdef MECK_AUDIO_VARIANT
{
@@ -43,6 +43,11 @@ class UITask;
class MyMesh;
extern MyMesh the_mesh;
#if defined(LilyGo_TDeck_Pro_Max)
#include "TDeckProMaxBoard.h"
extern TDeckProMaxBoard board;
#endif
// ---------------------------------------------------------------------------
// Auto-add config bitmask (mirrored from MyMesh.cpp for UI access)
// ---------------------------------------------------------------------------
@@ -124,6 +129,9 @@ static inline int findAutoLockIndex(uint8_t minutes) {
// Settings row types
// ---------------------------------------------------------------------------
enum SettingsRowType : uint8_t {
#if defined(LilyGo_TDeck_Pro_Max)
ROW_LORA_ANTENNA, // LoRa antenna select: internal/external (MAX only)
#endif
ROW_NAME, // Device name (text editor)
ROW_RADIO_PRESET, // Radio preset picker
ROW_FREQ, // Frequency (float)
@@ -249,14 +257,19 @@ enum FmPhase : uint8_t {
#endif
// Max rows in the settings list (increased for contact sub-toggles + WiFi)
#if defined(HAS_4G_MODEM) && defined(MECK_WIFI_COMPANION)
#define SETTINGS_MAX_ROWS 63 // Extra rows for IMEI, Carrier, APN, contacts, WiFi, scope, export
#elif defined(HAS_4G_MODEM)
#define SETTINGS_MAX_ROWS 61 // Extra rows for IMEI, Carrier, APN + contacts + scope + export
#elif defined(MECK_WIFI_COMPANION)
#define SETTINGS_MAX_ROWS 57 // Extra rows for contacts + WiFi + scope + export
#if defined(LilyGo_TDeck_Pro_Max)
#define SETTINGS_LORA_ANTENNA_ROWS 1 // LoRa antenna toggle (MAX only)
#else
#define SETTINGS_MAX_ROWS 55 // Contacts section + scope + export
#define SETTINGS_LORA_ANTENNA_ROWS 0
#endif
#if defined(HAS_4G_MODEM) && defined(MECK_WIFI_COMPANION)
#define SETTINGS_MAX_ROWS (63 + SETTINGS_LORA_ANTENNA_ROWS) // Extra rows for IMEI, Carrier, APN, contacts, WiFi, scope, export
#elif defined(HAS_4G_MODEM)
#define SETTINGS_MAX_ROWS (61 + SETTINGS_LORA_ANTENNA_ROWS) // Extra rows for IMEI, Carrier, APN + contacts + scope + export
#elif defined(MECK_WIFI_COMPANION)
#define SETTINGS_MAX_ROWS (57 + SETTINGS_LORA_ANTENNA_ROWS) // Extra rows for contacts + WiFi + scope + export
#else
#define SETTINGS_MAX_ROWS (55 + SETTINGS_LORA_ANTENNA_ROWS) // Contacts section + scope + export
#endif
#define SETTINGS_TEXT_BUF 33 // 32 chars + null
@@ -466,6 +479,9 @@ private:
#endif
} else {
// --- Top-level settings list ---
#if defined(LilyGo_TDeck_Pro_Max)
addRow(ROW_LORA_ANTENNA);
#endif
addRow(ROW_NAME);
addRow(ROW_RADIO_PRESET);
addRow(ROW_FREQ);
@@ -1900,6 +1916,14 @@ public:
break;
}
#if defined(LilyGo_TDeck_Pro_Max)
case ROW_LORA_ANTENNA:
snprintf(tmp, sizeof(tmp), "LoRa Antenna: %s",
_prefs->lora_antenna ? "External" : "Internal");
display.print(tmp);
break;
#endif
case ROW_DARK_MODE:
snprintf(tmp, sizeof(tmp), "Dark Mode: %s",
_prefs->dark_mode ? "ON" : "OFF");
@@ -3503,6 +3527,16 @@ public:
case ROW_GPS_BAUD:
startEditPicker(findGpsBaudIndex(_prefs->gps_baudrate));
break;
#if defined(LilyGo_TDeck_Pro_Max)
case ROW_LORA_ANTENNA:
_prefs->lora_antenna = _prefs->lora_antenna ? 0 : 1;
if (_prefs->lora_antenna) board.loraAntennaExternal();
else board.loraAntennaInternal();
the_mesh.savePrefs();
Serial.printf("Settings: LoRa antenna = %s\n",
_prefs->lora_antenna ? "External" : "Internal");
break;
#endif
case ROW_DARK_MODE:
_prefs->dark_mode = _prefs->dark_mode ? 0 : 1;
the_mesh.savePrefs();
+48 -12
View File
@@ -32,16 +32,30 @@
#include <Arduino.h>
#include <Wire.h>
// The CST328 pulses its INT line low (falling edge) when a new touch report is
// ready. We attach an edge interrupt that sets this flag, and only read/ack the
// controller when it has fired -- mirroring the Hynitron driver, which reads
// only on the INT edge instead of blind-polling. Blind polling at 50 Hz was the
// source of the i2cRead -1/263 errors (reading when no report was pending).
namespace {
volatile bool _touchIrqFired = false;
void IRAM_ATTR _touchIsr() { _touchIrqFired = true; }
}
class TouchInput {
public:
static const uint8_t TOUCH_ADDR = 0x1A;
TouchInput(TwoWire* wire = &Wire)
: _wire(wire), _intPin(-1), _initialized(false), _debugCount(0), _lastPoll(0) {}
: _wire(wire), _intPin(-1), _initialized(false), _debugCount(0) {}
bool begin(int intPin) {
_intPin = intPin;
pinMode(_intPin, INPUT);
// On ESP32 every GPIO is interrupt-capable and digitalPinToInterrupt is an
// identity macro (pin == interrupt number), but it is not always visible in
// this header's include context -- pass the GPIO number directly.
attachInterrupt(_intPin, _touchIsr, FALLING);
// Verify the touch controller is present on the bus
_wire->beginTransmission(TOUCH_ADDR);
@@ -52,38 +66,61 @@ public:
}
Serial.printf("[Touch] CST328 found at 0x%02X, INT=GPIO%d\n", TOUCH_ADDR, _intPin);
// Enter normal report mode: write command register 0xD109. The Hynitron
// driver does this once after reset (cst3xx_init -> set_workmode NOMAL_MODE).
_wire->beginTransmission(TOUCH_ADDR);
_wire->write(0xD1);
_wire->write(0x09);
_wire->endTransmission(true);
_initialized = true;
return true;
}
bool isReady() const { return _initialized; }
// Poll for touch. Returns true if a finger is down, fills x and y.
// Coordinates are in physical display space (0-239 X, 0-319 Y).
// NOTE: CST328 INT pin is pulse-based, not level. We cannot rely on
// digitalRead(INT) for touch state. Instead, always read and check buf[0].
// Returns true if a finger is down, fills x and y (physical display space:
// 0-239 X, 0-319 Y). Reads only when the INT edge interrupt has fired.
bool getPoint(int16_t &x, int16_t &y) {
if (!_initialized) return false;
// Rate limit: poll at most every 20ms (50 Hz) to avoid I2C bus congestion
unsigned long now = millis();
if (now - _lastPoll < 20) return false;
_lastPoll = now;
// Only touch the bus when the INT line has signalled a new report. With no
// pending report there is nothing to read, and reading anyway is what
// produced the i2cRead -1/263 errors.
if (!_touchIrqFired) return false;
_touchIrqFired = false;
uint8_t buf[7];
memset(buf, 0, sizeof(buf));
// Write register address 0xD000
// Write register address 0xD000.
// Use a STOP here (true), not a repeated start (false): the repeated-start
// combined read (i2cWriteReadNonStop) is what was throwing the -1/263 errors
// on this bus, while the keyboard's stop-then-read pattern never errors.
_wire->beginTransmission(TOUCH_ADDR);
_wire->write(0xD0);
_wire->write(0x00);
if (_wire->endTransmission(false) != 0) return false;
if (_wire->endTransmission(true) != 0) return false;
// Read 7 bytes of touch data
uint8_t received = _wire->requestFrom(TOUCH_ADDR, (uint8_t)7);
if (received < 7) return false;
for (int i = 0; i < 7; i++) buf[i] = _wire->read();
// Acknowledge the report: write 0xAB to register 0xD000 so the controller
// releases its buffer for the next frame. Required after EVERY read of
// 0xD000 -- without it the CST328 re-serves stale frames (phantom touches)
// and eventually NAKs the read. Matches the Hynitron driver tail-end write.
_wire->beginTransmission(TOUCH_ADDR);
_wire->write(0xD0);
_wire->write(0x00);
_wire->write(0xAB);
_wire->endTransmission(true);
// Check byte: a valid frame always has buf[6] == 0xAB. Reject anything else.
if (buf[6] != 0xAB) return false;
// buf[0] == 0xAB means idle (no touch active)
if (buf[0] == 0xAB) return false;
@@ -121,7 +158,6 @@ private:
int _intPin;
bool _initialized;
int _debugCount;
unsigned long _lastPoll;
};
#endif // TOUCH_INPUT_H