1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-06-27 02:12:35 +00:00

refactor(core): unify touch and button handling, enable usage of both in one model

[no changelog]
This commit is contained in:
tychovrahe 2023-04-25 22:44:59 +02:00
parent 7b442a2b20
commit f6572a84d3
13 changed files with 84 additions and 67 deletions

View File

@ -25,8 +25,9 @@
#include "embed/extmod/trezorobj.h" #include "embed/extmod/trezorobj.h"
#define USB_DATA_IFACE (253) #define USB_DATA_IFACE (253)
#define BUTTON_IFACE (254) #define INPUT_IFACE (255)
#define TOUCH_IFACE (255) #define TOUCH_INPUT_FLAG (0x40000000)
#define BUTTON_INPUT_FLAG (0x80000000)
#define POLL_READ (0x0000) #define POLL_READ (0x0000)
#define POLL_WRITE (0x0100) #define POLL_WRITE (0x0100)
@ -81,17 +82,36 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
#endif #endif
if (false) { if (false) {
} } else if (iface == INPUT_IFACE) {
#if defined USE_TOUCH uint32_t evt;
else if (iface == TOUCH_IFACE) { #ifdef USE_BUTTON
const uint32_t evt = touch_read(); evt = button_read();
if (evt & (BTN_EVT_DOWN | BTN_EVT_UP)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
uint32_t etype =
((evt >> 24) & 0x3U) | BUTTON_INPUT_FLAG; // button down/up
uint32_t en = evt & 0xFFFF; // button number
if (display_orientation(-1) == 180) {
en = (en == BTN_LEFT) ? BTN_RIGHT : BTN_LEFT;
}
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(en);
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = MP_OBJ_FROM_PTR(tuple);
return mp_const_true;
}
#endif
#ifdef USE_TOUCH
evt = touch_read();
if (evt) { if (evt) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
const uint32_t etype = (evt >> 24) & 0xFFU; // event type const uint32_t etype =
const uint32_t ex = (evt >> 12) & 0xFFFU; // x position ((evt >> 24) & 0xFFU) | TOUCH_INPUT_FLAG; // event type
const uint32_t ey = evt & 0xFFFU; // y position const uint32_t ex = (evt >> 12) & 0xFFFU; // x position
uint32_t exr; // rotated x position const uint32_t ey = evt & 0xFFFU; // y position
uint32_t eyr; // rotated y position uint32_t exr; // rotated x position
uint32_t eyr; // rotated y position
switch (display_orientation(-1)) { switch (display_orientation(-1)) {
case 90: case 90:
exr = ey; exr = ey;
@ -117,6 +137,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
ret->items[1] = MP_OBJ_FROM_PTR(tuple); ret->items[1] = MP_OBJ_FROM_PTR(tuple);
return mp_const_true; return mp_const_true;
} }
#endif
} else if (iface == USB_DATA_IFACE) { } else if (iface == USB_DATA_IFACE) {
bool usb_connected = usb_configured() == sectrue ? true : false; bool usb_connected = usb_configured() == sectrue ? true : false;
if (usb_connected != usb_connected_previously) { if (usb_connected != usb_connected_previously) {
@ -125,27 +146,7 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
ret->items[1] = usb_connected ? mp_const_true : mp_const_false; ret->items[1] = usb_connected ? mp_const_true : mp_const_false;
return mp_const_true; return mp_const_true;
} }
} } else if (mode == POLL_READ) {
#endif
#if USE_BUTTON
else if (iface == BUTTON_IFACE) {
const uint32_t evt = button_read();
if (evt & (BTN_EVT_DOWN | BTN_EVT_UP)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
uint32_t etype = (evt >> 24) & 0x3U; // button down/up
uint32_t en = evt & 0xFFFF; // button number
if (display_orientation(-1) == 180) {
en = (en == BTN_LEFT) ? BTN_RIGHT : BTN_LEFT;
}
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(en);
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = MP_OBJ_FROM_PTR(tuple);
return mp_const_true;
}
}
#endif
else if (mode == POLL_READ) {
if (sectrue == usb_hid_can_read(iface)) { if (sectrue == usb_hid_can_read(iface)) {
uint8_t buf[64] = {0}; uint8_t buf[64] = {0};
int len = usb_hid_read(iface, buf, sizeof(buf)); int len = usb_hid_read(iface, buf, sizeof(buf));

View File

@ -62,12 +62,12 @@ bool usb_connected_previously = true;
/// POLL_READ: int # wait until interface is readable and return read data /// POLL_READ: int # wait until interface is readable and return read data
/// POLL_WRITE: int # wait until interface is writable /// POLL_WRITE: int # wait until interface is writable
/// ///
/// TOUCH: int # interface id of the touch events /// INPUT: int # interface id of unified input events
///
/// TOUCH_START: int # event id of touch start event /// TOUCH_START: int # event id of touch start event
/// TOUCH_MOVE: int # event id of touch move event /// TOUCH_MOVE: int # event id of touch move event
/// TOUCH_END: int # event id of touch end event /// TOUCH_END: int # event id of touch end event
/// BUTTON: int # interface id of button events
/// BUTTON_PRESSED: int # button down event /// BUTTON_PRESSED: int # button down event
/// BUTTON_RELEASED: int # button up event /// BUTTON_RELEASED: int # button up event
/// BUTTON_LEFT: int # button number of left button /// BUTTON_LEFT: int # button number of left button
@ -88,19 +88,20 @@ STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_fatfs), MP_ROM_PTR(&mod_trezorio_fatfs_module)}, {MP_ROM_QSTR(MP_QSTR_fatfs), MP_ROM_PTR(&mod_trezorio_fatfs_module)},
{MP_ROM_QSTR(MP_QSTR_sdcard), MP_ROM_PTR(&mod_trezorio_sdcard_module)}, {MP_ROM_QSTR(MP_QSTR_sdcard), MP_ROM_PTR(&mod_trezorio_sdcard_module)},
#endif #endif
{MP_ROM_QSTR(MP_QSTR_INPUT), MP_ROM_INT(INPUT_IFACE)},
#ifdef USE_TOUCH #ifdef USE_TOUCH
{MP_ROM_QSTR(MP_QSTR_TOUCH), MP_ROM_INT(TOUCH_IFACE)}, {MP_ROM_QSTR(MP_QSTR_TOUCH_START),
{MP_ROM_QSTR(MP_QSTR_TOUCH_START), MP_ROM_INT((TOUCH_START >> 24) & 0xFFU)}, MP_ROM_INT(((TOUCH_START >> 24) & 0xFFU) | TOUCH_INPUT_FLAG)},
{MP_ROM_QSTR(MP_QSTR_TOUCH_MOVE), MP_ROM_INT((TOUCH_MOVE >> 24) & 0xFFU)}, {MP_ROM_QSTR(MP_QSTR_TOUCH_MOVE),
{MP_ROM_QSTR(MP_QSTR_TOUCH_END), MP_ROM_INT((TOUCH_END >> 24) & 0xFFU)}, MP_ROM_INT(((TOUCH_MOVE >> 24) & 0xFFU) | TOUCH_INPUT_FLAG)},
{MP_ROM_QSTR(MP_QSTR_TOUCH_END),
MP_ROM_INT(((TOUCH_END >> 24) & 0xFFU) | TOUCH_INPUT_FLAG)},
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
{MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_INT(BUTTON_IFACE)},
{MP_ROM_QSTR(MP_QSTR_BUTTON_PRESSED), {MP_ROM_QSTR(MP_QSTR_BUTTON_PRESSED),
MP_ROM_INT((BTN_EVT_DOWN >> 24) & 0x3U)}, MP_ROM_INT(((BTN_EVT_DOWN >> 24) & 0x3U) | BUTTON_INPUT_FLAG)},
{MP_ROM_QSTR(MP_QSTR_BUTTON_RELEASED), {MP_ROM_QSTR(MP_QSTR_BUTTON_RELEASED),
MP_ROM_INT((BTN_EVT_UP >> 24) & 0x3U)}, MP_ROM_INT(((BTN_EVT_UP >> 24) & 0x3U) | BUTTON_INPUT_FLAG)},
{MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_INT(BTN_LEFT)}, {MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_INT(BTN_LEFT)},
{MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_INT(BTN_RIGHT)}, {MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_INT(BTN_RIGHT)},
#endif #endif

View File

@ -384,6 +384,8 @@ STATIC mp_obj_str_t mod_trezorutils_full_name_obj = {
/// """Whether the hardware supports backlight brightness control.""" /// """Whether the hardware supports backlight brightness control."""
/// USE_OPTIGA: bool /// USE_OPTIGA: bool
/// """Whether the hardware supports Optiga secure element.""" /// """Whether the hardware supports Optiga secure element."""
/// USE_TOUCH: bool
/// USE_BUTTON: bool
/// MODEL: str /// MODEL: str
/// """Model name.""" /// """Model name."""
/// MODEL_FULL_NAME: str /// MODEL_FULL_NAME: str
@ -427,6 +429,16 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else #else
{MP_ROM_QSTR(MP_QSTR_USE_SD_CARD), mp_const_false}, {MP_ROM_QSTR(MP_QSTR_USE_SD_CARD), mp_const_false},
#endif #endif
#ifdef USE_TOUCH
{MP_ROM_QSTR(MP_QSTR_USE_TOUCH), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_USE_TOUCH), mp_const_false},
#endif
#ifdef USE_BUTTON
{MP_ROM_QSTR(MP_QSTR_USE_BUTTON), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_USE_BUTTON), mp_const_false},
#endif
#ifdef USE_BACKLIGHT #ifdef USE_BACKLIGHT
{MP_ROM_QSTR(MP_QSTR_USE_BACKLIGHT), mp_const_true}, {MP_ROM_QSTR(MP_QSTR_USE_BACKLIGHT), mp_const_true},
#else #else

View File

@ -26,7 +26,7 @@ impl ButtonEvent {
1 => PhysicalButton::Right, 1 => PhysicalButton::Right,
_ => return Err(error::Error::OutOfRange), _ => return Err(error::Error::OutOfRange),
}; };
let result = match event { let result = match event & 0xFF {
1 => Self::ButtonPressed(button), 1 => Self::ButtonPressed(button),
2 => Self::ButtonReleased(button), 2 => Self::ButtonReleased(button),
_ => return Err(error::Error::OutOfRange), _ => return Err(error::Error::OutOfRange),
@ -50,7 +50,7 @@ pub enum TouchEvent {
impl TouchEvent { impl TouchEvent {
pub fn new(event: u32, x: u32, y: u32) -> Result<Self, error::Error> { pub fn new(event: u32, x: u32, y: u32) -> Result<Self, error::Error> {
let point = Point::new(x.try_into()?, y.try_into()?); let point = Point::new(x.try_into()?, y.try_into()?);
let result = match event { let result = match event & 0xFF {
1 => Self::TouchStart(point), 1 => Self::TouchStart(point),
2 => Self::TouchMove(point), 2 => Self::TouchMove(point),
4 => Self::TouchEnd(point), 4 => Self::TouchEnd(point),

View File

@ -21,10 +21,4 @@
#include "display-unix.h" #include "display-unix.h"
#ifdef TREZOR_MODEL_R
#define USE_BUTTON 1
#elif TREZOR_MODEL_T
#define USE_TOUCH 1
#endif
#endif //_BOARD_UNIX_H #endif //_BOARD_UNIX_H

View File

@ -193,11 +193,10 @@ class WebUSB:
from . import fatfs, sdcard from . import fatfs, sdcard
POLL_READ: int # wait until interface is readable and return read data POLL_READ: int # wait until interface is readable and return read data
POLL_WRITE: int # wait until interface is writable POLL_WRITE: int # wait until interface is writable
TOUCH: int # interface id of the touch events INPUT: int # interface id of unified input events
TOUCH_START: int # event id of touch start event TOUCH_START: int # event id of touch start event
TOUCH_MOVE: int # event id of touch move event TOUCH_MOVE: int # event id of touch move event
TOUCH_END: int # event id of touch end event TOUCH_END: int # event id of touch end event
BUTTON: int # interface id of button events
BUTTON_PRESSED: int # button down event BUTTON_PRESSED: int # button down event
BUTTON_RELEASED: int # button up event BUTTON_RELEASED: int # button up event
BUTTON_LEFT: int # button number of left button BUTTON_LEFT: int # button number of left button

View File

@ -114,6 +114,8 @@ VERSION_PATCH: int
"""Patch version.""" """Patch version."""
USE_SD_CARD: bool USE_SD_CARD: bool
"""Whether the hardware supports SD card.""" """Whether the hardware supports SD card."""
USE_TOUCH: bool
USE_BUTTON: bool
USE_BACKLIGHT: bool USE_BACKLIGHT: bool
"""Whether the hardware supports backlight brightness control.""" """Whether the hardware supports backlight brightness control."""
USE_OPTIGA: bool USE_OPTIGA: bool

View File

@ -167,11 +167,11 @@ if __debug__:
# Incrementing the counter for last events so we know what to await # Incrementing the counter for last events so we know what to await
debug_events.last_event += 1 debug_events.last_event += 1
# TT click on specific coordinates, with possible hold # click on specific coordinates, with possible hold
if x is not None and y is not None and utils.INTERNAL_MODEL in ("T2T1", "D001"): if x is not None and y is not None:
click_chan.publish((debug_events.last_event, x, y, msg.hold_ms)) click_chan.publish((debug_events.last_event, x, y, msg.hold_ms))
# TR press specific button # press specific button
elif msg.physical_button is not None and utils.INTERNAL_MODEL in ("T2B1",): elif msg.physical_button is not None:
button_chan.publish( button_chan.publish(
(debug_events.last_event, msg.physical_button, msg.hold_ms) (debug_events.last_event, msg.physical_button, msg.hold_ms)
) )

View File

@ -227,7 +227,7 @@ class wait(Syscall):
Example: Example:
>>> hid_report, = await loop.wait(0xABCD) # await USB HID report >>> hid_report, = await loop.wait(0xABCD) # await USB HID report
>>> event, x, y = await loop.wait(io.TOUCH) # await touch event >>> event, x, y = await loop.wait(io.INPUT) # await input event
""" """
def __init__(self, msg_iface: int) -> None: def __init__(self, msg_iface: int) -> None:

View File

@ -218,7 +218,7 @@ class RustLayout(ui.Layout):
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator] def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
from trezor import workflow from trezor import workflow
button = loop.wait(io.BUTTON) button = loop.wait(io.INPUT)
self._first_paint() self._first_paint()
while True: while True:
# Using `yield` instead of `await` to avoid allocations. # Using `yield` instead of `await` to avoid allocations.

View File

@ -1,7 +1,7 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import trezorui2 import trezorui2
from trezor import io, loop, ui from trezor import io, loop, ui, utils
from trezor.enums import ButtonRequestType from trezor.enums import ButtonRequestType
from trezor.wire import ActionCancelled from trezor.wire import ActionCancelled
from trezor.wire.context import wait as ctx_wait from trezor.wire.context import wait as ctx_wait
@ -190,15 +190,21 @@ class RustLayout(ui.Layout):
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator] def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
from trezor import workflow from trezor import workflow
touch = loop.wait(io.TOUCH) input = loop.wait(io.INPUT)
self._first_paint() self._first_paint()
while True: while True:
# Using `yield` instead of `await` to avoid allocations. # Using `yield` instead of `await` to avoid allocations.
event, x, y = yield touch event, p0, p1 = yield input
workflow.idle_timer.touch() workflow.idle_timer.touch()
msg = None msg = None
if event in (io.TOUCH_START, io.TOUCH_MOVE, io.TOUCH_END): if utils.USE_TOUCH and event in (
msg = self.layout.touch_event(event, x, y) io.TOUCH_START,
io.TOUCH_MOVE,
io.TOUCH_END,
):
msg = self.layout.touch_event(event, p0, p1)
if utils.USE_BUTTON and event in (io.BUTTON_PRESSED, io.BUTTON_RELEASED):
msg = self.layout.button_event(event, p0)
if msg is not None: if msg is not None:
raise ui.Result(msg) raise ui.Result(msg)
self._paint() self._paint()

View File

@ -10,7 +10,9 @@ from trezorutils import ( # noqa: F401
UI_LAYOUT, UI_LAYOUT,
USE_BACKLIGHT, USE_BACKLIGHT,
USE_OPTIGA, USE_OPTIGA,
USE_BUTTON,
USE_SD_CARD, USE_SD_CARD,
USE_TOUCH,
VERSION_MAJOR, VERSION_MAJOR,
VERSION_MINOR, VERSION_MINOR,
VERSION_PATCH, VERSION_PATCH,

View File

@ -62,23 +62,23 @@ def test_touch(v):
d.refresh() d.refresh()
r = [0, 0] r = [0, 0]
# flush all events # flush all events
while io.poll([io.TOUCH], r, 10000): while io.poll([io.INPUT], r, 10000):
pass pass
# wait for event # wait for event
touch = False touch = False
while True: while True:
if not touch: if not touch:
if io.poll([io.TOUCH], r, 10000) and r[0] == io.TOUCH and r[1][0] == io.TOUCH_START: if io.poll([io.INPUT], r, 10000) and r[0] == io.INPUT and r[1][0] == io.TOUCH_START:
touch = True touch = True
else: else:
if io.poll([io.TOUCH], r, 10000) and r[0] == io.TOUCH and r[1][0] == io.TOUCH_END: if io.poll([io.INPUT], r, 10000) and r[0] == io.INPUT and r[1][0] == io.TOUCH_END:
print(f'OK {r[1][1]} {r[1][2]}') print(f'OK {r[1][1]} {r[1][2]}')
break break
if utime.ticks_us() > deadline: if utime.ticks_us() > deadline:
print('ERROR TIMEOUT') print('ERROR TIMEOUT')
break break
# flush all events # flush all events
while io.poll([io.TOUCH], r, 10000): while io.poll([io.INPUT], r, 10000):
pass pass
d.clear() d.clear()
d.refresh() d.refresh()