use mbus_core::{
data_unit::common::{MAX_PDU_DATA_LEN, Pdu},
errors::MbusError,
function_codes::public::FunctionCode,
};
use heapless::Vec;
pub(super) struct ReqPduCompiler {}
impl ReqPduCompiler {
pub(super) fn read_holding_registers_request(
address: u16,
quantity: u16,
) -> Result<Pdu, MbusError> {
if !(1..=125).contains(&quantity) {
return Err(MbusError::InvalidPduLength);
}
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&quantity.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
Ok(Pdu::new(FunctionCode::ReadHoldingRegisters, data_vec, 4))
}
pub(super) fn read_input_registers_request(
address: u16,
quantity: u16,
) -> Result<Pdu, MbusError> {
if !(1..=125).contains(&quantity) {
return Err(MbusError::InvalidPduLength);
}
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&quantity.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
Ok(Pdu::new(FunctionCode::ReadInputRegisters, data_vec, 4))
}
pub(super) fn write_single_register_request(
address: u16,
value: u16,
) -> Result<Pdu, MbusError> {
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&value.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
Ok(Pdu::new(FunctionCode::WriteSingleRegister, data_vec, 4))
}
pub(super) fn write_multiple_registers_request(
address: u16,
quantity: u16,
values: &[u16],
) -> Result<Pdu, MbusError> {
if !(1..=123).contains(&quantity) {
return Err(MbusError::InvalidPduLength);
}
if values.len() as u16 != quantity {
return Err(MbusError::InvalidPduLength); }
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&quantity.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
let byte_count = quantity * 2;
data_vec
.push(byte_count as u8)
.map_err(|_| MbusError::BufferLenMissmatch)?;
for &value in values {
data_vec
.extend_from_slice(&value.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
}
let data_len = data_vec.len() as u8;
Ok(Pdu::new(
FunctionCode::WriteMultipleRegisters,
data_vec,
data_len,
))
}
pub(super) fn read_write_multiple_registers_request(
read_address: u16,
read_quantity: u16,
write_address: u16,
write_values: &[u16],
) -> Result<Pdu, MbusError> {
if !(1..=125).contains(&read_quantity) {
return Err(MbusError::InvalidPduLength);
}
let write_quantity = write_values.len() as u16; if !(1..=121).contains(&write_quantity) {
return Err(MbusError::InvalidPduLength);
}
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&read_address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&read_quantity.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&write_address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&write_quantity.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
let byte_count = write_quantity * 2;
data_vec
.push(byte_count as u8)
.map_err(|_| MbusError::BufferLenMissmatch)?;
for &value in write_values {
data_vec
.extend_from_slice(&value.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
}
Ok(Pdu::new(
FunctionCode::ReadWriteMultipleRegisters,
data_vec,
9 + byte_count as u8, ))
}
pub(super) fn mask_write_register_request(
address: u16,
and_mask: u16,
or_mask: u16,
) -> Result<Pdu, MbusError> {
let mut data_vec: Vec<u8, MAX_PDU_DATA_LEN> = Vec::new();
data_vec
.extend_from_slice(&address.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&and_mask.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
data_vec
.extend_from_slice(&or_mask.to_be_bytes())
.map_err(|_| MbusError::BufferLenMissmatch)?;
Ok(Pdu::new(FunctionCode::MaskWriteRegister, data_vec, 6)) }
}