mirror of
https://github.com/pelgraine/Meck.git
synced 2026-07-31 22:02:52 +02:00
T-Watch S3: vibrate alarm clock in place of the Maps tile
Fixes a regression from the MECK_TWATCH rename. main.cpp's tap dispatch had
'#if defined(MECK_TWATCH) && HAS_GPS' wrapped around two unrelated things: the
map tap handler AND the early return that stops the watch falling through to the
T5S3 tile hit-test. MECK_TOUCH_ENABLED is defined for MECK_TWATCH (main.cpp:712),
so on the S3 that early return vanished and a plain tap on the home tile page ran
the T5S3 geometry (tileW=40, tileH=22). Split into two gates. The other three
HAS_GPS gates were audited and are genuinely map-only.
Adds WatchAlarmScreen: four slots, day-of-week presets, vibrate-only. It keeps
AlarmScreen.h's conventions (bit 0 = Sunday, dowFromEpoch, effect 14, the
3-buzz / 1200ms / 4000ms-pause cadence) but shares no code, because AlarmScreen
is bound to ESP32-audioI2S, an SD card and a 1-21 Audio volume scale, none of
which exist here. Config lives on the LittleFS 'maps' partition, already mounted.
Alarms are ticked from UITask::loop, not the screen's poll(), so one fires with
the display off or another screen showing. Navigating away while ringing counts
as a dismiss.
DRV2605Haptic.h is copied into the watch variant rather than shared, so MAX
builds are untouched. The watch needs no motorEnable(): the DRV2605 sits on
BLDO2, which power_init() already brings up.
The Maps tile becomes Alarms on LILYGO_TWATCH_S3 only. The Plus keeps Maps.
The 'buzz' CLI command now also builds on the watch and takes an optional effect
number ('buzz 14'), for characterising the motor. Exact-match behaviour of plain
'buzz' on the MAX is unchanged.
This commit is contained in:
@@ -12,8 +12,8 @@
|
||||
#include "ModemManager.h" // Serial CLI modem commands
|
||||
#endif
|
||||
|
||||
#if defined(LilyGo_TDeck_Pro_Max)
|
||||
#include "DRV2605Haptic.h" // TEMP: inline haptic driver for the 'buzz' CLI test command
|
||||
#if defined(LilyGo_TDeck_Pro_Max) || defined(LILYGO_TWATCH_S3)
|
||||
#include "DRV2605Haptic.h" // inline haptic driver for the 'buzz' CLI test command
|
||||
#endif
|
||||
|
||||
#define CMD_APP_START 1
|
||||
@@ -3613,20 +3613,29 @@ void MyMesh::checkCLIRescueCmd() {
|
||||
}
|
||||
|
||||
}
|
||||
#if defined(LilyGo_TDeck_Pro_Max)
|
||||
else if (strcmp(cli_command, "buzz") == 0) {
|
||||
// TEMP: fire the DRV2605 haptic motor once to confirm it works.
|
||||
// Lazy-inits the driver (and motor power rail) on first invocation.
|
||||
#if defined(LilyGo_TDeck_Pro_Max) || defined(LILYGO_TWATCH_S3)
|
||||
else if (strncmp(cli_command, "buzz", 4) == 0 &&
|
||||
(cli_command[4] == '\0' || cli_command[4] == ' ')) {
|
||||
// Fire a DRV2605 library-1 effect to confirm the motor works.
|
||||
// "buzz" uses effect 1 (strong click); "buzz <n>" fires effect n.
|
||||
// Lazy-inits the driver (and, on the MAX, its motor power rail).
|
||||
static DRV2605Haptic haptic;
|
||||
static bool haptic_ready = false;
|
||||
if (!haptic_ready) {
|
||||
board.motorEnable();
|
||||
#if defined(LilyGo_TDeck_Pro_Max)
|
||||
board.motorEnable(); // MAX: motor rail is behind an XL9555 pin
|
||||
delay(10); // let the motor rail settle before I2C
|
||||
#endif
|
||||
haptic_ready = haptic.begin();
|
||||
}
|
||||
if (haptic_ready) {
|
||||
haptic.buzz(1);
|
||||
Serial.println(" > buzz");
|
||||
int effect = 1;
|
||||
const char* arg = cli_command + 4;
|
||||
while (*arg == ' ') arg++;
|
||||
if (*arg) effect = atoi(arg);
|
||||
if (effect < 1 || effect > 123) effect = 1;
|
||||
haptic.buzz((uint8_t)effect);
|
||||
Serial.printf(" > buzz: effect %d\n", effect);
|
||||
} else {
|
||||
Serial.println(" > buzz: DRV2605 not found");
|
||||
}
|
||||
|
||||
@@ -1125,6 +1125,9 @@ static uint32_t _atoi(const char* sp) {
|
||||
/* GLOBAL OBJECTS */
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include "UITask.h"
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
#include "WatchAlarmScreen.h" // After UITask.h -- needs NodePrefs
|
||||
#endif
|
||||
#if defined(MECK_TWATCH) && HAS_GPS
|
||||
#include "WatchMapScreen.h" // After BLE -- PNGdec headers conflict with BLE if included earlier
|
||||
#elif HAS_GPS && !defined(LILYGO_TECHO_CARD)
|
||||
@@ -1360,6 +1363,18 @@ static void lastHeardToggleContact() {
|
||||
if (wms) wms->handleTap(x, y);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
// Alarm screen: rows, +/- steppers and the footer are all tap targets.
|
||||
// readTouch() already returns logical (UI_ZOOM-divided) coords on the watch,
|
||||
// which is the space WatchAlarmScreen lays out in. No further scaling.
|
||||
if (ui_task.isOnWatchAlarmScreen()) {
|
||||
WatchAlarmScreen* wa = (WatchAlarmScreen*)ui_task.getWatchAlarmScreen();
|
||||
if (wa) wa->handleTap(x, y);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(MECK_TWATCH)
|
||||
// Watch: tiles open on long-press and pages change on swipe, so a plain tap
|
||||
// on any home page does nothing -- skip the T5S3 tile hit-test below (wrong
|
||||
// geometry for the 2-column watch grid) and the left/right page cycling.
|
||||
@@ -1806,7 +1821,10 @@ static void lastHeardToggleContact() {
|
||||
if (row == 1 && col == 0) { ui_task.gotoSettingsScreen(); return 0; }
|
||||
if (row == 1 && col == 1) { ui_task.gotoDiscoveryScreen(); return 0; }
|
||||
if (row == 2 && col == 0) { ui_task.gotoTraceScreen(); return 0; }
|
||||
#if HAS_GPS
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
// No GNSS on the plain S3, so this slot is the vibrate alarm clock.
|
||||
if (row == 2 && col == 1) { ui_task.gotoWatchAlarmScreen(); return 0; }
|
||||
#elif HAS_GPS
|
||||
if (row == 2 && col == 1) {
|
||||
// Maps: mark the tile FS ready (detectZoomRange in enter() needs it)
|
||||
// before opening; GPS centre + markers are populated in the main loop.
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
#include "AudiobookPlayerScreen.h"
|
||||
#include "VoiceMessageScreen.h"
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
#include "WatchAlarmScreen.h"
|
||||
#endif
|
||||
#ifdef TWATCH_COMPOSE_ENABLED
|
||||
#include "TWatchComposeScreens.h"
|
||||
#endif
|
||||
@@ -687,7 +690,11 @@ public:
|
||||
const Tile tiles[4][2] = {
|
||||
{ {icon_envelope, "Messages", 0x0CB1}, {icon_people, "Contacts", 0xCAA0} },
|
||||
{ {icon_gear, "Settings", 0x0560}, {icon_search, "Discover", 0xF81F} },
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
{ {icon_trace, "Trace", 0xF800}, {icon_alarm, "Alarms", 0x231D} },
|
||||
#else
|
||||
{ {icon_trace, "Trace", 0xF800}, {icon_map, "Maps", 0x231D} },
|
||||
#endif
|
||||
{ {icon_notepad, "Notes", 0x07FF}, {icon_star, "Steps", 0xFFE0} },
|
||||
};
|
||||
const uint16_t TILE_FILL = 0x18C5; // dark navy
|
||||
@@ -1693,6 +1700,11 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
lock_screen = new ClockScreen(this, &rtc_clock, node_prefs);
|
||||
steps_screen = new StepsScreen(this);
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
// LittleFS ("/maps" partition) is mounted in setup() before UITask::begin().
|
||||
watch_alarm_screen = new WatchAlarmScreen(this, &rtc_clock, node_prefs);
|
||||
((WatchAlarmScreen*)watch_alarm_screen)->load();
|
||||
#endif
|
||||
#ifdef TWATCH_COMPOSE_ENABLED
|
||||
tw_picker = new TWatchChannelPicker(_display);
|
||||
tw_channel = new TWatchChannelScreen(_display);
|
||||
@@ -2383,6 +2395,24 @@ void UITask::loop() {
|
||||
if (buzzer.isPlaying()) buzzer.loop();
|
||||
#endif
|
||||
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
// 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) {
|
||||
WatchAlarmScreen* wa = (WatchAlarmScreen*)watch_alarm_screen;
|
||||
if (wa->tick()) {
|
||||
setCurrScreen(watch_alarm_screen);
|
||||
if (_display != NULL && !_display->isOn()) _display->turnOn();
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
_next_refresh = 0;
|
||||
} else if (wa->isRinging() && curr != watch_alarm_screen) {
|
||||
// Navigating away (e.g. the status-bar tap that goes home) counts as a
|
||||
// dismiss, otherwise the motor would keep buzzing off-screen.
|
||||
wa->dismiss();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (curr) curr->poll();
|
||||
|
||||
#ifdef TWATCH_COMPOSE_ENABLED
|
||||
@@ -3678,6 +3708,19 @@ void UITask::gotoStepsScreen() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
void UITask::gotoWatchAlarmScreen() {
|
||||
WatchAlarmScreen* wa = (WatchAlarmScreen*)watch_alarm_screen;
|
||||
if (wa) wa->enter();
|
||||
setCurrScreen(watch_alarm_screen);
|
||||
if (_display != NULL && !_display->isOn()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
_next_refresh = 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
void UITask::gotoGamesMenu() {
|
||||
GamesMenuScreen* gm = (GamesMenuScreen*)games_menu_screen;
|
||||
gm->enter();
|
||||
|
||||
@@ -123,6 +123,9 @@ class UITask : public AbstractUITask {
|
||||
UIScreen* steps_screen; // Steps screen (big daily step count)
|
||||
int32_t _lastStepDay = 0; // local day-of-epoch, for the midnight step reset
|
||||
uint32_t _stepBaseline = 0; // raw step count at the start of the local day
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
UIScreen* watch_alarm_screen; // Vibrate-only alarm clock (no audio hardware)
|
||||
#endif
|
||||
UIScreen* _screenBeforeLock = nullptr;
|
||||
bool _locked = false;
|
||||
@@ -229,6 +232,9 @@ public:
|
||||
void gotoStepsScreen(); // Navigate to the step counter screen
|
||||
uint32_t getTodaySteps(); // Daily step count (raw - baseline)
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
void gotoWatchAlarmScreen(); // Navigate to the vibrate alarm clock
|
||||
#endif
|
||||
#if HAS_GPS
|
||||
void gotoMapScreen(); // Navigate to map tile screen
|
||||
#endif
|
||||
@@ -292,6 +298,9 @@ public:
|
||||
bool isOnSnakeScreen() const { return curr == snake_screen; }
|
||||
#if defined(MECK_TWATCH)
|
||||
bool isOnStepsScreen() const { return curr == steps_screen; }
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
bool isOnWatchAlarmScreen() const { return curr == watch_alarm_screen; }
|
||||
#endif
|
||||
bool isOnMinesweeperScreen() const { return curr == minesweeper_screen; }
|
||||
bool isOnMapScreen() const { return curr == map_screen; }
|
||||
@@ -384,6 +393,9 @@ public:
|
||||
UIScreen* getSnakeScreen() const { return snake_screen; }
|
||||
#if defined(MECK_TWATCH)
|
||||
UIScreen* getStepsScreen() const { return steps_screen; }
|
||||
#endif
|
||||
#if defined(LILYGO_TWATCH_S3)
|
||||
UIScreen* getWatchAlarmScreen() const { return watch_alarm_screen; }
|
||||
#endif
|
||||
UIScreen* getMinesweeperScreen() const { return minesweeper_screen; }
|
||||
UIScreen* getMapScreen() const { return map_screen; }
|
||||
|
||||
Reference in New Issue
Block a user