i2c_tiny_usb/
i2c_impl.rs

1use crate::{error::*, protocol};
2use rusb::{Device, DeviceHandle, GlobalContext, UsbContext};
3use std::io::{Read, Write};
4
5pub struct I2c<T: UsbContext> {
6    device_handle: DeviceHandle<T>,
7    supported_flags: (i2c::ReadFlags, i2c::WriteFlags),
8    address: u16,
9}
10
11impl<T: UsbContext> I2c<T> {
12    #[inline]
13    fn open(device: &Device<T>) -> Result<Self> {
14        let device_handle = device.open()?;
15        device_handle.claim_interface(0)?;
16        let supported_flags = protocol::check_device(&device_handle)?;
17        Ok(Self {
18            device_handle,
19            supported_flags,
20            address: 0u16,
21        })
22    }
23}
24
25impl I2c<GlobalContext> {
26    pub fn open_single_device() -> Result<Self> {
27        let devs = crate::devices();
28        if devs.is_empty() {
29            return Err(rusb::Error::NoDevice.into());
30        }
31        if devs.len() > 1 {
32            return Err(rusb::Error::Other.into());
33        }
34        I2c::open(&devs[0])
35    }
36}
37
38impl<T: UsbContext> i2c::Master for I2c<T> {
39    type Error = Error;
40}
41
42impl<T: UsbContext> i2c::Address for I2c<T> {
43    fn set_slave_address(&mut self, addr: u16, tenbit: bool) -> Result<()> {
44        if tenbit {
45            Err(rusb::Error::NotSupported.into())
46        } else {
47            self.address = addr;
48            Ok(())
49        }
50    }
51}
52
53impl<T: UsbContext> Read for I2c<T> {
54    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
55        protocol::transfer(
56            &self.device_handle,
57            &mut [i2c::Message::Read {
58                address: self.address,
59                data: buf,
60                flags: Default::default(),
61            }],
62        )?;
63        Ok(buf.len())
64    }
65}
66
67impl<T: UsbContext> Write for I2c<T> {
68    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
69        protocol::transfer(
70            &self.device_handle,
71            &mut [i2c::Message::Write {
72                address: self.address,
73                data: buf,
74                flags: Default::default(),
75            }],
76        )?;
77        Ok(buf.len())
78    }
79
80    fn flush(&mut self) -> std::io::Result<()> {
81        Ok(()) // noop since no buffering is performed
82    }
83}
84
85// i2c::ReadWrite should be automatically implemented as long as requirements are met
86#[allow(dead_code)]
87const fn assert_impl_readwrite<T: i2c::ReadWrite>() {}
88const _: () = assert_impl_readwrite::<I2c<GlobalContext>>();
89
90impl<T: UsbContext> i2c::BulkTransfer for I2c<T> {
91    fn i2c_transfer_support(&mut self) -> Result<(i2c::ReadFlags, i2c::WriteFlags)> {
92        Ok(self.supported_flags)
93    }
94
95    fn i2c_transfer(&mut self, messages: &mut [i2c::Message]) -> Result<()> {
96        protocol::transfer(&self.device_handle, messages)
97    }
98}