mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-09 18:22:45 +02:00
T-Watch: fix discovery screen wrap. Add no alarm tick s3 temp diagnostic build and removed prior faulty temp no pmu diagnostic build. Updated tracescreen.h functionality and UI for t-watch builds.
This commit is contained in:
@@ -1612,6 +1612,28 @@ static void lastHeardToggleContact() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(MECK_TWATCH)
|
||||
// Trace screen (watch): tap to select row, tap same to activate. Mode row
|
||||
// toggles 1/2-byte; Type Path opens the keyboard (handleInput -> wantsKeyboard).
|
||||
// Guarded to the watch: selectRowAtVY uses the watch's 128-space coords, and
|
||||
// T5S3/T-Deck keep their existing boot-button/keyboard trace handling.
|
||||
if (ui_task.isOnTraceScreen()) {
|
||||
TraceScreen* ts = (TraceScreen*)ui_task.getTraceScreen();
|
||||
if (ts) {
|
||||
int result = ts->selectRowAtVY(vy);
|
||||
if (result == 1) {
|
||||
ui_task.forceRefresh();
|
||||
return 0;
|
||||
}
|
||||
if (result == 2) {
|
||||
if (ts->isOnModeRow()) return 'd'; // toggle 1-byte / 2-byte
|
||||
return KEY_ENTER; // Type Path / Add / Remove / Run / Exit / hop
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Discovery screen: tap to select, tap same to add
|
||||
if (ui_task.isOnDiscoveryScreen()) {
|
||||
DiscoveryScreen* ds = (DiscoveryScreen*)ui_task.getDiscoveryScreen();
|
||||
|
||||
@@ -104,11 +104,11 @@ public:
|
||||
display.setCursor(4, 28);
|
||||
display.print(active ? "Listening for adverts..." : "No nodes found");
|
||||
#if defined(MECK_TWATCH)
|
||||
display.setCursor(4, 38);
|
||||
display.print("Hold: Rescan");
|
||||
display.setCursor(4, 48);
|
||||
display.print("Tap: Select");
|
||||
display.print("Hold: Rescan");
|
||||
display.setCursor(4, 58);
|
||||
display.print("Tap: Select");
|
||||
display.setCursor(4, 68);
|
||||
display.print("Tap Again: Add");
|
||||
#else
|
||||
if (!active) {
|
||||
|
||||
@@ -91,6 +91,9 @@ private:
|
||||
int _resultScroll;
|
||||
|
||||
bool _wantExit;
|
||||
#if defined(MECK_TWATCH)
|
||||
bool _wantKeyboard; // Watch: Type Path tapped -> UITask opens the on-screen keyboard
|
||||
#endif
|
||||
|
||||
// --- Menu helpers (STATE_BUILD) ---
|
||||
// Menu layout:
|
||||
@@ -313,6 +316,56 @@ public:
|
||||
return _state == STATE_BUILD && menuItemAt(_menuSel) == MENU_TYPE_PATH;
|
||||
}
|
||||
|
||||
// True if the highlighted menu row is the Mode selector (STATE_BUILD only).
|
||||
bool isOnModeRow() const {
|
||||
return _state == STATE_BUILD && menuItemAt(_menuSel) == MENU_PATH_SIZE;
|
||||
}
|
||||
|
||||
#if defined(MECK_TWATCH)
|
||||
bool wantsKeyboard() const { return _wantKeyboard; }
|
||||
void clearWantKeyboard() { _wantKeyboard = false; }
|
||||
|
||||
// Tap-to-select row mapping for the watch (mirrors PathEditor/Discovery).
|
||||
// vy is in the 128-tall virtual touch space. Returns:
|
||||
// 0 = miss, 1 = moved the cursor, 2 = tapped the already-selected row.
|
||||
int selectRowAtVY(int vy) {
|
||||
if (_state == STATE_BUILD) return selectBuildRowAtVY(vy);
|
||||
if (_state == STATE_PICK_HOP) return selectPickerRowAtVY(vy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int selectBuildRowAtVY(int vy) {
|
||||
int menuCount = buildMenuCount();
|
||||
if (menuCount == 0) return 0;
|
||||
const int headerH = 14, footerH = 14, lineH = 11;
|
||||
const int bodyTop = headerH; // renderBuild draws row 0 at y=14
|
||||
if (vy < bodyTop || vy >= 128 - footerH) return 0;
|
||||
int maxVisible = (128 - headerH - footerH) / lineH;
|
||||
if (maxVisible < 1) maxVisible = 1;
|
||||
// Replicate renderBuild's scroll window so a tap maps to the drawn row.
|
||||
int scrollTop = 0;
|
||||
if (_menuSel >= scrollTop + maxVisible) scrollTop = _menuSel - maxVisible + 1;
|
||||
if (_menuSel < scrollTop) scrollTop = _menuSel;
|
||||
int tappedRow = scrollTop + (vy - bodyTop) / lineH;
|
||||
if (tappedRow < 0 || tappedRow >= menuCount) return 0;
|
||||
if (tappedRow == _menuSel) return 2;
|
||||
_menuSel = tappedRow;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int selectPickerRowAtVY(int vy) {
|
||||
if (_repCount == 0) return 0;
|
||||
const int headerH = 14, footerH = 14, lineH = 11;
|
||||
const int bodyTop = headerH; // renderPicker draws row 0 at y=14
|
||||
if (vy < bodyTop || vy >= 128 - footerH) return 0;
|
||||
int tappedRow = _repScroll + (vy - bodyTop) / lineH;
|
||||
if (tappedRow < 0 || tappedRow >= _repCount) return 0;
|
||||
if (tappedRow == _repSel) return 2;
|
||||
_repSel = tappedRow;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns the current path formatted as a comma-separated string, suitable
|
||||
// for pre-populating an external text editor (e.g. the T5S3 virtual keyboard).
|
||||
// The returned pointer references an internal buffer and is valid until the
|
||||
@@ -343,6 +396,9 @@ public:
|
||||
_repSel = 0;
|
||||
_repScroll = 0;
|
||||
_wantExit = false;
|
||||
#if defined(MECK_TWATCH)
|
||||
_wantKeyboard = false;
|
||||
#endif
|
||||
_resultScroll = 0;
|
||||
memset(_pathBuf, 0, sizeof(_pathBuf));
|
||||
memset(&_result, 0, sizeof(_result));
|
||||
@@ -462,6 +518,8 @@ private:
|
||||
} else {
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
snprintf(tmp, sizeof(tmp), "%c Type Path: [Long press]", prefix);
|
||||
#elif defined(MECK_TWATCH)
|
||||
snprintf(tmp, sizeof(tmp), "%c Type Path: [Tap]", prefix);
|
||||
#else
|
||||
snprintf(tmp, sizeof(tmp), "%c Type Path: [Press Enter]", prefix);
|
||||
#endif
|
||||
@@ -533,6 +591,8 @@ private:
|
||||
} else {
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.print("Boot:Exit Tap:Sel");
|
||||
#elif defined(MECK_TWATCH)
|
||||
display.print("Tap:Sel Hold:Go");
|
||||
#else
|
||||
display.print("Sh+Del:Exit W/S:Nav Ent:Sel");
|
||||
#endif
|
||||
@@ -596,6 +656,8 @@ private:
|
||||
display.setCursor(0, footerY);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.print("Boot:Back Tap:Add");
|
||||
#elif defined(MECK_TWATCH)
|
||||
display.print("Tap:Sel Hold:Add");
|
||||
#else
|
||||
display.print("Sh+Del:Back W/S:Scroll Ent:Add");
|
||||
#endif
|
||||
@@ -748,6 +810,8 @@ private:
|
||||
display.setCursor(0, footerY);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.print("Boot:Back Tap:New Trace");
|
||||
#elif defined(MECK_TWATCH)
|
||||
display.print("Hold: New Trace");
|
||||
#else
|
||||
display.print("Sh+Del:Back Ent:New Trace");
|
||||
#endif
|
||||
@@ -843,9 +907,15 @@ private:
|
||||
MenuItem item = menuItemAt(_menuSel);
|
||||
switch (item) {
|
||||
case MENU_TYPE_PATH:
|
||||
// Enter edit mode -- pre-fill with current path if any
|
||||
pathToEditBuf();
|
||||
#if defined(MECK_TWATCH)
|
||||
// Watch: no physical keys -- request the on-screen keyboard. The main
|
||||
// loop polls wantsKeyboard() and opens it, pre-filled with the path.
|
||||
_wantKeyboard = true;
|
||||
#else
|
||||
// Enter inline edit mode -- pre-fill with current path if any
|
||||
_editing = true;
|
||||
#endif
|
||||
return true;
|
||||
|
||||
case MENU_ADD_HOP:
|
||||
|
||||
@@ -1694,7 +1694,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
_sensors = sensors;
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON)) && !defined(MECK_DIAG_NO_PMU)
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON))
|
||||
user_btn.begin();
|
||||
#endif
|
||||
#if defined(PIN_USER_BTN_ANA)
|
||||
@@ -2291,7 +2291,7 @@ void UITask::shutdown(bool restart){
|
||||
}
|
||||
|
||||
bool UITask::isButtonPressed() const {
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON)) && !defined(MECK_DIAG_NO_PMU)
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON))
|
||||
return user_btn.isPressed();
|
||||
#else
|
||||
return false;
|
||||
@@ -2314,7 +2314,7 @@ void UITask::loop() {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON)) && !defined(MECK_DIAG_NO_PMU)
|
||||
#if (defined(PIN_USER_BTN) || defined(MECK_PMU_BUTTON))
|
||||
int ev = user_btn.check();
|
||||
if (ev == BUTTON_EVENT_CLICK) {
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
@@ -2511,7 +2511,7 @@ void UITask::loop() {
|
||||
if (buzzer.isPlaying()) buzzer.loop();
|
||||
#endif
|
||||
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
#if defined(LILYGO_TWATCH_S3) && !defined(MECK_DIAG_NO_ALARM)
|
||||
// Alarms are checked every loop, not from the screen's poll(), so one fires
|
||||
// with the display off or another screen showing.
|
||||
if (watch_alarm_screen) {
|
||||
@@ -2626,6 +2626,12 @@ if (curr) curr->poll();
|
||||
if (watch_channel_cfg_screen) setCurrScreen(watch_channel_cfg_screen);
|
||||
else gotoHomeScreen();
|
||||
if (serr) showAlert(serr, 1200);
|
||||
} else if (purpose == TWatchKeyboardScreen::TWKB_TRACE_PATH) {
|
||||
TraceScreen* ts = (TraceScreen*)getTraceScreen();
|
||||
if (ts) ts->setTypedPath(sendText);
|
||||
kb->clearOutBuf();
|
||||
if (trace_screen) setCurrScreen(trace_screen);
|
||||
else gotoHomeScreen();
|
||||
} else { // TWKB_ADMIN_PASSWORD or TWKB_ADMIN_CLI
|
||||
RepeaterAdminScreen* admin = (RepeaterAdminScreen*)getRepeaterAdminScreen();
|
||||
if (admin) {
|
||||
@@ -2666,6 +2672,14 @@ if (curr) curr->poll();
|
||||
gotoSettingsScreen();
|
||||
}
|
||||
}
|
||||
else if (curr == trace_screen && trace_screen != nullptr) {
|
||||
TraceScreen* ts = (TraceScreen*)trace_screen;
|
||||
if (ts->wantsKeyboard()) {
|
||||
ts->clearWantKeyboard();
|
||||
openTWatchKeyboard(TWatchKeyboardScreen::TWKB_TRACE_PATH, 0);
|
||||
((TWatchKeyboardScreen*)tw_keyboard)->setInitialText(ts->getCurrentPathAsText());
|
||||
}
|
||||
}
|
||||
else if (curr == settings_screen && settings_screen != nullptr) {
|
||||
SettingsScreen* ss = (SettingsScreen*)settings_screen;
|
||||
if (ss->wantsWatchChannels()) {
|
||||
|
||||
@@ -492,7 +492,7 @@ class TWatchKeyboardScreen : public UIScreen {
|
||||
uint8_t _channelIdx;
|
||||
|
||||
public:
|
||||
enum Purpose { TWKB_CHANNEL, TWKB_DM, TWKB_ADMIN_PASSWORD, TWKB_ADMIN_CLI, TWKB_PATH, TWKB_NOTE, TWKB_SCOPE };
|
||||
enum Purpose { TWKB_CHANNEL, TWKB_DM, TWKB_ADMIN_PASSWORD, TWKB_ADMIN_CLI, TWKB_PATH, TWKB_NOTE, TWKB_SCOPE, TWKB_TRACE_PATH };
|
||||
|
||||
private:
|
||||
Purpose _purpose;
|
||||
|
||||
@@ -180,17 +180,11 @@ bool TWatchS3Board::power_init() {
|
||||
|
||||
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
||||
PMU->clearIrqStatus();
|
||||
#if !defined(MECK_DIAG_NO_PMU)
|
||||
// SHORT gives the click; NEGATIVE/POSITIVE are the press/release edges that
|
||||
// back PMUButton::isPressed().
|
||||
PMU->enableIRQ(XPOWERS_AXP2101_PKEY_SHORT_IRQ |
|
||||
XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ |
|
||||
XPOWERS_AXP2101_PKEY_POSITIVE_IRQ);
|
||||
#endif
|
||||
// TEMP DIAGNOSTIC (MECK_DIAG_NO_PMU, power bisect): with the PKEY IRQs left
|
||||
// disabled above and PMUButton::check() skipped in UITask, the PMU-button
|
||||
// subsystem is fully inert -- no IRQ config, no 30 ms polling, no dangling
|
||||
// latch. disableIRQ(ALL)+clearIrqStatus above already left the PMU quiet.
|
||||
|
||||
// 150 mA = 0.32C on the 470 mAh cell -- a modest bump over the 125 mA
|
||||
// vendor default (LilyGoWatchS3.cpp uses 125), well under the 0.5C rule.
|
||||
|
||||
@@ -138,20 +138,19 @@ lib_deps =
|
||||
lib_ignore =
|
||||
AsyncTCP
|
||||
ESPAsyncWebServer
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; TEMP DIAGNOSTIC BUILD -- power-drain bisect (remove when concluded).
|
||||
; The S3 standalone firmware with the PMU-button subsystem fully disabled,
|
||||
; gated by MECK_DIAG_NO_PMU: the PKEY IRQ enable in power_init is skipped and
|
||||
; PMUButton::check()/begin()/isPressed() are compiled out of UITask, so there
|
||||
; is no IRQ config and no 30 ms I2C polling of the PMU (and no dangling latch).
|
||||
; Run the same wear test as the standalone S3 build; a materially slower drain
|
||||
; implicates the PMU-button subsystem in the S3-only excess. The PWR key does
|
||||
; nothing on this build (no click, no wake, no path-editor open) by design.
|
||||
; Revert: delete this env and grep MECK_DIAG_NO_PMU (one block in
|
||||
; TWatchS3Board.cpp, three in UITask.cpp).
|
||||
; Flash: pio run -e meck_twatch_s3_diag_nopmu -t upload
|
||||
; The S3 standalone firmware with the per-loop WatchAlarmScreen tick() disabled,
|
||||
; gated by MECK_DIAG_NO_ALARM: the alarm-check block in UITask::loop is compiled
|
||||
; out, so localNow() (an RTC read) and the slot scan no longer run every loop.
|
||||
; The alarm screen is still created and menu-reachable, but no alarm can fire on
|
||||
; this build by design. Run the same wear test as the standalone S3 build; a
|
||||
; materially slower drain implicates the alarm tick() in the S3-only excess.
|
||||
; Revert: delete this env and grep MECK_DIAG_NO_ALARM (one block in UITask.cpp).
|
||||
; Flash: pio run -e meck_twatch_s3_diag_noalarm -t upload
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:meck_twatch_s3_diag_nopmu]
|
||||
[env:meck_twatch_s3_diag_noalarm]
|
||||
extends = LilyGo_TWatchS3
|
||||
build_flags =
|
||||
${LilyGo_TWatchS3.build_flags}
|
||||
@@ -160,8 +159,8 @@ build_flags =
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=1
|
||||
-D ESP32_CPU_FREQ=80
|
||||
-D MECK_DIAG_NO_PMU
|
||||
-D FIRMWARE_VERSION='"Meck TWatch S3 DiagNoPMU v0.1"'
|
||||
-D MECK_DIAG_NO_ALARM
|
||||
-D FIRMWARE_VERSION='"Meck TWatch S3 DiagNoAlarm v0.1"'
|
||||
build_src_filter = ${LilyGo_TWatchS3.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
-<helpers/esp32/SerialBLEInterface.cpp>
|
||||
|
||||
@@ -492,7 +492,7 @@ class TWatchKeyboardScreen : public UIScreen {
|
||||
uint8_t _channelIdx;
|
||||
|
||||
public:
|
||||
enum Purpose { TWKB_CHANNEL, TWKB_DM, TWKB_ADMIN_PASSWORD, TWKB_ADMIN_CLI, TWKB_PATH, TWKB_NOTE, TWKB_SCOPE };
|
||||
enum Purpose { TWKB_CHANNEL, TWKB_DM, TWKB_ADMIN_PASSWORD, TWKB_ADMIN_CLI, TWKB_PATH, TWKB_NOTE, TWKB_SCOPE, TWKB_TRACE_PATH };
|
||||
|
||||
private:
|
||||
Purpose _purpose;
|
||||
|
||||
Reference in New Issue
Block a user