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

feat(core/prodtest): add touch-draw command to prodtest

[no changelog]
This commit is contained in:
tychovrahe 2025-02-24 09:35:39 +01:00 committed by TychoVrahe
parent 32bf5d82ff
commit 10f3011663
8 changed files with 130 additions and 3 deletions

View File

@ -220,6 +220,15 @@ haptic-test 3000
OK OK
``` ```
### touch-draw
Starts a drawing canvas, where user can draw with finger on pen. Canvas is exited by sending CTRL+C command.
```
touch-draw
# Starting drawing canvas...
# Press CTRL+C for exit.
ERROR abort
```
### touch-test ### touch-test
Tests the functionality of the display's touch screen. It draws a filled rectangle in one of the four display quadrants and waits for user interaction. Tests the functionality of the display's touch screen. It draws a filled rectangle in one of the four display quadrants and waits for user interaction.

View File

@ -336,6 +336,40 @@ static void prodtest_touch_test_sensitivity(cli_t* cli) {
screen_prodtest_welcome(); screen_prodtest_welcome();
} }
static void prodtest_touch_draw(cli_t* cli) {
#define MAX_EVENTS 256
if (cli_arg_count(cli) > 0) {
cli_error_arg_count(cli);
return;
}
cli_trace(cli, "Starting drawing canvas...");
cli_trace(cli, "Press CTRL+C for exit.");
uint32_t events[MAX_EVENTS] = {0};
uint32_t idx = 0;
screen_prodtest_draw(events, 0);
display_set_backlight(150);
for (;;) {
uint32_t evt = touch_get_event();
if (evt != 0) {
events[idx] = evt;
idx = (idx + 1) % MAX_EVENTS;
screen_prodtest_draw(events, MAX_EVENTS);
}
if (cli_aborted(cli)) {
break;
}
}
screen_prodtest_welcome();
}
// clang-format off // clang-format off
PRODTEST_CLI_CMD( PRODTEST_CLI_CMD(
@ -380,4 +414,11 @@ PRODTEST_CLI_CMD(
.args = "<sensitivity>" .args = "<sensitivity>"
) )
PRODTEST_CLI_CMD(
.name = "touch-draw",
.func = prodtest_touch_draw,
.info = "Simple drawing canvas",
.args = ""
)
#endif // USE_TOUCH #endif // USE_TOUCH

View File

@ -12,3 +12,5 @@ void screen_prodtest_show_text(const char* text, uint8_t text_len);
void screen_prodtest_touch(int16_t x0, int16_t y0, int16_t w, int16_t h); void screen_prodtest_touch(int16_t x0, int16_t y0, int16_t w, int16_t h);
void screen_prodtest_border(void); void screen_prodtest_border(void);
void screen_prodtest_draw(uint32_t* events, uint32_t events_len);

View File

@ -3,7 +3,11 @@ use crate::ui::{ui_prodtest::ProdtestUI, util::from_c_array, ModelUI};
#[cfg(feature = "touch")] #[cfg(feature = "touch")]
use crate::ui::geometry::{Offset, Point, Rect}; use crate::ui::geometry::{Offset, Point, Rect};
#[cfg(feature = "touch")] #[cfg(feature = "touch")]
use crate::ui::{event::TouchEvent, layout::simplified::touch_unpack};
#[cfg(feature = "touch")]
use cty::int16_t; use cty::int16_t;
#[cfg(feature = "touch")]
use heapless::Vec;
#[no_mangle] #[no_mangle]
extern "C" fn screen_prodtest_welcome() { extern "C" fn screen_prodtest_welcome() {
@ -47,3 +51,19 @@ extern "C" fn screen_prodtest_touch(x0: int16_t, y0: int16_t, w: int16_t, h: int
let area = Rect::from_top_left_and_size(Point::new(x0, y0), Offset::new(w, h)); let area = Rect::from_top_left_and_size(Point::new(x0, y0), Offset::new(w, h));
ModelUI::screen_prodtest_touch(area); ModelUI::screen_prodtest_touch(area);
} }
#[no_mangle]
#[cfg(feature = "touch")]
extern "C" fn screen_prodtest_draw(events: *const cty::uint32_t, events_len: u32) {
let events = unsafe { core::slice::from_raw_parts(events, events_len as usize) };
let mut v: Vec<TouchEvent, 256> = Vec::new();
for e in events.iter() {
if let Some(event) = touch_unpack(*e) {
unwrap!(v.push(event));
}
}
ModelUI::screen_prodtest_draw(v);
}

View File

@ -52,8 +52,7 @@ fn button_eval() -> Option<ButtonEvent> {
} }
#[cfg(feature = "touch")] #[cfg(feature = "touch")]
fn touch_eval() -> Option<TouchEvent> { pub fn touch_unpack(event: u32) -> Option<TouchEvent> {
let event = io_touch_get_event();
if event == 0 { if event == 0 {
return None; return None;
} }
@ -85,7 +84,7 @@ pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
#[cfg(all(feature = "button", not(feature = "touch")))] #[cfg(all(feature = "button", not(feature = "touch")))]
let event = button_eval(); let event = button_eval();
#[cfg(feature = "touch")] #[cfg(feature = "touch")]
let event = touch_eval(); let event = touch_unpack(io_touch_get_event());
if let Some(e) = event { if let Some(e) = event {
let mut ctx = EventCtx::new(); let mut ctx = EventCtx::new();
#[cfg(all(feature = "button", not(feature = "touch")))] #[cfg(all(feature = "button", not(feature = "touch")))]

View File

@ -3,12 +3,17 @@ use crate::ui::{
constant::screen, constant::screen,
display, display,
display::Color, display::Color,
event::{
TouchEvent,
TouchEvent::{TouchEnd, TouchMove, TouchStart},
},
geometry::{Alignment, Offset, Rect}, geometry::{Alignment, Offset, Rect},
layout_bolt::{fonts, theme, UIBolt}, layout_bolt::{fonts, theme, UIBolt},
shape, shape,
shape::render_on_display, shape::render_on_display,
ui_prodtest::ProdtestUI, ui_prodtest::ProdtestUI,
}; };
use heapless::Vec;
impl ProdtestUI for UIBolt { impl ProdtestUI for UIBolt {
fn screen_prodtest_welcome() { fn screen_prodtest_welcome() {
@ -133,4 +138,35 @@ impl ProdtestUI for UIBolt {
display::refresh(); display::refresh();
display::set_backlight(theme::backlight::get_backlight_normal()); display::set_backlight(theme::backlight::get_backlight_normal());
} }
fn screen_prodtest_draw(events: Vec<TouchEvent, 256>) {
display::sync();
render_on_display(None, Some(Color::black()), |target| {
for ev in events.iter() {
match ev {
TouchStart(p) => {
shape::Bar::new(Rect::from_center_and_size(*p, Offset::new(3, 3)))
.with_fg(Color::rgb(0, 255, 0))
.with_bg(Color::rgb(0, 255, 0))
.render(target);
}
TouchMove(p) => {
shape::Bar::new(Rect::from_center_and_size(*p, Offset::new(1, 1)))
.with_fg(Color::white())
.with_bg(Color::white())
.render(target);
}
TouchEnd(p) => {
shape::Bar::new(Rect::from_center_and_size(*p, Offset::new(3, 3)))
.with_fg(Color::rgb(255, 0, 0))
.with_bg(Color::rgb(255, 0, 0))
.render(target);
}
}
}
});
display::refresh();
}
} }

View File

@ -1,3 +1,5 @@
#[cfg(feature = "touch")]
use crate::ui::event::TouchEvent;
use crate::ui::{ use crate::ui::{
component::{base::Component, Qr}, component::{base::Component, Qr},
constant::screen, constant::screen,
@ -9,6 +11,8 @@ use crate::ui::{
shape::render_on_display, shape::render_on_display,
ui_prodtest::ProdtestUI, ui_prodtest::ProdtestUI,
}; };
#[cfg(feature = "touch")]
use heapless::Vec;
impl ProdtestUI for UICaesar { impl ProdtestUI for UICaesar {
fn screen_prodtest_welcome() { fn screen_prodtest_welcome() {
@ -109,7 +113,15 @@ impl ProdtestUI for UICaesar {
display::refresh(); display::refresh();
} }
// currently has to be here due to clippy limitations
#[cfg(feature = "touch")]
fn screen_prodtest_touch(_area: Rect) { fn screen_prodtest_touch(_area: Rect) {
unimplemented!(); unimplemented!();
} }
// currently has to be here due to clippy limitations
#[cfg(feature = "touch")]
fn screen_prodtest_draw(events: Vec<TouchEvent, 256>) {
unimplemented!()
}
} }

View File

@ -1,4 +1,8 @@
#[cfg(feature = "touch")]
use crate::ui::event::TouchEvent;
use crate::ui::geometry::Rect; use crate::ui::geometry::Rect;
#[cfg(feature = "touch")]
use heapless::Vec;
pub trait ProdtestUI { pub trait ProdtestUI {
fn screen_prodtest_welcome(); fn screen_prodtest_welcome();
@ -11,5 +15,9 @@ pub trait ProdtestUI {
fn screen_prodtest_bars(colors: &str); fn screen_prodtest_bars(colors: &str);
#[cfg(feature = "touch")]
fn screen_prodtest_touch(area: Rect); fn screen_prodtest_touch(area: Rect);
#[cfg(feature = "touch")]
fn screen_prodtest_draw(events: Vec<TouchEvent, 256>);
} }