async-modbus 0.7.1

A lightweight asynchronous Modbus protocol implementation for embedded environments.
Documentation
//! Client functions for [`embedded_io_async`]-based IO.

use core::error::Error as CoreError;
use std::fmt::Debug;

use defmt_or_log::*;
use embedded_io_async::{Read, ReadExactError, Write};
use zerocopy::{FromBytes, Immutable, IntoBytes};

mod generated {
    include!(concat!(env!("OUT_DIR"), "/client.rs"));
}

pub use generated::*;

use crate::pdu::{CrcError, ValidationError};

async fn write_frame<T, E>(mut dst: impl Write<Error = E>, frame: &T) -> Result<(), E>
where
    T: IntoBytes + Immutable + Debug,
{
    trace!("Writing frame: {:?}", frame);
    dst.write_all(frame.as_bytes()).await?;
    dst.flush().await
}

async fn read_frame<T, E>(mut src: impl Read<Error = E>) -> Result<T, ReadExactError<E>>
where
    T: FromBytes + IntoBytes + Debug,
{
    let mut message = T::new_zeroed();
    src.read_exact(message.as_mut_bytes()).await?;
    trace!("Read frame: {:?}", message);
    Ok(message)
}

/// Errors that can occur when talking to a Modbus server.
#[derive(Debug, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error<Io: CoreError> {
    /// IO error.
    #[error(transparent)]
    Io(Io),
    /// Unexpected end of file when reading.
    #[error("unexpected end of file")]
    UnexpectedEof,
    /// Invalid CRC checksum.
    #[error(transparent)]
    Crc(#[from] CrcError),
    /// Unexpected response from the Modbus server.
    #[error("unexpected response from server")]
    UnexpectedResponse,
}

impl<E: CoreError> From<ValidationError> for Error<E> {
    fn from(e: ValidationError) -> Self {
        match e {
            ValidationError::Crc(crc) => Error::Crc(crc),
            ValidationError::UnexpectedResponse => Error::UnexpectedResponse,
        }
    }
}

impl<E: CoreError> From<ReadExactError<E>> for Error<E> {
    fn from(e: ReadExactError<E>) -> Self {
        match e {
            ReadExactError::Other(e) => Self::Io(e),
            ReadExactError::UnexpectedEof => Self::UnexpectedEof,
        }
    }
}