use rusty_modbus_types::{DiagnosticSubFunction, FunctionCode};
use crate::error::{DecodeError, EncodeError};
use crate::request::Encode;
fn check_diagnostic_data_len_decode(data: &[u8]) -> Result<(), DecodeError> {
if data.len().is_multiple_of(2) {
Ok(())
} else {
Err(DecodeError::InvalidDiagnosticDataLength { length: data.len() })
}
}
fn check_diagnostic_data_len_encode(data: &[u8]) -> Result<(), EncodeError> {
if data.len().is_multiple_of(2) {
Ok(())
} else {
Err(EncodeError::InvalidDiagnosticDataLength { length: data.len() })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DiagnosticsRequest<'buf> {
pub sub_function: DiagnosticSubFunction,
pub data: &'buf [u8],
}
impl<'buf> DiagnosticsRequest<'buf> {
pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
if data.len() < 2 {
return Err(DecodeError::Truncated {
expected: 2,
actual: data.len(),
});
}
let raw_sub = u16::from_be_bytes([data[0], data[1]]);
let sub_function = DiagnosticSubFunction::from_raw(raw_sub)
.ok_or(DecodeError::UnknownDiagnosticSubFunction(raw_sub))?;
let payload = &data[2..];
check_diagnostic_data_len_decode(payload)?;
Ok(Self {
sub_function,
data: payload,
})
}
}
impl Encode for DiagnosticsRequest<'_> {
fn encode_into(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
let len = self.encoded_len();
if buf.len() < len {
return Err(EncodeError::BufferTooSmall {
required: len,
available: buf.len(),
});
}
check_diagnostic_data_len_encode(self.data)?;
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::Diagnostics.code();
buf[1..3].copy_from_slice(&self.sub_function.code().to_be_bytes());
buf[3..3 + self.data.len()].copy_from_slice(self.data);
Ok(len)
}
fn encoded_len(&self) -> usize {
3 + self.data.len()
}
}