Skip to main content

rustmod_client/
points.rs

1use crate::ClientError;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct CoilPoints {
5    start_address: u16,
6    values: Vec<bool>,
7}
8
9impl CoilPoints {
10    pub fn new(start_address: u16, count: usize) -> Self {
11        Self {
12            start_address,
13            values: vec![false; count],
14        }
15    }
16
17    pub fn from_values(start_address: u16, values: Vec<bool>) -> Self {
18        Self {
19            start_address,
20            values,
21        }
22    }
23
24    pub fn start_address(&self) -> u16 {
25        self.start_address
26    }
27
28    pub fn len(&self) -> usize {
29        self.values.len()
30    }
31
32    pub fn is_empty(&self) -> bool {
33        self.values.is_empty()
34    }
35
36    pub fn values(&self) -> &[bool] {
37        &self.values
38    }
39
40    pub fn get(&self, address: u16) -> Option<bool> {
41        let offset = usize::from(address.checked_sub(self.start_address)?);
42        self.values.get(offset).copied()
43    }
44
45    pub fn set(&mut self, address: u16, value: bool) -> Result<(), ClientError> {
46        let offset = usize::from(
47            address
48                .checked_sub(self.start_address)
49                .ok_or(ClientError::InvalidResponse("coil address out of range"))?,
50        );
51        let slot = self
52            .values
53            .get_mut(offset)
54            .ok_or(ClientError::InvalidResponse("coil address out of range"))?;
55        *slot = value;
56        Ok(())
57    }
58
59    pub fn apply_read(&mut self, start_address: u16, values: &[bool]) -> Result<(), ClientError> {
60        for (i, value) in values.iter().copied().enumerate() {
61            let addr = start_address
62                .checked_add(i as u16)
63                .ok_or(ClientError::InvalidResponse("coil address overflow"))?;
64            self.set(addr, value)?;
65        }
66        Ok(())
67    }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct RegisterPoints {
72    start_address: u16,
73    values: Vec<u16>,
74}
75
76impl RegisterPoints {
77    pub fn new(start_address: u16, count: usize) -> Self {
78        Self {
79            start_address,
80            values: vec![0; count],
81        }
82    }
83
84    pub fn from_values(start_address: u16, values: Vec<u16>) -> Self {
85        Self {
86            start_address,
87            values,
88        }
89    }
90
91    pub fn start_address(&self) -> u16 {
92        self.start_address
93    }
94
95    pub fn len(&self) -> usize {
96        self.values.len()
97    }
98
99    pub fn is_empty(&self) -> bool {
100        self.values.is_empty()
101    }
102
103    pub fn values(&self) -> &[u16] {
104        &self.values
105    }
106
107    pub fn get(&self, address: u16) -> Option<u16> {
108        let offset = usize::from(address.checked_sub(self.start_address)?);
109        self.values.get(offset).copied()
110    }
111
112    pub fn set(&mut self, address: u16, value: u16) -> Result<(), ClientError> {
113        let offset = usize::from(
114            address
115                .checked_sub(self.start_address)
116                .ok_or(ClientError::InvalidResponse("register address out of range"))?,
117        );
118        let slot = self
119            .values
120            .get_mut(offset)
121            .ok_or(ClientError::InvalidResponse("register address out of range"))?;
122        *slot = value;
123        Ok(())
124    }
125
126    pub fn apply_read(&mut self, start_address: u16, values: &[u16]) -> Result<(), ClientError> {
127        for (i, value) in values.iter().copied().enumerate() {
128            let addr = start_address
129                .checked_add(i as u16)
130                .ok_or(ClientError::InvalidResponse("register address overflow"))?;
131            self.set(addr, value)?;
132        }
133        Ok(())
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::{CoilPoints, RegisterPoints};
140
141    #[test]
142    fn coil_points_apply_read() {
143        let mut points = CoilPoints::new(10, 4);
144        points.apply_read(11, &[true, false]).unwrap();
145        assert_eq!(points.get(10), Some(false));
146        assert_eq!(points.get(11), Some(true));
147        assert_eq!(points.get(12), Some(false));
148    }
149
150    #[test]
151    fn register_points_apply_read() {
152        let mut points = RegisterPoints::new(100, 3);
153        points.apply_read(100, &[10, 20, 30]).unwrap();
154        assert_eq!(points.get(101), Some(20));
155        points.set(102, 42).unwrap();
156        assert_eq!(points.get(102), Some(42));
157    }
158}