mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-18 11:21:11 +00:00
refactor(core/embed): prepare touch drivers for low power mode
[no changelog]
This commit is contained in:
parent
089dc84f38
commit
3460c4b891
@ -112,7 +112,6 @@ SOURCE_MOD += [
|
||||
'embed/lib/image.c',
|
||||
'embed/lib/mini_printf.c',
|
||||
'embed/lib/terminal.c',
|
||||
'embed/lib/touch.c',
|
||||
'embed/lib/unit_variant.c',
|
||||
'vendor/micropython/lib/uzlib/adler32.c',
|
||||
'vendor/micropython/lib/uzlib/crc32.c',
|
||||
@ -150,11 +149,10 @@ SOURCE_TREZORHAL = [
|
||||
'embed/trezorhal/unix/fault_handlers.c',
|
||||
'embed/trezorhal/unix/flash.c',
|
||||
'embed/trezorhal/unix/flash_otp.c',
|
||||
'embed/trezorhal/unix/touch/touch.c',
|
||||
'embed/trezorhal/unix/rng.c',
|
||||
'embed/trezorhal/unix/usb.c',
|
||||
'embed/trezorhal/unix/random_delays.c',
|
||||
'embed/trezorhal/unix/rng.c',
|
||||
'embed/trezorhal/unix/secret.c',
|
||||
'embed/trezorhal/unix/usb.c',
|
||||
]
|
||||
|
||||
if NEW_RENDERING:
|
||||
|
@ -419,20 +419,19 @@ SOURCE_MICROPYTHON = [
|
||||
SOURCE_UNIX = [
|
||||
'embed/trezorhal/unix/boot_args.c',
|
||||
'embed/trezorhal/unix/common.c',
|
||||
'embed/trezorhal/unix/flash.c',
|
||||
'embed/trezorhal/unix/flash_otp.c',
|
||||
'embed/trezorhal/unix/flash.c',
|
||||
'embed/trezorhal/unix/random_delays.c',
|
||||
'embed/trezorhal/unix/rng.c',
|
||||
'embed/trezorhal/unix/usb.c',
|
||||
'embed/trezorhal/unix/touch/touch.c',
|
||||
'embed/unix/main.c',
|
||||
'embed/unix/main_main.c',
|
||||
'embed/unix/main.c',
|
||||
'embed/unix/profile.c',
|
||||
'vendor/micropython/shared/runtime/gchelper_generic.c',
|
||||
'vendor/micropython/ports/unix/alloc.c',
|
||||
'vendor/micropython/ports/unix/gccollect.c',
|
||||
'vendor/micropython/ports/unix/input.c',
|
||||
'vendor/micropython/ports/unix/unix_mphal.c',
|
||||
'vendor/micropython/shared/runtime/gchelper_generic.c',
|
||||
]
|
||||
|
||||
if NEW_RENDERING:
|
||||
|
@ -154,16 +154,16 @@ static void ui_screen_boot_wait(int wait_seconds) {
|
||||
|
||||
void ui_click(void) {
|
||||
// flush touch events if any
|
||||
while (touch_read()) {
|
||||
while (touch_get_event()) {
|
||||
}
|
||||
// wait for TOUCH_START
|
||||
while ((touch_read() & TOUCH_START) == 0) {
|
||||
while ((touch_get_event() & TOUCH_START) == 0) {
|
||||
}
|
||||
// wait for TOUCH_END
|
||||
while ((touch_read() & TOUCH_END) == 0) {
|
||||
while ((touch_get_event() & TOUCH_END) == 0) {
|
||||
}
|
||||
// flush touch events if any
|
||||
while (touch_read()) {
|
||||
while (touch_get_event()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,6 @@ int bootloader_main(void) {
|
||||
unit_variant_init();
|
||||
|
||||
#ifdef USE_TOUCH
|
||||
touch_power_on();
|
||||
#ifdef TREZOR_MODEL_T3T1
|
||||
// on T3T1, tester needs to run without touch, so making an exception
|
||||
// until unit variant is written in OTP
|
||||
@ -514,17 +513,22 @@ int bootloader_main(void) {
|
||||
uint32_t touched = 0;
|
||||
#ifdef USE_TOUCH
|
||||
if (firmware_present == sectrue && stay_in_bootloader != sectrue) {
|
||||
touch_wait_until_ready();
|
||||
// Wait until the touch controller is ready
|
||||
// (on hardware this may take a while)
|
||||
while (touch_ready() != sectrue) {
|
||||
hal_delay(1);
|
||||
}
|
||||
#ifdef TREZOR_EMULATOR
|
||||
hal_delay(500);
|
||||
#endif
|
||||
// Give the touch controller time to report events
|
||||
// if someone touches the screen
|
||||
for (int i = 0; i < 10; i++) {
|
||||
touched = touch_is_detected() | touch_read();
|
||||
if (touched) {
|
||||
if (touch_activity() == sectrue) {
|
||||
touched = 1;
|
||||
break;
|
||||
}
|
||||
#ifdef TREZOR_EMULATOR
|
||||
hal_delay(25);
|
||||
#else
|
||||
hal_delay_us(1000);
|
||||
#endif
|
||||
hal_delay(5);
|
||||
}
|
||||
}
|
||||
#elif defined USE_BUTTON
|
||||
|
@ -206,7 +206,6 @@ int main(void) {
|
||||
random_delays_init();
|
||||
#ifdef USE_TOUCH
|
||||
touch_init();
|
||||
touch_power_on();
|
||||
#endif
|
||||
|
||||
#ifdef USE_HASH_PROCESSOR
|
||||
|
@ -85,9 +85,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
|
||||
}
|
||||
#if defined USE_TOUCH
|
||||
else if (iface == TOUCH_IFACE) {
|
||||
|
||||
const uint32_t evt = touch_read();
|
||||
|
||||
const uint32_t evt = touch_get_event();
|
||||
if (evt) {
|
||||
// ignore TOUCH_MOVE events if they are too frequent
|
||||
if ((evt & TOUCH_MOVE) == 0 ||
|
||||
|
@ -1,22 +0,0 @@
|
||||
|
||||
#ifdef USE_TOUCH
|
||||
#include "touch.h"
|
||||
|
||||
uint32_t touch_click(void) {
|
||||
uint32_t r = 0;
|
||||
// flush touch events if any
|
||||
while (touch_read()) {
|
||||
}
|
||||
// wait for TOUCH_START
|
||||
while ((touch_read() & TOUCH_START) == 0) {
|
||||
}
|
||||
// wait for TOUCH_END
|
||||
while (((r = touch_read()) & TOUCH_END) == 0) {
|
||||
}
|
||||
// flush touch events if any
|
||||
while (touch_read()) {
|
||||
}
|
||||
// return last touch coordinate
|
||||
return r;
|
||||
}
|
||||
#endif
|
1
core/embed/prodtest/.changelog.d/3900.fixed
Normal file
1
core/embed/prodtest/.changelog.d/3900.fixed
Normal file
@ -0,0 +1 @@
|
||||
Fix TOUCH VERSION command
|
@ -312,15 +312,15 @@ static secbool touch_click_timeout(uint32_t *touch, uint32_t timeout_ms) {
|
||||
uint32_t deadline = HAL_GetTick() + timeout_ms;
|
||||
uint32_t r = 0;
|
||||
|
||||
while (touch_read())
|
||||
while (touch_get_event())
|
||||
;
|
||||
while ((touch_read() & TOUCH_START) == 0) {
|
||||
while ((touch_get_event() & TOUCH_START) == 0) {
|
||||
if (HAL_GetTick() > deadline) return secfalse;
|
||||
}
|
||||
while (((r = touch_read()) & TOUCH_END) == 0) {
|
||||
while (((r = touch_get_event()) & TOUCH_END) == 0) {
|
||||
if (HAL_GetTick() > deadline) return secfalse;
|
||||
}
|
||||
while (touch_read())
|
||||
while (touch_get_event())
|
||||
;
|
||||
|
||||
*touch = r;
|
||||
@ -348,7 +348,7 @@ static void test_touch(const char *args) {
|
||||
}
|
||||
display_refresh();
|
||||
|
||||
touch_power_on();
|
||||
touch_init();
|
||||
|
||||
uint32_t evt = 0;
|
||||
if (touch_click_timeout(&evt, timeout * 1000)) {
|
||||
@ -361,20 +361,20 @@ static void test_touch(const char *args) {
|
||||
display_clear();
|
||||
display_refresh();
|
||||
|
||||
touch_power_off();
|
||||
touch_deinit();
|
||||
}
|
||||
|
||||
static void test_sensitivity(const char *args) {
|
||||
int v = atoi(args);
|
||||
|
||||
touch_power_on();
|
||||
touch_sensitivity(v & 0xFF);
|
||||
touch_init();
|
||||
touch_set_sensitivity(v & 0xFF);
|
||||
|
||||
display_clear();
|
||||
display_refresh();
|
||||
|
||||
for (;;) {
|
||||
uint32_t evt = touch_read();
|
||||
uint32_t evt = touch_get_event();
|
||||
if (evt & TOUCH_START || evt & TOUCH_MOVE) {
|
||||
int x = touch_unpack_x(evt);
|
||||
int y = touch_unpack_y(evt);
|
||||
@ -387,14 +387,14 @@ static void test_sensitivity(const char *args) {
|
||||
}
|
||||
}
|
||||
|
||||
touch_power_off();
|
||||
touch_deinit();
|
||||
}
|
||||
|
||||
static void touch_version(void) {
|
||||
touch_power_on();
|
||||
touch_init();
|
||||
uint8_t version = touch_get_version();
|
||||
vcp_println("OK %d", version);
|
||||
touch_power_off();
|
||||
touch_deinit();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -442,7 +442,7 @@ fn generate_trezorhal_bindings() {
|
||||
//usb
|
||||
.allowlist_function("usb_configured")
|
||||
// touch
|
||||
.allowlist_function("touch_read")
|
||||
.allowlist_function("touch_get_event")
|
||||
// button
|
||||
.allowlist_function("button_read")
|
||||
// haptic
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::ffi;
|
||||
|
||||
#[cfg(feature = "touch")]
|
||||
pub fn io_touch_read() -> u32 {
|
||||
unsafe { ffi::touch_read() }
|
||||
pub fn io_touch_get_event() -> u32 {
|
||||
unsafe { ffi::touch_get_event() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "button")]
|
||||
|
@ -1,7 +1,7 @@
|
||||
#[cfg(feature = "button")]
|
||||
use crate::trezorhal::io::io_button_read;
|
||||
#[cfg(feature = "touch")]
|
||||
use crate::trezorhal::io::io_touch_read;
|
||||
use crate::trezorhal::io::io_touch_get_event;
|
||||
#[cfg(feature = "button")]
|
||||
use crate::ui::event::ButtonEvent;
|
||||
#[cfg(feature = "touch")]
|
||||
@ -56,7 +56,7 @@ fn button_eval() -> Option<ButtonEvent> {
|
||||
|
||||
#[cfg(feature = "touch")]
|
||||
fn touch_eval() -> Option<TouchEvent> {
|
||||
let event = io_touch_read();
|
||||
let event = io_touch_get_event();
|
||||
if event == 0 {
|
||||
return None;
|
||||
}
|
||||
|
@ -20,34 +20,105 @@
|
||||
#include STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "secbool.h"
|
||||
|
||||
#include "ft6x36.h"
|
||||
#include "i2c.h"
|
||||
#include "touch.h"
|
||||
|
||||
#define TOUCH_ADDRESS \
|
||||
(0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit
|
||||
#define TOUCH_PACKET_SIZE 7U
|
||||
#define EVENT_PRESS_DOWN 0x00U
|
||||
#define EVENT_CONTACT 0x80U
|
||||
#define EVENT_LIFT_UP 0x40U
|
||||
#define EVENT_NO_EVENT 0xC0U
|
||||
#define GESTURE_NO_GESTURE 0x00U
|
||||
#define X_POS_MSB (touch_data[3] & 0x0FU)
|
||||
#define X_POS_LSB (touch_data[4])
|
||||
#define Y_POS_MSB (touch_data[5] & 0x0FU)
|
||||
#define Y_POS_LSB (touch_data[6])
|
||||
typedef struct {
|
||||
// Set if the driver is initialized
|
||||
secbool initialized;
|
||||
// Set if the driver is ready to report touches.
|
||||
// FT6X36 needs about 300ms after power-up to stabilize.
|
||||
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;
|
||||
// Set if the touch controller is currently touched
|
||||
// (respectively, the we detected a touch event)
|
||||
bool pressed;
|
||||
// Previously reported x-coordinate
|
||||
uint16_t last_x;
|
||||
// Previously reported y-coordinate
|
||||
uint16_t last_y;
|
||||
|
||||
#define EVENT_OLD_TIMEOUT_MS 50
|
||||
#define EVENT_MISSING_TIMEOUT_MS 50
|
||||
} touch_driver_t;
|
||||
|
||||
static uint32_t touch_init_ticks = 0;
|
||||
// Touch driver instance
|
||||
static touch_driver_t g_touch_driver = {
|
||||
.initialized = secfalse,
|
||||
};
|
||||
|
||||
static void touch_default_pin_state(void) {
|
||||
// Reads a subsequent registers from the FT6X36.
|
||||
//
|
||||
// Returns: `sectrue` if the register was read
|
||||
// successfully, `secfalse` otherwise.
|
||||
//
|
||||
// If the I2C bus is busy, the function will cycle the
|
||||
// bus and retry the operation.
|
||||
static secbool ft6x36_read_regs(uint8_t reg, uint8_t* value, size_t count) {
|
||||
uint16_t i2c_bus = TOUCH_I2C_INSTANCE;
|
||||
uint8_t i2c_addr = FT6X36_I2C_ADDR;
|
||||
uint8_t txdata[] = {reg};
|
||||
uint8_t retries = 3;
|
||||
|
||||
do {
|
||||
int result = i2c_transmit(i2c_bus, i2c_addr, txdata, sizeof(txdata), 10);
|
||||
if (HAL_OK == result) {
|
||||
result = i2c_receive(i2c_bus, i2c_addr, value, count, 10);
|
||||
}
|
||||
|
||||
if (HAL_OK == result) {
|
||||
// success
|
||||
return sectrue;
|
||||
} else if (HAL_BUSY == result && retries > 0) {
|
||||
// I2C bus is busy, cycle it and try again
|
||||
i2c_cycle(i2c_bus);
|
||||
retries--;
|
||||
} else {
|
||||
// Aother error or retries exhausted
|
||||
return secfalse;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// Writes a register to the FT6X36.
|
||||
//
|
||||
// Returns: `sectrue` if the register was written
|
||||
// successfully, `secfalse` otherwise.
|
||||
//
|
||||
// If the I2C bus is busy, the function will cycle the
|
||||
// bus and retry the operation.
|
||||
static secbool ft6x36_write_reg(uint8_t reg, uint8_t value) {
|
||||
uint16_t i2c_bus = TOUCH_I2C_INSTANCE;
|
||||
uint8_t i2c_addr = FT6X36_I2C_ADDR;
|
||||
uint8_t txdata[] = {reg, value};
|
||||
uint8_t retries = 3;
|
||||
|
||||
do {
|
||||
int result = i2c_transmit(i2c_bus, i2c_addr, txdata, sizeof(txdata), 10);
|
||||
if (HAL_OK == result) {
|
||||
// success
|
||||
return sectrue;
|
||||
} else if (HAL_BUSY == result && retries > 0) {
|
||||
// I2C bus is busy, cycle it and try again
|
||||
i2c_cycle(i2c_bus);
|
||||
retries--;
|
||||
} else {
|
||||
// Another error or retries exhausted
|
||||
return secfalse;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// Powers down the touch controller and puts all
|
||||
// the pins in the proper state to save power.
|
||||
static void ft6x36_power_down(void) {
|
||||
GPIO_PinState state = HAL_GPIO_ReadPin(TOUCH_ON_PORT, TOUCH_ON_PIN);
|
||||
|
||||
// set power off and other pins as per section 3.5 of FT6236 datasheet
|
||||
@ -74,227 +145,291 @@ static void touch_default_pin_state(void) {
|
||||
GPIO_InitStructure.Pin = TOUCH_ON_PIN;
|
||||
HAL_GPIO_Init(TOUCH_ON_PORT, &GPIO_InitStructure);
|
||||
|
||||
// in-case power was on, or CTPM was active make sure to wait long enough
|
||||
// for these changes to take effect. a reset needs to be low for
|
||||
// a minimum of 5ms. also wait for power circuitry to stabilize (if it
|
||||
// changed).
|
||||
HAL_Delay(10);
|
||||
|
||||
if (state == GPIO_PIN_SET) {
|
||||
HAL_Delay(90); // add 90 ms for circuitry to stabilize (being conservative)
|
||||
// 90 ms for circuitry to stabilize (being conservative)
|
||||
hal_delay(90);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_active_pin_state(void) {
|
||||
HAL_GPIO_WritePin(TOUCH_ON_PORT, TOUCH_ON_PIN, GPIO_PIN_RESET); // CTP_ON
|
||||
HAL_Delay(10); // we need to wait until the circuit fully kicks-in
|
||||
// Powers up the touch controller and do proper reset sequence
|
||||
//
|
||||
// `ft6x36_power_down()` must be called before calling this first time function
|
||||
// to properly initialize the GPIO pins.
|
||||
static void ft6x36_power_up(void) {
|
||||
// Ensure the touch controller is in reset state
|
||||
HAL_GPIO_WritePin(TOUCH_RST_PORT, TOUCH_RST_PIN, GPIO_PIN_RESET);
|
||||
// Power up the touch controller
|
||||
HAL_GPIO_WritePin(TOUCH_ON_PORT, TOUCH_ON_PIN, GPIO_PIN_RESET);
|
||||
|
||||
// Wait until the circuit fully kicks-in
|
||||
// (5ms is the minimum time required for the reset signal to be effective)
|
||||
hal_delay(10);
|
||||
|
||||
// Enable intterrupt input
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
// capacitive touch panel module (CTPM) interrupt (INT) input
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = TOUCH_INT_PIN;
|
||||
HAL_GPIO_Init(TOUCH_INT_PORT, &GPIO_InitStructure);
|
||||
|
||||
// Release touch controller from reset
|
||||
HAL_GPIO_WritePin(TOUCH_RST_PORT, TOUCH_RST_PIN, GPIO_PIN_SET);
|
||||
|
||||
// Wait for the touch controller to boot up
|
||||
hal_delay(5);
|
||||
|
||||
// Clear the flag indicating rising edge on INT_PIN
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(TOUCH_INT_PIN);
|
||||
|
||||
HAL_GPIO_WritePin(TOUCH_RST_PORT, TOUCH_RST_PIN,
|
||||
GPIO_PIN_SET); // release CTPM reset
|
||||
|
||||
touch_init_ticks = hal_ticks_ms();
|
||||
|
||||
HAL_Delay(5);
|
||||
}
|
||||
|
||||
secbool touch_set_mode(void) {
|
||||
// set register 0xA4 G_MODE to interrupt trigger mode (0x01). basically, CTPM
|
||||
// generates a pulse when new data is available
|
||||
uint8_t touch_panel_config[] = {0xA4, 0x01};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (HAL_OK == i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS,
|
||||
touch_panel_config, sizeof(touch_panel_config),
|
||||
10)) {
|
||||
return sectrue;
|
||||
}
|
||||
i2c_cycle(TOUCH_I2C_INSTANCE);
|
||||
}
|
||||
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
void touch_power_on(void) {
|
||||
touch_default_pin_state();
|
||||
|
||||
// turn on CTP circuitry
|
||||
touch_active_pin_state();
|
||||
}
|
||||
|
||||
void touch_power_off(void) {
|
||||
// turn off CTP circuitry
|
||||
HAL_Delay(50);
|
||||
touch_default_pin_state();
|
||||
}
|
||||
|
||||
secbool touch_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = TOUCH_INT_PIN;
|
||||
HAL_GPIO_Init(TOUCH_INT_PORT, &GPIO_InitStructure);
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(TOUCH_INT_PIN);
|
||||
|
||||
if (sectrue != touch_set_mode()) {
|
||||
return secfalse;
|
||||
}
|
||||
return touch_sensitivity(TOUCH_SENSITIVITY);
|
||||
}
|
||||
|
||||
void touch_wait_until_ready(void) {
|
||||
// wait for the touch controller to be ready
|
||||
while (hal_ticks_ms() - touch_init_ticks < 310) {
|
||||
HAL_Delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
secbool touch_sensitivity(uint8_t value) {
|
||||
// set panel threshold (TH_GROUP) - default value is 0x12
|
||||
uint8_t touch_panel_threshold[] = {0x80, value};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (HAL_OK == i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS,
|
||||
touch_panel_threshold,
|
||||
sizeof(touch_panel_threshold), 10)) {
|
||||
return sectrue;
|
||||
}
|
||||
i2c_cycle(TOUCH_I2C_INSTANCE);
|
||||
}
|
||||
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
uint32_t touch_is_detected(void) {
|
||||
// check the interrupt line coming in from the CTPM.
|
||||
// the line make a short pulse, which sets an interrupt flag when new data is
|
||||
// available.
|
||||
// Reference section 1.2 of "Application Note for FT6x06 CTPM". we
|
||||
// configure the touch controller to use "interrupt trigger mode".
|
||||
|
||||
// Checks if the touch controller has an interrupt pending
|
||||
// which indicates that new data is available.
|
||||
//
|
||||
// The function clears the interrupt flag if it was set so the
|
||||
// next call returns `false` if no new impulses were detected.
|
||||
static bool ft6x36_test_and_clear_interrupt(void) {
|
||||
uint32_t event = __HAL_GPIO_EXTI_GET_FLAG(TOUCH_INT_PIN);
|
||||
if (event != 0) {
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(TOUCH_INT_PIN);
|
||||
}
|
||||
|
||||
return event;
|
||||
return event != 0;
|
||||
}
|
||||
|
||||
uint32_t check_timeout(uint32_t prev, uint32_t timeout) {
|
||||
uint32_t current = hal_ticks_ms();
|
||||
uint32_t diff = current - prev;
|
||||
// Configures the touch controller to the funtional state.
|
||||
static secbool ft6x36_configure(void) {
|
||||
const static uint8_t config[] = {
|
||||
// Set touch controller to the interrupt trigger mode.
|
||||
// Basically, CTPM generates a pulse when new data is available.
|
||||
FT6X36_REG_G_MODE,
|
||||
0x01,
|
||||
FT6X36_REG_TH_GROUP,
|
||||
TOUCH_SENSITIVITY,
|
||||
};
|
||||
|
||||
if (diff >= timeout) {
|
||||
return 1;
|
||||
}
|
||||
_Static_assert(sizeof(config) % 2 == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < sizeof(config); i += 2) {
|
||||
uint8_t reg = config[i];
|
||||
uint8_t value = config[i + 1];
|
||||
|
||||
uint32_t touch_read(void) {
|
||||
static uint8_t touch_data[TOUCH_PACKET_SIZE],
|
||||
previous_touch_data[TOUCH_PACKET_SIZE];
|
||||
static uint32_t xy;
|
||||
static uint32_t last_check_time = 0;
|
||||
static uint32_t last_event_time = 0;
|
||||
static int touching = 0;
|
||||
|
||||
uint32_t detected = touch_is_detected();
|
||||
|
||||
if (detected == 0) {
|
||||
last_check_time = hal_ticks_ms();
|
||||
|
||||
if (touching && check_timeout(last_event_time, EVENT_MISSING_TIMEOUT_MS)) {
|
||||
// we didn't detect an event for a long time, but there was an active
|
||||
// touch: send END event, as we probably missed the END event
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
if (sectrue != ft6x36_write_reg(reg, value)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((touching == 0) &&
|
||||
(check_timeout(last_check_time, EVENT_OLD_TIMEOUT_MS))) {
|
||||
// we have detected an event, but it might be too old, rather drop it
|
||||
// (only dropping old events if there was no touch active)
|
||||
last_check_time = hal_ticks_ms();
|
||||
return 0;
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool touch_init(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue == driver->initialized) {
|
||||
// The driver is already initialized
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
last_check_time = hal_ticks_ms();
|
||||
// Initialize GPIO to the default configuration
|
||||
// (touch controller is powered down)
|
||||
ft6x36_power_down();
|
||||
|
||||
uint8_t outgoing[] = {0x00}; // start reading from address 0x00
|
||||
int result = i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, outgoing,
|
||||
sizeof(outgoing), 1);
|
||||
if (result != HAL_OK) {
|
||||
if (result == HAL_BUSY) i2c_cycle(TOUCH_I2C_INSTANCE);
|
||||
return 0;
|
||||
// Power up the touch controller and perform the reset sequence
|
||||
ft6x36_power_up();
|
||||
|
||||
// Configure the touch controller
|
||||
if (sectrue != ft6x36_configure()) {
|
||||
ft6x36_power_down();
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
if (HAL_OK != i2c_receive(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, touch_data,
|
||||
TOUCH_PACKET_SIZE, 1)) {
|
||||
return 0; // read failure
|
||||
driver->init_ticks = hal_ticks_ms();
|
||||
driver->poll_ticks = driver->init_ticks;
|
||||
driver->initialized = sectrue;
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
void touch_deinit(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue == driver->initialized) {
|
||||
// Do not need to deinitialized the controller
|
||||
// just power it off
|
||||
ft6x36_power_down();
|
||||
|
||||
memset(driver, 0, sizeof(touch_driver_t));
|
||||
}
|
||||
}
|
||||
|
||||
secbool touch_ready(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
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) {
|
||||
driver->ready = sectrue;
|
||||
}
|
||||
}
|
||||
|
||||
last_event_time = hal_ticks_ms();
|
||||
return driver->ready;
|
||||
}
|
||||
|
||||
if (0 == memcmp(previous_touch_data, touch_data, TOUCH_PACKET_SIZE)) {
|
||||
return 0; // same data, filter it out
|
||||
secbool touch_set_sensitivity(uint8_t value) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue == driver->initialized) {
|
||||
return ft6x36_write_reg(FT6X36_REG_TH_GROUP, value);
|
||||
} else {
|
||||
memcpy(previous_touch_data, touch_data, TOUCH_PACKET_SIZE);
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
const uint32_t number_of_touch_points =
|
||||
touch_data[2] & 0x0F; // valid values are 0, 1, 2 (invalid 0xF before
|
||||
// first touch) (tested with FT6206)
|
||||
const uint32_t event_flag = touch_data[3] & 0xC0;
|
||||
if (touch_data[1] == GESTURE_NO_GESTURE) {
|
||||
xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB,
|
||||
(Y_POS_MSB << 8) | Y_POS_LSB);
|
||||
if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) {
|
||||
touching = 1;
|
||||
return TOUCH_START | xy;
|
||||
} else if ((number_of_touch_points == 1) && (event_flag == EVENT_CONTACT)) {
|
||||
if (touching) {
|
||||
return TOUCH_MOVE | xy;
|
||||
} else {
|
||||
touching = 1;
|
||||
return TOUCH_START | xy;
|
||||
}
|
||||
} else if ((number_of_touch_points == 0) && (event_flag == EVENT_LIFT_UP)) {
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) {
|
||||
uint8_t version = 0;
|
||||
uint8_t outgoing[] = {0xA6}; // start reading from address 0xA6
|
||||
int result = i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, outgoing,
|
||||
sizeof(outgoing), 1);
|
||||
if (result != HAL_OK) {
|
||||
if (result == HAL_BUSY) i2c_cycle(TOUCH_I2C_INSTANCE);
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue != driver->initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (HAL_OK != i2c_receive(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, &version,
|
||||
sizeof(version), 1)) {
|
||||
return 0; // read failure
|
||||
// After powering up the touch controller, we need to wait
|
||||
// for an unspecified amount of time (~100ms) before attempting
|
||||
// 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);
|
||||
}
|
||||
|
||||
return version;
|
||||
uint8_t fw_version = 0;
|
||||
|
||||
if (sectrue != ft6x36_read_regs(FT6X36_REG_FIRMID, &fw_version, 1)) {
|
||||
ft6x36_power_down();
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
return fw_version;
|
||||
}
|
||||
|
||||
secbool touch_activity(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue == driver->initialized) {
|
||||
if (ft6x36_test_and_clear_interrupt()) {
|
||||
return sectrue;
|
||||
}
|
||||
}
|
||||
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
uint32_t touch_get_event(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (sectrue != driver->initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Content of registers 0x00 - 0x06 read from the touch controller
|
||||
uint8_t regs[7];
|
||||
|
||||
// Ensure the registers are within the bounds
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_GEST_ID);
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_TD_STATUS);
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_P1_XH);
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_P1_XL);
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_P1_YH);
|
||||
_Static_assert(sizeof(regs) > FT6X63_REG_P1_YL);
|
||||
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read the set of registers containing touch event and coordinates
|
||||
if (sectrue != ft6x36_read_regs(0x00, regs, sizeof(regs))) {
|
||||
// Failed to read the touch registers
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract gesture ID (FT6X63_GESTURE_xxx)
|
||||
uint8_t gesture = regs[FT6X63_REG_GEST_ID];
|
||||
|
||||
if (gesture != FT6X36_GESTURE_NONE) {
|
||||
// This is here for unknown historical reasons
|
||||
// It seems we can't get here with FT6X36
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract number of touches (0, 1, 2) or 0x0F before
|
||||
// the first touch (tested with FT6206)
|
||||
uint8_t nb_touches = regs[FT6X63_REG_TD_STATUS] & 0x0F;
|
||||
|
||||
// Extract event flags (one of press down, contact, lift up)
|
||||
uint8_t flags = regs[FT6X63_REG_P1_XH] & FT6X63_EVENT_MASK;
|
||||
|
||||
// Extract touch coordinates
|
||||
uint16_t x = ((regs[FT6X63_REG_P1_XH] & 0x0F) << 8) | regs[FT6X63_REG_P1_XL];
|
||||
uint16_t y = ((regs[FT6X63_REG_P1_YH] & 0x0F) << 8) | regs[FT6X63_REG_P1_YL];
|
||||
|
||||
uint32_t event = 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 {
|
||||
// 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 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;
|
||||
}
|
||||
}
|
||||
} else if ((nb_touches == 0) && (flags == FT6X63_EVENT_LIFT_UP)) {
|
||||
if (driver->pressed) {
|
||||
// Finger was just lifted up
|
||||
event = TOUCH_END | xy;
|
||||
} else {
|
||||
// 1. Most likely, we have missed the PRESS_DOWN event.
|
||||
// Touch duration was too short (< 20ms) to be worth reporting.
|
||||
// 2. Finger is still lifted up. Since we have already sent the
|
||||
// TOUCH_END event => no event 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)) {
|
||||
driver->pressed = true;
|
||||
} else if (event & TOUCH_END) {
|
||||
driver->pressed = false;
|
||||
}
|
||||
|
||||
driver->last_x = x;
|
||||
driver->last_y = y;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
@ -20,4 +20,57 @@
|
||||
#ifndef _TOUCH_FT6X36_H
|
||||
#define _TOUCH_FT6X36_H
|
||||
|
||||
// I2C address of the FT6X36 on the I2C bus.
|
||||
// `<< 1` is required because the HAL expects the address to be shifted by 1.
|
||||
#define FT6X36_I2C_ADDR (0x38 << 1)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// FT6X36 registers
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Gesture ID (see `FT6X36_GESTURE_xxx`)
|
||||
#define FT6X63_REG_GEST_ID 0x01
|
||||
|
||||
// TD_STATUS (number of touch points in lower 4 bits)
|
||||
#define FT6X63_REG_TD_STATUS 0x02
|
||||
|
||||
// Event flags in higher 2 bits (see `FT6X63_EVENT_xxx`)
|
||||
// MSB of touch x-coordinate in lower 4 bits
|
||||
#define FT6X63_REG_P1_XH 0x03
|
||||
|
||||
// LSB of touch x-coordinate
|
||||
#define FT6X63_REG_P1_XL 0x04
|
||||
|
||||
// MSB of touch y-coordinate in lower 4 bits
|
||||
#define FT6X63_REG_P1_YH 0x05
|
||||
|
||||
// LSB of touch y-coordinate
|
||||
#define FT6X63_REG_P1_YL 0x06
|
||||
|
||||
// Threshold for touch detection
|
||||
#define FT6X36_REG_TH_GROUP 0x80
|
||||
|
||||
// Mode register
|
||||
// 0x00 - interrupt polling mode
|
||||
// 0x01 - interrupt trigger mode
|
||||
#define FT6X36_REG_G_MODE 0xA4
|
||||
|
||||
// Firmware version
|
||||
#define FT6X36_REG_FIRMID 0xA6
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Event bits (see FT6X63_REG_P1_XH)
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#define FT6X63_EVENT_PRESS_DOWN 0x00
|
||||
#define FT6X63_EVENT_CONTACT 0x80
|
||||
#define FT6X63_EVENT_LIFT_UP 0x40
|
||||
#define FT6X63_EVENT_MASK 0xC0
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Gesture types (see FT6X63_REG_GEST_ID)
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#define FT6X36_GESTURE_NONE 0x00
|
||||
|
||||
#endif
|
||||
|
@ -320,26 +320,6 @@ uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer,
|
||||
*/
|
||||
void IOE_Delay(uint32_t Delay) { HAL_Delay(Delay); }
|
||||
|
||||
static void touch_active_pin_state(void) {
|
||||
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); // CTP_ON/PB10
|
||||
// HAL_Delay(10); // we need to wait until the circuit fully kicks-in
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_15);
|
||||
|
||||
// HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // release CTPM reset
|
||||
// HAL_Delay(310); // "Time of starting to report point after resetting" min
|
||||
// is
|
||||
// 300ms, giving an extra 10ms
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the AF for the selected IO pin(s).
|
||||
* @param DeviceAddr: Device address on communication Bus.
|
||||
@ -439,17 +419,6 @@ void touch_set_mode(void) {
|
||||
IOE_Delay(2);
|
||||
}
|
||||
|
||||
void touch_power_on(void) {
|
||||
// turn on CTP circuitry
|
||||
touch_active_pin_state();
|
||||
HAL_Delay(50);
|
||||
}
|
||||
|
||||
void touch_power_off(void) {
|
||||
// turn off CTP circuitry
|
||||
HAL_Delay(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the stmpe811 by Software.
|
||||
* @param DeviceAddr: Device address on communication Bus.
|
||||
@ -470,55 +439,7 @@ void stmpe811_Reset() {
|
||||
IOE_Delay(2);
|
||||
}
|
||||
|
||||
secbool touch_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
|
||||
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_15);
|
||||
|
||||
stmpe811_Reset();
|
||||
touch_set_mode();
|
||||
touch_sensitivity(0x06);
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool touch_sensitivity(uint8_t value) {
|
||||
// set panel threshold (TH_GROUP) - default value is 0x12
|
||||
// uint8_t touch_panel_threshold[] = {0x80, value};
|
||||
// ensure(sectrue *
|
||||
// (HAL_OK == HAL_I2C_Master_Transmit(
|
||||
// &I2c_handle, TOUCH_ADDRESS, touch_panel_threshold,
|
||||
// sizeof(touch_panel_threshold), 10)),
|
||||
// NULL);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
uint32_t touch_is_detected(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;
|
||||
}
|
||||
|
||||
uint32_t touch_active(void) {
|
||||
// check the interrupt line coming in from the CTPM.
|
||||
// the line make a short pulse, which sets an interrupt flag when new data is
|
||||
// available.
|
||||
// Reference section 1.2 of "Application Note for FT6x06 CTPM". we
|
||||
// configure the touch controller to use "interrupt trigger mode".
|
||||
|
||||
// uint32_t event = __HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_15);
|
||||
// if (event != 0) {
|
||||
// __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_15);
|
||||
// }
|
||||
|
||||
static uint32_t touch_active(void) {
|
||||
uint8_t state;
|
||||
uint8_t ret = 0;
|
||||
|
||||
@ -539,17 +460,6 @@ uint32_t touch_active(void) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t check_timeout(uint32_t prev, uint32_t timeout) {
|
||||
uint32_t current = hal_ticks_ms();
|
||||
uint32_t diff = current - prev;
|
||||
|
||||
if (diff >= timeout) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the touch screen X and Y positions values
|
||||
* @param DeviceAddr: Device address on communication Bus.
|
||||
@ -647,62 +557,87 @@ void BSP_TS_GetState(TS_StateTypeDef *TsState) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t touch_read(void) {
|
||||
TS_StateTypeDef state = {0};
|
||||
static uint32_t xy = 0;
|
||||
static TS_StateTypeDef state_last = {0};
|
||||
// static uint16_t first = 1;
|
||||
static uint16_t touching = 0;
|
||||
typedef struct {
|
||||
// Set if driver is initialized
|
||||
secbool initialized;
|
||||
// Last lower-level driver state
|
||||
TS_StateTypeDef prev_state;
|
||||
|
||||
if (!touch_is_detected()) {
|
||||
if (touching) {
|
||||
// touch end
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
}
|
||||
return 0;
|
||||
} 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) {
|
||||
stmpe811_Reset();
|
||||
touch_set_mode();
|
||||
|
||||
driver->initialized = sectrue;
|
||||
}
|
||||
|
||||
BSP_TS_GetState(&state);
|
||||
return driver->initialized;
|
||||
}
|
||||
|
||||
if (state.TouchDetected == 0) {
|
||||
return 0;
|
||||
void touch_deinit(void) {
|
||||
touch_driver_t *driver = &g_touch_driver;
|
||||
|
||||
if (driver->initialized == sectrue) {
|
||||
// Not implemented properly
|
||||
|
||||
memset(driver, 0, sizeof(touch_driver_t));
|
||||
}
|
||||
}
|
||||
|
||||
// if (first != 0) {
|
||||
// memcpy(&state_last, &state, sizeof(state));
|
||||
// first = 0;
|
||||
// return 0;
|
||||
// }
|
||||
secbool touch_ready(void) {
|
||||
touch_driver_t *driver = &g_touch_driver;
|
||||
return driver->initialized;
|
||||
}
|
||||
|
||||
if ((state.TouchDetected == 0 && state_last.TouchDetected == 0) ||
|
||||
memcmp(&state, &state_last, sizeof(state)) == 0) {
|
||||
// no change detected
|
||||
return 0;
|
||||
}
|
||||
|
||||
xy = touch_pack_xy(state.X, state.Y);
|
||||
|
||||
if (state.TouchDetected && !state_last.TouchDetected) {
|
||||
// touch start
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 1;
|
||||
return TOUCH_START | xy;
|
||||
} else if (!state.TouchDetected && state_last.TouchDetected) {
|
||||
// touch end
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
} else {
|
||||
// touch move
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
return TOUCH_MOVE | xy;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void touch_wait_until_ready(void) {}
|
||||
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;
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) { return 0; }
|
||||
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) {
|
||||
uint32_t xy = touch_pack_xy(new_state.X, new_state.Y);
|
||||
event = TOUCH_MOVE | xy;
|
||||
}
|
||||
|
||||
driver->prev_state = new_state;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
@ -360,7 +360,6 @@ int32_t SITRONIX_GetState(SITRONIX_Object_t *pObj, SITRONIX_State_t *State) {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the touch screen Xn and Yn positions values in multi-touch mode
|
||||
* @param pObj Component object pointer
|
||||
@ -1135,86 +1134,100 @@ static int32_t SITRONIX_Probe(uint32_t Instance) {
|
||||
#include <string.h>
|
||||
#include "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) {
|
||||
TS_Init_t TsInit;
|
||||
touch_driver_t *driver = &g_touch_driver;
|
||||
|
||||
/* Initialize the TouchScreen */
|
||||
TsInit.Width = 480;
|
||||
TsInit.Height = 480;
|
||||
TsInit.Orientation = 0;
|
||||
TsInit.Accuracy = 10;
|
||||
if (sectrue != driver->initialized) {
|
||||
TS_Init_t TsInit;
|
||||
|
||||
BSP_TS_Init(0, &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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void touch_power_on(void) {}
|
||||
void touch_power_off(void) {}
|
||||
secbool touch_sensitivity(uint8_t value) { return sectrue; }
|
||||
|
||||
uint32_t touch_is_detected(void) { return sitronix_touching != 0; }
|
||||
|
||||
uint32_t touch_read(void) {
|
||||
TS_State_t state = {0};
|
||||
static uint32_t xy = 0;
|
||||
static TS_State_t state_last = {0};
|
||||
// static uint16_t first = 1;
|
||||
static uint16_t touching = 0;
|
||||
|
||||
BSP_TS_GetState(0, &state);
|
||||
|
||||
state.TouchDetected = touch_is_detected();
|
||||
state.TouchY = state.TouchY > 120 ? state.TouchY - 120 : 0;
|
||||
state.TouchX = state.TouchX > 120 ? state.TouchX - 120 : 0;
|
||||
|
||||
if (!touch_is_detected()) {
|
||||
// if (state.TouchDetected == 0) {
|
||||
if (touching) {
|
||||
// touch end
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state.TouchDetected == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if (first != 0) {
|
||||
// memcpy(&state_last, &state, sizeof(state));
|
||||
// first = 0;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
if ((state.TouchDetected == 0 && state_last.TouchDetected == 0) ||
|
||||
memcmp(&state, &state_last, sizeof(state)) == 0) {
|
||||
// no change detected
|
||||
return 0;
|
||||
}
|
||||
|
||||
xy = touch_pack_xy(state.TouchX, state.TouchY);
|
||||
|
||||
if (state.TouchDetected && !state_last.TouchDetected) {
|
||||
// touch start
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 1;
|
||||
return TOUCH_START | xy;
|
||||
} else if (!state.TouchDetected && state_last.TouchDetected) {
|
||||
// touch end
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
touching = 0;
|
||||
return TOUCH_END | xy;
|
||||
} else {
|
||||
// touch move
|
||||
memcpy(&state_last, &state, sizeof(state));
|
||||
return TOUCH_MOVE | xy;
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) {
|
||||
// Not implemented for the discovery kit
|
||||
return 0;
|
||||
}
|
||||
|
||||
void touch_wait_until_ready(void) {}
|
||||
secbool touch_activity(void) {
|
||||
if (sitronix_touching) {
|
||||
return sectrue;
|
||||
} else {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) { return 0; }
|
||||
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.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) {
|
||||
uint32_t xy = touch_pack_xy(new_state.TouchX, new_state.TouchY);
|
||||
event = TOUCH_MOVE | xy;
|
||||
}
|
||||
|
||||
driver->prev_state = new_state;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
@ -1,32 +1,90 @@
|
||||
#ifndef _TOUCH_H
|
||||
#define _TOUCH_H
|
||||
#ifndef TREZOR_HAL_TOUCH_H
|
||||
#define TREZOR_HAL_TOUCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
// Initializes the touch driver
|
||||
//
|
||||
// Powers on and initializes touch driver controller.
|
||||
// The function has no effect if the driver was already initialized.
|
||||
//
|
||||
// Returns `sectrue` if the hardware was successfuly initialized.
|
||||
secbool touch_init(void);
|
||||
|
||||
// Deinitializes the touch driver
|
||||
//
|
||||
// The function deinitializes touch controller and powers it off.
|
||||
void touch_deinit();
|
||||
|
||||
// Checks if the touch driver is ready to report touches
|
||||
//
|
||||
// Some drivers need time after power-up to stabilize. The app
|
||||
// may use this function to wait until touch controller is
|
||||
// fully functional.
|
||||
secbool touch_ready(void);
|
||||
|
||||
// Gets the touch controller firmware version
|
||||
//
|
||||
// Can be called only if the touch controller was initialized,
|
||||
// othervise returns 0.
|
||||
//
|
||||
// We do not interpret the value of the version, we just print it
|
||||
// during the production test.
|
||||
uint8_t touch_get_version(void);
|
||||
|
||||
// Sets touch controller sensitivity
|
||||
//
|
||||
// (Internally threadhsold for ????)
|
||||
secbool touch_set_sensitivity(uint8_t value);
|
||||
|
||||
// Checks if the touch is currently reporting any events
|
||||
//
|
||||
// The purpose of this function is very special. It is used
|
||||
// in bootloader startup to detect if the user is touching the screen.
|
||||
// On some hardware it's a bit more sensitive then `touch_get_event()`
|
||||
// since it does not filter out any events.
|
||||
//
|
||||
// The function should not be used together with `touch_get_event()`.
|
||||
secbool touch_activity(void);
|
||||
|
||||
// Returns the last event in packed 32-bit format
|
||||
//
|
||||
// Returns `0` if there's no event or the driver is not initialized.
|
||||
uint32_t touch_get_event(void);
|
||||
|
||||
// Touch event is packed 32-bit value
|
||||
//
|
||||
// 31 24 23 12 11 0
|
||||
// |--------|------------|------------|
|
||||
// | event | x-coord | y-coord |
|
||||
// |--------|------------|------------|
|
||||
//
|
||||
//
|
||||
|
||||
// Touch event bits
|
||||
#define TOUCH_START (1U << 24)
|
||||
#define TOUCH_MOVE (1U << 25)
|
||||
#define TOUCH_END (1U << 26)
|
||||
|
||||
secbool touch_init(void);
|
||||
void touch_power_on(void);
|
||||
void touch_power_off(void);
|
||||
void touch_wait_until_ready(void);
|
||||
|
||||
secbool touch_sensitivity(uint8_t value);
|
||||
uint32_t touch_read(void);
|
||||
uint32_t touch_click(void);
|
||||
uint32_t touch_is_detected(void);
|
||||
uint8_t touch_get_version(void);
|
||||
|
||||
// Returns x-coordinates from a packed touch event
|
||||
static inline uint16_t touch_unpack_x(uint32_t evt) {
|
||||
return (evt >> 12) & 0xFFF;
|
||||
}
|
||||
|
||||
// Returns y-coordinates from a packed touch event
|
||||
static inline uint16_t touch_unpack_y(uint32_t evt) {
|
||||
return (evt >> 0) & 0xFFF;
|
||||
}
|
||||
|
||||
// Creates packed touch event from x and y coordinates
|
||||
static inline uint32_t touch_pack_xy(uint16_t x, uint16_t y) {
|
||||
return ((x & 0xFFF) << 12) | (y & 0xFFF);
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// legacy:
|
||||
|
||||
uint32_t touch_is_detected(void);
|
||||
|
||||
#endif //_TOUCH_H
|
||||
|
70
core/embed/trezorhal/unix/button.c
Normal file
70
core/embed/trezorhal/unix/button.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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_BOARD
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "button.h"
|
||||
#include "common.h"
|
||||
#include "platform.h"
|
||||
|
||||
static char last_left = 0, last_right = 0;
|
||||
|
||||
char button_state_left(void) { return last_left; }
|
||||
|
||||
char button_state_right(void) { return last_right; }
|
||||
|
||||
uint32_t button_read(void) {
|
||||
SDL_Event event;
|
||||
SDL_PumpEvents();
|
||||
if (SDL_PollEvent(&event) > 0) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.repeat) {
|
||||
break;
|
||||
}
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
last_left = 1;
|
||||
return BTN_EVT_DOWN | BTN_LEFT;
|
||||
case SDLK_RIGHT:
|
||||
last_right = 1;
|
||||
return BTN_EVT_DOWN | BTN_RIGHT;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
if (event.key.repeat) {
|
||||
break;
|
||||
}
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
last_left = 0;
|
||||
return BTN_EVT_UP | BTN_LEFT;
|
||||
case SDLK_RIGHT:
|
||||
last_right = 0;
|
||||
return BTN_EVT_UP | BTN_RIGHT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void button_init(void) {}
|
@ -17,13 +17,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#ifdef USE_TOUCH
|
||||
|
||||
#include "common.h"
|
||||
#include "platform.h"
|
||||
#include "touch.h"
|
||||
@ -31,9 +30,6 @@
|
||||
extern int sdl_display_res_x, sdl_display_res_y;
|
||||
extern int sdl_touch_offset_x, sdl_touch_offset_y;
|
||||
|
||||
static int _touch_x = 0;
|
||||
static int _touch_y = 0;
|
||||
|
||||
// distance from the edge where arrow button swipe starts [px]
|
||||
static const int _btn_swipe_begin = 120;
|
||||
// length of the arrow button swipe [px]
|
||||
@ -53,9 +49,23 @@ typedef enum {
|
||||
BUTTON_SWIPE_UP_INITIATED,
|
||||
BUTTON_SWIPE_DOWN_INITIATED,
|
||||
BUTTON_SWIPE_COMPLETED
|
||||
} touch_input_state_t;
|
||||
} touch_state_t;
|
||||
|
||||
static touch_input_state_t input_state = IDLE;
|
||||
typedef struct {
|
||||
// Set if driver is initialized
|
||||
secbool initialized;
|
||||
// Current state of the touch driver
|
||||
touch_state_t state;
|
||||
// Last valid coordinates
|
||||
int last_x;
|
||||
int last_y;
|
||||
|
||||
} touch_driver_t;
|
||||
|
||||
// Touch driver instance
|
||||
static touch_driver_t g_touch_driver = {
|
||||
.initialized = secfalse,
|
||||
};
|
||||
|
||||
static bool is_inside_display(int x, int y) {
|
||||
return x >= sdl_touch_offset_x && y >= sdl_touch_offset_y &&
|
||||
@ -63,15 +73,15 @@ static bool is_inside_display(int x, int y) {
|
||||
y - sdl_touch_offset_y < sdl_display_res_y;
|
||||
}
|
||||
|
||||
static bool is_button_swipe_initiated() {
|
||||
return input_state == BUTTON_SWIPE_LEFT_INITIATED ||
|
||||
input_state == BUTTON_SWIPE_RIGHT_INITIATED ||
|
||||
input_state == BUTTON_SWIPE_UP_INITIATED ||
|
||||
input_state == BUTTON_SWIPE_DOWN_INITIATED;
|
||||
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(SDL_Event event, int* ev_type, int* ev_x,
|
||||
int* ev_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) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
@ -79,116 +89,167 @@ static void handle_mouse_events(SDL_Event event, int* ev_type, int* ev_x,
|
||||
*ev_x = event.button.x - sdl_touch_offset_x;
|
||||
*ev_y = event.button.y - sdl_touch_offset_y;
|
||||
*ev_type = TOUCH_START;
|
||||
input_state = MOUSE_DOWN_INSIDE;
|
||||
driver->state = MOUSE_DOWN_INSIDE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (input_state != IDLE) {
|
||||
*ev_x = inside_display ? event.button.x - sdl_touch_offset_x : _touch_x;
|
||||
*ev_y = inside_display ? event.button.y - sdl_touch_offset_y : _touch_y;
|
||||
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;
|
||||
input_state = IDLE;
|
||||
driver->state = IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
if (input_state != IDLE) {
|
||||
if (driver->state != IDLE) {
|
||||
if (inside_display) {
|
||||
*ev_x = event.motion.x - sdl_touch_offset_x;
|
||||
*ev_y = event.motion.y - sdl_touch_offset_y;
|
||||
// simulate TOUCH_START if pressed in mouse returned on visible area
|
||||
*ev_type =
|
||||
(input_state == MOUSE_DOWN_OUTSIDE) ? TOUCH_START : TOUCH_MOVE;
|
||||
input_state = MOUSE_DOWN_INSIDE;
|
||||
(driver->state == MOUSE_DOWN_OUTSIDE) ? TOUCH_START : TOUCH_MOVE;
|
||||
driver->state = MOUSE_DOWN_INSIDE;
|
||||
} else {
|
||||
if (input_state == MOUSE_DOWN_INSIDE) {
|
||||
if (driver->state == MOUSE_DOWN_INSIDE) {
|
||||
// use last valid coordinates and simulate TOUCH_END
|
||||
*ev_x = _touch_x;
|
||||
*ev_y = _touch_y;
|
||||
*ev_x = driver->last_x;
|
||||
*ev_y = driver->last_y;
|
||||
*ev_type = TOUCH_END;
|
||||
}
|
||||
input_state = MOUSE_DOWN_OUTSIDE;
|
||||
driver->state = MOUSE_DOWN_OUTSIDE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_button_events(SDL_Event event, int* ev_type, int* ev_x,
|
||||
int* ev_y) {
|
||||
static void handle_button_events(touch_driver_t* driver, SDL_Event event,
|
||||
int* ev_type, int* ev_x, int* ev_y) {
|
||||
// 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()) {
|
||||
!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;
|
||||
input_state = BUTTON_SWIPE_LEFT_INITIATED;
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_RIGHT_INITIATED;
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_UP_INITIATED;
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_DOWN_INITIATED;
|
||||
driver->state = BUTTON_SWIPE_DOWN_INITIATED;
|
||||
break;
|
||||
}
|
||||
} else if (event.type == SDL_KEYUP && input_state != IDLE) {
|
||||
} else if (event.type == SDL_KEYUP && driver->state != IDLE) {
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
if (input_state == BUTTON_SWIPE_LEFT_INITIATED) {
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_COMPLETED;
|
||||
driver->state = BUTTON_SWIPE_COMPLETED;
|
||||
}
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if (input_state == BUTTON_SWIPE_RIGHT_INITIATED) {
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_COMPLETED;
|
||||
driver->state = BUTTON_SWIPE_COMPLETED;
|
||||
}
|
||||
break;
|
||||
case SDLK_UP:
|
||||
if (input_state == BUTTON_SWIPE_UP_INITIATED) {
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_COMPLETED;
|
||||
driver->state = BUTTON_SWIPE_COMPLETED;
|
||||
}
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
if (input_state == BUTTON_SWIPE_DOWN_INITIATED) {
|
||||
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;
|
||||
input_state = BUTTON_SWIPE_COMPLETED;
|
||||
driver->state = BUTTON_SWIPE_COMPLETED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t touch_read(void) {
|
||||
if (input_state == BUTTON_SWIPE_COMPLETED) {
|
||||
input_state = IDLE;
|
||||
return TOUCH_END | touch_pack_xy(_touch_x, _touch_y);
|
||||
secbool touch_init(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (driver->initialized != sectrue) {
|
||||
memset(driver, 0, sizeof(touch_driver_t));
|
||||
driver->state = IDLE;
|
||||
driver->initialized = sectrue;
|
||||
}
|
||||
|
||||
return driver->initialized;
|
||||
}
|
||||
|
||||
void touch_deinit(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (driver->initialized == sectrue) {
|
||||
memset(driver, 0, sizeof(touch_driver_t));
|
||||
}
|
||||
}
|
||||
|
||||
secbool touch_ready(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
return driver->initialized;
|
||||
}
|
||||
|
||||
secbool touch_set_sensitivity(uint8_t value) {
|
||||
// Not implemented on the emulator
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) {
|
||||
// Not implemented on the emulator
|
||||
return 0;
|
||||
}
|
||||
|
||||
secbool touch_activity(void) {
|
||||
if (touch_get_event() != 0) {
|
||||
return sectrue;
|
||||
} else {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t touch_get_event(void) {
|
||||
touch_driver_t* driver = &g_touch_driver;
|
||||
|
||||
if (driver->initialized != sectrue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (driver->state == BUTTON_SWIPE_COMPLETED) {
|
||||
driver->state = IDLE;
|
||||
return TOUCH_END | touch_pack_xy(driver->last_x, driver->last_y);
|
||||
}
|
||||
|
||||
emulator_poll_events();
|
||||
@ -200,80 +261,18 @@ uint32_t touch_read(void) {
|
||||
int ev_type = 0;
|
||||
|
||||
while (SDL_PollEvent(&event) > 0) {
|
||||
if (input_state == IDLE || input_state == MOUSE_DOWN_INSIDE ||
|
||||
input_state == MOUSE_DOWN_OUTSIDE) {
|
||||
handle_mouse_events(event, &ev_type, &ev_x, &ev_y);
|
||||
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 (input_state == IDLE || is_button_swipe_initiated()) {
|
||||
handle_button_events(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) {
|
||||
_touch_x = ev_x;
|
||||
_touch_y = ev_y;
|
||||
driver->last_x = ev_x;
|
||||
driver->last_y = ev_y;
|
||||
}
|
||||
}
|
||||
return ev_type | touch_pack_xy(ev_x, ev_y);
|
||||
}
|
||||
|
||||
secbool touch_init(void) { return sectrue; }
|
||||
void touch_power_on(void) {}
|
||||
void touch_wait_until_ready(void) {}
|
||||
|
||||
uint32_t touch_is_detected(void) {
|
||||
return input_state == MOUSE_DOWN_INSIDE || is_button_swipe_initiated();
|
||||
}
|
||||
|
||||
uint8_t touch_get_version(void) { return 0; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
|
||||
#include "button.h"
|
||||
|
||||
static char last_left = 0, last_right = 0;
|
||||
|
||||
char button_state_left(void) { return last_left; }
|
||||
|
||||
char button_state_right(void) { return last_right; }
|
||||
|
||||
uint32_t button_read(void) {
|
||||
SDL_Event event;
|
||||
SDL_PumpEvents();
|
||||
if (SDL_PollEvent(&event) > 0) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.repeat) {
|
||||
break;
|
||||
}
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
last_left = 1;
|
||||
return BTN_EVT_DOWN | BTN_LEFT;
|
||||
case SDLK_RIGHT:
|
||||
last_right = 1;
|
||||
return BTN_EVT_DOWN | BTN_RIGHT;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
if (event.key.repeat) {
|
||||
break;
|
||||
}
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_LEFT:
|
||||
last_left = 0;
|
||||
return BTN_EVT_UP | BTN_LEFT;
|
||||
case SDLK_RIGHT:
|
||||
last_right = 0;
|
||||
return BTN_EVT_UP | BTN_RIGHT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void button_init(void) {}
|
||||
|
||||
#endif
|
@ -53,6 +53,7 @@
|
||||
#include "py/repl.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "touch.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@ -474,6 +475,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
|
||||
display_init();
|
||||
|
||||
#if USE_TOUCH
|
||||
touch_init();
|
||||
#endif
|
||||
|
||||
// Map trezor.flash to memory.
|
||||
flash_init();
|
||||
flash_otp_init();
|
||||
|
@ -71,7 +71,6 @@ def configure(
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/stm32f4/i2c.c"]
|
||||
sources += ["embed/trezorhal/stm32f4/touch/stmpe811.c"]
|
||||
sources += ["embed/lib/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
if "usb" in features_wanted:
|
||||
|
@ -60,9 +60,6 @@ def configure(
|
||||
sources += [
|
||||
"embed/trezorhal/stm32u5/i2c.c",
|
||||
]
|
||||
sources += [
|
||||
"embed/lib/touch.c",
|
||||
]
|
||||
sources += [
|
||||
"embed/trezorhal/stm32u5/touch/sitronix.c",
|
||||
]
|
||||
|
@ -31,6 +31,7 @@ def configure(
|
||||
defines += ["FLASH_BLOCK_WORDS=1"]
|
||||
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/unix/button.c"]
|
||||
features_available.append("button")
|
||||
|
||||
sources += ["embed/models/T1B1/model_T1B1_layout.c"]
|
||||
|
@ -41,6 +41,7 @@ def configure(
|
||||
features_available.append("optiga")
|
||||
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/unix/button.c"]
|
||||
features_available.append("button")
|
||||
|
||||
sources += ["embed/models/T2B1/model_T2B1_layout.c"]
|
||||
|
@ -51,6 +51,7 @@ def configure(
|
||||
sources += ["embed/trezorhal/unix/sbu.c"]
|
||||
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/unix/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
features_available.append("backlight")
|
||||
|
@ -82,7 +82,6 @@ def configure(
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/stm32f4/i2c.c"]
|
||||
sources += ["embed/trezorhal/stm32f4/touch/ft6x36.c"]
|
||||
sources += ["embed/lib/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
if "sd_card" in features_wanted:
|
||||
|
@ -59,6 +59,7 @@ def configure(
|
||||
sources += ["embed/trezorhal/unix/optiga.c"]
|
||||
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/unix/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
features_available.append("backlight")
|
||||
|
@ -73,7 +73,6 @@ def configure(
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/stm32u5/i2c.c"]
|
||||
sources += ["embed/trezorhal/stm32u5/touch/ft6x36.c"]
|
||||
sources += ["embed/lib/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
if "haptic" in features_wanted:
|
||||
|
@ -75,7 +75,6 @@ def configure(
|
||||
if "input" in features_wanted:
|
||||
sources += ["embed/trezorhal/stm32u5/i2c.c"]
|
||||
sources += ["embed/trezorhal/stm32u5/touch/ft6x36.c"]
|
||||
sources += ["embed/lib/touch.c"]
|
||||
features_available.append("touch")
|
||||
|
||||
if "haptic" in features_wanted:
|
||||
|
Loading…
Reference in New Issue
Block a user