Skip to content

Commit 29a41d3

Browse files
committed
pldm-platform: Add chrono conversion for Timestamp104
The PLDM file host example now sets updateTime to the local time for testing purposes. Signed-off-by: Matt Johnston <[email protected]>
1 parent f9b4937 commit 29a41d3

File tree

5 files changed

+83
-3
lines changed

5 files changed

+83
-3
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pldm-file/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pldm = { workspace = true }
1919

2020
[dev-dependencies]
2121
anyhow = "1.0"
22+
chrono = { workspace = true }
2223
mctp-linux = { workspace = true }
2324
pldm-platform = { workspace = true, features = ["alloc"] }
2425
smol = "2.0"

pldm-file/examples/host.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,16 @@ async fn handle_platform<R: AsyncRespChannel>(
105105

106106
let mut resp = req.response();
107107

108+
let update_time =
109+
Timestamp104::try_from(&chrono::Local::now().fixed_offset())
110+
.unwrap_or_default();
111+
108112
resp.cc = match Cmd::try_from(req.cmd)? {
109113
Cmd::GetPDRRepositoryInfo => {
110114
let pdrinfo = GetPDRRepositoryInfoResp {
111115
state: PDRRepositoryState::Available,
112-
update_time: [0u8; 13],
113-
oem_update_time: [0u8; 13],
116+
update_time,
117+
oem_update_time: Default::default(),
114118
record_count: 1,
115119
// TODO. "An implementation is allowed to round this number up to the nearest kilobyte (1024 bytes)."
116120
repository_size: 1024,

pldm-platform/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ repository.workspace = true
88
categories = ["network-programming", "embedded", "hardware-support"]
99

1010
[dependencies]
11+
chrono = { workspace = true }
1112
deku = { workspace = true }
1213
heapless = { workspace = true }
1314
log = { workspace = true }

pldm-platform/src/proto.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use deku::{
1313
DekuReader, DekuUpdate, DekuWrite, DekuWriter,
1414
};
1515

16+
use chrono::{DateTime, Datelike, FixedOffset, TimeDelta, TimeZone, Timelike};
17+
1618
use pldm::control::xfer_flag;
1719
use pldm::{proto_error, PldmError, PldmResult};
1820

@@ -531,7 +533,77 @@ pub enum PDRRepositoryState {
531533
}
532534

533535
// TODO
534-
pub type Timestamp104 = [u8; 13];
536+
#[deku_derive(DekuRead, DekuWrite)]
537+
#[derive(Clone, PartialEq, Eq, Default)]
538+
pub struct Timestamp104(pub [u8; 13]);
539+
540+
impl core::fmt::Debug for Timestamp104 {
541+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
542+
if let Ok(dt) = DateTime::<FixedOffset>::try_from(self) {
543+
write!(f, "Timestamp104({dt:?})")
544+
} else {
545+
write!(f, "Timestamp104(invalid {:?})", self.0)
546+
}
547+
}
548+
}
549+
550+
impl TryFrom<&Timestamp104> for DateTime<FixedOffset> {
551+
type Error = ();
552+
553+
fn try_from(t: &Timestamp104) -> Result<Self, Self::Error> {
554+
let t = &t.0;
555+
let tz = i16::from_le_bytes(t[..=1].try_into().unwrap());
556+
let tz = FixedOffset::east_opt(tz as i32 * 60).ok_or_else(|| {
557+
trace!("Bad timezone {tz}");
558+
})?;
559+
let year = u16::from_le_bytes(t[10..=11].try_into().unwrap());
560+
let dt = tz
561+
.with_ymd_and_hms(
562+
year as i32,
563+
t[9] as u32,
564+
t[8] as u32,
565+
t[7] as u32,
566+
t[6] as u32,
567+
t[5] as u32,
568+
)
569+
.earliest()
570+
.ok_or_else(|| {
571+
trace!("Bad timestamp");
572+
})?;
573+
// read a u32 and mask to 24 bit
574+
let micros =
575+
u32::from_le_bytes(t[2..=5].try_into().unwrap()) & 0xffffff;
576+
let dt = dt + TimeDelta::microseconds(micros as i64);
577+
Ok(dt)
578+
}
579+
}
580+
581+
impl TryFrom<&DateTime<FixedOffset>> for Timestamp104 {
582+
type Error = ();
583+
584+
fn try_from(dt: &DateTime<FixedOffset>) -> Result<Self, Self::Error> {
585+
let mut t = [0; 13];
586+
let off = dt.offset().local_minus_utc() as u16;
587+
t[0..=1].copy_from_slice(&off.to_le_bytes());
588+
589+
let date = dt.date_naive();
590+
let time = dt.time();
591+
// can be > 1e9 for leap seconds, discard that.
592+
let micros = (time.nanosecond() % 1_000_000_000) / 1000;
593+
t[2..=4].copy_from_slice(&micros.to_le_bytes()[..3]);
594+
t[5] = time.second() as u8;
595+
t[6] = time.minute() as u8;
596+
t[7] = time.hour() as u8;
597+
t[8] = date.day() as u8;
598+
t[9] = date.month() as u8;
599+
let year: u16 = date.year().try_into().map_err(|_| {
600+
trace!("Year out of range");
601+
})?;
602+
t[10..=11].copy_from_slice(&year.to_le_bytes());
603+
604+
Ok(Timestamp104(t))
605+
}
606+
}
535607

536608
#[deku_derive(DekuRead, DekuWrite)]
537609
#[derive(Debug, Clone, PartialEq, Eq)]

0 commit comments

Comments
 (0)