mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-10 10:42:42 +02:00
initial max updates - not yet working
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user