feat(esp32-s3-lcd-43): add touch test harness and coordinate transformation
This commit is contained in:
@@ -58,16 +58,137 @@ int DisplayDriverGFX::width() { return _gfx ? _gfx->width() : DISP_W; }
|
||||
|
||||
int DisplayDriverGFX::height() { return _gfx ? _gfx->height() : DISP_H; }
|
||||
|
||||
// ── Touch handling ──
|
||||
// Transform touch coordinates to match display orientation
|
||||
// GT911 touch panel on this board is rotated 180° relative to display
|
||||
void DisplayDriverGFX::transformTouch(int* x, int* y) {
|
||||
if(!x || !y)
|
||||
return;
|
||||
// Flip both axes: (0,0) becomes (width, height)
|
||||
*x = DISP_W - *x;
|
||||
*y = DISP_H - *y;
|
||||
}
|
||||
|
||||
// Test harness: parse serial commands to inject synthetic touches
|
||||
// Commands:
|
||||
// TEST:touch x y press - simulate press at (x, y) [raw panel coords]
|
||||
// TEST:touch x y release - simulate release at (x, y)
|
||||
// TEST:touch clear - clear test mode
|
||||
bool DisplayDriverGFX::parseTestTouch(int* outX, int* outY, bool* outPressed) {
|
||||
if(!Serial.available())
|
||||
return false;
|
||||
|
||||
// Only consume if it starts with 'T' - don't steal other commands
|
||||
// Use "TEST:" prefix to avoid conflict with [CMD] echo
|
||||
if(Serial.peek() != 'T') {
|
||||
return false;
|
||||
}
|
||||
|
||||
String cmd = Serial.readStringUntil('\n');
|
||||
cmd.trim();
|
||||
|
||||
if(!cmd.startsWith("TEST:touch"))
|
||||
return false;
|
||||
|
||||
// Parse: touch x y press|release
|
||||
int firstSpace = cmd.indexOf(' ');
|
||||
if(firstSpace < 0)
|
||||
return false;
|
||||
|
||||
String args = cmd.substring(firstSpace + 1);
|
||||
args.trim();
|
||||
|
||||
if(args.equals("clear")) {
|
||||
_testMode = false;
|
||||
Serial.println("[TEST] Test mode cleared");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse x y state
|
||||
int secondSpace = args.indexOf(' ');
|
||||
if(secondSpace < 0)
|
||||
return false;
|
||||
|
||||
String xStr = args.substring(0, secondSpace);
|
||||
String yState = args.substring(secondSpace + 1);
|
||||
yState.trim();
|
||||
|
||||
int x = xStr.toInt();
|
||||
int y = yState.substring(0, yState.indexOf(' ')).toInt();
|
||||
String state = yState.substring(yState.indexOf(' ') + 1);
|
||||
state.trim();
|
||||
|
||||
bool pressed = state.equals("press");
|
||||
|
||||
Serial.printf("[TEST] Injecting touch: (%d,%d) %s\n", x, y, pressed ? "press" : "release");
|
||||
|
||||
if(outX) *outX = x;
|
||||
if(outY) *outY = y;
|
||||
if(outPressed) *outPressed = pressed;
|
||||
|
||||
_testMode = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Touch handling
|
||||
|
||||
TouchEvent DisplayDriverGFX::readTouch() {
|
||||
TouchEvent evt;
|
||||
if(!_gfx)
|
||||
return evt;
|
||||
|
||||
// Check for test injection via serial
|
||||
int testX, testY;
|
||||
bool testPressed;
|
||||
if(parseTestTouch(&testX, &testY, &testPressed)) {
|
||||
// Handle test touch with same logic as real touch
|
||||
unsigned long now = millis();
|
||||
|
||||
if(testPressed && !_lastTouch.pressed) {
|
||||
evt.pressed = true;
|
||||
evt.downX = testX;
|
||||
evt.downY = testY;
|
||||
_lastTouch.downX = evt.downX;
|
||||
_lastTouch.downY = evt.downY;
|
||||
_touchBounced = false;
|
||||
} else if(!testPressed && _lastTouch.pressed) {
|
||||
evt.released = true;
|
||||
evt.downX = _lastTouch.downX;
|
||||
evt.downY = _lastTouch.downY;
|
||||
_lastReleaseMs = now;
|
||||
_touchBounced = true;
|
||||
}
|
||||
|
||||
if(testPressed) {
|
||||
evt.x = testX;
|
||||
evt.y = testY;
|
||||
evt.downX = _lastTouch.downX;
|
||||
evt.downY = _lastTouch.downY;
|
||||
_pressStartMs = millis();
|
||||
}
|
||||
|
||||
if(_touchBounced && now - _lastReleaseMs >= TOUCH_DEBOUNCE_MS) {
|
||||
_touchBounced = false;
|
||||
}
|
||||
|
||||
_lastTouch.pressed = testPressed;
|
||||
if(testPressed) {
|
||||
_lastTouch.x = evt.x;
|
||||
_lastTouch.y = evt.y;
|
||||
}
|
||||
return evt;
|
||||
}
|
||||
|
||||
int32_t x, y;
|
||||
bool pressed = _gfx->getTouch(&x, &y);
|
||||
|
||||
// Debounce: ignore repeated press events within debounce window after release
|
||||
unsigned long now = millis();
|
||||
if(pressed && _touchBounced) {
|
||||
// Within debounce window - ignore this press
|
||||
_lastTouch.pressed = pressed;
|
||||
return evt;
|
||||
}
|
||||
|
||||
// Detect transitions (press/release)
|
||||
if(pressed && !_lastTouch.pressed) {
|
||||
// Press transition: finger just touched down
|
||||
@@ -76,11 +197,15 @@ TouchEvent DisplayDriverGFX::readTouch() {
|
||||
evt.downY = static_cast<int>(y);
|
||||
_lastTouch.downX = evt.downX;
|
||||
_lastTouch.downY = evt.downY;
|
||||
_touchBounced = false;
|
||||
} else if(!pressed && _lastTouch.pressed) {
|
||||
// Release transition: finger just lifted
|
||||
evt.released = true;
|
||||
evt.downX = _lastTouch.downX;
|
||||
evt.downY = _lastTouch.downY;
|
||||
// Start debounce window
|
||||
_lastReleaseMs = now;
|
||||
_touchBounced = true;
|
||||
}
|
||||
|
||||
// Current position if still touched
|
||||
@@ -92,6 +217,11 @@ TouchEvent DisplayDriverGFX::readTouch() {
|
||||
_pressStartMs = millis();
|
||||
}
|
||||
|
||||
// Check if debounce window has expired
|
||||
if(_touchBounced && now - _lastReleaseMs >= TOUCH_DEBOUNCE_MS) {
|
||||
_touchBounced = false;
|
||||
}
|
||||
|
||||
// Track previous state
|
||||
_lastTouch.pressed = pressed;
|
||||
if(pressed) {
|
||||
@@ -252,15 +382,15 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) {
|
||||
_gfx->fillScreen(0x001030); // Dark blue
|
||||
|
||||
// Header
|
||||
_gfx->fillRect(0, 0, DISP_W, 30, 0x1A1A); // Dark gray
|
||||
_gfx->setFont(&fonts::Font0); // Built-in minimal font
|
||||
_gfx->fillRect(0, 0, DISP_W, 40, 0x1A1A); // Dark gray
|
||||
_gfx->setFont(&fonts::Font2);
|
||||
_gfx->setTextColor(0xFFFF);
|
||||
_gfx->setTextSize(1);
|
||||
_gfx->setCursor(5, 10);
|
||||
_gfx->setCursor(10, 12);
|
||||
_gfx->printf("KLUBHAUS");
|
||||
|
||||
// WiFi status
|
||||
_gfx->setCursor(DISP_W - 100, 10);
|
||||
_gfx->setCursor(DISP_W - 120, 12);
|
||||
_gfx->printf("WiFi:%s", state.wifiSsid.length() > 0 ? "ON" : "OFF");
|
||||
|
||||
// Get tile layouts from library helper
|
||||
|
||||
Reference in New Issue
Block a user