1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-07 15:18:08 +00:00

rust: add new trace methods

This commit is contained in:
grdddj 2023-03-30 18:55:13 +02:00
parent 9f6e4b8c79
commit b06cfb32d0
8 changed files with 125 additions and 38 deletions

View File

@ -1,3 +1,5 @@
use heapless::String;
/// Visitor passed into `Trace` types. /// Visitor passed into `Trace` types.
pub trait Tracer { pub trait Tracer {
fn int(&mut self, i: i64); fn int(&mut self, i: i64);
@ -6,12 +8,25 @@ pub trait Tracer {
fn symbol(&mut self, name: &str); fn symbol(&mut self, name: &str);
fn open(&mut self, name: &str); fn open(&mut self, name: &str);
fn field(&mut self, name: &str, value: &dyn Trace); fn field(&mut self, name: &str, value: &dyn Trace);
fn title(&mut self, title: &str);
fn button(&mut self, button: &str);
fn content_flag(&mut self);
fn kw_pair(&mut self, key: &str, value: &dyn Trace);
fn close(&mut self); fn close(&mut self);
} }
// Identifiers for tagging various parts of the Trace
// message - so that things like title or the main screen
// content can be read in debug mode by micropython.
pub const TITLE_TAG: &str = " **TITLE** ";
pub const BTN_TAG: &str = " **BTN** ";
pub const CONTENT_TAG: &str = " **CONTENT** ";
// For when the button is not used
pub const EMPTY_BTN: &str = "---";
/// Value that can describe own structure and data using the `Tracer` interface. /// Value that can describe own structure and data using the `Tracer` interface.
pub trait Trace { pub trait Trace {
fn trace(&self, d: &mut dyn Tracer); fn trace(&self, t: &mut dyn Tracer);
} }
impl Trace for &[u8] { impl Trace for &[u8] {
@ -26,6 +41,12 @@ impl<const N: usize> Trace for &[u8; N] {
} }
} }
impl<const N: usize> Trace for String<N> {
fn trace(&self, t: &mut dyn Tracer) {
t.string(&self[..])
}
}
impl Trace for &str { impl Trace for &str {
fn trace(&self, t: &mut dyn Tracer) { fn trace(&self, t: &mut dyn Tracer) {
t.string(self); t.string(self);
@ -68,24 +89,54 @@ mod tests {
} }
fn symbol(&mut self, name: &str) { fn symbol(&mut self, name: &str) {
self.extend(name.as_bytes()) self.string("<");
self.string(name);
self.string(">");
} }
fn open(&mut self, name: &str) { fn open(&mut self, name: &str) {
self.extend(b"<"); self.string("<");
self.extend(name.as_bytes()); self.string(name);
self.extend(b" "); self.string(" ");
} }
fn field(&mut self, name: &str, value: &dyn Trace) { fn field(&mut self, name: &str, value: &dyn Trace) {
self.extend(name.as_bytes()); self.string(name);
self.extend(b":"); self.string(":");
value.trace(self); value.trace(self);
self.extend(b" "); self.string(" ");
}
/// Mark the string as a title/header.
fn title(&mut self, title: &str) {
self.string(TITLE_TAG);
self.string(title);
self.string(TITLE_TAG);
}
/// Mark the string as a button content.
fn button(&mut self, button: &str) {
self.string(BTN_TAG);
self.string(button);
self.string(BTN_TAG);
}
// Mark the following as content visible on the screen,
// until it is called next time.
fn content_flag(&mut self) {
self.string(CONTENT_TAG);
}
/// Key-value pair for easy parsing
fn kw_pair(&mut self, key: &str, value: &dyn Trace) {
self.string(key);
self.string("::");
value.trace(self);
self.string(","); // mostly for human readability
} }
fn close(&mut self) { fn close(&mut self) {
self.extend(b">") self.string(">")
} }
} }
} }

View File

@ -239,6 +239,7 @@ pub mod trace {
impl<T: ParagraphSource> crate::trace::Trace for Paragraphs<T> { impl<T: ParagraphSource> crate::trace::Trace for Paragraphs<T> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("Paragraphs"); t.open("Paragraphs");
t.content_flag();
Self::foreach_visible( Self::foreach_visible(
&self.source, &self.source,
&self.visible, &self.visible,
@ -248,6 +249,7 @@ pub mod trace {
t.string("\n"); t.string("\n");
}, },
); );
t.content_flag();
t.close(); t.close();
} }
} }

View File

