use rusty_modbus_types::{Address, FunctionCode, Quantity};
use crate::error::{DecodeError, EncodeError};
use crate::request::Encode;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WriteSingleRegisterRequest {
pub address: Address,
pub value: u16,
}
impl WriteSingleRegisterRequest {
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
DecodeError::check_exact_len(data, 4)?;
let address = Address(u16::from_be_bytes([data[0], data[1]]));
let value = u16::from_be_bytes([data[2], data[3]]);
Ok(Self { address, value })
}
}
impl Encode for WriteSingleRegisterRequest {
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::WriteSingleRegister.code();
buf[1..3].copy_from_slice(&self.address.0.to_be_bytes());
buf[3..5].copy_from_slice(&self.value.to_be_bytes());
Ok(len)
}
fn encoded_len(&self) -> usize {
5
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WriteMultipleRegistersRequest<'buf> {
pub address: Address,
pub quantity: Quantity,
pub byte_count: u8,
pub register_values: &'buf [u8],
}
impl<'buf> WriteMultipleRegistersRequest<'buf> {
const MAX_QUANTITY: u16 = 123;
pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
if data.len() < 5 {
return Err(DecodeError::Truncated {
expected: 5,
actual: data.len(),
});
}
let address = Address(u16::from_be_bytes([data[0], data[1]]));
let quantity = u16::from_be_bytes([data[2], data[3]]);
if quantity == 0 || quantity > Self::MAX_QUANTITY {
return Err(DecodeError::QuantityOutOfRange { quantity });
}
let byte_count = data[4];
if u16::from(byte_count) != quantity * 2 {
return Err(DecodeError::ByteCountMismatch {
declared: usize::from(byte_count),
actual: (quantity * 2) as usize,
});
}
let remaining = data.len() - 5;
if byte_count as usize != remaining {
return Err(DecodeError::ByteCountMismatch {
declared: byte_count as usize,
actual: remaining,
});
}
let register_values = &data[5..];
Ok(Self {
address,
quantity: Quantity(quantity),
byte_count,
register_values,
})
}
}
impl Encode for WriteMultipleRegistersRequest<'_> {
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_quantity(self.quantity.0, Self::MAX_QUANTITY)?;
let expected_bytes = usize::from(self.quantity.0) * 2;
EncodeError::check_byte_count(usize::from(self.byte_count), expected_bytes)?;
EncodeError::check_byte_count(expected_bytes, self.register_values.len())?;
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::WriteMultipleRegisters.code();
buf[1..3].copy_from_slice(&self.address.0.to_be_bytes());
buf[3..5].copy_from_slice(&self.quantity.0.to_be_bytes());
buf[5] = self.byte_count;
buf[6..6 + self.register_values.len()].copy_from_slice(self.register_values);
Ok(len)
}
fn encoded_len(&self) -> usize {
6 + self.register_values.len()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MaskWriteRegisterRequest {
pub address: Address,
pub and_mask: u16,
pub or_mask: u16,
}
impl MaskWriteRegisterRequest {
pub fn decode(data: &[u8]) -> Result<Self, DecodeError> {
DecodeError::check_exact_len(data, 6)?;
let address = Address(u16::from_be_bytes([data[0], data[1]]));
let and_mask = u16::from_be_bytes([data[2], data[3]]);
let or_mask = u16::from_be_bytes([data[4], data[5]]);
Ok(Self {
address,
and_mask,
or_mask,
})
}
}
impl Encode for MaskWriteRegisterRequest {
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::MaskWriteRegister.code();
buf[1..3].copy_from_slice(&self.address.0.to_be_bytes());
buf[3..5].copy_from_slice(&self.and_mask.to_be_bytes());
buf[5..7].copy_from_slice(&self.or_mask.to_be_bytes());
Ok(len)
}
fn encoded_len(&self) -> usize {
7
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReadWriteMultipleRegistersRequest<'buf> {
pub read_address: Address,
pub read_quantity: Quantity,
pub write_address: Address,
pub write_quantity: Quantity,
pub write_byte_count: u8,
pub write_register_values: &'buf [u8],
}
impl<'buf> ReadWriteMultipleRegistersRequest<'buf> {
const MAX_READ_QUANTITY: u16 = 125;
const MAX_WRITE_QUANTITY: u16 = 121;
pub fn decode(data: &'buf [u8]) -> Result<Self, DecodeError> {
if data.len() < 9 {
return Err(DecodeError::Truncated {
expected: 9,
actual: data.len(),
});
}
let read_address = Address(u16::from_be_bytes([data[0], data[1]]));
let read_quantity = u16::from_be_bytes([data[2], data[3]]);
if read_quantity == 0 || read_quantity > Self::MAX_READ_QUANTITY {
return Err(DecodeError::QuantityOutOfRange {
quantity: read_quantity,
});
}
let write_address = Address(u16::from_be_bytes([data[4], data[5]]));
let write_quantity = u16::from_be_bytes([data[6], data[7]]);
if write_quantity == 0 || write_quantity > Self::MAX_WRITE_QUANTITY {
return Err(DecodeError::QuantityOutOfRange {
quantity: write_quantity,
});
}
let write_byte_count = data[8];
if u16::from(write_byte_count) != write_quantity * 2 {
return Err(DecodeError::ByteCountMismatch {
declared: usize::from(write_byte_count),
actual: (write_quantity * 2) as usize,
});
}
let remaining = data.len() - 9;
if write_byte_count as usize != remaining {
return Err(DecodeError::ByteCountMismatch {
declared: write_byte_count as usize,
actual: remaining,
});
}
let write_register_values = &data[9..];
Ok(Self {
read_address,
read_quantity: Quantity(read_quantity),
write_address,
write_quantity: Quantity(write_quantity),
write_byte_count,
write_register_values,
})
}
}
impl Encode for ReadWriteMultipleRegistersRequest<'_> {
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_quantity(self.read_quantity.0, Self::MAX_READ_QUANTITY)?;
EncodeError::check_quantity(self.write_quantity.0, Self::MAX_WRITE_QUANTITY)?;
let expected_bytes = usize::from(self.write_quantity.0) * 2;
EncodeError::check_byte_count(usize::from(self.write_byte_count), expected_bytes)?;
EncodeError::check_byte_count(expected_bytes, self.write_register_values.len())?;
EncodeError::check_pdu_len(len)?;
buf[0] = FunctionCode::ReadWriteMultipleRegisters.code();
buf[1..3].copy_from_slice(&self.read_address.0.to_be_bytes());
buf[3..5].copy_from_slice(&self.read_quantity.0.to_be_bytes());
buf[5..7].copy_from_slice(&self.write_address.0.to_be_bytes());
buf[7..9].copy_from_slice(&self.write_quantity.0.to_be_bytes());
buf[9] = self.write_byte_count;
buf[10..10 + self.write_register_values.len()].copy_from_slice(self.write_register_values);
Ok(len)
}
fn encoded_len(&self) -> usize {
10 + self.write_register_values.len()
}
}