rs-modbus 0.1.0

A pure Rust implementation of MODBUS protocol.
Documentation
use crate::error::ModbusError;
use crate::layers::application::ApplicationLayer;
use crate::types::{ApplicationDataUnit, FramedDataUnit};
use std::sync::atomic::{AtomicU16, Ordering};

#[derive(Default)]
pub struct TcpApplicationLayer {
    transaction_id: AtomicU16,
}

impl TcpApplicationLayer {
    pub fn new() -> Self {
        Self::default()
    }
}

impl ApplicationLayer for TcpApplicationLayer {
    fn encode(&self, adu: &ApplicationDataUnit) -> Vec<u8> {
        let data_len = adu.data.len();
        let mut buf = vec![0u8; data_len + 8];
        let tx = adu.transaction.unwrap_or_else(|| {
            let current = self.transaction_id.fetch_add(1, Ordering::Relaxed);
            if current == 0 {
                self.transaction_id.store(1, Ordering::Relaxed);
            }
            current.wrapping_add(1)
        });
        buf[0..2].copy_from_slice(&tx.to_be_bytes());
        buf[2..4].copy_from_slice(&[0x00, 0x00]);
        buf[4..6].copy_from_slice(&((data_len + 2) as u16).to_be_bytes());
        buf[6] = adu.unit;
        buf[7] = adu.fc;
        buf[8..].copy_from_slice(&adu.data);
        buf
    }

    fn decode(&self, data: &[u8]) -> Result<FramedDataUnit, ModbusError> {
        if data.len() < 8 {
            return Err(ModbusError::InsufficientData);
        }
        if data[2] != 0 || data[3] != 0 {
            return Err(ModbusError::InvalidData);
        }
        let len = u16::from_be_bytes([data[4], data[5]]) as usize;
        if len + 6 != data.len() {
            return Err(ModbusError::InvalidData);
        }
        let transaction = u16::from_be_bytes([data[0], data[1]]);
        let unit = data[6];
        let fc = data[7];
        let payload = data[8..].to_vec();
        Ok(FramedDataUnit {
            adu: ApplicationDataUnit {
                transaction: Some(transaction),
                unit,
                fc,
                data: payload,
            },
            raw: data.to_vec(),
        })
    }
}