use crate::error::{DecodeError, EncodeError};
use crate::request::Encode;
use rusty_modbus_types::{DiagnosticSubFunction, FunctionCode};
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)]
pub struct ReadExceptionStatusResponse {
pub status: u8,
}
impl ReadExceptionStatusResponse {
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
DecodeError::check_exact_len(data, 1)?;
Ok(Self { status: data[0] })
}
}
impl Encode for ReadExceptionStatusResponse {
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(),
});
}
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::ReadExceptionStatus.code();
buf[1] = self.status;
Ok(len)
}
fn encoded_len(&self) -> usize {
1 + 1
}
}
#[derive(Debug)]
pub struct DiagnosticsResponse<'buf> {
pub sub_function: DiagnosticSubFunction,
pub data: &'buf [u8],
}
impl<'buf> DiagnosticsResponse<'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 DiagnosticsResponse<'_> {
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();
let sf = self.sub_function.code().to_be_bytes();
buf[1] = sf[0];
buf[2] = sf[1];
buf[3..3 + self.data.len()].copy_from_slice(self.data);
Ok(len)
}
fn encoded_len(&self) -> usize {
1 + 2 + self.data.len()
}
}
#[derive(Debug)]
pub struct GetCommEventCounterResponse {
pub status: u16,
pub event_count: u16,
}
impl GetCommEventCounterResponse {
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
DecodeError::check_exact_len(data, 4)?;
let status = u16::from_be_bytes([data[0], data[1]]);
let event_count = u16::from_be_bytes([data[2], data[3]]);
Ok(Self {
status,
event_count,
})
}
}
impl Encode for GetCommEventCounterResponse {
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(),
});
}
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::GetCommEventCounter.code();
let st = self.status.to_be_bytes();
buf[1] = st[0];
buf[2] = st[1];
let ec = self.event_count.to_be_bytes();
buf[3] = ec[0];
buf[4] = ec[1];
Ok(len)
}
fn encoded_len(&self) -> usize {
1 + 4
}
}
#[derive(Debug)]
pub struct GetCommEventLogResponse<'buf> {
pub byte_count: u8,
pub status: u16,
pub event_count: u16,
pub message_count: u16,
pub events: &'buf [u8],
}
impl<'buf> GetCommEventLogResponse<'buf> {
pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
if data.len() < 7 {
return Err(DecodeError::Truncated {
expected: 7,
actual: data.len(),
});
}
let byte_count = data[0];
let status = u16::from_be_bytes([data[1], data[2]]);
let event_count = u16::from_be_bytes([data[3], data[4]]);
let message_count = u16::from_be_bytes([data[5], data[6]]);
let events = &data[7..];
if byte_count < 6 {
return Err(DecodeError::ByteCountMismatch {
declared: usize::from(byte_count),
actual: 6 + events.len(),
});
}
let declared_events_len = usize::from(byte_count) - 6;
if events.len() != declared_events_len {
return Err(DecodeError::ByteCountMismatch {
declared: usize::from(byte_count),
actual: 6 + events.len(),
});
}
Ok(Self {
byte_count,
status,
event_count,
message_count,
events,
})
}
}
impl Encode for GetCommEventLogResponse<'_> {
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(),
});
}
EncodeError::check_byte_count(usize::from(self.byte_count), 6 + self.events.len())?;
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::GetCommEventLog.code();
buf[1] = self.byte_count;
let st = self.status.to_be_bytes();
buf[2] = st[0];
buf[3] = st[1];
let ec = self.event_count.to_be_bytes();
buf[4] = ec[0];
buf[5] = ec[1];
let mc = self.message_count.to_be_bytes();
buf[6] = mc[0];
buf[7] = mc[1];
buf[8..8 + self.events.len()].copy_from_slice(self.events);
Ok(len)
}
fn encoded_len(&self) -> usize {
1 + 1 + 6 + self.events.len()
}
}
#[derive(Debug)]
pub struct ReportServerIdResponse<'buf> {
pub byte_count: u8,
pub data: &'buf [u8],
}
impl<'buf> ReportServerIdResponse<'buf> {
pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
if data.is_empty() {
return Err(DecodeError::Truncated {
expected: 1,
actual: 0,
});
}
let byte_count = data[0];
let payload = &data[1..];
if payload.len() != usize::from(byte_count) {
return Err(DecodeError::ByteCountMismatch {
declared: usize::from(byte_count),
actual: payload.len(),
});
}
Ok(Self {
byte_count,
data: payload,
})
}
}
impl Encode for ReportServerIdResponse<'_> {
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(),
});
}
EncodeError::check_byte_count(usize::from(self.byte_count), self.data.len())?;
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::ReportServerId.code();
buf[1] = self.byte_count;
buf[2..2 + usize::from(self.byte_count)].copy_from_slice(self.data);
Ok(len)
}
fn encoded_len(&self) -> usize {
1 + 1 + usize::from(self.byte_count)
}
}