@@ -13,6 +13,8 @@ use deku::{
1313 DekuReader , DekuUpdate , DekuWrite , DekuWriter ,
1414} ;
1515
16+ use chrono:: { DateTime , Datelike , FixedOffset , TimeDelta , TimeZone , Timelike } ;
17+
1618use pldm:: control:: xfer_flag;
1719use 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