1#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum Function {
8 ReadCoils {
10 starting_address: u16,
11 quantity: u16,
12 },
13
14 ReadDiscreteInputs {
16 starting_address: u16,
17 quantity: u16,
18 },
19
20 ReadHoldingRegisters {
22 starting_address: u16,
23 quantity: u16,
24 },
25
26 ReadInputRegisters {
28 starting_address: u16,
29 quantity: u16,
30 },
31
32 WriteSingleCoil { address: u16, value: bool },
34
35 WriteSingleRegister { address: u16, value: u16 },
37
38 WriteMultipleCoils {
40 starting_address: u16,
41 value: Box<[bool]>,
42 },
43
44 WriteMultipleRegisters {
46 starting_address: u16,
47 value: Box<[u16]>,
48 },
49}
50
51impl Function {
52 pub const fn kind(&self) -> crate::FunctionKind {
64 use crate::FunctionKind;
65 match self {
66 Function::ReadCoils { .. } => FunctionKind::ReadCoils,
67 Function::ReadDiscreteInputs { .. } => FunctionKind::ReadDiscreteInputs,
68 Function::ReadHoldingRegisters { .. } => FunctionKind::ReadHoldingRegisters,
69 Function::ReadInputRegisters { .. } => FunctionKind::ReadInputRegisters,
70 Function::WriteSingleCoil { .. } => FunctionKind::WriteSingleCoil,
71 Function::WriteSingleRegister { .. } => FunctionKind::WriteSingleRegister,
72 Function::WriteMultipleCoils { .. } => FunctionKind::WriteMultipleCoils,
73 Function::WriteMultipleRegisters { .. } => FunctionKind::WriteMultipleRegisters,
74 }
75 }
76
77 pub const fn as_code(&self) -> u8 {
89 self.kind().as_code()
90 }
91
92 pub(crate) fn to_bytes(&self) -> Result<Box<[u8]>, crate::error::RequestPacketError> {
108 let mut buf: Vec<u8> = Vec::with_capacity(5);
109 buf.push(self.kind().as_code());
110 match self {
111 Function::ReadCoils {
112 starting_address,
113 quantity,
114 }
115 | Function::ReadDiscreteInputs {
116 starting_address,
117 quantity,
118 } => {
119 #[cfg(not(feature = "unlimited_packet_size"))]
120 {
121 if *quantity > 2008 {
122 return Err(crate::error::RequestPacketError::ResponseWillTooBig);
123 }
124 }
125 buf.extend_from_slice(&starting_address.to_be_bytes());
126 buf.extend_from_slice(&quantity.to_be_bytes());
127 }
128 Function::ReadHoldingRegisters {
129 starting_address,
130 quantity,
131 }
132 | Function::ReadInputRegisters {
133 starting_address,
134 quantity,
135 } => {
136 #[cfg(not(feature = "unlimited_packet_size"))]
137 {
138 if *quantity > 125 {
139 return Err(crate::error::RequestPacketError::ResponseWillTooBig);
140 }
141 }
142 buf.extend_from_slice(&starting_address.to_be_bytes());
143 buf.extend_from_slice(&quantity.to_be_bytes());
144 }
145 Function::WriteSingleCoil { address, value } => {
146 buf.extend_from_slice(&address.to_be_bytes());
147 buf.push(if *value == true { 0xFF } else { 0x00 });
148 buf.push(0x00);
149 }
150 Function::WriteSingleRegister { address, value } => {
151 buf.extend_from_slice(&address.to_be_bytes());
152 buf.extend_from_slice(&value.to_be_bytes());
153 }
154 Function::WriteMultipleCoils {
155 starting_address,
156 value,
157 } => {
158 let quantity = value.len() as u16;
159 #[cfg(not(feature = "unlimited_packet_size"))]
160 {
161 if quantity > 1976 {
162 return Err(crate::error::RequestPacketError::RequestTooBig);
163 }
164 }
165 let byte_count = ((quantity + 7) / 8) as u8;
166 buf.extend_from_slice(&starting_address.to_be_bytes());
167 buf.extend_from_slice(&quantity.to_be_bytes());
168 buf.push(byte_count);
169 let mut chunks = value.chunks(8);
170 while let Some(chunk) = chunks.next() {
171 let mut byte: u8 = 0x00;
172 for (i, value) in chunk.iter().enumerate() {
173 if *value == true {
174 byte |= 0b1 << i;
175 } else {
176 byte &= !(0b1 << i);
177 }
178 }
179 buf.push(byte);
180 }
181 }
182 Function::WriteMultipleRegisters {
183 starting_address,
184 value,
185 } => {
186 let quantity = value.len() as u16;
187 #[cfg(not(feature = "unlimited_packet_size"))]
188 {
189 if quantity > 123 {
190 return Err(crate::error::RequestPacketError::RequestTooBig);
191 }
192 }
193 let byte_count = (quantity * 2) as u8;
194 buf.extend_from_slice(&starting_address.to_be_bytes());
195 buf.extend_from_slice(&quantity.to_be_bytes());
196 buf.push(byte_count);
197 for each in value {
198 buf.extend_from_slice(&each.to_be_bytes());
199 }
200 }
201 }
202 Ok(buf.into_boxed_slice())
203 }
204
205 pub const fn expected_len(&self) -> usize {
220 match self {
221 Function::ReadCoils { quantity, .. } |
222 Function::ReadDiscreteInputs { quantity, .. } => 5 + ((*quantity as usize + 7) / 8),
223 Function::ReadHoldingRegisters { quantity, .. } |
224 Function::ReadInputRegisters { quantity, .. } => 5 + (*quantity as usize * 2),
225 Function::WriteSingleCoil { .. } |
226 Function::WriteSingleRegister { .. } |
227 Function::WriteMultipleCoils { .. } |
228 Function::WriteMultipleRegisters { .. } => 8,
229 }
230 }
231}