Skip to main content

async_modbus/
client.rs

1//! Client functions for [`embedded_io_async`]-based IO.
2
3use embedded_io_async::{Read, ReadExactError, Write};
4use zerocopy::{FromBytes, Immutable, IntoBytes};
5
6mod generated {
7    include!(concat!(env!("OUT_DIR"), "/client.rs"));
8}
9
10pub use generated::*;
11
12use crate::pdu::{CrcError, ValidationError};
13
14async fn write_frame<T, E>(mut dst: impl Write<Error = E>, frame: &T) -> Result<(), E>
15where
16    T: IntoBytes + Immutable,
17{
18    dst.write_all(frame.as_bytes()).await?;
19    dst.flush().await
20}
21
22async fn read_frame<T, E>(mut src: impl Read<Error = E>) -> Result<T, ReadExactError<E>>
23where
24    T: FromBytes + IntoBytes,
25{
26    let mut message = T::new_zeroed();
27    src.read_exact(message.as_mut_bytes()).await?;
28    Ok(message)
29}
30
31/// Errors that can occur when talking to a Modbus server.
32#[derive(Debug, thiserror_no_std::Error)]
33pub enum Error<Io> {
34    /// IO error.
35    #[error(transparent)]
36    Io(Io),
37    /// Unexpected end of file when reading.
38    #[error("unexpected end of file")]
39    UnexpectedEof,
40    /// Invalid CRC checksum.
41    #[error(transparent)]
42    Crc(#[from] CrcError),
43    /// Unexpected response from the Modbus server.
44    #[error("unexpected response from server")]
45    UnexpectedResponse,
46}
47
48impl<E> From<ValidationError> for Error<E> {
49    fn from(e: ValidationError) -> Self {
50        match e {
51            ValidationError::Crc(crc) => Error::Crc(crc),
52            ValidationError::UnexpectedResponse => Error::UnexpectedResponse,
53        }
54    }
55}
56
57impl<E> From<ReadExactError<E>> for Error<E> {
58    fn from(e: ReadExactError<E>) -> Self {
59        match e {
60            ReadExactError::Other(e) => Self::Io(e),
61            ReadExactError::UnexpectedEof => Self::UnexpectedEof,
62        }
63    }
64}