Skip to main content

plc_comm_hostlink/
model.rs

1use std::sync::Arc;
2use std::time::SystemTime;
3use time::{Month, OffsetDateTime};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum HostLinkTransportMode {
7    Tcp,
8    Udp,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum KvPlcMode {
13    Program = 0,
14    Run = 1,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum HostLinkTraceDirection {
19    Send,
20    Receive,
21}
22
23#[derive(Debug, Clone)]
24pub struct HostLinkTraceFrame {
25    pub direction: HostLinkTraceDirection,
26    pub data: Vec<u8>,
27    pub timestamp: SystemTime,
28}
29
30pub type TraceHook = Arc<dyn Fn(HostLinkTraceFrame) + Send + Sync>;
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct KvModelInfo {
34    pub code: String,
35    pub model: String,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct HostLinkClock {
40    pub year: u8,
41    pub month: u8,
42    pub day: u8,
43    pub hour: u8,
44    pub minute: u8,
45    pub second: u8,
46    pub week: u8,
47}
48
49impl HostLinkClock {
50    pub fn now_local() -> Self {
51        let now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
52        Self::from_offset_datetime(now)
53    }
54
55    fn from_offset_datetime(now: OffsetDateTime) -> Self {
56        let week = now.weekday().number_days_from_sunday();
57        Self {
58            year: (now.year() % 100) as u8,
59            month: month_to_number(now.month()),
60            day: now.day(),
61            hour: now.hour(),
62            minute: now.minute(),
63            second: now.second(),
64            week,
65        }
66    }
67}
68
69fn month_to_number(month: Month) -> u8 {
70    match month {
71        Month::January => 1,
72        Month::February => 2,
73        Month::March => 3,
74        Month::April => 4,
75        Month::May => 5,
76        Month::June => 6,
77        Month::July => 7,
78        Month::August => 8,
79        Month::September => 9,
80        Month::October => 10,
81        Month::November => 11,
82        Month::December => 12,
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::HostLinkClock;
89    use time::{Date, Month, Time};
90
91    fn clock_for(year: i32, month: Month, day: u8) -> HostLinkClock {
92        let date = Date::from_calendar_date(year, month, day).unwrap();
93        let time = Time::from_hms(1, 2, 3).unwrap();
94        HostLinkClock::from_offset_datetime(date.with_time(time).assume_utc())
95    }
96
97    #[test]
98    fn clock_uses_sunday_based_weekday() {
99        assert_eq!(clock_for(2026, Month::March, 15).week, 0);
100        assert_eq!(clock_for(2026, Month::March, 16).week, 1);
101        assert_eq!(clock_for(2026, Month::March, 21).week, 6);
102    }
103}
104
105#[derive(Debug, Clone)]
106pub struct HostLinkConnectionOptions {
107    pub host: String,
108    pub port: u16,
109    pub timeout: std::time::Duration,
110    pub transport: HostLinkTransportMode,
111    pub append_lf_on_send: bool,
112}
113
114impl HostLinkConnectionOptions {
115    pub fn new(host: impl Into<String>) -> Self {
116        Self {
117            host: host.into(),
118            port: 8501,
119            timeout: std::time::Duration::from_secs(3),
120            transport: HostLinkTransportMode::Tcp,
121            append_lf_on_send: false,
122        }
123    }
124}