Skip to main content

mbus_client/services/fifo_queue/
apis.rs

1use crate::app::FifoQueueResponse;
2use crate::services::{ClientCommon, ClientServices, OperationMeta, fifo_queue};
3use mbus_core::{
4    errors::MbusError,
5    transport::{Transport, UnitIdOrSlaveAddr},
6};
7
8impl<TRANSPORT, APP, const N: usize> ClientServices<TRANSPORT, APP, N>
9where
10    TRANSPORT: Transport,
11    APP: ClientCommon + FifoQueueResponse,
12{
13    /// Sends a Read FIFO Queue request (Function Code 0x18).
14    ///
15    /// This function allows reading the contents of a remote FIFO queue of registers.
16    /// The FIFO structure is address-specific, and the response contains the current
17    /// count of registers in the queue followed by the register data itself.
18    ///
19    /// # Parameters
20    /// - `txn_id`: Transaction ID of the original request. While Modbus Serial (RTU/ASCII)
21    ///   does not natively use transaction IDs, the stack preserves the ID provided in
22    ///   the request and returns it here to allow for asynchronous tracking.
23    /// - `unit_id_slave_addr`: The target Modbus unit ID or slave address.
24    ///   - `unit_id`: if transport is tcp
25    ///   - `slave_addr`: if transport is serial
26    /// - `address`: The starting address of the FIFO queue.
27    ///
28    /// # Returns
29    /// - `Ok(())`: If the request was successfully built, the expectation was queued,
30    ///   and the frame was transmitted via the transport layer.
31    /// - `Err(MbusError)`: If the address is a broadcast address, if the frame
32    ///   construction fails, or if the transport layer fails to send.
33    #[must_use = "request submission errors should be handled; the request may not have been queued/sent"]
34    pub fn read_fifo_queue(
35        &mut self,
36        txn_id: u16,
37        unit_id_slave_addr: UnitIdOrSlaveAddr,
38        address: u16,
39    ) -> Result<(), MbusError> {
40        // Modbus protocol specification: Broadcast is not supported for Read operations.
41        if unit_id_slave_addr.is_broadcast() {
42            return Err(MbusError::BroadcastNotAllowed); // Modbus forbids broadcast Read operations
43        }
44
45        let frame = fifo_queue::service::ServiceBuilder::read_fifo_queue(
46            txn_id,
47            unit_id_slave_addr.get(),
48            address,
49            self.transport.transport_type(),
50        )?;
51
52        // Register an expectation in the client state machine.
53        // This ensures that when a response arrives, it is routed to the correct handler.
54        self.add_an_expectation(
55            txn_id,
56            unit_id_slave_addr,
57            &frame,
58            OperationMeta::Other,
59            Self::handle_read_fifo_queue_response,
60        )?;
61
62        // Dispatch the compiled ADU frame through the underlying transport (TCP/RTU/ASCII).
63        self.transport
64            .send(&frame)
65            .map_err(|_e| MbusError::SendFailed)?;
66        Ok(())
67    }
68}