1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-05-08 01:49:02 +00:00

feat(core): add event polling to touch driver

[no changelog]
This commit is contained in:
cepetr 2025-04-01 09:06:10 +02:00 committed by cepetr
parent 8d7a25e5eb
commit 4815118a6d
21 changed files with 1030 additions and 524 deletions

View File

@ -24,6 +24,7 @@
#include <io/i2c_bus.h>
#include <io/touch.h>
#include <sys/sysevent_source.h>
#include <sys/systick.h>
#include "ft6x36.h"
@ -33,6 +34,8 @@
#include "panels/lhs200kb-if21.h"
#endif
#include "../touch_fsm.h"
// #define TOUCH_TRACE_REGS
// #define TOUCH_TRACE_EVENT
@ -46,17 +49,12 @@ typedef struct {
secbool ready;
// Captured tick counter when `touch_init()` was called
uint32_t init_ticks;
// Time (in ticks) when touch_get_event() was called last time
uint32_t poll_ticks;
// Time (in ticks) when the touch registers were read last time
uint32_t read_ticks;
// Set if the touch controller is currently touched
// (respectively, that we detected a touch event)
bool pressed;
// Previously reported x-coordinate
uint16_t last_x;
// Previously reported y-coordinate
uint16_t last_y;
// Last reported touch state
uint32_t state;
// Touch state machine for each task
touch_fsm_t tls[SYSTASK_MAX_TASKS];
} touch_driver_t;
@ -65,6 +63,9 @@ static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
// Forward declarations
static const syshandle_vmt_t g_touch_handle_vmt;
// Reads a subsequent registers from the FT6X36.
//
// Returns: `sectrue` if the register was read
@ -192,7 +193,7 @@ static void ft6x36_power_down(void) {
if (state == GPIO_PIN_SET) {
// 90 ms for circuitry to stabilize (being conservative)
hal_delay(90);
systick_delay_ms(90);
}
#endif
}
@ -214,7 +215,7 @@ static void ft6x36_power_up(void) {
// Wait until the circuit fully kicks-in
// (5ms is the minimum time required for the reset signal to be effective)
hal_delay(10);
systick_delay_ms(10);
// Enable intterrupt input
GPIO_InitTypeDef GPIO_InitStructure = {0};
@ -230,7 +231,7 @@ static void ft6x36_power_up(void) {
#endif
// Wait for the touch controller to boot up
hal_delay(5);
systick_delay_ms(5);
// Clear the flag indicating rising edge on INT_PIN
__HAL_GPIO_EXTI_CLEAR_FLAG(TOUCH_INT_PIN);
@ -316,28 +317,29 @@ secbool touch_init(void) {
goto cleanup;
}
driver->init_ticks = hal_ticks_ms();
driver->poll_ticks = driver->init_ticks;
if (!syshandle_register(SYSHANDLE_TOUCH, &g_touch_handle_vmt, driver)) {
goto cleanup;
}
driver->init_ticks = systick_ms();
driver->read_ticks = driver->init_ticks;
driver->initialized = sectrue;
return sectrue;
cleanup:
i2c_bus_close(driver->i2c_bus);
ft6x36_power_down();
memset(driver, 0, sizeof(touch_driver_t));
touch_deinit();
return secfalse;
}
void touch_deinit(void) {
touch_driver_t* driver = &g_touch_driver;
syshandle_unregister(SYSHANDLE_TOUCH);
i2c_bus_close(driver->i2c_bus);
if (sectrue == driver->initialized) {
i2c_bus_close(driver->i2c_bus);
ft6x36_power_down();
memset(driver, 0, sizeof(touch_driver_t));
}
memset(driver, 0, sizeof(touch_driver_t));
}
void touch_power_set(bool on) {
@ -355,7 +357,7 @@ secbool touch_ready(void) {
if (sectrue == driver->initialized && sectrue != driver->ready) {
// FT6X36 does not report events for 300ms
// after it is released from the reset state
if ((int)(hal_ticks_ms() - driver->init_ticks) >= 310) {
if ((int)(systick_ms() - driver->init_ticks) >= 310) {
driver->ready = sectrue;
}
}
@ -386,7 +388,7 @@ uint8_t touch_get_version(void) {
// to read the firmware version. If we try to read too soon, we get 0x00
// and the chip behaves unpredictably.
while (sectrue != touch_ready()) {
hal_delay(1);
systick_delay_ms(1);
}
ft6x36_wake_up(driver->i2c_bus);
@ -442,7 +444,7 @@ void trace_regs(uint8_t* regs) {
event = '-';
}
uint32_t time = hal_ticks_ms() % 10000;
uint32_t time = systicks_ms() % 10000;
printf("%04ld [gesture=%02X, nb_touches=%d, flags=%c, x=%3d, y=%3d]\r\n",
time, gesture, nb_touches, event, x, y);
@ -461,17 +463,16 @@ void trace_event(uint32_t event) {
uint32_t time = hal_ticks_ms() % 10000;
printf("%04ld [event=%c, x=%3d, y=%3d]\r\n", time, event_type, x, y);
systask_id_t task_id = systask_id(systask_active());
printf("%04ld [task=%d, event=%c, x=%3d, y=%3d]\r\n", time, task_id,
event_type, x, y);
}
#endif
uint32_t touch_get_event(void) {
touch_driver_t* driver = &g_touch_driver;
if (sectrue != driver->initialized) {
return 0;
}
// Reads touch registers and returns the last touch event
// (state of touch registers) the controller is reporting.
static uint32_t touch_get_state(touch_driver_t* driver) {
// Content of registers 0x00 - 0x06 read from the touch controller
uint8_t regs[7];
@ -485,18 +486,16 @@ uint32_t touch_get_event(void) {
uint32_t ticks = hal_ticks_ms();
// Test if the touch_get_event() is starving (not called frequently enough)
bool starving = (int32_t)(ticks - driver->poll_ticks) > 300 /* ms */;
driver->poll_ticks = ticks;
// Test if the touch controller is polled too frequently
// (less than 20ms since the last read)
bool toofast = (int32_t)(ticks - driver->read_ticks) < 20 /* ms */;
// Fast track: if there is no new event and the touch controller
// is not touched, we do not need to read the registers
if (!ft6x36_test_and_clear_interrupt() && (!driver->pressed || toofast)) {
return 0;
bool pressed = (driver->state & TOUCH_START) || (driver->state & TOUCH_MOVE);
if (!ft6x36_test_and_clear_interrupt() && (!pressed || toofast)) {
return driver->state;
}
driver->read_ticks = ticks;
@ -537,71 +536,35 @@ uint32_t touch_get_event(void) {
ft6x36_panel_correction(x_raw, y_raw, &x, &y);
uint32_t event = 0;
uint32_t state = 0;
uint32_t xy = touch_pack_xy(x, y);
if ((nb_touches == 1) && (flags == FT6X63_EVENT_PRESS_DOWN)) {
if (!driver->pressed) {
// Finger was just pressed down
event = TOUCH_START | xy;
} else {
if ((x != driver->last_x) || (y != driver->last_y)) {
// It looks like we have missed the lift up event
// We should send the TOUCH_END event here with old coordinates
event = TOUCH_END | touch_pack_xy(driver->last_x, driver->last_y);
} else {
// We have received the same coordinates as before,
// probably this is the same start event, or a quick bounce,
// we should ignore it.
}
}
state = TOUCH_START | xy;
} else if ((nb_touches == 1) && (flags == FT6X63_EVENT_CONTACT)) {
if (driver->pressed) {
if ((x != driver->last_x) || (y != driver->last_y)) {
// Report the move event only if the coordinates
// have changed
event = TOUCH_MOVE | xy;
}
} else {
// We have missed the press down event, we have to simulate it.
// But ensure we don't simulate TOUCH_START if touch_get_event() is not
// called frequently enough to not produce false events.
if (!starving) {
event = TOUCH_START | xy;
}
}
state = TOUCH_MOVE | xy;
} else if ((nb_touches == 0) && (flags == FT6X63_EVENT_LIFT_UP)) {
if (driver->pressed) {
// Finger was just lifted up
event = TOUCH_END | xy;
} else {
if (!starving && ((x != driver->last_x) || (y != driver->last_y))) {
// We have missed the PRESS_DOWN event.
// Report the start event only if the coordinates
// have changed and driver is not starving.
// This suggests that the previous touch was very short,
// or/and the driver is not called very frequently.
event = TOUCH_START | xy;
} else {
// Either the driver is starving or the coordinates
// have not changed, which would suggest that the TOUCH_END
// is repeated, so no event is needed -this should not happen
// since two consecutive LIFT_UPs are not possible due to
// testing the interrupt line before reading the registers.
}
}
state = TOUCH_END | xy;
}
// remember the last state
if ((event & TOUCH_START) || (event & TOUCH_MOVE)) {
driver->pressed = true;
} else if (event & TOUCH_END) {
driver->pressed = false;
driver->state = state;
return state;
}
uint32_t touch_get_event(void) {
touch_driver_t* driver = &g_touch_driver;
if (sectrue != driver->initialized) {
return 0;
}
driver->last_x = x;
driver->last_y = y;
touch_fsm_t* fsm = &driver->tls[systask_id(systask_active())];
uint32_t touch_state = touch_get_state(driver);
uint32_t event = touch_fsm_get_event(fsm, touch_state);
#ifdef TOUCH_TRACE_EVENT
trace_event(event);
@ -610,4 +573,41 @@ uint32_t touch_get_event(void) {
return event;
}
static void on_task_created(void* context, systask_id_t task_id) {
touch_driver_t* driver = (touch_driver_t*)context;
touch_fsm_t* fsm = &driver->tls[task_id];
touch_fsm_init(fsm);
}
static void on_event_poll(void* context, bool read_awaited,
bool write_awaited) {
touch_driver_t* driver = (touch_driver_t*)context;
UNUSED(write_awaited);
if (read_awaited) {
uint32_t touch_state = touch_get_state(driver);
if (touch_state != 0) {
syshandle_signal_read_ready(SYSHANDLE_TOUCH, &touch_state);
}
}
}
static bool on_check_read_ready(void* context, systask_id_t task_id,
void* param) {
touch_driver_t* driver = (touch_driver_t*)context;
touch_fsm_t* fsm = &driver->tls[task_id];
uint32_t touch_state = *(uint32_t*)param;
return touch_fsm_event_ready(fsm, touch_state);
}
static const syshandle_vmt_t g_touch_handle_vmt = {
.task_created = on_task_created,
.task_killed = NULL,
.check_read_ready = on_check_read_ready,
.check_write_ready = NULL,
.poll = on_event_poll,
};
#endif // KERNEL_MODE

View File

@ -17,8 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TOUCH_FT6X36_H
#define _TOUCH_FT6X36_H
#pragma once
// I2C address of the FT6X36 on the I2C bus.
#define FT6X36_I2C_ADDR 0x38
@ -71,5 +70,3 @@
// ------------------------------------------------------------
#define FT6X36_GESTURE_NONE 0x00
#endif

View File

@ -658,6 +658,9 @@ __attribute__((optimize("-O0"))) int32_t SITRONIX_DetectTouch(
*
******************************************************************************
*/
#include "sitronix.h"
/* TS instances */
#define TS_INSTANCES_NBR 1U
#define TS_TOUCH_NBR 10U
@ -671,13 +674,6 @@ __attribute__((optimize("-O0"))) int32_t SITRONIX_DetectTouch(
/** @defgroup STM32U5x9J_DISCOVERY_TS_Exported_Types TS Exported Types
* @{
*/
typedef struct {
uint32_t Width; /* Screen width */
uint32_t Height; /* Screen height */
uint32_t Orientation; /* Touch screen orientation */
uint32_t Accuracy; /* Expressed in pixel and means the x or y difference vs
old position to consider the new values valid */
} TS_Init_t;
typedef struct {
uint8_t MultiTouch;
@ -687,12 +683,6 @@ typedef struct {
uint32_t MaxYl;
} TS_Capabilities_t;
typedef struct {
uint32_t TouchDetected;
uint32_t TouchX;
uint32_t TouchY;
} TS_State_t;
typedef struct {
uint32_t TouchDetected;
uint32_t TouchX[2];
@ -1206,119 +1196,4 @@ static int32_t SITRONIX_Probe(uint32_t Instance) {
* @}
*/
#include <trezor_rtl.h>
#include <io/touch.h>
// Touch driver
typedef struct {
// Set if driver is initialized
secbool initialized;
// Last lower-level driver state
TS_State_t prev_state;
} touch_driver_t;
// Touch driver instance
static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
secbool touch_init(void) {
touch_driver_t *driver = &g_touch_driver;
if (sectrue != driver->initialized) {
TS_Init_t TsInit;
/* Initialize the TouchScreen */
TsInit.Width = 480;
TsInit.Height = 480;
TsInit.Orientation = 0;
TsInit.Accuracy = 10;
BSP_TS_Init(0, &TsInit);
driver->initialized = sectrue;
}
return driver->initialized;
}
void touch_deinit(void) {
touch_driver_t *driver = &g_touch_driver;
if (sectrue == driver->initialized) {
BSP_TS_DeInit(0);
memset(driver, 0, sizeof(touch_driver_t));
}
}
void touch_power_set(bool on) {
// Not implemented for the discovery kit
}
secbool touch_ready(void) {
touch_driver_t *driver = &g_touch_driver;
return driver->initialized;
}
secbool touch_set_sensitivity(uint8_t value) {
// Not implemented for the discovery kit
return sectrue;
}
uint8_t touch_get_version(void) {
// Not implemented for the discovery kit
return 0;
}
secbool touch_activity(void) {
touch_driver_t *driver = &g_touch_driver;
if (sectrue != driver->initialized) {
return secfalse;
}
TS_State_t new_state = {0};
BSP_TS_GetState(0, &new_state);
return sitronix_touching ? sectrue : secfalse;
}
uint32_t touch_get_event(void) {
touch_driver_t *driver = &g_touch_driver;
if (sectrue != driver->initialized) {
return 0;
}
TS_State_t new_state = {0};
BSP_TS_GetState(0, &new_state);
new_state.TouchDetected = (sitronix_touching != 0);
new_state.TouchX = new_state.TouchX > 120 ? new_state.TouchX - 120 : 0;
new_state.TouchY = new_state.TouchY > 120 ? new_state.TouchY - 120 : 0;
uint32_t event = 0;
if (new_state.TouchDetected && !driver->prev_state.TouchDetected) {
uint32_t xy = touch_pack_xy(new_state.TouchX, new_state.TouchY);
event = TOUCH_START | xy;
} else if (!new_state.TouchDetected && driver->prev_state.TouchDetected) {
uint32_t xy =
touch_pack_xy(driver->prev_state.TouchX, driver->prev_state.TouchY);
event = TOUCH_END | xy;
} else if (new_state.TouchDetected) {
if ((new_state.TouchX != driver->prev_state.TouchX) ||
(new_state.TouchY != driver->prev_state.TouchY)) {
uint32_t xy = touch_pack_xy(new_state.TouchX, new_state.TouchY);
event = TOUCH_MOVE | xy;
}
}
driver->prev_state = new_state;
return event;
}
#endif

View File

@ -0,0 +1,34 @@
#pragma once
// TS orientations
#define TS_ORIENTATION_PORTRAIT 0U
#define TS_ORIENTATION_LANDSCAPE 1U
#define TS_ORIENTATION_PORTRAIT_ROT180 2U
#define TS_ORIENTATION_LANDSCAPE_ROT180 3U
typedef struct {
// Screen width
uint32_t Width;
// Screen width
uint32_t Height;
// Touch screen orientation
uint32_t Orientation;
// Expressed in pixel and means the x or y difference vs
// old position to consider the new values valid
uint32_t Accuracy;
} TS_Init_t;
typedef struct {
uint32_t TouchDetected;
uint32_t TouchX;
uint32_t TouchY;
} TS_State_t;
extern uint8_t sitronix_touching;
int32_t BSP_TS_Init(uint32_t Instance, TS_Init_t *TS_Init);
int32_t BSP_TS_DeInit(uint32_t Instance);
int32_t BSP_TS_GetState(uint32_t Instance, TS_State_t *TS_State);

View File

@ -0,0 +1,210 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef KERNEL_MODE
#include <trezor_rtl.h>
#include <io/touch.h>
#include <sys/sysevent_source.h>
#include "../touch_fsm.h"
#include "sitronix.h"
// Touch driver
typedef struct {
// Set if driver is initialized
secbool initialized;
// Last reported touch state
uint32_t state;
// Touch state machine for each task
touch_fsm_t tls[SYSTASK_MAX_TASKS];
} touch_driver_t;
// Touch driver instance
static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
// Forward declarations
static const syshandle_vmt_t g_touch_handle_vmt;
secbool touch_init(void) {
touch_driver_t* drv = &g_touch_driver;
if (sectrue == drv->initialized) {
// The driver is already initialized
return sectrue;
}
TS_Init_t TsInit;
// Initialize the TouchScreen
TsInit.Width = 480;
TsInit.Height = 480;
TsInit.Orientation = 0;
TsInit.Accuracy = 2;
if (0 != BSP_TS_Init(0, &TsInit)) {
goto cleanup;
}
if (!syshandle_register(SYSHANDLE_TOUCH, &g_touch_handle_vmt, drv)) {
goto cleanup;
}
drv->initialized = sectrue;
return sectrue;
cleanup:
touch_deinit();
return secfalse;
}
void touch_deinit(void) {
touch_driver_t* drv = &g_touch_driver;
BSP_TS_DeInit(0);
syshandle_unregister(SYSHANDLE_TOUCH);
memset(drv, 0, sizeof(touch_driver_t));
}
void touch_power_set(bool on) {
// Not implemented for the discovery kit
}
secbool touch_ready(void) {
touch_driver_t* drv = &g_touch_driver;
return drv->initialized;
}
secbool touch_set_sensitivity(uint8_t value) {
// Not implemented for the discovery kit
return sectrue;
}
uint8_t touch_get_version(void) {
// Not implemented for the discovery kit
return 0;
}
secbool touch_activity(void) {
touch_driver_t* drv = &g_touch_driver;
if (sectrue != drv->initialized) {
return secfalse;
}
TS_State_t new_state = {0};
BSP_TS_GetState(0, &new_state);
return sitronix_touching ? sectrue : secfalse;
}
static uint32_t touch_get_state(touch_driver_t* drv) {
TS_State_t ts = {0};
BSP_TS_GetState(0, &ts);
uint32_t state = drv->state;
ts.TouchDetected = sitronix_touching ? 1 : 0;
ts.TouchX = ts.TouchX > 120 ? ts.TouchX - 120 : 0;
ts.TouchY = ts.TouchY > 120 ? ts.TouchY - 120 : 0;
uint32_t xy = touch_pack_xy(ts.TouchX, ts.TouchY);
if (ts.TouchDetected) {
if ((drv->state & TOUCH_END) || (drv->state == 0)) {
state = TOUCH_START | xy;
} else if (drv->state & TOUCH_MOVE) {
state = TOUCH_MOVE | xy;
} else {
state = TOUCH_START | xy;
if (state != drv->state) {
state = TOUCH_MOVE | xy;
}
}
} else {
if (drv->state & (TOUCH_START | TOUCH_MOVE)) {
state = drv->state & ~(TOUCH_START | TOUCH_MOVE);
state |= TOUCH_END;
}
}
drv->state = state;
return state;
}
uint32_t touch_get_event(void) {
touch_driver_t* drv = &g_touch_driver;
if (sectrue != drv->initialized) {
return 0;
}
touch_fsm_t* fsm = &drv->tls[systask_id(systask_active())];
uint32_t touch_state = touch_get_state(drv);
uint32_t event = touch_fsm_get_event(fsm, touch_state);
return event;
}
static void on_task_created(void* context, systask_id_t task_id) {
touch_driver_t* drv = (touch_driver_t*)context;
touch_fsm_t* fsm = &drv->tls[task_id];
touch_fsm_init(fsm);
}
static void on_event_poll(void* context, bool read_awaited,
bool write_awaited) {
touch_driver_t* drv = (touch_driver_t*)context;
UNUSED(write_awaited);
if (read_awaited) {
uint32_t touch_state = touch_get_state(drv);
if (touch_state != 0) {
syshandle_signal_read_ready(SYSHANDLE_TOUCH, &touch_state);
}
}
}
static bool on_check_read_ready(void* context, systask_id_t task_id,
void* param) {
touch_driver_t* drv = (touch_driver_t*)context;
touch_fsm_t* fsm = &drv->tls[task_id];
uint32_t touch_state = *(uint32_t*)param;
return touch_fsm_event_ready(fsm, touch_state);
}
static const syshandle_vmt_t g_touch_handle_vmt = {
.task_created = on_task_created,
.task_killed = NULL,
.check_read_ready = on_check_read_ready,
.check_write_ready = NULL,
.poll = on_event_poll,
};
#endif // KERNEL_MODE

View File

@ -17,13 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <trezor_bsp.h>
#include <trezor_rtl.h>
#ifdef KERNEL_MODE
#include <io/i2c_bus.h>
#include <io/touch.h>
#include <sys/systick.h>
#include "stmpe811.h"
/* Chip IDs */
@ -175,7 +175,7 @@
uint32_t I2cxTimeout =
I2Cx_TIMEOUT_MAX; /*<! Value of Timeout when I2C communication fails */
static i2c_bus_t *i2c_bus = NULL;
static i2c_bus_t *g_i2c_bus = NULL;
/**
* @brief Writes a value in a register of the device through BUS.
@ -199,7 +199,7 @@ static void I2Cx_WriteData(uint8_t Addr, uint8_t Reg, uint8_t Value) {
.ops = ops,
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt);
i2c_status_t status = i2c_bus_submit_and_wait(g_i2c_bus, &pkt);
(void)status;
}
@ -233,7 +233,7 @@ static void I2Cx_WriteBuffer(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer,
.ops = ops,
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt);
i2c_status_t status = i2c_bus_submit_and_wait(g_i2c_bus, &pkt);
(void)status;
}
@ -267,7 +267,7 @@ static uint8_t I2Cx_ReadData(uint8_t Addr, uint8_t Reg) {
.ops = ops,
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt);
i2c_status_t status = i2c_bus_submit_and_wait(g_i2c_bus, &pkt);
(void)status;
@ -304,7 +304,7 @@ static uint8_t I2Cx_ReadBuffer(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer,
.ops = ops,
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &pkt);
i2c_status_t status = i2c_bus_submit_and_wait(g_i2c_bus, &pkt);
return status == I2C_STATUS_OK ? 0 : 1;
}
@ -356,7 +356,7 @@ uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer,
* @brief IOE Delay.
* @param Delay in ms
*/
void IOE_Delay(uint32_t Delay) { HAL_Delay(Delay); }
void IOE_Delay(uint32_t Delay) { systick_delay_ms(Delay); }
/**
* @brief Enable the AF for the selected IO pin(s).
@ -462,7 +462,9 @@ void touch_set_mode(void) {
* @param DeviceAddr: Device address on communication Bus.
* @retval None
*/
void stmpe811_Reset() {
void stmpe811_Reset(i2c_bus_t *i2c_bus) {
g_i2c_bus = i2c_bus;
/* Power Down the stmpe811 */
IOE_Write(TS_I2C_ADDRESS, STMPE811_REG_SYS_CTRL1, 2);
@ -477,7 +479,7 @@ void stmpe811_Reset() {
IOE_Delay(2);
}
static uint32_t touch_active(void) {
uint32_t touch_active(void) {
uint8_t state;
uint8_t ret = 0;
@ -523,174 +525,81 @@ void stmpe811_TS_GetXY(uint16_t *X, uint16_t *Y) {
/* Enable the FIFO again */
IOE_Write(TS_I2C_ADDRESS, STMPE811_REG_FIFO_STA, 0x00);
}
typedef struct {
uint16_t TouchDetected;
uint16_t X;
uint16_t Y;
uint16_t Z;
} TS_StateTypeDef;
/**
* @brief Returns status and positions of the touch screen.
* @param TsState: Pointer to touch screen current state structure
*/
void BSP_TS_GetState(TS_StateTypeDef *TsState) {
static bool _detected = false;
static uint32_t _x = 0, _y = 0;
uint16_t xDiff, yDiff, x, y, xr, yr;
TsState->TouchDetected = touch_active();
TsState->TouchDetected = _detected;
TsState->X = _x;
TsState->Y = _y;
if (TsState->TouchDetected) {
stmpe811_TS_GetXY(&x, &y);
bool detected = (IOE_Read(TS_I2C_ADDRESS, STMPE811_REG_TSC_CTRL) &
STMPE811_TS_CTRL_STATUS) != 0;
/* Y value first correction */
y -= 360;
if (!detected) {
TsState->TouchDetected = _detected = false;
return;
} else {
if (IOE_Read(TS_I2C_ADDRESS, STMPE811_REG_FIFO_SIZE) > 0) {
stmpe811_TS_GetXY(&x, &y);
/* Y value second correction */
yr = y / 11;
/* Y value first correction */
y -= 360;
/* Return y position value */
if (yr <= 0) {
yr = 0;
} else if (yr > 320) {
yr = 320 - 1;
} else {
yr = 320 - yr;
}
y = yr;
/* Y value second correction */
yr = y / 11;
/* X value first correction */
if (x <= 3000) {
x = 3870 - x;
} else {
x = 3800 - x;
}
/* Return y position value */
if (yr <= 0) {
yr = 0;
} else if (yr > 320) {
yr = 320 - 1;
} else {
yr = 320 - yr;
}
y = yr;
/* X value second correction */
xr = x / 15;
/* X value first correction */
if (x <= 3000) {
x = 3870 - x;
} else {
x = 3800 - x;
}
/* Return X position value */
if (xr <= 0) {
xr = 0;
} else if (xr > 240) {
xr = 240 - 1;
} else {
}
/* X value second correction */
xr = x / 15;
x = xr;
xDiff = x > _x ? (x - _x) : (_x - x);
yDiff = y > _y ? (y - _y) : (_y - y);
/* Return X position value */
if (xr <= 0) {
xr = 0;
} else if (xr > 240) {
xr = 240 - 1;
} else {
}
if (xDiff + yDiff > 5) {
_x = x;
_y = y;
}
x = xr;
xDiff = x > _x ? (x - _x) : (_x - x);
yDiff = y > _y ? (y - _y) : (_y - y);
/* Update the X position */
TsState->X = _x;
if (xDiff + yDiff > 5) {
_x = x;
_y = y;
}
/* Update the Y position */
TsState->Y = _y;
}
}
_detected = true;
typedef struct {
// Set if driver is initialized
secbool initialized;
// Last lower-level driver state
TS_StateTypeDef prev_state;
/* Update the X position */
TsState->X = _x;
} touch_driver_t;
// Touch driver instance
static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
secbool touch_init(void) {
touch_driver_t *driver = &g_touch_driver;
if (driver->initialized != sectrue) {
i2c_bus = i2c_bus_open(TOUCH_I2C_INSTANCE);
if (i2c_bus == NULL) {
return secfalse;
}
stmpe811_Reset();
touch_set_mode();
driver->initialized = sectrue;
}
return driver->initialized;
}
void touch_deinit(void) {
touch_driver_t *driver = &g_touch_driver;
if (driver->initialized == sectrue) {
// Not implemented properly
i2c_bus_close(i2c_bus);
memset(driver, 0, sizeof(touch_driver_t));
}
}
void touch_power_set(bool on) {
// Not implemented for the discovery kit
}
secbool touch_ready(void) {
touch_driver_t *driver = &g_touch_driver;
return driver->initialized;
}
secbool touch_set_sensitivity(uint8_t value) {
// Not implemented for the discovery kit
return sectrue;
}
uint8_t touch_get_version(void) {
// Not implemented for the discovery kit
return 0;
}
secbool touch_activity(void) {
uint8_t state = ((IOE_Read(TS_I2C_ADDRESS, STMPE811_REG_TSC_CTRL) &
(uint8_t)STMPE811_TS_CTRL_STATUS) == (uint8_t)0x80);
return state > 0 ? sectrue : secfalse;
}
uint32_t touch_get_event(void) {
touch_driver_t *driver = &g_touch_driver;
if (driver->initialized != sectrue) {
return 0;
}
TS_StateTypeDef new_state = {0};
BSP_TS_GetState(&new_state);
uint32_t event = 0;
if (new_state.TouchDetected && !driver->prev_state.TouchDetected) {
uint32_t xy = touch_pack_xy(new_state.X, new_state.Y);
event = TOUCH_START | xy;
} else if (!new_state.TouchDetected && driver->prev_state.TouchDetected) {
uint32_t xy = touch_pack_xy(driver->prev_state.X, driver->prev_state.Y);
event = TOUCH_END | xy;
} else if (new_state.TouchDetected) {
if ((new_state.X != driver->prev_state.X) ||
(new_state.Y != driver->prev_state.Y)) {
uint32_t xy = touch_pack_xy(new_state.X, new_state.Y);
event = TOUCH_MOVE | xy;
/* Update the Y position */
TsState->Y = _y;
}
}
driver->prev_state = new_state;
return event;
}
#endif

View File

@ -1,6 +1,39 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef _STMPE811_H
#define _STMPE811_H
#include <trezor_types.h>
#endif //_STMPE811_H
#include <io/i2c_bus.h>
typedef struct {
uint16_t TouchDetected;
uint16_t X;
uint16_t Y;
uint16_t Z;
} TS_StateTypeDef;
void BSP_TS_GetState(TS_StateTypeDef *TsState);
void stmpe811_Reset(i2c_bus_t *i2c_bus);
void touch_set_mode(void);
uint32_t touch_active(void);

View File

@ -0,0 +1,199 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <trezor_bsp.h>
#include <trezor_rtl.h>
#ifdef KERNEL_MODE
#include <io/touch.h>
#include <sys/sysevent_source.h>
#include "../touch_fsm.h"
#include "stmpe811.h"
typedef struct {
// Set if driver is initialized
secbool initialized;
// I2C Bus driver
i2c_bus_t* i2c_bus;
// Last reported touch state
uint32_t state;
// Touch state machine for each task
touch_fsm_t tls[SYSTASK_MAX_TASKS];
} touch_driver_t;
// Touch driver instance
static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
// Forward declarations
static const syshandle_vmt_t g_touch_handle_vmt;
secbool touch_init(void) {
touch_driver_t* drv = &g_touch_driver;
if (drv->initialized == sectrue) {
return sectrue;
}
memset(drv, 0, sizeof(drv));
drv->i2c_bus = i2c_bus_open(TOUCH_I2C_INSTANCE);
if (drv->i2c_bus == NULL) {
goto cleanup;
}
if (!syshandle_register(SYSHANDLE_TOUCH, &g_touch_handle_vmt, drv)) {
goto cleanup;
}
stmpe811_Reset(drv->i2c_bus);
touch_set_mode();
drv->initialized = sectrue;
return sectrue;
cleanup:
touch_deinit();
return secfalse;
}
void touch_deinit(void) {
touch_driver_t* drv = &g_touch_driver;
syshandle_unregister(SYSHANDLE_TOUCH);
i2c_bus_close(drv->i2c_bus);
memset(drv, 0, sizeof(touch_driver_t));
}
void touch_power_set(bool on) {
// Not implemented for the discovery kit
}
secbool touch_ready(void) {
touch_driver_t* drv = &g_touch_driver;
return drv->initialized;
}
secbool touch_set_sensitivity(uint8_t value) {
// Not implemented for the discovery kit
return sectrue;
}
uint8_t touch_get_version(void) {
// Not implemented for the discovery kit
return 0;
}
secbool touch_activity(void) {
return touch_active() ? sectrue : secfalse;
/* uint8_t state = ((IOE_Read(TS_I2C_ADDRESS, STMPE811_REG_TSC_CTRL) &
(uint8_t)STMPE811_TS_CTRL_STATUS) == (uint8_t)0x80);
return state > 0 ? sectrue : secfalse;*/
}
static uint32_t touch_get_state(touch_driver_t* drv) {
TS_StateTypeDef ts = {0};
BSP_TS_GetState(&ts);
uint32_t state = drv->state;
uint32_t xy = touch_pack_xy(ts.X, ts.Y);
if (ts.TouchDetected) {
if ((drv->state & TOUCH_END) || (drv->state == 0)) {
state = TOUCH_START | xy;
} else if (drv->state & TOUCH_MOVE) {
state = TOUCH_MOVE | xy;
} else {
state = TOUCH_START | xy;
if (state != drv->state) {
state = TOUCH_MOVE | xy;
}
}
} else {
if (drv->state & (TOUCH_START | TOUCH_MOVE)) {
state = drv->state & ~(TOUCH_START | TOUCH_MOVE);
state |= TOUCH_END;
}
}
drv->state = state;
return state;
}
uint32_t touch_get_event(void) {
touch_driver_t* drv = &g_touch_driver;
if (sectrue != drv->initialized) {
return 0;
}
touch_fsm_t* fsm = &drv->tls[systask_id(systask_active())];
uint32_t touch_state = touch_get_state(drv);
uint32_t event = touch_fsm_get_event(fsm, touch_state);
return event;
}
static void on_task_created(void* context, systask_id_t task_id) {
touch_driver_t* drv = (touch_driver_t*)context;
touch_fsm_t* fsm = &drv->tls[task_id];
touch_fsm_init(fsm);
}
static void on_event_poll(void* context, bool read_awaited,
bool write_awaited) {
touch_driver_t* drv = (touch_driver_t*)context;
UNUSED(write_awaited);
if (read_awaited) {
uint32_t touch_state = touch_get_state(drv);
if (touch_state != 0) {
syshandle_signal_read_ready(SYSHANDLE_TOUCH, &touch_state);
}
}
}
static bool on_check_read_ready(void* context, systask_id_t task_id,
void* param) {
touch_driver_t* drv = (touch_driver_t*)context;
touch_fsm_t* fsm = &drv->tls[task_id];
uint32_t touch_state = *(uint32_t*)param;
return touch_fsm_event_ready(fsm, touch_state);
}
static const syshandle_vmt_t g_touch_handle_vmt = {
.task_created = on_task_created,
.task_killed = NULL,
.check_read_ready = on_check_read_ready,
.check_write_ready = NULL,
.poll = on_event_poll,
};
#endif // KERNEL_MODE

View File

@ -0,0 +1,118 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef KERNEL_MODE
#include <trezor_rtl.h>
#include <io/touch.h>
#include <sys/systick.h>
#include "touch_fsm.h"
void touch_fsm_init(touch_fsm_t* fsm) {
memset(fsm, 0, sizeof(touch_fsm_t));
fsm->update_ticks = systick_ms();
}
bool touch_fsm_event_ready(touch_fsm_t* fsm, uint32_t touch_state) {
return fsm->state != touch_state;
}
uint32_t touch_fsm_get_event(touch_fsm_t* fsm, uint32_t touch_state) {
fsm->state = touch_state;
uint32_t ticks = hal_ticks_ms();
// Test if the touch_get_event() is starving (not called frequently enough)
bool starving = (int32_t)(ticks - fsm->update_ticks) > 300 /* ms */;
fsm->update_ticks = ticks;
uint16_t x = touch_unpack_x(touch_state);
uint16_t y = touch_unpack_y(touch_state);
uint32_t event = 0;
uint32_t xy = touch_pack_xy(x, y);
if (touch_state & TOUCH_START) {
if (!fsm->pressed) {
// Finger was just pressed down
event = TOUCH_START | xy;
} else {
if ((x != fsm->last_x) || (y != fsm->last_y)) {
// It looks like we have missed the lift up event
// We should send the TOUCH_END event here with old coordinates
event = TOUCH_END | touch_pack_xy(fsm->last_x, fsm->last_y);
} else {
// We have received the same coordinates as before,
// probably this is the same start event, or a quick bounce,
// we should ignore it.
}
}
} else if (touch_state & TOUCH_MOVE) {
if (fsm->pressed) {
if ((x != fsm->last_x) || (y != fsm->last_y)) {
// Report the move event only if the coordinates
// have changed
event = TOUCH_MOVE | xy;
}
} else {
// We have missed the press down event, we have to simulate it.
// But ensure we don't simulate TOUCH_START if touch_get_event() is not
// called frequently enough to not produce false events.
if (!starving) {
event = TOUCH_START | xy;
}
}
} else if (touch_state & TOUCH_END) {
if (fsm->pressed) {
// Finger was just lifted up
event = TOUCH_END | xy;
} else {
if (!starving && ((x != fsm->last_x) || (y != fsm->last_y))) {
// We have missed the PRESS_DOWN event.
// Report the start event only if the coordinates
// have changed and driver is not starving.
// This suggests that the previous touch was very short,
// or/and the driver is not called very frequently.
event = TOUCH_START | xy;
} else {
// Either the driver is starving or the coordinates
// have not changed, which would suggest that the TOUCH_END
// is repeated, so no event is needed -this should not happen
// since two consecutive LIFT_UPs are not possible due to
// testing the interrupt line before reading the registers.
}
}
}
// remember the last state
if ((event & TOUCH_START) || (event & TOUCH_MOVE)) {
fsm->pressed = true;
} else if (event & TOUCH_END) {
fsm->pressed = false;
}
fsm->last_x = x;
fsm->last_y = y;
return event;
}
#endif // KERNEL_MODE

View File

@ -0,0 +1,63 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// This module is a simple finite state machine for touch events.
//
// It is designed to be used in a polling loop, where the state of the touch
// is read periodically. The module keeps track of the state changes and
// provides a simple interface to get the events that happened since the last
// call to touch_fsm_get_event().
//
// The benefit of using this module is that it can properly handle situations
// when the touch panel is not read frequently enough or when some
// touch events are missed.
//
// The structure is designed to be used in a multi-threaded environment, where
// each thread has its own state machine. The state machines are stored in an
// array indexed by the task ID.
typedef struct {
// Time (in ticks) when the tls was last updated
uint32_t update_ticks;
// Last reported touch state
uint32_t state;
// Set if the touch controller is currently touched
// (respectively, that we detected a touch event)
bool pressed;
// Previously reported x-coordinate
uint16_t last_x;
// Previously reported y-coordinate
uint16_t last_y;
} touch_fsm_t;
// Initializes button finite state machine
void touch_fsm_init(touch_fsm_t* fsm);
// Checks if touch_fsm_get_event() would return `true` on the next call
bool touch_fsm_event_ready(touch_fsm_t* fsm, uint32_t touch_state);
// Processes the new state of thetouch panel and fills the event structure.
//
// `touch_state` is the current state of the touch panel. The state has
// the same format as the return value of `touch_get_state()`.
//
// Returns `true` if the event structure was filled.
uint32_t touch_fsm_get_event(touch_fsm_t* fsm, uint32_t touch_state);

View File

@ -20,9 +20,12 @@
#include <trezor_bsp.h>
#include <trezor_rtl.h>
#include <SDL.h>
#include <io/touch.h>
#include <sys/sysevent_source.h>
#include <sys/systick.h>
#include <sys/unix/sdl_event.h>
#include "../touch_fsm.h"
extern int sdl_display_res_x, sdl_display_res_y;
extern int sdl_touch_offset_x, sdl_touch_offset_y;
@ -41,11 +44,7 @@ typedef enum {
IDLE,
MOUSE_DOWN_INSIDE,
MOUSE_DOWN_OUTSIDE,
BUTTON_SWIPE_LEFT_INITIATED,
BUTTON_SWIPE_RIGHT_INITIATED,
BUTTON_SWIPE_UP_INITIATED,
BUTTON_SWIPE_DOWN_INITIATED,
BUTTON_SWIPE_COMPLETED
BUTTON_SWIPE_INITIATED,
} touch_state_t;
typedef struct {
@ -53,9 +52,18 @@ typedef struct {
secbool initialized;
// Current state of the touch driver
touch_state_t state;
// Last valid coordinates
int last_x;
int last_y;
uint32_t swipe_time;
int swipe_start_x;
int swipe_start_y;
int swipe_end_x;
int swipe_end_y;
int swipe_key;
// Last event not yet read
uint32_t last_event;
// Touch state machine for each task
touch_fsm_t tls[SYSTASK_MAX_TASKS];
} touch_driver_t;
@ -64,153 +72,164 @@ static touch_driver_t g_touch_driver = {
.initialized = secfalse,
};
// Forward declarations
static const syshandle_vmt_t g_touch_handle_vmt;
static bool is_inside_display(int x, int y) {
return x >= sdl_touch_offset_x && y >= sdl_touch_offset_y &&
x - sdl_touch_offset_x < sdl_display_res_x &&
y - sdl_touch_offset_y < sdl_display_res_y;
}
static bool is_button_swipe_initiated(const touch_driver_t* driver) {
return driver->state == BUTTON_SWIPE_LEFT_INITIATED ||
driver->state == BUTTON_SWIPE_RIGHT_INITIATED ||
driver->state == BUTTON_SWIPE_UP_INITIATED ||
driver->state == BUTTON_SWIPE_DOWN_INITIATED;
}
static void handle_mouse_events(touch_driver_t* drv, SDL_Event* event) {
bool inside_display = is_inside_display(event->button.x, event->button.y);
static void handle_mouse_events(touch_driver_t* driver, SDL_Event event,
int* ev_type, int* ev_x, int* ev_y) {
bool inside_display = is_inside_display(event.button.x, event.button.y);
switch (event.type) {
switch (event->type) {
case SDL_MOUSEBUTTONDOWN:
if (inside_display) {
*ev_x = event.button.x - sdl_touch_offset_x;
*ev_y = event.button.y - sdl_touch_offset_y;
*ev_type = TOUCH_START;
driver->state = MOUSE_DOWN_INSIDE;
int x = event->button.x - sdl_touch_offset_x;
int y = event->button.y - sdl_touch_offset_y;
drv->last_event = TOUCH_START | touch_pack_xy(x, y);
drv->state = MOUSE_DOWN_INSIDE;
}
break;
case SDL_MOUSEBUTTONUP:
if (driver->state != IDLE) {
*ev_x = inside_display ? event.button.x - sdl_touch_offset_x
: driver->last_x;
*ev_y = inside_display ? event.button.y - sdl_touch_offset_y
: driver->last_y;
*ev_type = TOUCH_END;
driver->state = IDLE;
if (drv->state != IDLE) {
int x = inside_display ? event->button.x - sdl_touch_offset_x
: touch_unpack_x(drv->last_event);
int y = inside_display ? event->button.y - sdl_touch_offset_y
: touch_unpack_y(drv->last_event);
;
drv->last_event = TOUCH_END | touch_pack_xy(x, y);
drv->state = IDLE;
}
break;
case SDL_MOUSEMOTION:
if (driver->state != IDLE) {
if (drv->state != IDLE) {
if (inside_display) {
*ev_x = event.motion.x - sdl_touch_offset_x;
*ev_y = event.motion.y - sdl_touch_offset_y;
int x = event->motion.x - sdl_touch_offset_x;
int y = event->motion.y - sdl_touch_offset_y;
// simulate TOUCH_START if pressed in mouse returned on visible area
*ev_type =
(driver->state == MOUSE_DOWN_OUTSIDE) ? TOUCH_START : TOUCH_MOVE;
driver->state = MOUSE_DOWN_INSIDE;
} else {
if (driver->state == MOUSE_DOWN_INSIDE) {
// use last valid coordinates and simulate TOUCH_END
*ev_x = driver->last_x;
*ev_y = driver->last_y;
*ev_type = TOUCH_END;
if (drv->state == MOUSE_DOWN_OUTSIDE) {
drv->last_event = TOUCH_START | touch_pack_xy(x, y);
} else {
drv->last_event = TOUCH_MOVE | touch_pack_xy(x, y);
}
driver->state = MOUSE_DOWN_OUTSIDE;
drv->state = MOUSE_DOWN_INSIDE;
} else {
if (drv->state == MOUSE_DOWN_INSIDE) {
// use last valid coordinates and simulate TOUCH_END
int x = touch_unpack_x(drv->last_event);
int y = touch_unpack_y(drv->last_event);
drv->last_event = TOUCH_END | touch_pack_xy(x, y);
}
drv->state = MOUSE_DOWN_OUTSIDE;
}
}
break;
}
}
static void handle_button_events(touch_driver_t* driver, SDL_Event event,
int* ev_type, int* ev_x, int* ev_y) {
static void handle_button_events(touch_driver_t* drv, SDL_Event* event) {
// Handle arrow buttons to trigger a scroll movement by set length in the
// direction of the button
if (event.type == SDL_KEYDOWN && !event.key.repeat &&
!is_button_swipe_initiated(driver)) {
switch (event.key.keysym.sym) {
case SDLK_LEFT:
*ev_x = _btn_swipe_begin;
*ev_y = sdl_display_res_y / 2;
*ev_type = TOUCH_START;
driver->state = BUTTON_SWIPE_LEFT_INITIATED;
break;
case SDLK_RIGHT:
*ev_x = sdl_display_res_x - _btn_swipe_begin;
*ev_y = sdl_display_res_y / 2;
*ev_type = TOUCH_START;
driver->state = BUTTON_SWIPE_RIGHT_INITIATED;
break;
case SDLK_UP:
*ev_x = sdl_display_res_x / 2;
*ev_y = _btn_swipe_begin;
*ev_type = TOUCH_START;
driver->state = BUTTON_SWIPE_UP_INITIATED;
break;
case SDLK_DOWN:
*ev_x = sdl_display_res_x / 2;
*ev_y = sdl_display_res_y - _btn_swipe_begin;
*ev_type = TOUCH_START;
driver->state = BUTTON_SWIPE_DOWN_INITIATED;
break;
if (event->type == SDL_KEYDOWN && !event->key.repeat) {
if (drv->state != BUTTON_SWIPE_INITIATED) {
switch (event->key.keysym.sym) {
case SDLK_LEFT:
drv->swipe_start_x = _btn_swipe_begin;
drv->swipe_start_y = sdl_display_res_y / 2;
drv->swipe_end_x = drv->swipe_start_x + _btn_swipe_length;
drv->swipe_end_y = drv->swipe_start_y;
drv->state = BUTTON_SWIPE_INITIATED;
break;
case SDLK_RIGHT:
drv->swipe_start_x = sdl_display_res_x - _btn_swipe_begin;
drv->swipe_start_y = sdl_display_res_y / 2;
drv->swipe_end_x = drv->swipe_start_x - _btn_swipe_length;
drv->swipe_end_y = drv->swipe_start_y;
drv->state = BUTTON_SWIPE_INITIATED;
break;
case SDLK_UP:
drv->swipe_start_x = sdl_display_res_x / 2;
drv->swipe_start_y = _btn_swipe_begin;
drv->swipe_end_x = drv->swipe_start_x;
drv->swipe_end_y = drv->swipe_start_y + _btn_swipe_length;
drv->state = BUTTON_SWIPE_INITIATED;
break;
case SDLK_DOWN:
drv->swipe_start_x = sdl_display_res_x / 2;
drv->swipe_start_y = sdl_display_res_y - _btn_swipe_begin;
drv->swipe_end_x = drv->swipe_start_x;
drv->swipe_end_y = drv->swipe_start_y - _btn_swipe_length;
drv->state = BUTTON_SWIPE_INITIATED;
break;
}
if (drv->state == BUTTON_SWIPE_INITIATED) {
drv->swipe_key = event->key.keysym.sym;
drv->swipe_time = systick_ms();
drv->last_event =
TOUCH_START | touch_pack_xy(drv->swipe_start_x, drv->swipe_start_y);
}
}
} else if (event.type == SDL_KEYUP && driver->state != IDLE) {
switch (event.key.keysym.sym) {
case SDLK_LEFT:
if (driver->state == BUTTON_SWIPE_LEFT_INITIATED) {
*ev_x = _btn_swipe_begin + _btn_swipe_length;
*ev_y = sdl_display_res_y / 2;
*ev_type = TOUCH_MOVE;
driver->state = BUTTON_SWIPE_COMPLETED;
}
break;
case SDLK_RIGHT:
if (driver->state == BUTTON_SWIPE_RIGHT_INITIATED) {
*ev_x = sdl_display_res_x - _btn_swipe_begin - _btn_swipe_length;
*ev_y = sdl_display_res_y / 2;
*ev_type = TOUCH_MOVE;
driver->state = BUTTON_SWIPE_COMPLETED;
}
break;
case SDLK_UP:
if (driver->state == BUTTON_SWIPE_UP_INITIATED) {
*ev_x = sdl_display_res_x / 2;
*ev_y = _btn_swipe_begin + _btn_swipe_length;
*ev_type = TOUCH_MOVE;
driver->state = BUTTON_SWIPE_COMPLETED;
}
break;
case SDLK_DOWN:
if (driver->state == BUTTON_SWIPE_DOWN_INITIATED) {
*ev_x = sdl_display_res_x / 2;
*ev_y = sdl_display_res_y - _btn_swipe_begin - _btn_swipe_length;
*ev_type = TOUCH_MOVE;
driver->state = BUTTON_SWIPE_COMPLETED;
}
break;
} else if (event->type == SDL_KEYUP &&
event->key.keysym.sym == drv->swipe_key) {
if (drv->state == BUTTON_SWIPE_INITIATED) {
drv->last_event =
TOUCH_END | touch_pack_xy(drv->swipe_end_x, drv->swipe_end_y);
drv->state = IDLE;
}
}
}
// Called from global event loop to filter and process SDL events
static void touch_sdl_event_filter(void* context, SDL_Event* sdl_event) {
touch_driver_t* drv = (touch_driver_t*)context;
if (drv->state == IDLE || drv->state == MOUSE_DOWN_INSIDE ||
drv->state == MOUSE_DOWN_OUTSIDE) {
handle_mouse_events(drv, sdl_event);
}
if (drv->state == IDLE || drv->state == BUTTON_SWIPE_INITIATED) {
handle_button_events(drv, sdl_event);
}
}
secbool touch_init(void) {
touch_driver_t* driver = &g_touch_driver;
touch_driver_t* drv = &g_touch_driver;
if (driver->initialized != sectrue) {
memset(driver, 0, sizeof(touch_driver_t));
driver->state = IDLE;
driver->initialized = sectrue;
if (drv->initialized) {
return sectrue;
}
return driver->initialized;
memset(drv, 0, sizeof(touch_driver_t));
drv->state = IDLE;
if (!syshandle_register(SYSHANDLE_TOUCH, &g_touch_handle_vmt, drv)) {
goto cleanup;
}
if (!sdl_events_register(touch_sdl_event_filter, drv)) {
goto cleanup;
}
drv->initialized = sectrue;
return drv->initialized;
cleanup:
return secfalse;
}
void touch_deinit(void) {
touch_driver_t* driver = &g_touch_driver;
touch_driver_t* drv = &g_touch_driver;
if (driver->initialized == sectrue) {
memset(driver, 0, sizeof(touch_driver_t));
if (drv->initialized == sectrue) {
syshandle_unregister(SYSHANDLE_TOUCH);
memset(drv, 0, sizeof(touch_driver_t));
}
}
@ -219,8 +238,8 @@ void touch_power_set(bool on) {
}
secbool touch_ready(void) {
touch_driver_t* driver = &g_touch_driver;
return driver->initialized;
touch_driver_t* drv = &g_touch_driver;
return drv->initialized;
}
secbool touch_set_sensitivity(uint8_t value) {
@ -241,37 +260,74 @@ secbool touch_activity(void) {
}
}
uint32_t touch_get_state(touch_driver_t* drv) {
sdl_events_poll();
if (drv->state == BUTTON_SWIPE_INITIATED) {
if (drv->last_event & TOUCH_START) {
// Emulate swipe by sending MOVE event after 100ms
uint32_t time_delta = systick_ms() - drv->swipe_time;
if (time_delta > 100) {
int x = (drv->swipe_start_x + drv->swipe_end_x) / 2;
int y = (drv->swipe_start_y + drv->swipe_end_y) / 2;
drv->last_event = TOUCH_MOVE | touch_pack_xy(x, y);
}
}
}
return drv->last_event;
}
uint32_t touch_get_event(void) {
touch_driver_t* driver = &g_touch_driver;
if (driver->initialized != sectrue) {
if (sectrue != driver->initialized) {
return 0;
}
if (driver->state == BUTTON_SWIPE_COMPLETED) {
driver->state = IDLE;
return TOUCH_END | touch_pack_xy(driver->last_x, driver->last_y);
}
touch_fsm_t* fsm = &driver->tls[systask_id(systask_active())];
SDL_Event event;
uint32_t touch_state = touch_get_state(driver);
int ev_x = 0;
int ev_y = 0;
int ev_type = 0;
uint32_t event = touch_fsm_get_event(fsm, touch_state);
while (SDL_PollEvent(&event) > 0) {
if (driver->state == IDLE || driver->state == MOUSE_DOWN_INSIDE ||
driver->state == MOUSE_DOWN_OUTSIDE) {
handle_mouse_events(driver, event, &ev_type, &ev_x, &ev_y);
}
if (driver->state == IDLE || is_button_swipe_initiated(driver)) {
handle_button_events(driver, event, &ev_type, &ev_x, &ev_y);
}
if (ev_type != 0) {
driver->last_x = ev_x;
driver->last_y = ev_y;
}
}
return ev_type | touch_pack_xy(ev_x, ev_y);
return event;
}
static void on_task_created(void* context, systask_id_t task_id) {
touch_driver_t* dr = (touch_driver_t*)context;
touch_fsm_t* fsm = &dr->tls[task_id];
touch_fsm_init(fsm);
}
static void on_event_poll(void* context, bool read_awaited,
bool write_awaited) {
touch_driver_t* drv = (touch_driver_t*)context;
UNUSED(write_awaited);
if (read_awaited) {
uint32_t touch_state = touch_get_state(drv);
if (touch_state != 0) {
syshandle_signal_read_ready(SYSHANDLE_TOUCH, &touch_state);
}
}
}
static bool on_check_read_ready(void* context, systask_id_t task_id,
void* param) {
touch_driver_t* drv = (touch_driver_t*)context;
touch_fsm_t* fsm = &drv->tls[task_id];
uint32_t touch_state = *(uint32_t*)param;
return touch_fsm_event_ready(fsm, touch_state);
}
static const syshandle_vmt_t g_touch_handle_vmt = {
.task_created = on_task_created,
.task_killed = NULL,
.check_read_ready = on_check_read_ready,
.check_write_ready = NULL,
.poll = on_event_poll,
};

View File

@ -72,6 +72,8 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/i2c_bus/stm32f4/i2c_bus.c"]
sources += ["embed/io/touch/stmpe811/stmpe811.c"]
sources += ["embed/io/touch/stmpe811/touch.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/i2c_bus/inc"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")

View File

@ -55,7 +55,9 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/i2c_bus/stm32u5/i2c_bus.c"]
sources += ["embed/io/touch/sitronix/touch.c"]
sources += ["embed/io/touch/sitronix/sitronix.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/i2c_bus/inc"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")

View File

@ -52,6 +52,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/unix/touch.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
defines += [("USE_TOUCH", "1")]

View File

@ -63,6 +63,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/i2c_bus/stm32f4/i2c_bus.c"]
sources += ["embed/io/touch/ft6x36/ft6x36.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/i2c_bus/inc"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")

View File

@ -62,6 +62,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/unix/touch.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
defines += [("USE_TOUCH", "1")]

View File

@ -66,6 +66,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/i2c_bus/stm32u5/i2c_bus.c"]
sources += ["embed/io/touch/ft6x36/ft6x36.c"]
sources += ["embed/io/touch/touch_fsm.c"]
sources += ["embed/io/touch/ft6x36/panels/lx154a2422cpt23.c"]
paths += ["embed/io/i2c_bus/inc"]
paths += ["embed/io/touch/inc"]

View File

@ -81,6 +81,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/unix/touch.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
defines += [("USE_TOUCH", "1")]

View File

@ -60,6 +60,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/ft6x36/ft6x36.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
sources += ["embed/io/button/stm32/button.c"]

View File

@ -60,6 +60,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/ft6x36/ft6x36.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
sources += ["embed/io/button/stm32/button.c"]

View File

@ -60,6 +60,7 @@ def configure(
if "input" in features_wanted:
sources += ["embed/io/touch/ft6x36/ft6x36.c"]
sources += ["embed/io/touch/touch_fsm.c"]
paths += ["embed/io/touch/inc"]
features_available.append("touch")
sources += ["embed/io/button/stm32/button.c"]