use crate::app::FifoQueueResponse;
use crate::services::fifo_queue::MAX_FIFO_QUEUE_COUNT_PER_PDU;
use crate::services::{ClientCommon, ClientServices, ExpectedResponse, fifo_queue};
use mbus_core::{
data_unit::common::{ModbusMessage, Pdu},
errors::MbusError,
function_codes::public::FunctionCode,
transport::Transport,
};
pub(super) struct ResponseParser;
impl ResponseParser {
pub(super) fn parse_read_fifo_queue_response(
pdu: &Pdu,
) -> Result<([u16; MAX_FIFO_QUEUE_COUNT_PER_PDU], usize), MbusError> {
if pdu.function_code() != FunctionCode::ReadFifoQueue {
return Err(MbusError::InvalidFunctionCode);
}
let fp = pdu.fifo_payload()?;
let fifo_byte_count = fp.fifo_byte_count as usize;
let fifo_count = fp.fifo_count as usize;
if fp.values.len() + 2 != fifo_byte_count {
return Err(MbusError::InvalidAduLength);
}
if fifo_byte_count != 2 + fifo_count * 2 {
return Err(MbusError::ParseError);
}
if fifo_count > MAX_FIFO_QUEUE_COUNT_PER_PDU {
return Err(MbusError::BufferLenMissmatch);
}
let mut values = [0u16; MAX_FIFO_QUEUE_COUNT_PER_PDU];
let mut index = 0;
for chunk in fp.values.chunks_exact(2) {
if index >= MAX_FIFO_QUEUE_COUNT_PER_PDU {
return Err(MbusError::BufferLenMissmatch);
}
values[index] = u16::from_be_bytes([chunk[0], chunk[1]]);
index += 1;
}
if index != fifo_count {
return Err(MbusError::ParseError);
}
Ok((values, fifo_count))
}
}
impl<TRANSPORT, APP, const N: usize> ClientServices<TRANSPORT, APP, N>
where
TRANSPORT: Transport,
APP: ClientCommon + FifoQueueResponse,
{
pub(super) fn handle_read_fifo_queue_response(
&mut self,
ctx: &ExpectedResponse<TRANSPORT, APP, N>,
message: &ModbusMessage,
) {
let pdu = message.pdu();
let function_code = pdu.function_code();
let transaction_id = ctx.txn_id;
let unit_id_or_slave_addr = message.unit_id_or_slave_addr();
let register_rsp = match fifo_queue::service::ServiceDecompiler::handle_read_fifo_queue_rsp(
function_code,
pdu,
) {
Ok(register_response) => register_response,
Err(e) => {
self.app
.request_failed(transaction_id, unit_id_or_slave_addr, e);
return;
}
};
self.app
.read_fifo_queue_response(transaction_id, unit_id_or_slave_addr, ®ister_rsp);
}
}