T-Watch target.cpp: fixed preamble = (sf <= 8) ? 32 : 16 to (sf <= 9) which I should have done in the first place to match meshcore PR 1954. Testing on Watch before applying wider change.

T-Watch: So many UI changes. Also swapped render battery indicator to use the AXP2101 gauge for hopefully higher accuracy. Also implemnted meck rx duty cycle for watch builds only to test out power saving effects first on watch build before implementing elsewhere.
This commit is contained in:
Pelgraine
2026-07-07 21:58:32 +10:00
parent d4286fdf84
commit 973d02df60
16 changed files with 308 additions and 29 deletions
@@ -405,6 +405,17 @@ class TWatchKeyboardScreen : public UIScreen {
DisplayDriver* _display;
uint8_t _channelIdx;
public:
enum Purpose { TWKB_CHANNEL, TWKB_DM, TWKB_ADMIN_PASSWORD, TWKB_ADMIN_CLI };
private:
Purpose _purpose;
int _contextIdx; // channel idx (channel) or contact idx (DM/admin)
bool _mask; // render composed text as '*' (admin password)
unsigned long _lastCharAt; // when the last char was typed (for reveal window)
static const unsigned long PW_REVEAL_MS = 2000; // show last char this long before masking
char _outBuf[TW_OUT_BUF_LEN];
uint16_t _outLen;
@@ -436,10 +447,10 @@ class TWatchKeyboardScreen : public UIScreen {
}
void appendChar(char ch) {
if (_outLen < MAXLEN) { _outBuf[_outLen++] = ch; _outBuf[_outLen] = 0; }
if (_outLen < MAXLEN) { _outBuf[_outLen++] = ch; _outBuf[_outLen] = 0; _lastCharAt = millis(); }
}
void backspace() {
if (_outLen > 0) { _outLen--; _outBuf[_outLen] = 0; }
if (_outLen > 0) { _outLen--; _outBuf[_outLen] = 0; _lastCharAt = 0; }
}
void cycleMode() {
_mode = (_mode == LOWER) ? UPPER : (_mode == UPPER ? SYM : LOWER);
@@ -454,7 +465,9 @@ class TWatchKeyboardScreen : public UIScreen {
public:
TWatchKeyboardScreen(DisplayDriver* display)
: _display(display), _channelIdx(0), _outLen(0), _mode(LOWER),
: _display(display), _channelIdx(0),
_purpose(TWKB_CHANNEL), _contextIdx(0), _mask(false), _lastCharAt(0),
_outLen(0), _mode(LOWER),
_touchDown(false), _downX(0), _downY(0),
_wantsSend(false), _wantsExit(false) {
_outBuf[0] = 0;
@@ -464,11 +477,28 @@ public:
void activate(uint8_t idx, const char* name) {
(void)name;
_channelIdx = idx;
_purpose = TWKB_CHANNEL;
_contextIdx = idx;
_mask = false;
_outLen = 0; _outBuf[0] = 0;
_mode = LOWER;
_touchDown = false; _wantsSend = false; _wantsExit = false;
}
// Enter text for a non-channel purpose (DM / admin password / admin CLI).
void activateFor(Purpose purpose, int contextIdx) {
_purpose = purpose;
_contextIdx = contextIdx;
_channelIdx = 0;
_mask = (purpose == TWKB_ADMIN_PASSWORD);
_outLen = 0; _outBuf[0] = 0;
_mode = LOWER;
_touchDown = false; _wantsSend = false; _wantsExit = false;
}
Purpose getPurpose() const { return _purpose; }
int getContextIdx() const { return _contextIdx; }
uint8_t getChannelIdx() const { return _channelIdx; }
bool consumeSendRequest(const char** textOut) {
if (!_wantsSend) return false;
@@ -515,15 +545,26 @@ public:
display.setColor(DisplayDriver::LIGHT);
{
// Mask the composed text with '*' for the admin password purpose.
char masked[TW_OUT_BUF_LEN];
const char* src = _outBuf;
if (_mask) {
int m = (_outLen < TW_OUT_BUF_LEN - 1) ? _outLen : TW_OUT_BUF_LEN - 1;
for (int i = 0; i < m; i++) masked[i] = '*';
// Reveal the most recently typed char briefly so it can be read.
if (m > 0 && (millis() - _lastCharAt < PW_REVEAL_MS)) masked[m - 1] = _outBuf[m - 1];
masked[m] = 0;
src = masked;
}
const int avail = W - 16 - 4; // room after the back arrow, minus cursor
int len = _outLen;
int fit = 0;
for (int n = 1; n <= len; n++) {
if (display.getTextWidth(_outBuf + (len - n)) > avail) break;
if (display.getTextWidth(src + (len - n)) > avail) break;
fit = n;
}
char tail[TW_OUT_BUF_LEN + 2];
strncpy(tail, _outBuf + (len - fit), sizeof(tail) - 2);
strncpy(tail, src + (len - fit), sizeof(tail) - 2);
tail[sizeof(tail) - 2] = 0;
size_t tl = strlen(tail);
tail[tl] = '_'; tail[tl + 1] = 0;
@@ -1,6 +1,12 @@
#include <Arduino.h>
#include "TWatchS3PlusBoard.h"
#include <SensorBMA423.hpp>
#include <esp_bt.h> // TEMP power-debug: esp_bt_controller_get_status()
volatile bool TWatchS3PlusBoard::_tilt_flag = false;
volatile uint32_t TWatchS3PlusBoard::_tilt_isr_count = 0; // TEMP diagnostic
void IRAM_ATTR TWatchS3PlusBoard::onTiltISR() { _tilt_flag = true; _tilt_isr_count++; }
void TWatchS3PlusBoard::begin() {
ESP32Board::begin();
@@ -13,12 +19,16 @@ void TWatchS3PlusBoard::begin() {
_accel->setRemapAxes(SensorRemap::BOTTOM_LAYER_TOP_RIGHT_CORNER);
_accel->configAccelerometer(OperationMode::NORMAL, AccelFullScaleRange::FS_2G,
50.0f, AccelBandwidth::OSR2_AVG2, AccelPerfMode::CIC_AVG_MODE);
_accel->enableTiltDetector(true, true);
// INT1 pin electrical config: level trigger, active high, push-pull,
// output enabled. INT1_IO_CTRL resets to output-disabled, so without
// this the pin never drives and INPUT_PULLDOWN reads low forever.
_accel->setInterruptPinConfig(InterruptPinMap::PIN1, false, false, true, false);
pinMode(PIN_ACCEL_IRQ, INPUT_PULLDOWN);
// Attach the edge ISR BEFORE enabling the tilt source, so the first
// assertion cannot occur before the handler is armed (a missed first edge
// on a self-clearing line otherwise locks tilt-wake out permanently).
attachInterrupt(digitalPinToInterrupt(PIN_ACCEL_IRQ), onTiltISR, RISING);
_accel->enableTiltDetector(true, true);
}
esp_reset_reason_t reason = esp_reset_reason();
@@ -80,9 +90,30 @@ bool TWatchS3PlusBoard::power_init() {
PMU->enableBattVoltageMeasure();
PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
// TEMP power-debug: one-shot rail dump at boot. Rail OFF means the attached
// chip has no power at all (not merely sleeping).
Serial.printf("[PWR] rails: ALDO2(bl)=%d ALDO3(disp/touch)=%d ALDO4(LoRa)=%d BLDO1(GPS)=%d BLDO2(haptic)=%d\n",
PMU->isPowerChannelEnable(XPOWERS_ALDO2),
PMU->isPowerChannelEnable(XPOWERS_ALDO3),
PMU->isPowerChannelEnable(XPOWERS_ALDO4),
PMU->isPowerChannelEnable(XPOWERS_BLDO1),
PMU->isPowerChannelEnable(XPOWERS_BLDO2));
Serial.printf("[PWR] GPS rail (BLDO1) at boot: %s\n",
PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "ON" : "OFF (fully powered down)");
return true;
}
// TEMP power-debug probe.
void TWatchS3PlusBoard::printPowerDebug() {
if (!PMU) return;
Serial.printf("[PWR] batt=%dmV %d%% vbus=%dmV charging=%d cpu=%dMHz bt=%d gps_rail=%s\n",
PMU->getBattVoltage(), PMU->getBatteryPercent(),
PMU->getVbusVoltage(), PMU->isCharging(),
getCpuFrequencyMhz(), (int)esp_bt_controller_get_status(),
PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "ON" : "OFF");
}
void TWatchS3PlusBoard::gpsPowerOn() {
if (PMU) {
PMU->enablePowerOutput(XPOWERS_BLDO1);
@@ -95,9 +126,18 @@ void TWatchS3PlusBoard::gpsPowerOff() {
}
bool TWatchS3PlusBoard::tiltFired() {
if (digitalRead(PIN_ACCEL_IRQ)) { // only the tilt IRQ is enabled
_accel->update(); // reading the status clears the latched INT
if (_tilt_flag) { // set by the GPIO14 rising-edge ISR
_tilt_flag = false;
_accel->update(); // reading the status clears the sensor INT
return true;
}
// TEMP diagnostic: periodically report the raw INT pin level and ISR count,
// to distinguish "pin stuck high / never re-arms" from "never asserts".
static unsigned long _tilt_dbg_next = 0;
if (millis() >= _tilt_dbg_next) {
_tilt_dbg_next = millis() + 5000;
Serial.printf("[TILT] pin=%d isr_count=%u\n",
digitalRead(PIN_ACCEL_IRQ), (unsigned)_tilt_isr_count);
}
return false;
}
@@ -17,6 +17,9 @@ class SensorBMA423; // full include kept in the .cpp to avoid a BLE-build heade
class TWatchS3PlusBoard : public ESP32Board {
XPowersLibInterface* PMU = NULL;
SensorBMA423* _accel = nullptr;
static volatile bool _tilt_flag;
static volatile uint32_t _tilt_isr_count; // TEMP diagnostic
static void IRAM_ATTR onTiltISR(); // defined in the .cpp (IRAM relocation)
bool power_init();
@@ -50,11 +53,19 @@ public:
return PMU ? PMU->getBattVoltage() : 0;
}
uint8_t getBatteryPercent() override {
return PMU ? PMU->getBatteryPercent() : 0;
}
// GPS power is the AXP2101 BLDO1 rail. Off at boot; toggled at runtime via
// the gps_enabled pref (boot) and the "gps on/off" CLI command (live).
void gpsPowerOn();
void gpsPowerOff();
// TEMP power-debug probe: battery, VBUS, CPU clock, BT controller state and
// live rail states (incl. GPS/BLDO1). Called periodically from UITask::loop.
void printPowerDebug();
const char* getManufacturerName() const override {
return "LilyGo T-Watch S3 Plus";
}
@@ -12,6 +12,7 @@ build_flags =
-I variants/lilygo_twatch_s3_plus
-D LILYGO_TWATCH_S3_PLUS
-D TWATCH_COMPOSE_ENABLED
-D MECK_RX_DUTY_CYCLE
-D BOARD_HAS_PSRAM=1
-D CORE_DEBUG_LEVEL=1
-D FORMAT_SPIFFS_IF_FAILED=1
+1 -1
View File
@@ -51,7 +51,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
// Longer preamble for low SF improves reliability -- each symbol is shorter
// at low SF, so more symbols are needed for reliable detection.
uint16_t preamble = (sf <= 8) ? 32 : 16;
uint16_t preamble = (sf <= 9) ? 32 : 16;
radio.setPreambleLength(preamble);
}