diff --git a/src/ButtonThread.h b/src/ButtonThread.h
index fcbb73af0..255ab5162 100644
--- a/src/ButtonThread.h
+++ b/src/ButtonThread.h
@@ -101,23 +101,8 @@ class ButtonThread : public concurrency::OSThread
#endif
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
// else LOG_DEBUG("sleep ok\n");
-#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
- int x, y = 0;
- screen->getTouch(&x, &y);
- if (x > 0 && y > 0) {
-#ifdef T_WATCH_S3
- drv.setWaveform(0, 75);
- drv.setWaveform(1, 0); // end waveform
- drv.go();
-#endif
- LOG_DEBUG("touch %d %d\n", x, y);
- powerFSM.trigger(EVENT_PRESS);
- return 150; // Check for next touch every in 150ms
- }
-#endif
-
- return 5;
+ return 50;
}
private:
diff --git a/src/commands.h b/src/commands.h
index 7c7595143..03ede5982 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -15,4 +15,6 @@ enum class Cmd {
PRINT,
START_SHUTDOWN_SCREEN,
START_REBOOT_SCREEN,
+ SHOW_PREV_FRAME,
+ SHOW_NEXT_FRAME
};
\ No newline at end of file
diff --git a/src/configuration.h b/src/configuration.h
index 3e289ef54..aa9064251 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -98,8 +98,9 @@ along with this program. If not, see .
// Define if screen should be mirrored left to right
// #define SCREEN_MIRROR
-// The m5stack I2C Keyboard (also RAK14004)
+// I2C Keyboards (M5Stack, RAK14004, T-Deck)
#define CARDKB_ADDR 0x5F
+#define TDECK_KB_ADDR 0x55
// -----------------------------------------------------------------------------
// SENSOR
@@ -173,6 +174,12 @@ along with this program. If not, see .
#ifndef HAS_BUTTON
#define HAS_BUTTON 0
#endif
+#ifndef HAS_TRACKBALL
+#define HAS_TRACKBALL 0
+#endif
+#ifndef HAS_TOUCHSCREEN
+#define HAS_TOUCHSCREEN 0
+#endif
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 0
#endif
diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp
index 75b23f419..996bdf62a 100644
--- a/src/detect/ScanI2C.cpp
+++ b/src/detect/ScanI2C.cpp
@@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
- ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
- return firstOfOrNONE(2, types);
+ ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
+ return firstOfOrNONE(3, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 559cff7ec..418a6bf5e 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -16,6 +16,7 @@ class ScanI2C
RTC_RV3028,
RTC_PCF8563,
CARDKB,
+ TDECKKB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 66e092951..30f9e7b7c 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -212,6 +212,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
}
break;
+ SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index b8abec66e..fbd99d252 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include "gps/GeoCoord.h"
#include "gps/RTC.h"
#include "graphics/images.h"
+#include "input/TouchScreenImpl1.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "mesh/Channels.h"
@@ -1044,12 +1045,18 @@ void Screen::setup()
#endif
serialSinceMsec = millis();
+#if HAS_TOUCHSCREEN
+ touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
+ touchScreenImpl1->init();
+#endif
+
// Subscribe to status updates
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
if (textMessageModule)
textMessageObserver.observe(textMessageModule);
+ inputObserver.observe(inputBroker);
// Modules can notify screen about refresh
MeshModule::observeUIEvents(&uiFrameEventObserver);
@@ -1127,6 +1134,12 @@ int32_t Screen::runOnce()
handleOnPress();
}
break;
+ case Cmd::SHOW_PREV_FRAME:
+ handleShowPrevFrame();
+ break;
+ case Cmd::SHOW_NEXT_FRAME:
+ handleShowNextFrame();
+ break;
case Cmd::START_BLUETOOTH_PIN_SCREEN:
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
break;
@@ -1420,6 +1433,28 @@ void Screen::handleOnPress()
}
}
+void Screen::handleShowPrevFrame()
+{
+ // If screen was off, just wake it, otherwise go back to previous frame
+ // If we are in a transition, the press must have bounced, drop it.
+ if (ui.getUiState()->frameState == FIXED) {
+ ui.previousFrame();
+ lastScreenTransition = millis();
+ setFastFramerate();
+ }
+}
+
+void Screen::handleShowNextFrame()
+{
+ // If screen was off, just wake it, otherwise advance to next frame
+ // If we are in a transition, the press must have bounced, drop it.
+ if (ui.getUiState()->frameState == FIXED) {
+ ui.nextFrame();
+ lastScreenTransition = millis();
+ setFastFramerate();
+ }
+}
+
#ifndef SCREEN_TRANSITION_FRAMERATE
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
#endif
@@ -1857,6 +1892,20 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
return 0;
}
+int Screen::handleInputEvent(const InputEvent *event)
+{
+ if (showingNormalScreen && moduleFrames.size() == 0) {
+ LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
+ if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
+ showPrevFrame();
+ } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
+ showNextFrame();
+ }
+ }
+
+ return 0;
+}
+
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index 9ebe1c75a..8812b7c70 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -53,6 +53,7 @@ class Screen
#include "commands.h"
#include "concurrency/LockGuard.h"
#include "concurrency/OSThread.h"
+#include "input/InputBroker.h"
#include "mesh/MeshModule.h"
#include "power.h"
#include
@@ -118,6 +119,8 @@ class Screen : public concurrency::OSThread
CallbackObserver(this, &Screen::handleTextMessage);
CallbackObserver uiFrameEventObserver =
CallbackObserver(this, &Screen::handleUIFrameEvent);
+ CallbackObserver inputObserver =
+ CallbackObserver(this, &Screen::handleInputEvent);
public:
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
@@ -152,8 +155,10 @@ class Screen : public concurrency::OSThread
void blink();
- /// Handles a button press.
+ /// Handle button press, trackball or swipe action)
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
+ void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
+ void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness
void adjustBrightness();
@@ -301,9 +306,11 @@ class Screen : public concurrency::OSThread
// Use this handle to set things like battery status, user count, GPS status, etc.
DebugInfo *debug_info() { return &debugInfo; }
+ // Handle observer events
int handleStatusUpdate(const meshtastic::Status *arg);
int handleTextMessage(const meshtastic_MeshPacket *arg);
int handleUIFrameEvent(const UIFrameEvent *arg);
+ int handleInputEvent(const InputEvent *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
@@ -313,13 +320,6 @@ class Screen : public concurrency::OSThread
void setWelcomeFrames();
- void getTouch(int *x, int *y)
- {
-#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
- dispdev.getTouch(x, y);
-#endif
- };
-
protected:
/// Updates the UI.
//
@@ -350,6 +350,8 @@ class Screen : public concurrency::OSThread
// Implementations of various commands, called from doTask().
void handleSetOn(bool on);
void handleOnPress();
+ void handleShowNextFrame();
+ void handleShowPrevFrame();
void handleStartBluetoothPinScreen(uint32_t pin);
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index 1f67f90c9..4c9196b2f 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -174,7 +174,7 @@ class LGFX : public lgfx::LGFX_Device
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
- cfg.invert = true; // true to invert the brightness of the backlight
+ cfg.invert = false; // true to invert the brightness of the backlight
// cfg.pwm_channel = 0;
_light_instance.config(cfg);
@@ -196,7 +196,7 @@ class LGFX : public lgfx::LGFX_Device
// cfg.freq = 2500000;
// I2C
- cfg.i2c_port = 1;
+ cfg.i2c_port = TOUCH_I2C_PORT;
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
#ifdef SCREEN_TOUCH_USE_I2C1
cfg.pin_sda = I2C_SDA1;
@@ -205,7 +205,7 @@ class LGFX : public lgfx::LGFX_Device
cfg.pin_sda = I2C_SDA;
cfg.pin_scl = I2C_SCL;
#endif
- cfg.freq = 400000;
+ // cfg.freq = 400000;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
@@ -275,6 +275,9 @@ void TFTDisplay::sendCommand(uint8_t com)
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW);
+#endif
+#ifndef M5STACK
+ tft.setBrightness(128);
#endif
break;
}
@@ -284,6 +287,9 @@ void TFTDisplay::sendCommand(uint8_t com)
#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
+#endif
+#ifndef M5STACK
+ tft.setBrightness(0);
#endif
break;
}
@@ -294,6 +300,24 @@ void TFTDisplay::sendCommand(uint8_t com)
// Drop all other commands to device (we just update the buffer)
}
+bool TFTDisplay::hasTouch(void)
+{
+#ifndef M5STACK
+ return tft.touch() != nullptr;
+#else
+ return false;
+#endif
+}
+
+bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
+{
+#ifndef M5STACK
+ return tft.getTouch(x, y);
+#else
+ return false;
+#endif
+}
+
void TFTDisplay::setDetected(uint8_t detected)
{
(void)detected;
@@ -322,12 +346,4 @@ bool TFTDisplay::connect()
return true;
}
-// Get touch coords from the display
-void TFTDisplay::getTouch(int *x, int *y)
-{
-#ifndef M5STACK
- tft.getTouch(x, y);
-#endif
-}
-
#endif
\ No newline at end of file
diff --git a/src/graphics/TFTDisplay.h b/src/graphics/TFTDisplay.h
index 03293d6f4..325765b1f 100644
--- a/src/graphics/TFTDisplay.h
+++ b/src/graphics/TFTDisplay.h
@@ -22,14 +22,16 @@ class TFTDisplay : public OLEDDisplay
// Write the buffer to the display memory
virtual void display(void) override;
+ // Touch screen (static handlers)
+ static bool hasTouch(void);
+ static bool getTouch(int16_t *x, int16_t *y);
+
/**
* shim to make the abstraction happy
*
*/
void setDetected(uint8_t detected);
- void getTouch(int *x, int *y);
-
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) override { return 0; }
diff --git a/src/input/TouchScreenBase.cpp b/src/input/TouchScreenBase.cpp
new file mode 100644
index 000000000..dad1bb56c
--- /dev/null
+++ b/src/input/TouchScreenBase.cpp
@@ -0,0 +1,137 @@
+#include "TouchScreenBase.h"
+#include "main.h"
+
+#ifndef TIME_LONG_PRESS
+#define TIME_LONG_PRESS 400
+#endif
+
+// move a minimum distance over the screen to detect a "swipe"
+#ifndef TOUCH_THRESHOLD_X
+#define TOUCH_THRESHOLD_X 30
+#endif
+
+#ifndef TOUCH_THRESHOLD_Y
+#define TOUCH_THRESHOLD_Y 20
+#endif
+
+TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t height)
+ : concurrency::OSThread(name), _display_width(width), _display_height(height), _first_x(0), _last_x(0), _first_y(0),
+ _last_y(0), _start(0), _tapped(false), _originName(name)
+{
+}
+
+void TouchScreenBase::init(bool hasTouch)
+{
+ if (hasTouch) {
+ LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
+ this->setInterval(100);
+ } else {
+ disable();
+ this->setInterval(UINT_MAX);
+ }
+}
+
+int32_t TouchScreenBase::runOnce()
+{
+ TouchEvent e;
+ e.touchEvent = static_cast(TOUCH_ACTION_NONE);
+
+ // process touch events
+ int16_t x, y;
+ bool touched = getTouch(x, y);
+ if (touched) {
+ hapticFeedback();
+ this->setInterval(20);
+ _last_x = x;
+ _last_y = y;
+ }
+ if (touched != _touchedOld) {
+ if (touched) {
+ _state = TOUCH_EVENT_OCCURRED;
+ _start = millis();
+ _first_x = x;
+ _first_y = y;
+ } else {
+ _state = TOUCH_EVENT_CLEARED;
+ time_t duration = millis() - _start;
+ x = _last_x;
+ y = _last_y;
+ this->setInterval(50);
+
+ // compute distance
+ int16_t dx = x - _first_x;
+ int16_t dy = y - _first_y;
+ uint16_t adx = abs(dx);
+ uint16_t ady = abs(dy);
+
+ // swipe horizontal
+ if (adx > ady && adx > TOUCH_THRESHOLD_X) {
+ if (0 > dx) { // swipe right to left
+ e.touchEvent = static_cast(TOUCH_ACTION_LEFT);
+ LOG_DEBUG("action SWIPE: right to left\n");
+ } else { // swipe left to right
+ e.touchEvent = static_cast(TOUCH_ACTION_RIGHT);
+ LOG_DEBUG("action SWIPE: left to right\n");
+ }
+ }
+ // swipe vertical
+ else if (ady > adx && ady > TOUCH_THRESHOLD_Y) {
+ if (0 > dy) { // swipe bottom to top
+ e.touchEvent = static_cast(TOUCH_ACTION_UP);
+ LOG_DEBUG("action SWIPE: bottom to top\n");
+ } else { // swipe top to bottom
+ e.touchEvent = static_cast(TOUCH_ACTION_DOWN);
+ LOG_DEBUG("action SWIPE: top to bottom\n");
+ }
+ }
+ // tap
+ else {
+ if (duration > 0 && duration < TIME_LONG_PRESS) {
+ if (_tapped) {
+ _tapped = false;
+ e.touchEvent = static_cast(TOUCH_ACTION_DOUBLE_TAP);
+ LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
+ } else {
+ _tapped = true;
+ }
+ } else {
+ _tapped = false;
+ }
+ }
+ }
+ }
+ _touchedOld = touched;
+
+ // fire TAP event when no 2nd tap occured within time
+ if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
+ _tapped = false;
+ e.touchEvent = static_cast(TOUCH_ACTION_TAP);
+ LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
+ }
+
+ // fire LONG_PRESS event without the need for release
+ if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {
+ // tricky: prevent reoccurring events and another touch event when releasing
+ _start = millis() + 30000;
+ e.touchEvent = static_cast(TOUCH_ACTION_LONG_PRESS);
+ LOG_DEBUG("action LONG PRESS(%d/%d)\n", _last_x, _last_y);
+ }
+
+ if (e.touchEvent != TOUCH_ACTION_NONE) {
+ e.source = this->_originName;
+ e.x = _last_x;
+ e.y = _last_y;
+ onEvent(e);
+ }
+
+ return interval;
+}
+
+void TouchScreenBase::hapticFeedback()
+{
+#ifdef T_WATCH_S3
+ drv.setWaveform(0, 75);
+ drv.setWaveform(1, 0); // end waveform
+ drv.go();
+#endif
+}
\ No newline at end of file
diff --git a/src/input/TouchScreenBase.h b/src/input/TouchScreenBase.h
new file mode 100644
index 000000000..a68c23e99
--- /dev/null
+++ b/src/input/TouchScreenBase.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "InputBroker.h"
+#include "concurrency/OSThread.h"
+#include "mesh/NodeDB.h"
+
+typedef struct _TouchEvent {
+ const char *source;
+ char touchEvent;
+ uint16_t x;
+ uint16_t y;
+} TouchEvent;
+
+class TouchScreenBase : public Observable, public concurrency::OSThread
+{
+ public:
+ explicit TouchScreenBase(const char *name, uint16_t width, uint16_t height);
+ void init(bool hasTouch);
+
+ protected:
+ enum TouchScreenBaseStateType { TOUCH_EVENT_OCCURRED, TOUCH_EVENT_CLEARED };
+
+ enum TouchScreenBaseEventType {
+ TOUCH_ACTION_NONE,
+ TOUCH_ACTION_UP,
+ TOUCH_ACTION_DOWN,
+ TOUCH_ACTION_LEFT,
+ TOUCH_ACTION_RIGHT,
+ TOUCH_ACTION_TAP,
+ TOUCH_ACTION_DOUBLE_TAP,
+ TOUCH_ACTION_LONG_PRESS
+ };
+
+ virtual int32_t runOnce() override;
+
+ virtual bool getTouch(int16_t &x, int16_t &y) = 0;
+ virtual void onEvent(const TouchEvent &event) = 0;
+
+ volatile TouchScreenBaseStateType _state = TOUCH_EVENT_CLEARED;
+ volatile TouchScreenBaseEventType _action = TOUCH_ACTION_NONE;
+ void hapticFeedback();
+
+ protected:
+ uint16_t _display_width;
+ uint16_t _display_height;
+
+ private:
+ bool _touchedOld = false; // previous touch state
+ int16_t _first_x, _last_x; // horizontal swipe direction
+ int16_t _first_y, _last_y; // vertical swipe direction
+ time_t _start; // for LONG_PRESS
+ bool _tapped; // for DOUBLE_TAP
+
+ const char *_originName;
+};
diff --git a/src/input/TouchScreenImpl1.cpp b/src/input/TouchScreenImpl1.cpp
new file mode 100644
index 000000000..9a7ecd4a2
--- /dev/null
+++ b/src/input/TouchScreenImpl1.cpp
@@ -0,0 +1,68 @@
+#include "TouchScreenImpl1.h"
+#include "InputBroker.h"
+#include "configuration.h"
+
+TouchScreenImpl1 *touchScreenImpl1;
+
+TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
+ : TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch)
+{
+}
+
+void TouchScreenImpl1::init()
+{
+#if !HAS_TOUCHSCREEN
+ TouchScreenBase::init(false);
+ return;
+#else
+ TouchScreenBase::init(true);
+ inputBroker->registerSource(this);
+#endif
+}
+
+bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
+{
+ return _getTouch(&x, &y);
+}
+
+/**
+ * @brief forward touchscreen event
+ *
+ * @param event
+ *
+ * The touchscreen events are translated to input events and reversed
+ */
+void TouchScreenImpl1::onEvent(const TouchEvent &event)
+{
+ InputEvent e;
+ e.source = event.source;
+ switch (event.touchEvent) {
+ case TOUCH_ACTION_LEFT: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
+ break;
+ }
+ case TOUCH_ACTION_RIGHT: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
+ break;
+ }
+ case TOUCH_ACTION_UP: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
+ break;
+ }
+ case TOUCH_ACTION_DOWN: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
+ break;
+ }
+ case TOUCH_ACTION_DOUBLE_TAP: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
+ break;
+ }
+ case TOUCH_ACTION_LONG_PRESS: {
+ e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
+ break;
+ }
+ default:
+ return;
+ }
+ this->notifyObservers(&e);
+}
\ No newline at end of file
diff --git a/src/input/TouchScreenImpl1.h b/src/input/TouchScreenImpl1.h
new file mode 100644
index 000000000..0c5338459
--- /dev/null
+++ b/src/input/TouchScreenImpl1.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "TouchScreenBase.h"
+
+class TouchScreenImpl1 : public TouchScreenBase
+{
+ public:
+ TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *));
+ void init(void);
+
+ protected:
+ virtual bool getTouch(int16_t &x, int16_t &y);
+ virtual void onEvent(const TouchEvent &event);
+
+ bool (*_getTouch)(int16_t *, int16_t *);
+};
+
+extern TouchScreenImpl1 *touchScreenImpl1;
diff --git a/src/input/TrackballInterruptBase.cpp b/src/input/TrackballInterruptBase.cpp
new file mode 100644
index 000000000..649e4b362
--- /dev/null
+++ b/src/input/TrackballInterruptBase.cpp
@@ -0,0 +1,78 @@
+#include "TrackballInterruptBase.h"
+#include "configuration.h"
+
+TrackballInterruptBase::TrackballInterruptBase(const char *name)
+{
+ this->_originName = name;
+}
+
+void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
+ char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
+ void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
+ void (*onIntPress)())
+{
+ this->_pinDown = pinDown;
+ this->_pinUp = pinUp;
+ this->_pinLeft = pinLeft;
+ this->_pinRight = pinRight;
+ this->_eventDown = eventDown;
+ this->_eventUp = eventUp;
+ this->_eventLeft = eventLeft;
+ this->_eventRight = eventRight;
+ this->_eventPressed = eventPressed;
+
+ pinMode(pinPress, INPUT_PULLUP);
+ pinMode(this->_pinDown, INPUT_PULLUP);
+ pinMode(this->_pinUp, INPUT_PULLUP);
+ pinMode(this->_pinLeft, INPUT_PULLUP);
+ pinMode(this->_pinRight, INPUT_PULLUP);
+
+ attachInterrupt(pinPress, onIntPress, RISING);
+ attachInterrupt(this->_pinDown, onIntDown, RISING);
+ attachInterrupt(this->_pinUp, onIntUp, RISING);
+ attachInterrupt(this->_pinLeft, onIntLeft, RISING);
+ attachInterrupt(this->_pinRight, onIntRight, RISING);
+
+ LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
+ pinPress);
+}
+
+void TrackballInterruptBase::intPressHandler()
+{
+ InputEvent e;
+ e.source = this->_originName;
+ e.inputEvent = this->_eventPressed;
+ this->notifyObservers(&e);
+}
+
+void TrackballInterruptBase::intDownHandler()
+{
+ InputEvent e;
+ e.source = this->_originName;
+ e.inputEvent = this->_eventDown;
+ this->notifyObservers(&e);
+}
+
+void TrackballInterruptBase::intUpHandler()
+{
+ InputEvent e;
+ e.source = this->_originName;
+ e.inputEvent = this->_eventUp;
+ this->notifyObservers(&e);
+}
+
+void TrackballInterruptBase::intLeftHandler()
+{
+ InputEvent e;
+ e.source = this->_originName;
+ e.inputEvent = this->_eventLeft;
+ this->notifyObservers(&e);
+}
+
+void TrackballInterruptBase::intRightHandler()
+{
+ InputEvent e;
+ e.source = this->_originName;
+ e.inputEvent = this->_eventRight;
+ this->notifyObservers(&e);
+}
diff --git a/src/input/TrackballInterruptBase.h b/src/input/TrackballInterruptBase.h
new file mode 100644
index 000000000..a82a20cb0
--- /dev/null
+++ b/src/input/TrackballInterruptBase.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "InputBroker.h"
+#include "mesh/NodeDB.h"
+
+class TrackballInterruptBase : public Observable
+{
+ public:
+ explicit TrackballInterruptBase(const char *name);
+ void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
+ char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
+ void (*onIntRight)(), void (*onIntPress)());
+ void intPressHandler();
+ void intDownHandler();
+ void intUpHandler();
+ void intLeftHandler();
+ void intRightHandler();
+
+ private:
+ uint8_t _pinDown = 0;
+ uint8_t _pinUp = 0;
+ uint8_t _pinLeft = 0;
+ uint8_t _pinRight = 0;
+ char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
+ char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
+ char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
+ char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
+ char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
+ const char *_originName;
+};
diff --git a/src/input/TrackballInterruptImpl1.cpp b/src/input/TrackballInterruptImpl1.cpp
new file mode 100644
index 000000000..0a73b83b6
--- /dev/null
+++ b/src/input/TrackballInterruptImpl1.cpp
@@ -0,0 +1,54 @@
+#include "TrackballInterruptImpl1.h"
+#include "InputBroker.h"
+#include "configuration.h"
+
+TrackballInterruptImpl1 *trackballInterruptImpl1;
+
+TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
+
+void TrackballInterruptImpl1::init()
+{
+#if !HAS_TRACKBALL
+ // Input device is disabled.
+ return;
+#else
+ uint8_t pinUp = TB_UP;
+ uint8_t pinDown = TB_DOWN;
+ uint8_t pinLeft = TB_LEFT;
+ uint8_t pinRight = TB_RIGHT;
+ uint8_t pinPress = TB_PRESS;
+
+ char eventDown = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
+ char eventUp = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
+ char eventLeft = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
+ char eventRight = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
+ char eventPressed = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
+
+ TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
+ eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
+ TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
+ TrackballInterruptImpl1::handleIntPressed);
+ inputBroker->registerSource(this);
+#endif
+}
+
+void TrackballInterruptImpl1::handleIntDown()
+{
+ trackballInterruptImpl1->intDownHandler();
+}
+void TrackballInterruptImpl1::handleIntUp()
+{
+ trackballInterruptImpl1->intUpHandler();
+}
+void TrackballInterruptImpl1::handleIntLeft()
+{
+ trackballInterruptImpl1->intLeftHandler();
+}
+void TrackballInterruptImpl1::handleIntRight()
+{
+ trackballInterruptImpl1->intRightHandler();
+}
+void TrackballInterruptImpl1::handleIntPressed()
+{
+ trackballInterruptImpl1->intPressHandler();
+}
diff --git a/src/input/TrackballInterruptImpl1.h b/src/input/TrackballInterruptImpl1.h
new file mode 100644
index 000000000..36efac6a6
--- /dev/null
+++ b/src/input/TrackballInterruptImpl1.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "TrackballInterruptBase.h"
+
+class TrackballInterruptImpl1 : public TrackballInterruptBase
+{
+ public:
+ TrackballInterruptImpl1();
+ void init();
+ static void handleIntDown();
+ static void handleIntUp();
+ static void handleIntLeft();
+ static void handleIntRight();
+ static void handleIntPressed();
+};
+
+extern TrackballInterruptImpl1 *trackballInterruptImpl1;
diff --git a/src/input/UpDownInterruptBase.cpp b/src/input/UpDownInterruptBase.cpp
index 7c340bab0..ecc3b944a 100644
--- a/src/input/UpDownInterruptBase.cpp
+++ b/src/input/UpDownInterruptBase.cpp
@@ -23,7 +23,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING);
- LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
+ LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
}
void UpDownInterruptBase::intPressHandler()
diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp
index 686f4b5a2..44db1d952 100644
--- a/src/input/cardKbI2cImpl.cpp
+++ b/src/input/cardKbI2cImpl.cpp
@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
- if (cardkb_found.address != CARDKB_ADDR) {
+ if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
disable();
return;
}
diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp
index 6850eff51..cdffbaf7e 100644
--- a/src/input/kbI2cBase.cpp
+++ b/src/input/kbI2cBase.cpp
@@ -41,7 +41,7 @@ void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
int32_t KbI2cBase::runOnce()
{
- if (cardkb_found.address != CARDKB_ADDR) {
+ if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
// Input device is not detected.
return INT32_MAX;
}
@@ -85,9 +85,9 @@ int32_t KbI2cBase::runOnce()
e.kbchar = PrintDataBuf;
this->notifyObservers(&e);
}
- } else {
- // m5 cardkb
- i2cBus->requestFrom(CARDKB_ADDR, 1);
+ } else if (kb_model == 0x00 || kb_model == 0x10) {
+ // m5 cardkb and T-Deck
+ i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
while (i2cBus->available()) {
char c = i2cBus->read();
@@ -132,6 +132,8 @@ int32_t KbI2cBase::runOnce()
this->notifyObservers(&e);
}
}
+ } else {
+ LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
}
- return 500;
+ return 300;
}
diff --git a/src/main.cpp b/src/main.cpp
index 8559c32f1..12ee157a5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -96,7 +96,7 @@ ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the cardkb or RAK14004 (if found)
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
-// 0x02 for RAK14004 and 0x00 for cardkb
+// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
uint8_t kb_model;
// The I2C address of the RTC Module (if found)
@@ -300,6 +300,15 @@ void setup()
#endif
#endif
+#ifdef T_DECK
+ // enable keyboard
+ pinMode(KB_POWERON, OUTPUT);
+ digitalWrite(KB_POWERON, HIGH);
+ // There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
+ // otherwise keyboard and touch screen will not work
+ delay(800);
+#endif
+
// Currently only the tbeam has a PMU
// PMU initialization needs to be placed before i2c scanning
power = new Power();
@@ -372,8 +381,15 @@ void setup()
kb_model = 0x02;
break;
case ScanI2C::DeviceType::CARDKB:
+ kb_model = 0x00;
+ break;
+ case ScanI2C::DeviceType::TDECKKB:
+ // assign an arbitrary value to distinguish from other models
+ kb_model = 0x10;
+ break;
default:
// use this as default since it's also just zero
+ LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
kb_model = 0x00;
}
}
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index d3a450371..b788d6a06 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -164,12 +164,21 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
(event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
(event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
- if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
+ // tweak for left/right events generated via trackball/touch with empty kbchar
+ if (!event->kbchar) {
+ if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
+ this->payload = 0xb4;
+ this->destSelect = true;
+ } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
+ this->payload = 0xb7;
+ this->destSelect = true;
+ }
+ } else {
// pass the pressed key
this->payload = event->kbchar;
- this->lastTouchMillis = millis();
- validEvent = true;
}
+ this->lastTouchMillis = millis();
+ validEvent = true;
}
if (event->inputEvent == static_cast(ANYKEY)) {
LOG_DEBUG("Canned message event any key pressed\n");
@@ -225,7 +234,7 @@ int32_t CannedMessageModule::runOnce()
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
return INT32_MAX;
}
- LOG_DEBUG("Check status\n");
+ // LOG_DEBUG("Check status\n");
UIFrameEvent e = {false, true};
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
// TODO: might have some feedback of sendig state
@@ -300,8 +309,7 @@ int32_t CannedMessageModule::runOnce()
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
}
- } else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
- e.frameChanged = true;
+ } else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
switch (this->payload) {
case 0xb4: // left
if (this->destSelect) {
@@ -347,38 +355,49 @@ int32_t CannedMessageModule::runOnce()
}
}
break;
- case 0x08: // backspace
- if (this->freetext.length() > 0) {
- if (this->cursor == this->freetext.length()) {
- this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
- } else {
- this->freetext = this->freetext.substring(0, this->cursor - 1) +
- this->freetext.substring(this->cursor, this->freetext.length());
- }
- this->cursor--;
- }
- break;
- case 0x09: // tab
- if (this->destSelect) {
- this->destSelect = false;
- } else {
- this->destSelect = true;
- }
- break;
default:
- if (this->cursor == this->freetext.length()) {
- this->freetext += this->payload;
- } else {
- this->freetext =
- this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
- }
- this->cursor += 1;
- if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
- this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
- this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
- }
break;
}
+ if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
+ e.frameChanged = true;
+ switch (this->payload) {
+ case 0x08: // backspace
+ if (this->freetext.length() > 0) {
+ if (this->cursor == this->freetext.length()) {
+ this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
+ } else {
+ this->freetext = this->freetext.substring(0, this->cursor - 1) +
+ this->freetext.substring(this->cursor, this->freetext.length());
+ }
+ this->cursor--;
+ }
+ break;
+ case 0x09: // tab
+ if (this->destSelect) {
+ this->destSelect = false;
+ } else {
+ this->destSelect = true;
+ }
+ break;
+ case 0xb4: // left
+ case 0xb7: // right
+ // already handled above
+ break;
+ default:
+ if (this->cursor == this->freetext.length()) {
+ this->freetext += this->payload;
+ } else {
+ this->freetext =
+ this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
+ }
+ this->cursor += 1;
+ if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
+ this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
+ this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
+ }
+ break;
+ }
+ }
this->lastTouchMillis = millis();
this->notifyObservers(&e);
@@ -406,6 +425,11 @@ const char *CannedMessageModule::getNextMessage()
{
return this->messages[this->getNextIndex()];
}
+const char *CannedMessageModule::getMessageByIndex(int index)
+{
+ return (index >= 0 && index < this->messagesCount) ? this->messages[index] : "";
+}
+
const char *CannedMessageModule::getNodeName(NodeNum node)
{
if (node == NODENUM_BROADCAST) {
@@ -482,12 +506,31 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
- display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
- display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
- display->setColor(BLACK);
- display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
- display->setColor(WHITE);
- display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
+ int lines = (display->getHeight() / FONT_HEIGHT_SMALL) - 1;
+ if (lines == 3) {
+ // static (old) behavior for small displays
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
+ display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
+ display->setColor(BLACK);
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
+ display->setColor(WHITE);
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
+ } else {
+ // use entire display height for larger displays
+ int topMsg = (messagesCount > lines && currentMessageIndex >= lines - 1) ? currentMessageIndex - lines + 2 : 0;
+ for (int i = 0; i < std::min(messagesCount, lines); i++) {
+ if (i == currentMessageIndex - topMsg) {
+ display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), x + display->getWidth(),
+ y + FONT_HEIGHT_SMALL);
+ display->setColor(BLACK);
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), cannedMessageModule->getCurrentMessage());
+ display->setColor(WHITE);
+ } else {
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1),
+ cannedMessageModule->getMessageByIndex(topMsg + i));
+ }
+ }
+ }
}
}
}
diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h
index 5858a473c..4e9dadccf 100644
--- a/src/modules/CannedMessageModule.h
+++ b/src/modules/CannedMessageModule.h
@@ -30,6 +30,7 @@ class CannedMessageModule : public SinglePortModule, public Observableinit();
#endif
+#if HAS_TRACKBALL
+ trackballInterruptImpl1 = new TrackballInterruptImpl1();
+ trackballInterruptImpl1->init();
+#endif
#if HAS_SCREEN
cannedMessageModule = new CannedMessageModule();
#endif
diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h
index e434cd35d..04f20fa74 100644
--- a/variants/t-deck/variant.h
+++ b/variants/t-deck/variant.h
@@ -16,8 +16,11 @@
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define SCREEN_ROTATE
-#define SCREEN_TRANSITION_FRAMERATE 1 // fps
+#define SCREEN_TRANSITION_FRAMERATE 5
+
+#define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 16
+#define TOUCH_I2C_PORT 0
#define TOUCH_SLAVE_ADDRESS 0x5D // GT911
#define BUTTON_PIN 0
@@ -43,14 +46,25 @@
// keyboard
#define I2C_SDA 18 // I2C pins for this board
#define I2C_SCL 8
-#define BOARD_POWERON 10 // must be set to HIGH
-#define KB_SLAVE_ADDRESS 0x55
-#define KB_BL_PIN 46 // INT, set to INPUT
-#define KB_UP 2
-#define KB_DOWN 3
-#define KB_LEFT 1
-#define KB_RIGHT 15
+#define KB_POWERON 10 // must be set to HIGH
+#define KB_SLAVE_ADDRESS TDECK_KB_ADDR // 0x55
+#define KB_BL_PIN 46 // not used for now
+// trackball
+#define HAS_TRACKBALL 1
+#define TB_UP 3
+#define TB_DOWN 15
+#define TB_LEFT 1
+#define TB_RIGHT 2
+#define TB_PRESS BUTTON_PIN
+
+// microphone
+#define ES7210_SCK 47
+#define ES7210_DIN 14
+#define ES7210_LRCK 21
+#define ES7210_MCLK 48
+
+// LoRa
#define USE_SX1262
#define USE_SX1268
diff --git a/variants/t-watch-s3/variant.h b/variants/t-watch-s3/variant.h
index 652696c3f..8c0fc9122 100644
--- a/variants/t-watch-s3/variant.h
+++ b/variants/t-watch-s3/variant.h
@@ -16,10 +16,13 @@
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define SCREEN_ROTATE
-#define SCREEN_TRANSITION_FRAMERATE 1 // fps
+#define SCREEN_TRANSITION_FRAMERATE 5 // fps
+
+#define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 16
-#define SCREEN_TOUCH_USE_I2C1 1
-#define TOUCH_SLAVE_ADDRESS 0x38 // GT911
+#define SCREEN_TOUCH_USE_I2C1
+#define TOUCH_I2C_PORT 1
+#define TOUCH_SLAVE_ADDRESS 0x38
#define I2C_SDA1 39 // Used for capacitive touch
#define I2C_SCL1 40 // Used for capacitive touch