espflash 0.1.1

ESP8266 and ESP32 serial flasher
Documentation
use std::io::Write;
use std::thread::sleep;
use std::time::Duration;

use crate::encoder::SlipEncoder;
use crate::error::{Error, RomError};
use binread::io::Cursor;
use binread::{BinRead, BinReaderExt};
use serial::SerialPort;
use slip_codec::Decoder;

pub struct Connection {
    serial: Box<dyn SerialPort>,
    decoder: Decoder,
}

#[derive(Debug, Copy, Clone, BinRead)]
pub struct CommandResponse {
    pub resp: u8,
    pub return_op: u8,
    pub return_length: u16,
    pub value: u32,
    pub status: u8,
    pub error: u8,
}

impl Connection {
    pub fn new(serial: impl SerialPort + 'static) -> Self {
        Connection {
            serial: Box::new(serial),
            decoder: Decoder::new(1024),
        }
    }

    pub fn reset(&mut self) -> Result<(), Error> {
        sleep(Duration::from_millis(100));

        self.serial.set_dtr(false)?;
        self.serial.set_rts(true)?;

        sleep(Duration::from_millis(100));

        self.serial.set_rts(false)?;

        Ok(())
    }

    pub fn reset_to_flash(&mut self) -> Result<(), Error> {
        self.serial.set_dtr(false)?;
        self.serial.set_rts(true)?;

        sleep(Duration::from_millis(100));

        self.serial.set_dtr(true)?;
        self.serial.set_rts(false)?;

        sleep(Duration::from_millis(50));

        self.serial.set_dtr(true)?;

        Ok(())
    }

    pub fn set_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
        self.serial.set_timeout(timeout)?;
        Ok(())
    }

    pub fn with_timeout<T, F: FnMut(&mut Connection) -> Result<T, Error>>(
        &mut self,
        timeout: Duration,
        mut f: F,
    ) -> Result<T, Error> {
        let old_timeout = self.serial.timeout();
        self.serial.set_timeout(timeout)?;
        let result = f(self);
        self.serial.set_timeout(old_timeout)?;
        result
    }

    pub fn read_response(&mut self) -> Result<Option<CommandResponse>, Error> {
        let response = self.read()?;
        if response.len() < 10 {
            return Ok(None);
        }

        let mut cursor = Cursor::new(response);
        let header = cursor.read_le()?;

        Ok(Some(header))
    }

    pub fn write_command(
        &mut self,
        command: u8,
        data: impl LazyBytes<Box<dyn SerialPort>>,
        check: u32,
    ) -> Result<(), Error> {
        let mut encoder = SlipEncoder::new(&mut self.serial)?;
        encoder.write(&[0])?;
        encoder.write(&[command])?;
        encoder.write(&(data.length().to_le_bytes()))?;
        encoder.write(&(check.to_le_bytes()))?;
        data.write(&mut encoder)?;
        encoder.finish()?;
        Ok(())
    }

    pub fn command<'a, Data: LazyBytes<Box<dyn SerialPort>>>(
        &mut self,
        command: u8,
        data: Data,
        check: u32,
    ) -> Result<u32, Error> {
        self.write_command(command, data, check)?;

        match self.read_response()? {
            Some(response) if response.return_op == command as u8 => {
                if response.status == 1 {
                    Err(Error::RomError(RomError::from(response.error)))
                } else {
                    Ok(response.value)
                }
            }
            _ => Err(Error::ConnectionFailed),
        }
    }

    fn read(&mut self) -> Result<Vec<u8>, Error> {
        Ok(self.decoder.decode(&mut self.serial)?)
    }

    pub fn flush(&mut self) -> Result<(), Error> {
        self.serial.flush()?;
        Ok(())
    }
}

pub trait LazyBytes<W: Write> {
    fn write(self, encoder: &mut SlipEncoder<W>) -> Result<(), Error>;

    fn length(&self) -> u16;
}

impl<W: Write> LazyBytes<W> for &[u8] {
    fn write(self, encoder: &mut SlipEncoder<W>) -> Result<(), Error> {
        encoder.write(self)?;
        Ok(())
    }

    fn length(&self) -> u16 {
        self.len() as u16
    }
}

impl<W: Write, F: Fn(&mut SlipEncoder<W>) -> Result<(), Error>> LazyBytes<W> for (u16, F) {
    fn write(self, encoder: &mut SlipEncoder<W>) -> Result<(), Error> {
        self.1(encoder)
    }

    fn length(&self) -> u16 {
        self.0
    }
}