Skip to content

Commit

Permalink
Merge pull request #789 from andresovela/time-display-hints
Browse files Browse the repository at this point in the history
Add support for new time-related display hints
  • Loading branch information
jonathanpallant authored Dec 15, 2023
2 parents 06650b9 + 5238d75 commit c6e0e95
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 12 additions & 8 deletions book/src/hints.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
68 changes: 67 additions & 1 deletion decoder/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -388,13 +402,64 @@ 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,
precision: &TimePrecision,
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"
),
Expand All @@ -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,
})
Expand Down
5 changes: 5 additions & 0 deletions firmware/qemu/src/bin/hints.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions firmware/qemu/src/bin/hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_u64);
defmt::info!("Sec us {:us}", 1_234_567_u64);

// Timestamps with time format
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)
}
Expand Down
15 changes: 11 additions & 4 deletions parser/src/display_hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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` `:ts`, formats integers as human-readable time
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
Expand Down Expand Up @@ -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,
Expand All @@ -99,9 +105,10 @@ impl DisplayHint {
}
}

/// Precision of ISO8601 datetime
/// Precision of timestamp
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TimePrecision {
Micros,
Millis,
Seconds,
}
Expand Down
5 changes: 5 additions & 0 deletions parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down

0 comments on commit c6e0e95

Please sign in to comment.