What changed, and why it matters
This commit is a routine internal refactoring of how the BitBox02/BitBox03 firmware handles delays. It moves delay logic behind a new shared 'Timer' interface and removes old device-specific delay modules. There is no indication in the commit that this fixes a security bug or introduces a vulnerability; it appears to be a code-cleanup and architecture change.
No security action required. Treat as normal code-review item; verify that the new `BitBox03Timer` stub is not compiled into production firmware and that the `todo!()` is resolved before release.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces a bitbox_hal::timer::Timer trait with an async delay_for(Duration) method. It implements this trait for the host simulator (HostTimer), BitBox02 (BitBox02Timer), and adds a stub for BitBox03 (BitBox03Timer with todo!()). It removes the old delay.rs modules in bitbox02 and bitbox03, deletes the LVGL LvTimer wrapper, and threads the timer type through the HAL structs (BitBox02Hal, BitBox02System, BitBox02Ui, BitBox03Ui). The production BitBox02 implementation is functionally unchanged: it still uses bitbox02_sys::delay_init_ms with a C callback and a DelayGuard that cancels on drop. The commit message and diff do not describe any security relevance.
Changed components
src/rust/bitbox-hal/src/timer.rssrc/rust/bitbox-platform-host/src/timer.rssrc/rust/bitbox02/src/hal/timer.rssrc/rust/bitbox02/src/hal/system.rssrc/rust/bitbox02/src/hal/ui.rssrc/rust/bitbox03/src/timer.rssrc/rust/bitbox03/src/ui.rssrc/rust/bitbox-lvgl/src/timer.rsInspect captured patch +255 / −322
diff --git a/src/rust/bitbox-hal/src/lib.rs b/src/rust/bitbox-hal/src/lib.rs
index 52626f0..18e30d6 100644
--- a/src/rust/bitbox-hal/src/lib.rs
+++ b/src/rust/bitbox-hal/src/lib.rs
@@ -10,6 +10,7 @@ pub mod random;
pub mod sd;
pub mod securechip;
pub mod system;
+pub mod timer;
pub mod ui;
pub use eeprom::Eeprom;
@@ -18,6 +19,7 @@ pub use random::Random;
pub use sd::Sd;
pub use securechip::SecureChip;
pub use system::System;
+pub use timer::Timer;
pub use ui::Ui;
pub struct HalSubsystems<
diff --git a/src/rust/bitbox-hal/src/timer.rs b/src/rust/bitbox-hal/src/timer.rs
new file mode 100644
index 0000000..acc9f8f
--- /dev/null
+++ b/src/rust/bitbox-hal/src/timer.rs
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use core::time::Duration;
+
+#[allow(async_fn_in_trait)]
+pub trait Timer {
+ async fn delay_for(duration: Duration);
+}
diff --git a/src/rust/bitbox-lvgl/src/timer.rs b/src/rust/bitbox-lvgl/src/timer.rs
index 2aa5945..5b26099 100644
--- a/src/rust/bitbox-lvgl/src/timer.rs
+++ b/src/rust/bitbox-lvgl/src/timer.rs
@@ -1,8 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
-use alloc::{boxed::Box, rc::Rc};
-use core::{cell::RefCell, ffi::c_void, ptr::NonNull};
-
use crate::ffi;
pub fn handler() {
@@ -10,125 +7,3 @@ pub fn handler() {
ffi::lv_timer_handler();
}
}
-
-type TimerCallback = RefCell<Box<dyn FnMut() + 'static>>;
-
-pub struct LvTimer {
- raw: NonNull<ffi::lv_timer_t>,
- _callback: Rc<TimerCallback>,
-}
-
-unsafe extern "C" fn timer_cb_trampoline(timer: *mut ffi::lv_timer_t) {
- let user_data = unsafe { ffi::lv_timer_get_user_data(timer) };
- if user_data.is_null() {
- return;
- }
-
- let callback_ptr = user_data.cast::<TimerCallback>().cast_const();
- // Keep the callback alive for the duration of this call, even if the timer drops itself.
- unsafe {
- Rc::increment_strong_count(callback_ptr);
- }
- let callback = unsafe { Rc::from_raw(callback_ptr) };
- let mut callback = callback.borrow_mut();
- callback.as_mut()();
-}
-
-impl LvTimer {
- /// Creates a timer that invokes `cb` every `period_ms`.
- ///
- /// LVGL's auto-delete is disabled so the timer lifetime is fully owned by this Rust wrapper
- /// and cleanup remains explicit through `Drop`.
- pub fn new<F>(period_ms: u32, cb: F) -> Option<Self>
- where
- F: FnMut() + 'static,
- {
- let callback: Rc<TimerCallback> = Rc::new(RefCell::new(Box::new(cb)));
- let callback_ptr = Rc::as_ptr(&callback);
- let raw = NonNull::new(unsafe {
- ffi::lv_timer_create(
- Some(timer_cb_trampoline),
- period_ms,
- callback_ptr.cast_mut().cast::<c_void>(),
- )
- })?;
- unsafe {
- ffi::lv_timer_set_auto_delete(raw.as_ptr(), false);
- }
- Some(Self {
- raw,
- _callback: callback,
- })
- }
-
- pub fn pause(&self) {
- unsafe {
- ffi::lv_timer_pause(self.raw.as_ptr());
- }
- }
-
- pub fn resume(&self) {
- unsafe {
- ffi::lv_timer_resume(self.raw.as_ptr());
- }
- }
-
- pub fn set_period(&self, period_ms: u32) {
- unsafe {
- ffi::lv_timer_set_period(self.raw.as_ptr(), period_ms);
- }
- }
-
- pub fn ready(&self) {
- unsafe {
- ffi::lv_timer_ready(self.raw.as_ptr());
- }
- }
-
- pub fn set_repeat_count(&self, repeat_count: i32) {
- unsafe {
- ffi::lv_timer_set_repeat_count(self.raw.as_ptr(), repeat_count);
- }
- }
-}
-
-impl Drop for LvTimer {
- fn drop(&mut self) {
- unsafe {
- ffi::lv_timer_delete(self.raw.as_ptr());
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- extern crate std;
-
- use alloc::rc::Rc;
- use core::cell::{Cell, RefCell};
-
- use super::*;
-
- #[test]
- fn test_drop_during_callback_is_safe() {
- let _lock = crate::test_util::lock_and_init();
-
- let called = Rc::new(Cell::new(false));
- let called_cb = Rc::clone(&called);
- let timer_slot = Rc::new(RefCell::new(None));
- let timer_slot_cb = Rc::clone(&timer_slot);
-
- let timer = LvTimer::new(0, move || {
- called_cb.set(true);
- let dropped = timer_slot_cb.borrow_mut().take();
- drop(dropped);
- })
- .unwrap();
- *timer_slot.borrow_mut() = Some(timer);
-
- handler();
-
- assert!(called.get());
- assert!(timer_slot.borrow().is_none());
- }
-}
diff --git a/src/rust/bitbox-platform-host/src/lib.rs b/src/rust/bitbox-platform-host/src/lib.rs
index 4342a38..d12d0dc 100644
--- a/src/rust/bitbox-platform-host/src/lib.rs
+++ b/src/rust/bitbox-platform-host/src/lib.rs
@@ -4,8 +4,10 @@
#[macro_use]
extern crate alloc;
+extern crate std;
pub mod eeprom;
pub mod memory;
pub mod sd;
pub mod securechip;
+pub mod timer;
diff --git a/src/rust/bitbox-platform-host/src/timer.rs b/src/rust/bitbox-platform-host/src/timer.rs
new file mode 100644
index 0000000..9378c3e
--- /dev/null
+++ b/src/rust/bitbox-platform-host/src/timer.rs
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use alloc::sync::Arc;
+use core::task::{Poll, Waker};
+use core::time::Duration;
+use std::sync::Mutex;
+use std::thread;
+
+pub struct HostTimer;
+
+impl bitbox_hal::timer::Timer for HostTimer {
+ async fn delay_for(duration: Duration) {
+ struct SharedState {
+ waker: Option<Waker>,
+ result: Option<()>,
+ }
+
+ if duration == Duration::ZERO {
+ return;
+ }
+
+ let shared_state = Arc::new(Mutex::new(SharedState {
+ waker: None,
+ result: None,
+ }));
+
+ let mut handle = Some(thread::spawn({
+ let shared_state = Arc::clone(&shared_state);
+ move || {
+ thread::sleep(duration);
+ let mut shared_state = shared_state.lock().unwrap();
+ shared_state.result = Some(());
+ if let Some(waker) = shared_state.waker.as_ref() {
+ waker.wake_by_ref()
+ }
+ }
+ }));
+
+ core::future::poll_fn({
+ let shared_state = Arc::clone(&shared_state);
+ move |cx| {
+ let mut shared_state = shared_state.lock().unwrap();
+
+ if let Some(result) = shared_state.result {
+ if let Some(handle) = handle.take() {
+ handle.join().unwrap();
+ }
+ Poll::Ready(result)
+ } else {
+ shared_state.waker = Some(cx.waker().clone());
+ Poll::Pending
+ }
+ }
+ })
+ .await
+ }
+}
diff --git a/src/rust/bitbox02/src/delay.rs b/src/rust/bitbox02/src/delay.rs
deleted file mode 100644
index 250c603..0000000
--- a/src/rust/bitbox02/src/delay.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-use core::time::Duration;
-
-// Active in C simulator and Rust unit tests.
-#[cfg(any(feature = "c-unit-testing", feature = "testing"))]
-pub async fn delay_for(_duration: Duration) {
- // Do not delay in (non-graphical) simulator and Rust unit tests.
-}
-
-// Active in production firmware.
-#[cfg(not(any(
- feature = "testing",
- feature = "c-unit-testing",
- feature = "simulator-graphical"
-)))]
-pub async fn delay_for(duration: Duration) {
- use alloc::boxed::Box;
- use core::cell::RefCell;
- use core::ffi::c_void;
- use core::task::{Poll, Waker};
-
- let mut bitbox02_delay = bitbox02_sys::delay_t { id: 0 };
-
- // Shared between the async context and the c callback
- struct SharedState {
- waker: Option<Waker>,
- result: Option<()>,
- }
- let shared_state = Box::new(RefCell::new(SharedState {
- waker: None,
- result: None,
- }));
- let shared_state_ptr = shared_state.as_ref() as *const RefCell<SharedState> as *mut c_void;
- unsafe extern "C" fn callback(user_data: *mut c_void) {
- let shared_state = unsafe { &*(user_data as *mut RefCell<SharedState>) };
- let mut shared_state = shared_state.borrow_mut();
- shared_state.result = Some(());
- if let Some(waker) = shared_state.waker.as_ref() {
- waker.wake_by_ref();
- }
- }
- unsafe {
- bitbox02_sys::delay_init_ms(
- &mut bitbox02_delay as *mut _,
- duration.as_millis() as u32,
- Some(callback),
- shared_state_ptr,
- )
- }
- struct DelayGuard<'a>(&'a bitbox02_sys::delay_t);
- impl Drop for DelayGuard<'_> {
- fn drop(&mut self) {
- unsafe {
- bitbox02_sys::delay_cancel(self.0 as *const _);
- }
- }
- }
- let _delay_guard = DelayGuard(&bitbox02_delay);
- core::future::poll_fn({
- let shared_state = &shared_state;
- move |cx| {
- let mut shared_state = shared_state.borrow_mut();
-
- if let Some(result) = shared_state.result {
- Poll::Ready(result)
- } else {
- // Store the waker so the callback can wake up this task
- shared_state.waker = Some(cx.waker().clone());
- Poll::Pending
- }
- }
- })
- .await
-}
-
-// Active in the graphical simulators.
-#[cfg(all(feature = "simulator-graphical", not(feature = "testing")))]
-pub async fn delay_for(duration: Duration) {
- use alloc::sync::Arc;
- use core::task::{Poll, Waker};
- use std::sync::Mutex;
-
- // Shared between the async context and the c callback
- struct SharedState {
- waker: Option<Waker>,
- result: Option<()>,
- }
-
- if duration == Duration::ZERO {
- return;
- }
-
- let shared_state = Arc::new(Mutex::new(SharedState {
- waker: None,
- result: None,
- }));
-
- let mut handle: Option<std::thread::JoinHandle<()>> = Some(std::thread::spawn({
- let shared_state = Arc::clone(&shared_state);
- move || {
- std::thread::sleep(duration);
- let mut shared_state = shared_state.lock().unwrap();
- shared_state.result = Some(());
- if let Some(waker) = shared_state.waker.as_ref() {
- waker.wake_by_ref()
- }
- }
- }));
-
- core::future::poll_fn({
- let shared_state = Arc::clone(&shared_state);
- move |cx| {
- let mut shared_state = shared_state.lock().unwrap();
-
- if let Some(result) = shared_state.result {
- if let Some(handle) = handle.take() {
- handle.join().unwrap();
- }
- Poll::Ready(result)
- } else {
- // Store the waker so the callback can wake up this task
- shared_state.waker = Some(cx.waker().clone());
- Poll::Pending
- }
- }
- })
- .await
-}
diff --git a/src/rust/bitbox02/src/hal.rs b/src/rust/bitbox02/src/hal.rs
index 265a72a..abb99dd 100644
--- a/src/rust/bitbox02/src/hal.rs
+++ b/src/rust/bitbox02/src/hal.rs
@@ -6,52 +6,53 @@ pub mod random;
pub mod sd;
pub mod securechip;
pub mod system;
+pub mod timer;
pub mod ui;
use bitbox_hal::Hal;
-pub struct BitBox02Hal {
- ui: ui::BitBox02Ui,
+pub struct BitBox02Hal<Timer = timer::BitBox02Timer> {
+ ui: ui::BitBox02Ui<Timer>,
sd: sd::BitBox02Sd,
random: random::BitBox02Random,
securechip: securechip::BitBox02SecureChip,
memory: memory::BitBox02Memory,
eeprom: eeprom::BitBox02Eeprom,
- system: system::BitBox02System,
+ system: system::BitBox02System<Timer>,
}
-impl grounded::const_init::ConstInit for BitBox02Hal {
+impl<Timer: bitbox_hal::timer::Timer> grounded::const_init::ConstInit for BitBox02Hal<Timer> {
const VAL: Self = Self::new();
}
-impl BitBox02Hal {
+impl<Timer> BitBox02Hal<Timer> {
pub const fn new() -> Self {
Self {
- ui: ui::BitBox02Ui,
+ ui: ui::BitBox02Ui::new(),
sd: sd::BitBox02Sd,
random: random::BitBox02Random,
securechip: securechip::BitBox02SecureChip,
memory: memory::BitBox02Memory,
eeprom: eeprom::BitBox02Eeprom,
- system: system::BitBox02System,
+ system: system::BitBox02System::new(),
}
}
}
-impl Default for BitBox02Hal {
+impl<Timer> Default for BitBox02Hal<Timer> {
fn default() -> Self {
Self::new()
}
}
-impl Hal for BitBox02Hal {
- type Ui = ui::BitBox02Ui;
+impl<Timer: bitbox_hal::timer::Timer> Hal for BitBox02Hal<Timer> {
+ type Ui = ui::BitBox02Ui<Timer>;
type Random = random::BitBox02Random;
type Sd = sd::BitBox02Sd;
type SecureChip = securechip::BitBox02SecureChip;
type Memory = memory::BitBox02Memory;
type Eeprom = eeprom::BitBox02Eeprom;
- type System = system::BitBox02System;
+ type System = system::BitBox02System<Timer>;
fn as_mut(
&mut self,
diff --git a/src/rust/bitbox02/src/hal/system.rs b/src/rust/bitbox02/src/hal/system.rs
index ecd78f0..6cf11c5 100644
--- a/src/rust/bitbox02/src/hal/system.rs
+++ b/src/rust/bitbox02/src/hal/system.rs
@@ -1,11 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
use bitbox_hal::System;
+use core::marker::PhantomData;
use core::time::Duration;
-pub struct BitBox02System;
+pub struct BitBox02System<Timer = super::timer::BitBox02Timer> {
+ _timer: PhantomData<Timer>,
+}
+
+impl<Timer> BitBox02System<Timer> {
+ pub const fn new() -> Self {
+ Self {
+ _timer: PhantomData,
+ }
+ }
+}
+
+impl<Timer> Default for BitBox02System<Timer> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
-impl System for BitBox02System {
+impl<Timer: bitbox_hal::timer::Timer> System for BitBox02System<Timer> {
async fn startup() {
let upside_down = crate::ui::choose_orientation().await;
if upside_down {
@@ -13,7 +30,7 @@ impl System for BitBox02System {
}
// During this delay the bb02 logotype is shown.
- crate::delay::delay_for(Duration::from_millis(1300)).await;
+ Timer::delay_for(Duration::from_millis(1300)).await;
// Switch to lockscreen that shows "See the bitbox app" and device name.
crate::ui::screen_process_waiting_switch_to_lockscreen();
diff --git a/src/rust/bitbox02/src/hal/timer.rs b/src/rust/bitbox02/src/hal/timer.rs
new file mode 100644
index 0000000..5bb2d90
--- /dev/null
+++ b/src/rust/bitbox02/src/hal/timer.rs
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use core::time::Duration;
+
+pub struct BitBox02Timer;
+
+impl bitbox_hal::timer::Timer for BitBox02Timer {
+ // Active in C simulator.
+ #[cfg(feature = "c-unit-testing")]
+ async fn delay_for(_duration: Duration) {
+ // Do not delay in (non-graphical) simulator and Rust unit tests.
+ }
+
+ // Active in production firmware.
+ #[cfg(not(feature = "c-unit-testing"))]
+ async fn delay_for(duration: Duration) {
+ use alloc::boxed::Box;
+ use core::cell::RefCell;
+ use core::ffi::c_void;
+ use core::task::{Poll, Waker};
+
+ let mut bitbox02_delay = bitbox02_sys::delay_t { id: 0 };
+
+ // Shared between the async context and the c callback
+ struct SharedState {
+ waker: Option<Waker>,
+ result: Option<()>,
+ }
+ let shared_state = Box::new(RefCell::new(SharedState {
+ waker: None,
+ result: None,
+ }));
+ let shared_state_ptr = shared_state.as_ref() as *const RefCell<SharedState> as *mut c_void;
+ unsafe extern "C" fn callback(user_data: *mut c_void) {
+ let shared_state = unsafe { &*(user_data as *mut RefCell<SharedState>) };
+ let mut shared_state = shared_state.borrow_mut();
+ shared_state.result = Some(());
+ if let Some(waker) = shared_state.waker.as_ref() {
+ waker.wake_by_ref();
+ }
+ }
+ unsafe {
+ bitbox02_sys::delay_init_ms(
+ &mut bitbox02_delay as *mut _,
+ duration.as_millis() as u32,
+ Some(callback),
+ shared_state_ptr,
+ )
+ }
+ struct DelayGuard<'a>(&'a bitbox02_sys::delay_t);
+ impl Drop for DelayGuard<'_> {
+ fn drop(&mut self) {
+ unsafe {
+ bitbox02_sys::delay_cancel(self.0 as *const _);
+ }
+ }
+ }
+ let _delay_guard = DelayGuard(&bitbox02_delay);
+ core::future::poll_fn({
+ let shared_state = &shared_state;
+ move |cx| {
+ let mut shared_state = shared_state.borrow_mut();
+
+ if let Some(result) = shared_state.result {
+ Poll::Ready(result)
+ } else {
+ shared_state.waker = Some(cx.waker().clone());
+ Poll::Pending
+ }
+ }
+ })
+ .await
+ }
+}
diff --git a/src/rust/bitbox02/src/hal/ui.rs b/src/rust/bitbox02/src/hal/ui.rs
index 2e82be0..9e3908e 100644
--- a/src/rust/bitbox02/src/hal/ui.rs
+++ b/src/rust/bitbox02/src/hal/ui.rs
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
use alloc::string::String;
+use core::marker::PhantomData;
use core::time::Duration;
use bitbox_hal::Ui;
@@ -9,7 +10,9 @@ use bitbox_hal::ui::{
TrinaryChoice, UserAbort,
};
-pub struct BitBox02Ui;
+pub struct BitBox02Ui<Timer = super::timer::BitBox02Timer> {
+ _timer: PhantomData<Timer>,
+}
pub struct BitBox02Progress {
component: crate::ui::Component,
@@ -72,7 +75,21 @@ fn to_hal_trinary_choice(choice: crate::ui::TrinaryChoice) -> TrinaryChoice {
}
}
-impl Ui for BitBox02Ui {
+impl<Timer> BitBox02Ui<Timer> {
+ pub const fn new() -> Self {
+ Self {
+ _timer: PhantomData,
+ }
+ }
+}
+
+impl<Timer> Default for BitBox02Ui<Timer> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<Timer: bitbox_hal::timer::Timer> Ui for BitBox02Ui<Timer> {
type Progress = BitBox02Progress;
type Empty = BitBox02Empty;
@@ -127,7 +144,9 @@ impl Ui for BitBox02Ui {
#[inline(always)]
async fn status(&mut self, title: &str, status_success: bool) {
- crate::ui::status(title, status_success).await
+ let mut component = crate::ui::status_create(title, status_success);
+ component.screen_stack_push();
+ Timer::delay_for(Duration::from_millis(2000)).await;
}
fn print_screen(&mut self, duration: Duration, msg: &str) {
diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs
index 2ac61a8..ddae004 100644
--- a/src/rust/bitbox02/src/lib.rs
+++ b/src/rust/bitbox02/src/lib.rs
@@ -21,7 +21,6 @@ pub mod testing;
pub mod da14531_handler;
pub mod da14531_protocol;
-pub mod delay;
#[cfg(feature = "simulator-graphical")]
pub mod event;
pub mod hal;
diff --git a/src/rust/bitbox02/src/ui/ui.rs b/src/rust/bitbox02/src/ui/ui.rs
index 50ab0c2..d6990c7 100644
--- a/src/rust/bitbox02/src/ui/ui.rs
+++ b/src/rust/bitbox02/src/ui/ui.rs
@@ -14,7 +14,6 @@ use alloc::string::String;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::task::{Poll, Waker};
-use core::time::Duration;
/// Wraps the C component_t to be used in Rust.
pub struct Component {
@@ -249,19 +248,17 @@ pub fn screen_process() {
}
}
-pub async fn status(text: &str, status_success: bool) {
+pub fn status_create(text: &str, status_success: bool) -> Component {
let component = unsafe {
bitbox02_sys::status_create(
util::strings::str_to_cstr_vec(text).unwrap().as_ptr(), // copied in C
status_success,
)
};
- let mut component = Component {
+ Component {
component,
is_pushed: false,
- };
- component.screen_stack_push();
- crate::delay::delay_for(Duration::from_millis(2000)).await;
+ }
}
pub async fn sdcard() -> SdcardResponse {
diff --git a/src/rust/bitbox02/src/ui/ui_stub.rs b/src/rust/bitbox02/src/ui/ui_stub.rs
index 9319a06..dcf7662 100644
--- a/src/rust/bitbox02/src/ui/ui_stub.rs
+++ b/src/rust/bitbox02/src/ui/ui_stub.rs
@@ -50,8 +50,8 @@ pub async fn confirm(_params: &ConfirmParams<'_>) -> ConfirmResponse {
pub fn screen_process() {}
-pub async fn status(_text: &str, _status_success: bool) {
- panic!("not used");
+pub fn status_create(_text: &str, _status_success: bool) -> Component {
+ Component { is_pushed: false }
}
pub async fn sdcard() -> SdcardResponse {
diff --git a/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs b/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs
index 871e054..3603df7 100644
--- a/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs
+++ b/src/rust/bitbox02/src/ui/ui_stub_c_unit_tests.rs
@@ -57,11 +57,12 @@ pub async fn confirm(params: &ConfirmParams<'_>) -> ConfirmResponse {
pub fn screen_process() {}
-pub async fn status(text: &str, _status_success: bool) {
+pub fn status_create(text: &str, _status_success: bool) -> Component {
crate::print_stdout(&format!(
"STATUS SCREEN START\nTITLE: {}\nSTATUS SCREEN END\n",
text,
));
+ Component { is_pushed: false }
}
pub async fn sdcard() -> SdcardResponse {
diff --git a/src/rust/bitbox03/src/delay.rs b/src/rust/bitbox03/src/delay.rs
deleted file mode 100644
index 19e5010..0000000
--- a/src/rust/bitbox03/src/delay.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-use core::time::Duration;
-
-use bitbox_lvgl::timer::LvTimer;
-
-pub async fn delay_for(duration: Duration) {
- let (responder, result) = util::futures::completion::completion();
- let timer = LvTimer::new(duration.as_millis() as u32, move || responder.resolve(()))
- .expect("failed to create delay timer");
- timer.set_repeat_count(1);
- let _timer = timer;
- result.await;
-}
diff --git a/src/rust/bitbox03/src/lib.rs b/src/rust/bitbox03/src/lib.rs
index 9fcb9fb..4b39e41 100644
--- a/src/rust/bitbox03/src/lib.rs
+++ b/src/rust/bitbox03/src/lib.rs
@@ -3,7 +3,6 @@
#![no_std]
extern crate alloc;
-pub mod delay;
use core::cell::UnsafeCell;
mod eeprom;
pub mod io;
@@ -12,6 +11,7 @@ mod random;
mod sd;
mod securechip;
mod system;
+pub mod timer;
pub mod ui;
use bitbox_hal as hal;
@@ -78,17 +78,11 @@ impl BitBox03 {
impl hal::Hal for BitBox03 {
type Ui = ui::BitBox03Ui;
-
type Random = random::BitBox03Random;
-
type Sd = sd::BitBox03Sd;
-
type SecureChip = securechip::BitBox03SecureChip;
-
type Memory = memory::BitBox03Memory;
-
type Eeprom = eeprom::BitBox03Eeprom;
-
type System = system::BitBox03System;
fn as_mut(
diff --git a/src/rust/bitbox03/src/timer.rs b/src/rust/bitbox03/src/timer.rs
new file mode 100644
index 0000000..245a965
--- /dev/null
+++ b/src/rust/bitbox03/src/timer.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use core::time::Duration;
+
+pub struct BitBox03Timer;
+
+impl bitbox_hal::timer::Timer for BitBox03Timer {
+ async fn delay_for(duration: Duration) {
+ let _ = duration;
+ todo!()
+ }
+}
diff --git a/src/rust/bitbox03/src/ui.rs b/src/rust/bitbox03/src/ui.rs
index 5b4befc..867e1e3 100644
--- a/src/rust/bitbox03/src/ui.rs
+++ b/src/rust/bitbox03/src/ui.rs
@@ -6,6 +6,7 @@ use bitbox_lvgl::{
self as lvgl, LabelExt, LvAlign, LvDisplay, LvHandle, LvLabel, LvObj, LvOpacityLevel, LvPart,
LvSpangroup, ObjExt, SpangroupExt,
};
+use core::marker::PhantomData;
use tracing::info;
use util::futures::completion;
@@ -15,20 +16,21 @@ mod status;
const LOGO: &[u8] = include_bytes!("../splash.png");
-pub struct BitBox03Ui {
+pub struct BitBox03Ui<Timer = crate::timer::BitBox03Timer> {
display: Option<LvDisplay>,
stack: Vec<LvHandle>,
+ _timer: PhantomData<Timer>,
}
pub struct BitBox03UiProgress;
pub struct BitBox03UiEmpty;
-struct ScreenGuard<'a> {
- ui: &'a mut BitBox03Ui,
+struct ScreenGuard<'a, Timer> {
+ ui: &'a mut BitBox03Ui<Timer>,
}
-impl Drop for ScreenGuard<'_> {
+impl<Timer> Drop for ScreenGuard<'_, Timer> {
fn drop(&mut self) {
self.ui.pop();
}
@@ -42,7 +44,7 @@ impl hal::ui::Progress for BitBox03UiProgress {
impl hal::ui::Empty for BitBox03UiEmpty {}
-impl hal::ui::Ui for BitBox03Ui {
+impl<Timer: bitbox_hal::timer::Timer> hal::ui::Ui for BitBox03Ui<Timer> {
type Progress = BitBox03UiProgress;
type Empty = BitBox03UiEmpty;
@@ -79,7 +81,7 @@ impl hal::ui::Ui for BitBox03Ui {
async fn status(&mut self, title: &str, status_success: bool) {
let screen = status::build_status_screen(title, status_success);
let _screen = self.push_guard(screen);
- crate::delay::delay_for(Duration::from_millis(2000)).await;
+ Timer::delay_for(Duration::from_millis(2000)).await;
}
fn print_screen(&mut self, _duration: core::time::Duration, _msg: &str) {
@@ -172,11 +174,12 @@ fn set_background(display: &mut LvDisplay) {
img.align(LvAlign::LV_ALIGN_CENTER, 0, 0);
}
-impl BitBox03Ui {
- pub const fn new() -> BitBox03Ui {
+impl<Timer> BitBox03Ui<Timer> {
+ pub const fn new() -> BitBox03Ui<Timer> {
BitBox03Ui {
display: None,
stack: Vec::new(),
+ _timer: PhantomData,
}
}
pub fn init(&mut self, mut display: LvDisplay) {
@@ -251,14 +254,14 @@ impl BitBox03Ui {
}
}
- fn push_guard(&mut self, screen: LvObj) -> ScreenGuard<'_> {
+ fn push_guard(&mut self, screen: LvObj) -> ScreenGuard<'_, Timer> {
self.push(screen);
ScreenGuard { ui: self }
}
- async fn with_result_screen<T, F>(&mut self, build_screen: F) -> T
+ async fn with_result_screen<R, F>(&mut self, build_screen: F) -> R
where
- F: FnOnce(completion::Responder<T>) -> LvObj,
+ F: FnOnce(completion::Responder<R>) -> LvObj,
{
let (responder, result) = completion::completion();
let screen = build_screen(responder);
diff --git a/test/simulator-graphical-bb03/src/hal.rs b/test/simulator-graphical-bb03/src/hal.rs
index 16f8e06..3fbe48c 100644
--- a/test/simulator-graphical-bb03/src/hal.rs
+++ b/test/simulator-graphical-bb03/src/hal.rs
@@ -6,6 +6,7 @@ use bitbox_hal as hal;
use bitbox_lvgl::LvDisplay;
use bitbox_platform_host::{
eeprom::FakeEeprom, memory::FakeMemory, sd::FakeSd, securechip::FakeSecureChip,
+ timer::HostTimer,
};
use bitbox03::ui;
use core::cell::UnsafeCell;
@@ -16,7 +17,7 @@ mod random;
mod system;
struct BitBox03State {
- ui: ui::BitBox03Ui,
+ ui: ui::BitBox03Ui<HostTimer>,
random: random::BitBox03Random,
sd: FakeSd,
securechip: FakeSecureChip,
@@ -83,7 +84,7 @@ impl BitBox03 {
}
impl hal::Hal for BitBox03 {
- type Ui = ui::BitBox03Ui;
+ type Ui = ui::BitBox03Ui<HostTimer>;
type Random = random::BitBox03Random;
type Sd = FakeSd;
type SecureChip = FakeSecureChip;
diff --git a/test/simulator-graphical/Cargo.lock b/test/simulator-graphical/Cargo.lock
index 98c8d1f..dfa91d8 100644
--- a/test/simulator-graphical/Cargo.lock
+++ b/test/simulator-graphical/Cargo.lock
@@ -327,6 +327,16 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "bitbox-platform-host"
+version = "0.1.0"
+dependencies = [
+ "bitbox-hal",
+ "bitcoin",
+ "hex_lit",
+ "zeroize",
+]
+
[[package]]
name = "bitbox-secp256k1"
version = "0.1.0"
@@ -2862,6 +2872,7 @@ name = "simulator-graphical"
version = "0.1.0"
dependencies = [
"bitbox-aes",
+ "bitbox-platform-host",
"bitbox02",
"bitbox02-rust",
"bitbox02-rust-c",
diff --git a/test/simulator-graphical/Cargo.toml b/test/simulator-graphical/Cargo.toml
index 8bd3a07..d5effad 100644
--- a/test/simulator-graphical/Cargo.toml
+++ b/test/simulator-graphical/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
bitbox02-rust = { path="../../src/rust/bitbox02-rust", features=["simulator-graphical"] }
bitbox02-rust-c = { path="../../src/rust/bitbox02-rust-c", features=["simulator-graphical"] }
bitbox02 = { path="../../src/rust/bitbox02", features=["simulator-graphical"] }
+bitbox-platform-host = { path = "../../src/rust/bitbox-platform-host" }
bitbox-aes = { path="../../src/rust/bitbox-aes"}
winit = "0.30.12"
tracing = {version = "0.1.41", features=["log"]}
diff --git a/test/simulator-graphical/src/main.rs b/test/simulator-graphical/src/main.rs
index 82c3b0b..4286d7a 100644
--- a/test/simulator-graphical/src/main.rs
+++ b/test/simulator-graphical/src/main.rs
@@ -44,6 +44,8 @@ use bitbox02_rust::hal::{Eeprom, Hal, Memory, System};
// Explicitly link library for its C exports
extern crate bitbox02_rust_c;
+type SimulatorHal = bitbox02::hal::BitBox02Hal<bitbox_platform_host::timer::HostTimer>;
+
static BG: &[u8; 325362] = include_bytes!("../bg.png");
const MARGIN: usize = 20;
@@ -139,7 +141,7 @@ static ACCEPTING_CONNECTIONS: AtomicBool = AtomicBool::new(false);
fn init_hww(
preseed: bool,
-) -> Option<bitbox02_rust::hww::transport::HwwTransport<bitbox02::hal::BitBox02Hal>> {
+) -> Option<bitbox02_rust::hww::transport::HwwTransport<SimulatorHal>> {
bitbox02::screen::init(pixel_fn, mirror_fn, clear_fn);
bitbox02::screen::splash();
@@ -159,7 +161,7 @@ fn init_hww(
bitbox02::memory::fake_nova();
info!("Memory setup: success");
- let mut hal = bitbox02::hal::BitBox02Hal::new();
+ let mut hal = SimulatorHal::new();
if preseed {
let mnemonic = "boring mistake dish oyster truth pigeon viable emerge sort crash wire portion cannon couple enact box walk height pull today solid off enable tide";
@@ -171,9 +173,7 @@ fn init_hww(
hal.eeprom().setup();
hal.eeprom().init();
- Some(bitbox02_rust::hww::transport::hww_transport::<
- bitbox02::hal::BitBox02Hal,
- >())
+ Some(bitbox02_rust::hww::transport::hww_transport::<SimulatorHal>())
}
#[derive(Debug)]
@@ -224,7 +224,7 @@ struct App {
outbound_in: Option<mpsc::Sender<[u8; 64]>>,
inbound_out: Option<mpsc::Receiver<[u8; 64]>>,
startup_task: Option<util::bb02_async::Task<'static, ()>>,
- transport: Option<bitbox02_rust::hww::transport::HwwTransport<bitbox02::hal::BitBox02Hal>>,
+ transport: Option<bitbox02_rust::hww::transport::HwwTransport<SimulatorHal>>,
started_at: std::time::Instant,
}
@@ -707,7 +707,9 @@ impl ApplicationHandler<UserEvent> for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.create_window(event_loop, None)
.expect("failed to create initial window");
- self.startup_task = Some(Box::pin(bitbox02::hal::system::BitBox02System::startup()));
+ self.startup_task = Some(Box::pin(
+ bitbox02::hal::system::BitBox02System::<bitbox_platform_host::timer::HostTimer>::startup(),
+ ));
}
}
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.