@ -231,30 +231,51 @@ impl LayoutObj {
} }
fn symbol(&mut self, name: &str) { fn symbol(&mut self, name: &str) {
self.0 self.string("<");
.call_with_n_args(&[ self.string(name);
"<".try_into().unwrap(), self.string(">");
name.try_into().unwrap(),
">".try_into().unwrap(),
])
.unwrap();
} }
fn open(&mut self, name: &str) { fn open(&mut self, name: &str) {
self.0 self.string("<");
.call_with_n_args(&["<".try_into().unwrap(), name.try_into().unwrap()]) self.string(name);
.unwrap(); self.string(" ");
} }
fn field(&mut self, name: &str, value: &dyn Trace) { fn field(&mut self, name: &str, value: &dyn Trace) {
self.0 self.string(name);
.call_with_n_args(&[name.try_into().unwrap(), ": ".try_into().unwrap()]) self.string(":");
.unwrap();
value.trace(self); value.trace(self);
self.string(" ");
}
/// Mark the string as a title/header.
fn title(&mut self, title: &str) {
self.string(crate::trace::TITLE_TAG);
self.string(title);
self.string(crate::trace::TITLE_TAG);
}
/// Mark the string as a button content.
fn button(&mut self, button: &str) {
self.string(crate::trace::BTN_TAG);
self.string(button);
self.string(crate::trace::BTN_TAG);
}
fn content_flag(&mut self) {
self.string(crate::trace::CONTENT_TAG);
}
fn kw_pair(&mut self, key: &str, value: &dyn Trace) {
self.string(key);
self.string("::");
value.trace(self);
self.string(","); // mostly for human readability
} }
fn close(&mut self) { fn close(&mut self) {
self.0.call_with_n_args(&[">".try_into().unwrap()]).unwrap(); self.string(">")
} }
} }

View File

