rusty_modbus_codec/request/
diagnostic.rs1use rusty_modbus_types::{DiagnosticSubFunction, FunctionCode};
11
12use crate::error::{DecodeError, EncodeError};
13use crate::request::Encode;
14
15fn check_diagnostic_data_len_decode(data: &[u8]) -> Result<(), DecodeError> {
16 if data.len().is_multiple_of(2) {
17 Ok(())
18 } else {
19 Err(DecodeError::InvalidDiagnosticDataLength { length: data.len() })
20 }
21}
22
23fn check_diagnostic_data_len_encode(data: &[u8]) -> Result<(), EncodeError> {
24 if data.len().is_multiple_of(2) {
25 Ok(())
26 } else {
27 Err(EncodeError::InvalidDiagnosticDataLength { length: data.len() })
28 }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub struct DiagnosticsRequest<'buf> {
37 pub sub_function: DiagnosticSubFunction,
39 pub data: &'buf [u8],
41}
42
43impl<'buf> DiagnosticsRequest<'buf> {
44 pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
54 if data.len() < 2 {
55 return Err(DecodeError::Truncated {
56 expected: 2,
57 actual: data.len(),
58 });
59 }
60 let raw_sub = u16::from_be_bytes([data[0], data[1]]);
61 let sub_function = DiagnosticSubFunction::from_raw(raw_sub)
62 .ok_or(DecodeError::UnknownDiagnosticSubFunction(raw_sub))?;
63 let payload = &data[2..];
64 check_diagnostic_data_len_decode(payload)?;
65 Ok(Self {
66 sub_function,
67 data: payload,
68 })
69 }
70}
71
72impl Encode for DiagnosticsRequest<'_> {
73 fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
74 let len = self.encoded_len();
75 if buf.len() < len {
76 return Err(EncodeError::BufferTooSmall {
77 required: len,
78 available: buf.len(),
79 });
80 }
81 check_diagnostic_data_len_encode(self.data)?;
82 EncodeError::check_pdu_len(len)?;
83 buf[0] = FunctionCode::Diagnostics.code();
84 buf[1..3].copy_from_slice(&self.sub_function.code().to_be_bytes());
85 buf[3..3 + self.data.len()].copy_from_slice(self.data);
86 Ok(len)
87 }
88
89 fn encoded_len(&self) -> usize {
90 3 + self.data.len()
92 }
93}