From 95b0bb67cd094aed09839c9de813de76b61c9291 Mon Sep 17 00:00:00 2001 From: "Andres O. Vela" Date: Sun, 15 Oct 2023 15:15:59 +0200 Subject: [PATCH 1/5] Add support for new time-related display hints --- decoder/src/frame.rs | 68 ++++++++++++++++++++++++++++++++- firmware/qemu/src/bin/hints.out | 5 +++ firmware/qemu/src/bin/hints.rs | 9 +++++ parser/src/display_hint.rs | 15 ++++++-- parser/src/tests.rs | 5 +++ 5 files changed, 97 insertions(+), 5 deletions(-) diff --git a/decoder/src/frame.rs b/decoder/src/frame.rs index 12901944..f6b2fc8c 100644 --- a/decoder/src/frame.rs +++ b/decoder/src/frame.rs @@ -240,11 +240,25 @@ impl<'t> Frame<'t> { (true, false) => write!(buf, "{x:#0zero_pad$x}")?, (true, true) => write!(buf, "{x:#0zero_pad$X}")?, }, - Some(DisplayHint::Microseconds) => { + Some(DisplayHint::Seconds(TimePrecision::Micros)) => { let seconds = x / 1_000_000; let micros = x % 1_000_000; write!(buf, "{seconds}.{micros:06}")?; } + Some(DisplayHint::Seconds(TimePrecision::Millis)) => { + let seconds = x / 1_000; + let millis = x % 1_000; + write!(buf, "{seconds}.{millis:03}")?; + } + Some(DisplayHint::Time(TimePrecision::Micros)) => { + self.format_time(x, &TimePrecision::Micros, buf)?; + } + Some(DisplayHint::Time(TimePrecision::Millis)) => { + self.format_time(x, &TimePrecision::Millis, buf)?; + } + Some(DisplayHint::Time(TimePrecision::Seconds)) => { + self.format_time(x, &TimePrecision::Seconds, buf)?; + } Some(DisplayHint::Bitflags { name, package, @@ -388,6 +402,54 @@ impl<'t> Frame<'t> { Ok(()) } + fn format_time( + &self, + timestamp: u128, + precision: &TimePrecision, + buf: &mut String, + ) -> Result<(), fmt::Error> { + let div_rem = |x, y| (x / y, x % y); + + let (timestamp, decimals) = match precision { + TimePrecision::Micros => div_rem(timestamp, 1_000_000), + TimePrecision::Millis => div_rem(timestamp, 1_000), + TimePrecision::Seconds => (timestamp, 0), + }; + + let (timestamp, seconds) = div_rem(timestamp, 60); + let (timestamp, minutes) = div_rem(timestamp, 60); + let (timestamp, hours) = div_rem(timestamp, 24); + let days = timestamp; + + if days > 0 { + match precision { + TimePrecision::Micros => write!( + buf, + "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}" + ), + TimePrecision::Millis => write!( + buf, + "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}" + ), + TimePrecision::Seconds => write!(buf, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}"), + } + } else { + match precision { + TimePrecision::Micros => write!( + buf, + "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}" + ), + TimePrecision::Millis => write!( + buf, + "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}" + ), + TimePrecision::Seconds => { + write!(buf, "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}") + } + } + } + } + fn format_iso8601( &self, timestamp: u64, @@ -395,6 +457,9 @@ impl<'t> Frame<'t> { buf: &mut String, ) -> Result<(), fmt::Error> { let format = match precision { + TimePrecision::Micros => format_description!( + "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z" + ), TimePrecision::Millis => format_description!( "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z" ), @@ -403,6 +468,7 @@ impl<'t> Frame<'t> { } }; let date_time = OffsetDateTime::from_unix_timestamp_nanos(match precision { + TimePrecision::Micros => timestamp as i128 * 1_000, TimePrecision::Millis => timestamp as i128 * 1_000_000, TimePrecision::Seconds => timestamp as i128 * 1_000_000_000, }) diff --git a/firmware/qemu/src/bin/hints.out b/firmware/qemu/src/bin/hints.out index 0716bdca..735b9457 100644 --- a/firmware/qemu/src/bin/hints.out +++ b/firmware/qemu/src/bin/hints.out @@ -59,3 +59,8 @@ 0.000058 INFO Debug 10 0.000059 INFO ISO8601 2021-04-20T09:23:44.804Z 0.000060 INFO ISO8601 +53271-03-27T11:46:44Z +0.000061 INFO Sec ms 1234.567 +0.000062 INFO Sec us 1.234567 +0.000063 INFO Time s 14:06:56:07 +0.000064 INFO Time ms 00:20:34.567 +0.000065 INFO Time us 00:00:01.234567 diff --git a/firmware/qemu/src/bin/hints.rs b/firmware/qemu/src/bin/hints.rs index 1a9d9748..4aea5101 100644 --- a/firmware/qemu/src/bin/hints.rs +++ b/firmware/qemu/src/bin/hints.rs @@ -127,6 +127,15 @@ fn main() -> ! { defmt::info!("ISO8601 {:iso8601ms}", 1618910624804_u64); defmt::info!("ISO8601 {:iso8601s}", 1618910624804_u64); + // Timestamps with seconds + defmt::info!("Sec ms {:ms}", 1_234_567); + defmt::info!("Sec us {:us}", 1_234_567); + + // Timestamps with time format + defmt::info!("Time s {:ts}", 1_234_567); + defmt::info!("Time ms {:tms}", 1_234_567); + defmt::info!("Time us {:tus}", 1_234_567); + loop { debug::exit(debug::EXIT_SUCCESS) } diff --git a/parser/src/display_hint.rs b/parser/src/display_hint.rs index dd599c69..6452dbe4 100644 --- a/parser/src/display_hint.rs +++ b/parser/src/display_hint.rs @@ -21,8 +21,10 @@ pub enum DisplayHint { Ascii, /// `:?` Debug, - /// `:us`, formats integers as timestamps in microseconds - Microseconds, + /// `:us` `:ms`, formats integers as timestamps in seconds + Seconds(TimePrecision), + /// `:tus` `:tms`, formats integers as time, where 0 is 00:00:00.000 + Time(TimePrecision), /// `:iso8601{ms,s}`, formats integers as timestamp in ISO8601 date time format ISO8601(TimePrecision), /// `__internal_bitflags_NAME` instructs the decoder to print the flags that are set, instead of @@ -75,7 +77,11 @@ impl DisplayHint { Some(match s { "" => DisplayHint::NoHint { zero_pad }, - "us" => DisplayHint::Microseconds, + "us" => DisplayHint::Seconds(TimePrecision::Micros), + "ms" => DisplayHint::Seconds(TimePrecision::Millis), + "tus" => DisplayHint::Time(TimePrecision::Micros), + "tms" => DisplayHint::Time(TimePrecision::Millis), + "ts" => DisplayHint::Time(TimePrecision::Seconds), "a" => DisplayHint::Ascii, "b" => DisplayHint::Binary { alternate, @@ -99,9 +105,10 @@ impl DisplayHint { } } -/// Precision of ISO8601 datetime +/// Precision of timestamp #[derive(Clone, Debug, Eq, PartialEq)] pub enum TimePrecision { + Micros, Millis, Seconds, } diff --git a/parser/src/tests.rs b/parser/src/tests.rs index 97662407..4fc7735c 100644 --- a/parser/src/tests.rs +++ b/parser/src/tests.rs @@ -31,6 +31,11 @@ fn all_parse_param_cases( #[case(":#x", DisplayHint::Hexadecimal { alternate: true, uppercase: false, zero_pad: 0 })] #[case(":X", DisplayHint::Hexadecimal { alternate: false, uppercase: true, zero_pad: 0 })] #[case(":#X", DisplayHint::Hexadecimal { alternate: true, uppercase: true, zero_pad: 0 })] +#[case(":ms", DisplayHint::Seconds(TimePrecision::Millis))] +#[case(":us", DisplayHint::Seconds(TimePrecision::Micros))] +#[case(":ts", DisplayHint::Time(TimePrecision::Seconds))] +#[case(":tms", DisplayHint::Time(TimePrecision::Millis))] +#[case(":tus", DisplayHint::Time(TimePrecision::Micros))] #[case(":iso8601ms", DisplayHint::ISO8601(TimePrecision::Millis))] #[case(":iso8601s", DisplayHint::ISO8601(TimePrecision::Seconds))] #[case(":?", DisplayHint::Debug)] From 5b0bd9940903a001f518559bdadae9496b88c125 Mon Sep 17 00:00:00 2001 From: "Andres O. Vela" Date: Sun, 15 Oct 2023 15:25:01 +0200 Subject: [PATCH 2/5] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13ea8078..4fa144af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- [#789]: `defmt`: Add support for new time-related display hints + +[#789]: https://github.com/knurling-rs/defmt/pull/789 + ## defmt-decoder v0.3.9, defmt-print v0.3.10 - 2023-10-04 - [#784]: `defmt-decoder`: Prepare `defmt-decoder v0.3.9` release From 60f96adadde519f035109583c87bd5e6852a9a36 Mon Sep 17 00:00:00 2001 From: "Andres O. Vela" Date: Sun, 15 Oct 2023 15:55:20 +0200 Subject: [PATCH 3/5] Fix hints test --- firmware/qemu/src/bin/hints.rs | 10 +++++----- parser/src/display_hint.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/qemu/src/bin/hints.rs b/firmware/qemu/src/bin/hints.rs index 4aea5101..50f13f19 100644 --- a/firmware/qemu/src/bin/hints.rs +++ b/firmware/qemu/src/bin/hints.rs @@ -128,13 +128,13 @@ fn main() -> ! { defmt::info!("ISO8601 {:iso8601s}", 1618910624804_u64); // Timestamps with seconds - defmt::info!("Sec ms {:ms}", 1_234_567); - defmt::info!("Sec us {:us}", 1_234_567); + defmt::info!("Sec ms {:ms}", 1_234_567_u64); + defmt::info!("Sec us {:us}", 1_234_567_u64); // Timestamps with time format - defmt::info!("Time s {:ts}", 1_234_567); - defmt::info!("Time ms {:tms}", 1_234_567); - defmt::info!("Time us {:tus}", 1_234_567); + defmt::info!("Time s {:ts}", 1_234_567_u64); + defmt::info!("Time ms {:tms}", 1_234_567_u64); + defmt::info!("Time us {:tus}", 1_234_567_u64); loop { debug::exit(debug::EXIT_SUCCESS) diff --git a/parser/src/display_hint.rs b/parser/src/display_hint.rs index 6452dbe4..9e7fa583 100644 --- a/parser/src/display_hint.rs +++ b/parser/src/display_hint.rs @@ -23,7 +23,7 @@ pub enum DisplayHint { Debug, /// `:us` `:ms`, formats integers as timestamps in seconds Seconds(TimePrecision), - /// `:tus` `:tms`, formats integers as time, where 0 is 00:00:00.000 + /// `:tus` `:tms` `:ts`, formats integers as human-readable time Time(TimePrecision), /// `:iso8601{ms,s}`, formats integers as timestamp in ISO8601 date time format ISO8601(TimePrecision), From b2a6964dc43de6b27c7d65a57e12d8056ad84e2e Mon Sep 17 00:00:00 2001 From: "Andres O. Vela" Date: Sun, 15 Oct 2023 16:00:57 +0200 Subject: [PATCH 4/5] Update book --- book/src/hints.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/book/src/hints.md b/book/src/hints.md index 79717574..97a67781 100644 --- a/book/src/hints.md +++ b/book/src/hints.md @@ -8,14 +8,18 @@ The hint follows the syntax `:Display` and must come after the type within the b The following display hints are currently supported: -| hint | name | -| :---- | :--------------------------------------------- | -| `:x` | lowercase hexadecimal | -| `:X` | uppercase hexadecimal | -| `:?` | `core::fmt::Debug`-like | -| `:b` | binary | -| `:a` | ASCII | -| `:us` | microseconds (formats integers as time stamps) | +| hint | name | +| :----- | :------------------------------------------------------- | +| `:x` | lowercase hexadecimal | +| `:X` | uppercase hexadecimal | +| `:?` | `core::fmt::Debug`-like | +| `:b` | binary | +| `:a` | ASCII | +| `:ms` | timestamp in seconds (input in milliseconds) | +| `:us` | timestamp in seconds (input in microseconds) | +| `:ts` | timestamp in human-readable time (input in seconds) | +| `:tms` | timestamp in human-readable time (input in milliseconds) | +| `:tus` | timestamp in human-readable time (input in microseconds) | The first 4 display hints resemble what's supported in `core::fmt`, for example: From 5238d75dc622ca69a993e19e054eb497c5da3d2c Mon Sep 17 00:00:00 2001 From: "Andres O. Vela" Date: Sun, 15 Oct 2023 16:08:34 +0200 Subject: [PATCH 5/5] Fix inverted if condition --- decoder/src/frame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/decoder/src/frame.rs b/decoder/src/frame.rs index f6b2fc8c..bcc9b72a 100644 --- a/decoder/src/frame.rs +++ b/decoder/src/frame.rs @@ -421,7 +421,7 @@ impl<'t> Frame<'t> { let (timestamp, hours) = div_rem(timestamp, 24); let days = timestamp; - if days > 0 { + if days == 0 { match precision { TimePrecision::Micros => write!( buf,