mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-02 03:48:58 +00:00
chore(core/rust): Add IO module and polling function
This commit is contained in:
parent
53918e1a4b
commit
c0962be091
89
core/embed/rust/src/io.rs
Normal file
89
core/embed/rust/src/io.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use crate::{
|
||||||
|
error::Error,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
trezorhal::usb::{usb_is_ready_to_read, usb_is_ready_to_write, IfaceTicket},
|
||||||
|
util::wait_in_busy_loop,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod ffi {
|
||||||
|
extern "C" {
|
||||||
|
#[cfg(feature = "model_t1")]
|
||||||
|
pub fn button_read() -> u32;
|
||||||
|
#[cfg(feature = "model_tt")]
|
||||||
|
pub fn touch_read() -> u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "model_t1")]
|
||||||
|
pub fn button_read() -> u32 {
|
||||||
|
unsafe { ffi::button_read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "model_tt")]
|
||||||
|
pub fn touch_read() -> u32 {
|
||||||
|
unsafe { ffi::touch_read() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Resource {
|
||||||
|
#[cfg(feature = "model_t1")]
|
||||||
|
Button,
|
||||||
|
#[cfg(feature = "model_tt")]
|
||||||
|
Touch,
|
||||||
|
UsbRead(IfaceTicket),
|
||||||
|
UsbWrite(IfaceTicket),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
#[cfg(feature = "model_t1")]
|
||||||
|
Button(u32), // TODO: We should somehow use `ButtonEvent` from UI here.
|
||||||
|
#[cfg(feature = "model_tt")]
|
||||||
|
Touch(u32), // TODO: We should somehow use `TouchEvent` from UI here.
|
||||||
|
UsbRead(IfaceTicket),
|
||||||
|
UsbWrite(IfaceTicket),
|
||||||
|
TimedOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_io(resources: &[Resource], timeout: Duration) -> Result<Event, Error> {
|
||||||
|
let deadline = Instant::now()
|
||||||
|
.checked_add(timeout)
|
||||||
|
.ok_or(Error::OutOfRange)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Poll all resources, return if ready.
|
||||||
|
for &resource in resources {
|
||||||
|
match resource {
|
||||||
|
#[cfg(feature = "model_t1")]
|
||||||
|
Resource::Button => {
|
||||||
|
let event = button_read();
|
||||||
|
if event != 0 {
|
||||||
|
return Ok(Event::Button(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "model_tt")]
|
||||||
|
Resource::Touch => {
|
||||||
|
let event = touch_read();
|
||||||
|
if event != 0 {
|
||||||
|
return Ok(Event::Touch(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Resource::UsbRead(ticket) => {
|
||||||
|
if usb_is_ready_to_read(ticket) {
|
||||||
|
return Ok(Event::UsbRead(ticket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Resource::UsbWrite(ticket) => {
|
||||||
|
if usb_is_ready_to_write(ticket) {
|
||||||
|
return Ok(Event::UsbWrite(ticket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No resource is ready yet, wait or exit on timeout.
|
||||||
|
if Instant::now() < deadline {
|
||||||
|
wait_in_busy_loop();
|
||||||
|
} else {
|
||||||
|
return Ok(Event::TimedOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ mod trezorhal;
|
|||||||
#[cfg(feature = "ui")]
|
#[cfg(feature = "ui")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod ui;
|
mod ui;
|
||||||
|
mod io;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[cfg(not(feature = "test"))]
|
#[cfg(not(feature = "test"))]
|
||||||
|
@ -13,20 +13,6 @@ pub enum UsbError {
|
|||||||
InterfaceNotFound,
|
InterfaceNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Interest {
|
|
||||||
/// Caller is interested to read bytes/messages.
|
|
||||||
Read,
|
|
||||||
/// Caller is interested to write bytes/messages.
|
|
||||||
Write,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Event {
|
|
||||||
/// Resource is ready to perform on selected `Interest`.
|
|
||||||
Ready,
|
|
||||||
/// Resource is not yet ready. No side-effect was performed.
|
|
||||||
Pending,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize the USB stack with information from `config`, register all
|
/// Initialize the USB stack with information from `config`, register all
|
||||||
/// present USB interfaces, and start the communication.
|
/// present USB interfaces, and start the communication.
|
||||||
///
|
///
|
||||||
@ -60,24 +46,23 @@ pub fn usb_open(mut config: UsbConfig) -> Result<(), UsbError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if interface `ticket` is ready to perform on selected `interest`.
|
/// Check if interface `ticket` is ready to read a report.
|
||||||
///
|
///
|
||||||
/// Returns immediately, does not block. Useful for constructing event loops.
|
/// Returns immediately, does not block. Useful for constructing event loops.
|
||||||
pub fn usb_poll(ticket: IfaceTicket, interest: Interest) -> Event {
|
pub fn usb_is_ready_to_read(ticket: IfaceTicket) -> bool {
|
||||||
let ready = match ticket {
|
match ticket {
|
||||||
IfaceTicket::Hid(iface_num) => match interest {
|
IfaceTicket::Hid(iface_num) => HidConfig::ready_to_read(iface_num),
|
||||||
Interest::Read => HidConfig::ready_to_read(iface_num),
|
IfaceTicket::WebUsb(iface_num) => WebUsbConfig::ready_to_read(iface_num),
|
||||||
Interest::Write => HidConfig::ready_to_write(iface_num),
|
}
|
||||||
},
|
}
|
||||||
IfaceTicket::WebUsb(iface_num) => match interest {
|
|
||||||
Interest::Read => WebUsbConfig::ready_to_read(iface_num),
|
/// Check if interface `ticket` is ready to write a report.
|
||||||
Interest::Write => WebUsbConfig::ready_to_write(iface_num),
|
///
|
||||||
},
|
/// Returns immediately, does not block. Useful for constructing event loops.
|
||||||
};
|
pub fn usb_is_ready_to_write(ticket: IfaceTicket) -> bool {
|
||||||
if ready {
|
match ticket {
|
||||||
Event::Ready
|
IfaceTicket::Hid(iface_num) => HidConfig::ready_to_write(iface_num),
|
||||||
} else {
|
IfaceTicket::WebUsb(iface_num) => WebUsbConfig::ready_to_write(iface_num),
|
||||||
Event::Pending
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use core::slice;
|
use core::slice;
|
||||||
|
|
||||||
|
use crate::micropython::time;
|
||||||
|
use crate::time::Duration;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
micropython::{
|
micropython::{
|
||||||
@ -9,6 +11,22 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Wait an unspecified short amount of time. To be used in busy loops.
|
||||||
|
pub fn wait_in_busy_loop() {
|
||||||
|
match () {
|
||||||
|
#[cfg(cortex_m)]
|
||||||
|
() => {
|
||||||
|
// In device context, run the WFI instruction.
|
||||||
|
unsafe { asm!("wfi" :::: "volatile") }
|
||||||
|
}
|
||||||
|
#[cfg(not(cortex_m))]
|
||||||
|
() => {
|
||||||
|
// In desktop context, we sleep for 1ms.
|
||||||
|
time::sleep(Duration::from_millis(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a call and convert errors into a raised MicroPython exception.
|
/// Perform a call and convert errors into a raised MicroPython exception.
|
||||||
/// Should only called when returning from Rust to C. See `raise_exception` for
|
/// Should only called when returning from Rust to C. See `raise_exception` for
|
||||||
/// details.
|
/// details.
|
||||||
|
Loading…
Reference in New Issue
Block a user