autd3_core/ethercat/
dc_sys_time.rs1use time::OffsetDateTime;
2
3use thiserror::Error;
4
5#[derive(Error, Debug, PartialEq, Clone)]
6#[error("Invalid date time")]
7pub struct InvalidDateTime;
8
9use super::ECAT_DC_SYS_TIME_BASE;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[repr(C)]
18pub struct DcSysTime {
19 dc_sys_time: u64,
20}
21
22impl DcSysTime {
23 pub const ZERO: Self = Self { dc_sys_time: 0 };
25
26 #[must_use]
28 pub const fn sys_time(&self) -> u64 {
29 self.dc_sys_time
30 }
31
32 #[must_use]
34 pub fn to_utc(&self) -> OffsetDateTime {
35 ECAT_DC_SYS_TIME_BASE + std::time::Duration::from_nanos(self.dc_sys_time)
36 }
37
38 pub fn from_utc(utc: OffsetDateTime) -> Result<Self, InvalidDateTime> {
40 Ok(Self {
41 dc_sys_time: u64::try_from((utc - ECAT_DC_SYS_TIME_BASE).whole_nanoseconds())
42 .map_err(|_| InvalidDateTime)?,
43 })
44 }
45
46 #[must_use]
48 pub fn now() -> Self {
49 Self::from_utc(OffsetDateTime::now_utc()).unwrap()
50 }
51}
52
53impl std::ops::Add<std::time::Duration> for DcSysTime {
54 type Output = Self;
55
56 fn add(self, rhs: std::time::Duration) -> Self::Output {
57 Self {
58 dc_sys_time: self.dc_sys_time + rhs.as_nanos() as u64,
59 }
60 }
61}
62
63impl std::ops::Sub<std::time::Duration> for DcSysTime {
64 type Output = Self;
65
66 fn sub(self, rhs: std::time::Duration) -> Self::Output {
67 Self {
68 dc_sys_time: self.dc_sys_time - rhs.as_nanos() as u64,
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn now_dc_sys_time() {
79 let t = DcSysTime::now();
80 assert!(t.sys_time() > 0);
81 }
82
83 #[rstest::rstest]
84 #[test]
85 #[case(Ok(DcSysTime { dc_sys_time: 0 }), time::macros::datetime!(2000-01-01 0:0:0 UTC))]
86 #[case(Ok(DcSysTime { dc_sys_time: 1000000000 }), time::macros::datetime!(2000-01-01 0:0:1 UTC))]
87 #[case(Ok(DcSysTime { dc_sys_time: 31622400000000000 }), time::macros::datetime!(2001-01-01 0:0:0 UTC))]
88 #[case(Err(InvalidDateTime), time::macros::datetime!(1999-01-01 0:0:1 UTC))]
89 #[case(Err(InvalidDateTime), time::macros::datetime!(9999-01-01 0:0:1 UTC))]
90 fn from_utc(#[case] expect: Result<DcSysTime, InvalidDateTime>, #[case] utc: OffsetDateTime) {
91 assert_eq!(expect, DcSysTime::from_utc(utc));
92 }
93
94 #[rstest::rstest]
95 #[test]
96 #[case(time::macros::datetime!(2000-01-01 0:0:1 UTC))]
97 #[case(time::macros::datetime!(2001-01-01 0:0:0 UTC))]
98 fn to_utc(#[case] utc: OffsetDateTime) {
99 assert_eq!(utc, DcSysTime::from_utc(utc).unwrap().to_utc());
100 }
101
102 #[test]
103 fn addsub() {
104 let utc = time::macros::datetime!(2000-01-01 0:0:0 UTC);
105 let t = DcSysTime::from_utc(utc);
106 assert!(t.is_ok());
107 let t = t.unwrap() + std::time::Duration::from_secs(1);
108 assert_eq!(1000000000, t.sys_time());
109
110 let t = t - std::time::Duration::from_secs(1);
111 assert_eq!(0, t.sys_time());
112 }
113}