#![doc = include_str!("../README.md")]
#[macro_use]
extern crate scan_fmt;
use std::io::prelude::*;
use std::marker::PhantomData;
use std::time::Duration;
mod error;
pub use crate::error::{Error, ProtocolError};
mod status;
pub use crate::status::Status;
pub struct I2CDriver<MODE> {
mode: PhantomData<MODE>,
serial: Box<dyn serialport::SerialPort>,
}
impl I2CDriver<NormalMode> {
pub fn open(port: &str) -> Result<Self, Error> {
let serial = serialport::new(port, 1_000_000)
.data_bits(serialport::DataBits::Eight)
.flow_control(serialport::FlowControl::None)
.parity(serialport::Parity::None)
.stop_bits(serialport::StopBits::One)
.timeout(Duration::from_millis(1000))
.open()
.map_err(|source| Error::Open {
path: port.to_string(),
source,
})?;
let mut d = I2CDriver::<NormalMode> {
mode: PhantomData,
serial,
};
d.reset_driver()?;
Ok(d)
}
pub fn echo(&mut self, char: u8) -> Result<u8, Error> {
self.serial.write_all(&[b'e', char])?;
self.serial.flush()?;
let mut buf = [0u8; 1];
self.serial.read_exact(&mut buf)?;
Ok(buf[0])
}
pub fn reboot(&mut self) -> Result<(), Error> {
self.serial.write_all(&[b'_'])?;
self.serial.flush()?;
Ok(())
}
pub fn reset(&mut self) -> Result<(), Error> {
self.serial.write_all(&[b'x'])?;
self.serial.flush()?;
let mut buf = [0u8; 1];
self.serial.read_exact(&mut buf)?;
if buf[0] & 0b11 != 0b11 {
Err(Error::Arbitration)
} else {
Ok(())
}
}
pub fn status(&mut self) -> Result<Status, Error> {
self.serial.write_all(&[b'?'])?;
self.serial.flush()?;
let mut buf = [0u8; 80];
self.serial.read_exact(&mut buf)?;
let st = std::str::from_utf8(&buf).map_err(|e| Error::Protocol(e.into()))?;
st.parse()
}
pub fn speed100k(&mut self) -> Result<(), Error> {
self.serial.write_all(&[b'1'])?;
self.serial.flush()?;
Ok(())
}
pub fn speed400k(&mut self) -> Result<(), Error> {
self.serial.write_all(&[b'4'])?;
self.serial.flush()?;
Ok(())
}
pub fn scan(&mut self) -> Result<Vec<u8>, Error> {
self.serial.write_all(&[b'd'])?;
self.serial.flush()?;
let mut buf = [0u8; 112];
self.serial.read_exact(&mut buf)?;
Ok(buf
.into_iter()
.enumerate()
.filter_map(|(i, r)| {
if r == b'1' {
Some(<usize as TryInto<u8>>::try_into(i).unwrap() + 8)
} else {
None
}
})
.collect())
}
pub fn start_monitor(mut self) -> Result<I2CDriver<MonitorMode>, Error> {
self.serial.write_all(&[b'm'])?;
self.serial.flush()?;
Ok(I2CDriver::<MonitorMode> {
mode: PhantomData,
serial: self.serial,
})
}
pub fn start(&mut self, addr7: u8, read: bool) -> Result<(), Error> {
if addr7 & 0x80 != 0 {
return Err(Error::Address(addr7));
}
self.serial.write_all(&[b's', addr7 << 1 | read as u8])?;
self.serial.flush()?;
let mut buf = [0u8; 1];
self.serial.read_exact(&mut buf)?;
match buf[0] & 0b111 {
1 => Ok(()),
0b100 => Err(Error::Arbitration),
0b010 => Err(Error::Timeout),
0 => Err(Error::MissingAddrAck),
_ => Err(ProtocolError::Parse(buf.to_vec()).into()),
}
}
pub fn stop(&mut self) -> Result<(), Error> {
self.serial.write_all(&[b'p'])?;
self.serial.flush()?;
Ok(())
}
pub fn raw_write(&mut self, buf: &[u8]) -> Result<(), Error> {
for chunk in buf.chunks(64) {
self.serial
.write_all(&[0b11000000 | (chunk.len() - 1) as u8])?;
self.serial.write_all(chunk)?;
self.serial.flush()?;
let mut buf = [0u8; 1];
self.serial.read_exact(&mut buf)?;
match buf[0] & 0b111 {
0b100 => return Err(Error::Arbitration),
0b010 => return Err(Error::Timeout),
0 => return Err(Error::MissingDataAck),
_ => continue,
}
}
Ok(())
}
pub fn raw_read_into(&mut self, buf: &mut [u8], nak: bool) -> Result<(), Error> {
let mut iter: std::iter::Peekable<std::slice::ChunksMut<'_, u8>> =
buf.chunks_mut(64).peekable();
while let Some(chunk) = iter.next() {
if iter.peek().is_none() && nak {
self.serial
.write_all(&[0b10000000 | (chunk.len() - 1) as u8])?;
} else {
self.serial.write_all(&[b'a', chunk.len() as u8])?;
}
self.serial.flush()?;
self.serial.read_exact(chunk)?;
}
Ok(())
}
}
impl<T> I2CDriver<T> {
fn reset_driver(&mut self) -> Result<(), Error> {
self.serial.write_all(&[0x20, b'i'])?;
self.serial.flush()?;
Ok(())
}
}
impl I2CDriver<MonitorMode> {
pub fn stop_monitor(mut self) -> Result<I2CDriver<NormalMode>, Error> {
self.reset_driver()?;
Ok(I2CDriver::<NormalMode> {
mode: PhantomData,
serial: self.serial,
})
}
}
pub struct MonitorMode;
pub struct NormalMode;
#[cfg(feature = "eh1")]
impl embedded_hal_1::i2c::ErrorType for I2CDriver<NormalMode> {
type Error = Error;
}
#[cfg(feature = "eh1")]
impl embedded_hal_1::i2c::I2c<embedded_hal_1::i2c::SevenBitAddress> for I2CDriver<NormalMode> {
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
#[derive(PartialEq)]
enum RWState {
None,
Reading,
Writing,
}
let mut previous = RWState::None;
let last = operations.len() - 1;
for (i, op) in operations.iter_mut().enumerate() {
match op {
embedded_hal_1::i2c::Operation::Write(bytes) => {
if previous != RWState::Writing {
self.start(address, false)?;
}
self.raw_write(bytes)?;
previous = RWState::Writing;
}
embedded_hal_1::i2c::Operation::Read(buffer) => {
if previous != RWState::Reading {
self.start(address, true)?;
}
self.raw_read_into(buffer, i == last)?;
previous = RWState::Reading;
}
}
}
self.stop()?;
Ok(())
}
}
#[cfg(feature = "async")]
impl embedded_hal_async::i2c::I2c<embedded_hal_1::i2c::SevenBitAddress> for I2CDriver<NormalMode> {
async fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
embedded_hal_1::i2c::I2c::<embedded_hal_1::i2c::SevenBitAddress>::transaction(
self, address, operations,
)
}
}
#[cfg(feature = "eh0")]
impl embedded_hal_0::blocking::i2c::Write for I2CDriver<NormalMode> {
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.start(addr, false)?;
self.raw_write(bytes)?;
self.stop()?;
Ok(())
}
}
#[cfg(feature = "eh0")]
impl embedded_hal_0::blocking::i2c::Read for I2CDriver<NormalMode> {
type Error = Error;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.start(address, true)?;
self.raw_read_into(buffer, true)?;
self.stop()?;
Ok(())
}
}
#[cfg(feature = "eh0")]
impl embedded_hal_0::blocking::i2c::WriteRead for I2CDriver<NormalMode> {
type Error = Error;
fn write_read(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
if !bytes.is_empty() {
self.start(address, false)?;
self.raw_write(bytes)?;
}
if !buffer.is_empty() {
self.start(address, true)?;
self.raw_read_into(buffer, true)?;
}
self.stop()?;
Ok(())
}
}