serialport_srwp 2.0.0

A simple serial port protocol (SRWP) for read/write operations with the Blaustahl Storage Device. Enables memory access via basic commands for data transmission and device control.
Documentation
use std::{
    thread::sleep,
    time::{Duration, Instant},
};

use super::{DeviceError, SerialPortDataManager};

const SRWP_CMD: u8 = 0x00;
const CMD_TEST: u8 = 0x00;
const CMD_READ: u8 = 0x01;
const CMD_WRITE: u8 = 0x02;
const MAX_BYTES_PER_SECOND: u64 = 9600 / 8;
const MAX_BYTES_PER_TRANSACTION: u32 = 32;
const MAX_TIME_PER_TRANSACTION: u64 =
    1000 * MAX_BYTES_PER_TRANSACTION as u64 / MAX_BYTES_PER_SECOND;

impl SerialPortDataManager {
    pub fn test(&mut self, data: &[u8]) -> Result<Vec<u8>, DeviceError> {
        let serial_port = self.get_serial_port()?;
        serial_port.clear()?;

        let mut buffer = vec![0u8; 6 + data.len()];
        buffer[0] = SRWP_CMD;
        buffer[1] = CMD_TEST;
        buffer[2..6].copy_from_slice(&(data.len() as u32).to_le_bytes());
        buffer[6..].copy_from_slice(data);

        serial_port.write_data_terminal_ready(true)?;
        serial_port.write_request_to_send(true)?;
        serial_port.write(&buffer)?;
        serial_port.flush()?;
        serial_port.write_request_to_send(false)?;
        serial_port.write_data_terminal_ready(false)?;

        let mut data = vec![0u8; data.len()];
        serial_port.read(&mut data)?;
        Ok(data)
    }

    fn _read_data(&mut self, address: u32, length: u32) -> Result<Vec<u8>, DeviceError> {
        let serial_port = self.get_serial_port()?;
        serial_port.clear()?;

        let mut buffer = vec![0u8; 10];
        buffer[0] = SRWP_CMD;
        buffer[1] = CMD_READ;
        buffer[2..6].copy_from_slice(&address.to_le_bytes());
        buffer[6..10].copy_from_slice(&length.to_le_bytes());

        serial_port.write_data_terminal_ready(true)?;
        serial_port.write_request_to_send(true)?;
        serial_port.write(&buffer)?;
        serial_port.flush()?;
        serial_port.write_request_to_send(false)?;
        serial_port.write_data_terminal_ready(false)?;

        serial_port.read_data_set_ready()?;
        let mut count = 0u32;
        let mut data = vec![0u8; length as usize];
        while count < data.len() as u32 {
            let size = serial_port.read(&mut data[count as usize..])?;
            count += size as u32;
        }
        Ok(data)
    }

    fn _write_data(&mut self, address: u32, data: &[u8]) -> Result<(), DeviceError> {
        let serial_port = self.get_serial_port()?;
        serial_port.clear()?;

        let mut buffer = vec![0u8; 10 + data.len()];
        buffer[0] = SRWP_CMD;
        buffer[1] = CMD_WRITE;
        buffer[2..6].copy_from_slice(&address.to_le_bytes());
        buffer[6..10].copy_from_slice(&(data.len() as u32).to_le_bytes());
        buffer[10..].copy_from_slice(data);

        serial_port.write_data_terminal_ready(true)?;
        serial_port.write_request_to_send(true)?;
        serial_port.write(&buffer)?;
        serial_port.flush()?;
        serial_port.write_request_to_send(false)?;
        serial_port.write_data_terminal_ready(false)?;
        Ok(())
    }

    pub fn read_data(&mut self, address: u32, length: u32) -> Result<Vec<u8>, DeviceError> {
        let mut data = Vec::new();
        let mut count = 0u32;
        while count < length {
            let start_time = Instant::now();
            let size = std::cmp::min(length - count, MAX_BYTES_PER_TRANSACTION);
            let data_part = self._read_data(address + count, size)?;
            data.extend_from_slice(&data_part);
            count += size;
            let elapsed = start_time.elapsed().as_millis() as u64;
            if elapsed < MAX_TIME_PER_TRANSACTION {
                sleep(Duration::from_millis(MAX_TIME_PER_TRANSACTION - elapsed));
            }
        }
        Ok(data)
    }

    pub fn write_data(&mut self, address: u32, data: &[u8]) -> Result<(), DeviceError> {
        let mut count = 0u32;
        while count < data.len() as u32 {
            let start_time = Instant::now();
            let size = std::cmp::min(data.len() as u32 - count, MAX_BYTES_PER_TRANSACTION);
            self._write_data(
                address + count,
                &data[count as usize..count as usize + size as usize],
            )?;
            count += size;
            let elapsed = start_time.elapsed().as_millis() as u64;
            if elapsed < MAX_TIME_PER_TRANSACTION {
                sleep(Duration::from_millis(MAX_TIME_PER_TRANSACTION - elapsed));
            }
        }
        Ok(())
    }
}