1use crate::{ValidationError, request};
8
9use super::util::modbus_message;
10use zerocopy::{IntoBytes, big_endian, little_endian};
11use zerocopy_derive::*;
12
13modbus_message! {
14 WriteHolding {
16 function_code: 0x06,
17 register: big_endian::U16,
18 value: big_endian::U16,
19 }
20}
21
22impl Response<request::WriteHolding> for WriteHolding {
23 type Data = ();
24
25 fn into_data(self, req: &request::WriteHolding) -> Result<(), ValidationError> {
26 self.validate_crc()?;
27
28 if self.address() == req.address()
29 && self.function() == req.function()
30 && self.register == req.register
31 && self.value == req.value
32 {
33 Ok(())
34 } else {
35 Err(ValidationError::UnexpectedResponse)
36 }
37 }
38}
39
40modbus_message! {
41 ReadHoldings<const N: usize> {
43 function_code: 0x03,
44 data_bytes: u8,
45 data: [big_endian::U16; N],
46 }
47}
48
49impl<const N: usize> ReadHoldings<N> {
50 #[inline]
56 pub fn new(addr: u8, data: [big_endian::U16; N]) -> Self {
57 Self::new_inner(addr, 2 * N as u8, data)
58 }
59
60 #[inline]
62 pub fn new_with(addr: u8, f: impl FnOnce(&mut [big_endian::U16; N])) -> Self {
63 Self::new_with_inner(addr, |m| f(&mut m.data))
64 }
65
66 pub fn data_mut(&mut self) -> &mut [big_endian::U16; N] {
67 &mut self.data
68 }
69}
70
71pub struct ReadHoldingsBuilder<const N: usize>(ReadHoldings<N>);
72
73impl<const N: usize> Default for ReadHoldingsBuilder<N> {
74 fn default() -> Self {
75 Self::new(0)
76 }
77}
78
79impl<const N: usize> ReadHoldingsBuilder<N> {
80 pub const fn new(addr: u8) -> Self {
81 Self(ReadHoldings {
82 addr,
83 function: ReadHoldings::<N>::FUNCTION,
84 data_bytes: 2 * N as u8,
85 data: [big_endian::U16::ZERO; N],
86 crc: little_endian::U16::ZERO,
87 })
88 }
89
90 pub fn data_mut(&mut self) -> &mut [big_endian::U16; N] {
91 &mut self.0.data
92 }
93
94 pub fn finish_ref(&mut self) -> &mut ReadHoldings<N> {
95 self.0.update_crc();
96 &mut self.0
97 }
98
99 pub fn finish(mut self) -> ReadHoldings<N> {
100 self.0.update_crc();
101 self.0
102 }
103}
104
105impl<const N: usize> Response<request::ReadHoldings> for ReadHoldings<N> {
106 type Data = [big_endian::U16; N];
107
108 fn into_data(self, req: &request::ReadHoldings) -> Result<Self::Data, ValidationError> {
109 self.validate_crc()?;
110
111 if self.address() == req.address()
112 && self.function() == req.function()
113 && self.data_bytes == 2 * req.n_registers.get() as u8
114 {
115 Ok(self.data)
116 } else {
117 Err(ValidationError::UnexpectedResponse)
118 }
119 }
120}
121
122modbus_message! {
123 WriteHoldings {
125 function_code: 0x10,
126 starting_register: big_endian::U16,
127 n_registers: big_endian::U16,
128 }
129}
130
131impl<const N: usize> Response<request::WriteHoldings<N>> for WriteHoldings {
132 type Data = ();
133
134 fn into_data(self, req: &request::WriteHoldings<N>) -> Result<(), ValidationError> {
135 self.validate_crc()?;
136
137 if self.address() == req.address()
138 && self.function() == req.function()
139 && self.starting_register == req.starting_register
140 && self.n_registers == req.n_registers
141 {
142 Ok(())
143 } else {
144 Err(ValidationError::UnexpectedResponse)
145 }
146 }
147}
148
149modbus_message! {
150 ReadInputs<const N: usize> {
152 function_code: 0x04,
153 data_bytes: u8,
154 data: [big_endian::U16; N],
155 }
156}
157
158impl<const N: usize> Response<request::ReadInputs> for ReadInputs<N> {
159 type Data = [big_endian::U16; N];
160
161 fn into_data(self, req: &request::ReadInputs) -> Result<Self::Data, ValidationError> {
162 self.validate_crc()?;
163
164 if self.address() == req.address()
165 && self.function() == req.function()
166 && self.data_bytes == 2 * req.n_registers.get() as u8
167 {
168 Ok(self.data)
169 } else {
170 Err(ValidationError::UnexpectedResponse)
171 }
172 }
173}
174
175pub trait Response<Request> {
177 type Data;
179
180 fn into_data(self, request: &Request) -> Result<Self::Data, ValidationError>;
183}