1#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum Response {
5 Status(Box<[bool]>),
7
8 Value(Box<[u16]>),
10
11 Success,
13
14 Exception(crate::Exception),
16}
17
18impl Response {
19 pub fn from_bytes(
51 request: &crate::Request,
52 bytes: &[u8],
53 ) -> Result<Self, crate::error::ResponsePacketError> {
54 let len = bytes.len();
56 if len < 5 {
57 return Err(crate::error::ResponsePacketError::TooShort(len));
58 }
59
60 crate::crc::validate(&bytes)?;
62
63 let function_code = bytes[1];
65 if function_code & 0x80 != 0 {
66 let code = bytes[2];
67 return Ok(Self::Exception(crate::Exception::from_code(code)));
68 }
69
70 if bytes[0] != request.modbus_id() {
72 return Err(crate::error::ResponsePacketError::UnexpectedResponder(
73 bytes[0],
74 ));
75 }
76
77 let function_kind = match crate::FunctionKind::from_code(function_code) {
79 Some(kind) => kind,
80 None => return Err(crate::error::ResponsePacketError::InvalidFormat),
81 };
82 if function_kind != request.function().kind() {
83 return Err(crate::error::ResponsePacketError::InvalidFormat);
84 }
85
86 let packet = &bytes[2..(len - 2)];
88
89 match function_kind {
91 crate::FunctionKind::ReadCoils | crate::FunctionKind::ReadDiscreteInputs => {
92 let byte_count = packet[0];
93 let quantity = match request.function() {
94 crate::Function::ReadCoils { quantity, .. }
95 | crate::Function::ReadDiscreteInputs { quantity, .. } => *quantity,
96 _ => unreachable!(),
97 };
98 if byte_count < (quantity as u8 + 7) / 8 {
99 return Err(crate::error::ResponsePacketError::InvalidFormat);
100 }
101 if packet.len() < byte_count as usize + 1 {
102 return Err(crate::error::ResponsePacketError::InvalidFormat);
103 }
104 let mut list: Vec<bool> = Vec::with_capacity(quantity as usize);
105 for (i, byte) in packet[1..].iter().enumerate() {
106 for j in 0..8_usize {
107 if (i * 8) + j >= quantity as usize {
108 break;
109 }
110 let value = byte & (0b1 << j) != 0;
111 list.push(value);
112 }
113 }
114 Ok(Self::Status(list.into_boxed_slice()))
115 }
116 crate::FunctionKind::ReadHoldingRegisters | crate::FunctionKind::ReadInputRegisters => {
117 let byte_count = packet[0];
118 let quantity = match request.function() {
119 crate::Function::ReadHoldingRegisters { quantity, .. }
120 | crate::Function::ReadInputRegisters { quantity, .. } => *quantity,
121 _ => unreachable!(),
122 };
123 if byte_count < quantity as u8 * 2 {
124 return Err(crate::error::ResponsePacketError::InvalidFormat);
125 }
126 if packet.len() < byte_count as usize + 1 {
127 return Err(crate::error::ResponsePacketError::InvalidFormat);
128 }
129 let mut list: Vec<u16> = Vec::with_capacity(quantity as usize * 2);
130 for i in 0..(quantity as usize) {
131 let hi = packet[1 + (i * 2)];
132 let lo = packet[2 + (i * 2)];
133 let value = u16::from_be_bytes([hi, lo]);
134 list.push(value);
135 }
136 Ok(Self::Value(list.into_boxed_slice()))
137 }
138 crate::FunctionKind::WriteSingleCoil | crate::FunctionKind::WriteSingleRegister => {
139 if packet.len() != 4 {
140 return Err(crate::error::ResponsePacketError::InvalidFormat);
141 }
142 let (req_address, req_value) = match request.function() {
143 crate::Function::WriteSingleCoil { address, value } => {
144 (*address, if *value == true { 0xFF00 } else { 0x0000 })
145 }
146 crate::Function::WriteSingleRegister { address, value } => (*address, *value),
147 _ => unreachable!(),
148 };
149 let res_address = u16::from_be_bytes([packet[0], packet[1]]);
150 let res_value = u16::from_be_bytes([packet[2], packet[3]]);
151 if req_address != res_address || req_value != res_value {
152 return Err(crate::error::ResponsePacketError::InvalidFormat);
153 }
154 Ok(Self::Success)
155 }
156 crate::FunctionKind::WriteMultipleCoils
157 | crate::FunctionKind::WriteMultipleRegisters => {
158 if packet.len() != 4 {
159 return Err(crate::error::ResponsePacketError::InvalidFormat);
160 }
161 let (req_address, req_quantity) = match request.function() {
162 crate::Function::WriteMultipleCoils {
163 starting_address,
164 value,
165 } => (*starting_address, value.len() as u16),
166 crate::Function::WriteMultipleRegisters {
167 starting_address,
168 value,
169 } => (*starting_address, value.len() as u16),
170 _ => unreachable!(),
171 };
172 let res_address = u16::from_be_bytes([packet[0], packet[1]]);
173 let res_quantity = u16::from_be_bytes([packet[2], packet[3]]);
174 if req_address != res_address || req_quantity != res_quantity {
175 return Err(crate::error::ResponsePacketError::InvalidFormat);
176 }
177 Ok(Self::Success)
178 }
179 }
180 }
181
182 pub fn is_success(&self) -> bool {
199 match self {
200 Response::Status(_) | Response::Value(_) | Response::Success => true,
201 Response::Exception(exception) => *exception == crate::Exception::Acknowledge,
202 }
203 }
204}
205
206impl std::fmt::Display for Response {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 write!(
209 f,
210 "{}",
211 match self {
212 Response::Status(items) => format!("{:?}", items),
213 Response::Value(items) => format!("{:?}", items),
214 Response::Success => "Success".to_string(),
215 Response::Exception(exception) => exception.to_string(),
216 }
217 )
218 }
219}