linux_embedded_hal/
i2c.rs
1use std::fmt;
6use std::ops;
7use std::path::{Path, PathBuf};
8
9use embedded_hal::i2c::NoAcknowledgeSource;
10
11pub struct I2cdev {
15 inner: i2cdev::linux::LinuxI2CDevice,
16 path: PathBuf,
17 address: Option<u16>,
18}
19
20impl I2cdev {
21 pub fn new<P>(path: P) -> Result<Self, i2cdev::linux::LinuxI2CError>
25 where
26 P: AsRef<Path>,
27 {
28 let dev = I2cdev {
29 path: path.as_ref().to_path_buf(),
30 inner: i2cdev::linux::LinuxI2CDevice::new(path, 0)?,
31 address: None,
32 };
33 Ok(dev)
34 }
35
36 fn set_address(&mut self, address: u16) -> Result<(), i2cdev::linux::LinuxI2CError> {
37 if self.address != Some(address) {
38 self.inner = i2cdev::linux::LinuxI2CDevice::new(&self.path, address)?;
39 self.address = Some(address);
40 }
41 Ok(())
42 }
43}
44
45impl ops::Deref for I2cdev {
46 type Target = i2cdev::linux::LinuxI2CDevice;
47
48 fn deref(&self) -> &Self::Target {
49 &self.inner
50 }
51}
52
53impl ops::DerefMut for I2cdev {
54 fn deref_mut(&mut self) -> &mut Self::Target {
55 &mut self.inner
56 }
57}
58
59mod embedded_hal_impl {
60 use super::*;
61 use embedded_hal::i2c::ErrorType;
62 use embedded_hal::i2c::{I2c, Operation as I2cOperation, SevenBitAddress, TenBitAddress};
63 use i2cdev::core::{I2CMessage, I2CTransfer};
64 use i2cdev::linux::LinuxI2CMessage;
65 impl ErrorType for I2cdev {
66 type Error = I2CError;
67 }
68
69 impl I2c<TenBitAddress> for I2cdev {
70 fn transaction(
71 &mut self,
72 address: u16,
73 operations: &mut [I2cOperation],
74 ) -> Result<(), Self::Error> {
75 let mut messages: Vec<_> = operations
77 .as_mut()
78 .iter_mut()
79 .map(|a| match a {
80 I2cOperation::Write(w) => LinuxI2CMessage::write(w),
81 I2cOperation::Read(r) => LinuxI2CMessage::read(r),
82 })
83 .collect();
84
85 self.set_address(address)?;
86 self.inner
87 .transfer(&mut messages)
88 .map(drop)
89 .map_err(|err| I2CError { err })
90 }
91 }
92
93 impl I2c<SevenBitAddress> for I2cdev {
94 fn transaction(
95 &mut self,
96 address: u8,
97 operations: &mut [I2cOperation],
98 ) -> Result<(), Self::Error> {
99 I2c::<TenBitAddress>::transaction(self, u16::from(address), operations)
100 }
101 }
102}
103
104#[derive(Debug)]
106pub struct I2CError {
107 err: i2cdev::linux::LinuxI2CError,
108}
109
110impl I2CError {
111 pub fn inner(&self) -> &i2cdev::linux::LinuxI2CError {
113 &self.err
114 }
115}
116
117impl From<i2cdev::linux::LinuxI2CError> for I2CError {
118 fn from(err: i2cdev::linux::LinuxI2CError) -> Self {
119 Self { err }
120 }
121}
122
123impl fmt::Display for I2CError {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{}", self.err)
126 }
127}
128
129impl std::error::Error for I2CError {
130 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
131 Some(&self.err)
132 }
133}
134
135impl embedded_hal::i2c::Error for I2CError {
136 fn kind(&self) -> embedded_hal::i2c::ErrorKind {
137 use embedded_hal::i2c::ErrorKind;
138 use nix::errno::Errno::*;
139
140 let errno = match &self.err {
141 i2cdev::linux::LinuxI2CError::Errno(e) => nix::Error::from_i32(*e),
142 i2cdev::linux::LinuxI2CError::Io(e) => match e.raw_os_error() {
143 Some(r) => nix::Error::from_i32(r),
144 None => return ErrorKind::Other,
145 },
146 };
147
148 match errno {
150 EBUSY | EINVAL | EIO => ErrorKind::Bus,
151 EAGAIN => ErrorKind::ArbitrationLoss,
152 ENODEV => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data),
153 ENXIO => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
154 _ => ErrorKind::Other,
155 }
156 }
157}