diff --git a/examples/rtu-client.rs b/examples/rtu-client.rs index 0e6c5c2..550012b 100644 --- a/examples/rtu-client.rs +++ b/examples/rtu-client.rs @@ -3,30 +3,46 @@ //! Asynchronous RTU client example -#[tokio::main(flavor = "current_thread")] -async fn main() -> Result<(), Box> { - use tokio_serial::SerialStream; +use tokio_modbus::{prelude::*, Address, Quantity, Slave}; +use tokio_serial::SerialStream; + +const SERIAL_PATH: &str = "/dev/ttyUSB0"; - use tokio_modbus::prelude::*; +const BAUD_RATE: u32 = 19_200; - let tty_path = "/dev/ttyUSB0"; - let slave = Slave(0x17); +const SERVER: Slave = Slave(0x17); - let builder = tokio_serial::new(tty_path, 19200); - let port = SerialStream::open(&builder).unwrap(); +const SENSOR_ADDRESS: Address = 0x082B; - let mut conn = rtu::ClientConnection::new(port); - println!("Reading a sensor value"); - let request = Request::ReadHoldingRegisters(0x082B, 2); - let request_context = conn.send_request(request, slave).await?; - let Response::ReadHoldingRegisters(value) = conn.recv_response(request_context).await?? else { +const SENSOR_QUANTITY: Quantity = 2; + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<(), Box> { + let builder = tokio_serial::new(SERIAL_PATH, BAUD_RATE); + let transport = SerialStream::open(&builder).unwrap(); + + let mut connection = rtu::ClientConnection::new(transport); + + println!("Reading sensor values (request/response"); + let request = Request::ReadHoldingRegisters(SENSOR_ADDRESS, SENSOR_QUANTITY); + let request_context = connection.send_request(request, SERVER).await?; + let Response::ReadHoldingRegisters(values) = + connection.recv_response(request_context).await?? + else { // The response variant will always match its corresponding request variant if successful. unreachable!(); }; - println!("Sensor value is: {value:?}"); + println!("Sensor responded with: {values:?}"); + + println!("Reading sensor values (call"); + let mut context = rtu::client_context(connection, SERVER); + let values = context + .read_holding_registers(SENSOR_ADDRESS, SENSOR_QUANTITY) + .await??; + println!("Sensor responded with: {values:?}"); println!("Disconnecting"); - conn.disconnect().await?; + context.disconnect().await?; Ok(()) } diff --git a/src/client/rtu.rs b/src/client/rtu.rs index 03f3479..0e9e078 100644 --- a/src/client/rtu.rs +++ b/src/client/rtu.rs @@ -5,6 +5,8 @@ use tokio::io::{AsyncRead, AsyncWrite}; +use crate::prelude::rtu::ClientConnection; + use super::*; /// Connect to no particular Modbus slave device for sending @@ -21,7 +23,16 @@ pub fn attach_slave(transport: T, slave: Slave) -> Context where T: AsyncRead + AsyncWrite + Debug + Unpin + Send + 'static, { - let client = crate::service::rtu::Client::new(transport, slave); + let connection = ClientConnection::new(transport); + client_context(connection, slave) +} + +/// Creates a client/server connection. +pub fn client_context(connection: ClientConnection, server: Slave) -> Context +where + T: AsyncRead + AsyncWrite + Debug + Unpin + Send + 'static, +{ + let client = crate::service::rtu::Client::new(connection, server); Context { client: Box::new(client), } diff --git a/src/service/rtu.rs b/src/service/rtu.rs index eb00beb..cae2288 100644 --- a/src/service/rtu.rs +++ b/src/service/rtu.rs @@ -96,8 +96,7 @@ impl Client where T: AsyncRead + AsyncWrite + Unpin, { - pub(crate) fn new(transport: T, slave: Slave) -> Self { - let connection = ClientConnection::new(transport); + pub(crate) fn new(connection: ClientConnection, slave: Slave) -> Self { let slave_id = slave.into(); Self { connection: Some(connection), @@ -149,7 +148,6 @@ where #[cfg(test)] mod tests { - use core::{ pin::Pin, task::{Context, Poll}, @@ -158,6 +156,8 @@ mod tests { use crate::Error; + use super::*; + #[derive(Debug)] struct MockTransport; @@ -190,8 +190,9 @@ mod tests { #[tokio::test] async fn handle_broken_pipe() { let transport = MockTransport; + let connection = ClientConnection::new(transport); let mut client = - crate::service::rtu::Client::new(transport, crate::service::rtu::Slave::broadcast()); + crate::service::rtu::Client::new(connection, crate::service::rtu::Slave::broadcast()); let res = client .call(crate::service::rtu::Request::ReadCoils(0x00, 5)) .await;