@ -190,9 +190,9 @@ where
{ {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("Frame"); t.open("Frame");
t.field("title", &self.title); t.title(self.title.inner().text().as_ref());
if let Some(s) = &self.subtitle { if let Some(s) = &self.subtitle {
t.field("subtitle", s); t.title(s.inner().text().as_ref());
} }
if let Some(b) = &self.button { if let Some(b) = &self.button {
t.field("button", b); t.field("button", b);
@ -283,7 +283,7 @@ where
{ {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("NotificationFrame"); t.open("NotificationFrame");
t.field("title", &self.title); t.title(self.title.as_ref());
t.field("content", &self.content); t.field("content", &self.content);
t.close(); t.close();
} }

View File

@ -193,6 +193,7 @@ pub enum MnemonicInputMsg {
#[cfg(feature = "ui_debug")] #[cfg(feature = "ui_debug")]
impl<T, U> crate::trace::Trace for MnemonicKeyboard<T, U> { impl<T, U> crate::trace::Trace for MnemonicKeyboard<T, U> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
// TODO: could differentiate between BIP39 and SLIP39
t.open("MnemonicKeyboard"); t.open("MnemonicKeyboard");
t.close(); t.close();
} }

View File

@ -378,6 +378,7 @@ impl Component for Input {
impl crate::trace::Trace for PassphraseKeyboard { impl crate::trace::Trace for PassphraseKeyboard {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("PassphraseKeyboard"); t.open("PassphraseKeyboard");
t.kw_pair("textbox", &self.input.inner().textbox.content());
t.close(); t.close();
} }
} }

View File

@ -469,6 +469,17 @@ where
{ {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("PinKeyboard"); t.open("PinKeyboard");
// So that debuglink knows the locations of the buttons
let mut digits_order: String<10> = String::new();
for btn in self.digit_btns.iter() {
let btn_content = btn.inner().content();
if let ButtonContent::Text(text) = btn_content {
unwrap!(digits_order.push_str(text));
}
}
t.kw_pair("digits_order", &digits_order);
// TODO: textbox does not get updated when the pin is changed
t.kw_pair("textbox", &self.textbox.inner().pin());
t.close(); t.close();
} }
} }

View File

@ -312,8 +312,8 @@ where
{ {
fn trace(&self, t: &mut dyn crate::trace::Tracer) { fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.open("SwipePage"); t.open("SwipePage");
t.field("active_page", &self.scrollbar.active_page); t.kw_pair("active_page", &self.scrollbar.active_page);
t.field("page_count", &self.scrollbar.page_count); t.kw_pair("page_count", &self.scrollbar.page_count);
t.field("content", &self.content); t.field("content", &self.content);
t.field("controls", &self.controls); t.field("controls", &self.controls);
t.close(); t.close();
@ -561,7 +561,7 @@ mod tests {
page.place(SCREEN); page.place(SCREEN);
let expected = let expected =
"<SwipePage active_page:0 page_count:1 content:<Paragraphs > controls:<Empty > >"; "<SwipePage active_page::0,page_count::1,content:<Paragraphs **CONTENT** **CONTENT** > buttons:<Empty > >";
assert_eq!(trace(&page), expected); assert_eq!(trace(&page), expected);
swipe_up(&mut page); swipe_up(&mut page);
@ -588,7 +588,7 @@ mod tests {
); );
page.place(SCREEN); page.place(SCREEN);
let expected = "<SwipePage active_page:0 page_count:1 content:<Paragraphs This is the first\nparagraph and it should\nfit on the screen\nentirely.\nSecond, bold, paragraph\nshould also fit on the\nscreen whole I think.\n> controls:<Empty > >"; let expected = "<SwipePage active_page:0,page_count:1,content:<Paragraphs **CONTENT** This is the first\nparagraph and it should\nfit on the screen\nentirely.\nSecond, bold, paragraph\nshould also fit on the\nscreen whole I think.\n **CONTENT** > controls:<Empty > >";
assert_eq!(trace(&page), expected); assert_eq!(trace(&page), expected);
swipe_up(&mut page); swipe_up(&mut page);
@ -611,8 +611,8 @@ mod tests {
); );
page.place(SCREEN); page.place(SCREEN);
let expected1 = "<SwipePage active_page:0 page_count:2 content:<Paragraphs This is somewhat long\nparagraph that goes on\nand on and on and on and\non and will definitely not\nfit on just a single\nscreen. You have to\nswipe a bit to see all the\ntext it contains I guess....\n> controls:<FixedHeightBar inner:<Button text:NO > > >"; let expected1 = "<SwipePage active_page:0 page_count:2 content:<Paragraphs **CONTENT** This is somewhat long\nparagraph that goes on\nand on and on and on and\non and will definitely not\nfit on just a single\nscreen. You have to\nswipe a bit to see all the\ntext it contains I guess....\n **CONTENT** > controls:<FixedHeightBar inner:<Button text:NO > > >";
let expected2 = "<SwipePage active_page:1 page_count:2 content:<Paragraphs There's just so much\nletters in it.\n> controls:<FixedHeightBar inner:<Button text:NO > > >"; let expected2 = "<SwipePage active_page:1 page_count:2 content:<Paragraphs **CONTENT** There's just so much\nletters in it.\n **CONTENT** > controls:<FixedHeightBar inner:<Button text:NO > > >";
assert_eq!(trace(&page), expected1); assert_eq!(trace(&page), expected1);
swipe_down(&mut page); swipe_down(&mut page);
@ -647,9 +647,9 @@ mod tests {
); );
page.place(SCREEN); page.place(SCREEN);
let expected1 = "<SwipePage active_page:0 page_count:3 content:<Paragraphs This paragraph is using a\nbold font. It doesn't need\nto be all that long.\nAnd this one is u\nsing MONO. Monosp\nace is nice for n\numbers, they...\n> controls:<FixedHeightBar inner:<Button text:IDK > > >"; let expected1 = "<SwipePage active_page:0 page_count:3 content:<Paragraphs **CONTENT** This paragraph is using a\nbold font. It doesn't need\nto be all that long.\nAnd this one is u\nsing MONO. Monosp\nace is nice for n\numbers, they...\n **CONTENT** > controls:<FixedHeightBar inner:<Button text:IDK > > >";
let expected2 = "<SwipePage active_page:1 page_count:3 content:<Paragraphs ...have the same\nwidth and can be\nscanned quickly.\nEven if they span\nseveral pages or\nsomething.\nLet's add another one...\n> controls:<FixedHeightBar inner:<Button text:IDK > > >"; let expected2 = "<SwipePage active_page:1 page_count:3 content:<Paragraphs **CONTENT** ...have the same\nwidth and can be\nscanned quickly.\nEven if they span\nseveral pages or\nsomething.\nLet's add another one...\n **CONTENT** > controls:<FixedHeightBar inner:<Button text:IDK > > >";
let expected3 = "<SwipePage active_page:2 page_count:3 content:<Paragraphs for a good measure. This\none should overflow all\nthe way to the third page\nwith a bit of luck.\n> controls:<FixedHeightBar inner:<Button text:IDK > > >"; let expected3 = "<SwipePage active_page:2 page_count:3 content:<Paragraphs **CONTENT** for a good measure. This\none should overflow all\nthe way to the third page\nwith a bit of luck.\n **CONTENT** > controls:<FixedHeightBar inner:<Button text:IDK > > >";
assert_eq!(trace(&page), expected1); assert_eq!(trace(&page), expected1);
swipe_down(&mut page); swipe_down(&mut page);
@ -681,9 +681,9 @@ mod tests {
); );
page.place(SCREEN); page.place(SCREEN);
let expected1 = "<SwipePage active_page:0 page_count:3 content:<Paragraphs Short one.\n> controls:<FixedHeightBar inner:<Empty > > >"; let expected1 = "<SwipePage active_page:0,page_count:3,content:<Paragraphs **CONTENT** Short one.\n **CONTENT** > controls:<FixedHeightBar inner:<Empty > > >";
let expected2 = "<SwipePage active_page:1 page_count:3 content:<Paragraphs Short two.\n> controls:<FixedHeightBar inner:<Empty > > >"; let expected2 = "<SwipePage active_page:1,page_count:3,content:<Paragraphs **CONTENT** Short two.\n **CONTENT** > controls:<FixedHeightBar inner:<Empty > > >";
let expected3 = "<SwipePage active_page:2 page_count:3 content:<Paragraphs Short three.\n> controls:<FixedHeightBar inner:<Empty > > >"; let expected3 = "<SwipePage active_page:2,page_count:3,content:<Paragraphs **CONTENT** Short three.\n **CONTENT** > controls:<FixedHeightBar inner:<Empty > > >";
assert_eq!(trace(&page), expected1); assert_eq!(trace(&page), expected1);
swipe_up(&mut page); swipe_up(&mut page);