1use std::{
6 error, fmt,
7 fs::OpenOptions,
8 io,
9 os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
10};
11
12pub struct I2cBus(RawFd);
13
14#[derive(Debug)]
18pub struct I2cError(io::Error);
19
20impl fmt::Display for I2cError {
21 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22 write!(f, "{}", self.0)
23 }
24}
25
26impl From<io::Error> for I2cError {
27 fn from(err: io::Error) -> I2cError {
28 I2cError(err)
29 }
30}
31
32impl error::Error for I2cError {
33 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
34 Some(&self.0)
35 }
36}
37
38impl embedded_hal::i2c::Error for I2cError {
39 fn kind(&self) -> embedded_hal::i2c::ErrorKind {
40 use embedded_hal::i2c::ErrorKind::*;
41 match self.0.raw_os_error() {
42 Some(libc::EALREADY) => Bus,
43 Some(libc::EOVERFLOW) => Overrun, _ => Other,
46 }
47 }
48}
49
50impl FromRawFd for I2cBus {
51 unsafe fn from_raw_fd(fd: RawFd) -> Self {
52 I2cBus(fd)
53 }
54}
55
56impl IntoRawFd for I2cBus {
57 fn into_raw_fd(self) -> RawFd {
58 self.0
59 }
60}
61
62impl AsRawFd for I2cBus {
63 fn as_raw_fd(&self) -> RawFd {
64 self.0
65 }
66}
67
68impl Drop for I2cBus {
69 fn drop(&mut self) {
70 unsafe { libc::close(self.0) };
71 }
72}
73
74impl I2cBus {
75 pub fn from_unit(unit: u32) -> Result<I2cBus, I2cError> {
76 Self::from_path(format!("/dev/iic{}", unit))
77 }
78
79 pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> Result<I2cBus, I2cError> {
80 OpenOptions::new()
81 .read(true)
82 .write(true)
83 .open(path)
84 .map(|f| I2cBus(f.into_raw_fd()))
85 .map_err(|e| e.into())
86 }
87}
88
89impl embedded_hal::i2c::blocking::Read for I2cBus {
90 type Error = I2cError;
91
92 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
93 rdwr(
94 self.0,
95 &[iic_msg {
96 addr: (address as u16) << 1,
97 flags: IIC_M_RD,
98 len: buffer.len() as u16,
99 buf: buffer as *const _ as *mut _,
100 }],
101 )
102 }
103}
104
105impl embedded_hal::i2c::blocking::Write for I2cBus {
106 type Error = I2cError;
107
108 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
109 rdwr(
110 self.0,
111 &[iic_msg {
112 addr: (address as u16) << 1,
113 flags: IIC_M_WR,
114 len: bytes.len() as u16,
115 buf: bytes as *const _ as *mut _,
116 }],
117 )
118 }
119}
120
121impl embedded_hal::i2c::blocking::WriteIter for I2cBus {
122 type Error = I2cError;
123
124 fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
125 where
126 B: IntoIterator<Item = u8>,
127 {
128 use embedded_hal::i2c::blocking::Write;
129 self.write(address, &mut bytes.into_iter().collect::<Vec<_>>())
130 }
131}
132
133impl embedded_hal::i2c::blocking::WriteRead for I2cBus {
134 type Error = I2cError;
135
136 fn write_read(
137 &mut self,
138 address: u8,
139 bytes: &[u8],
140 buffer: &mut [u8],
141 ) -> Result<(), Self::Error> {
142 rdwr(
143 self.0,
144 &[
145 iic_msg {
146 addr: (address as u16) << 1,
147 flags: IIC_M_WR | IIC_M_NOSTOP,
148 len: bytes.len() as u16,
149 buf: bytes as *const _ as *mut _,
150 },
151 iic_msg {
152 addr: (address as u16) << 1,
153 flags: IIC_M_RD,
154 len: buffer.len() as u16,
155 buf: buffer as *const _ as *mut _,
156 },
157 ],
158 )
159 }
160}
161
162impl embedded_hal::i2c::blocking::WriteIterRead for I2cBus {
163 type Error = I2cError;
164
165 fn write_iter_read<B>(
166 &mut self,
167 address: u8,
168 bytes: B,
169 buffer: &mut [u8],
170 ) -> Result<(), Self::Error>
171 where
172 B: IntoIterator<Item = u8>,
173 {
174 use embedded_hal::i2c::blocking::WriteRead;
175 self.write_read(address, &mut bytes.into_iter().collect::<Vec<_>>(), buffer)
176 }
177}
178
179#[derive(PartialEq)]
180enum OpState {
181 First,
182 WasRead,
183 WasWrite,
184}
185
186impl embedded_hal::i2c::blocking::Transactional for I2cBus {
187 type Error = I2cError;
188
189 fn exec<'a>(
190 &mut self,
191 address: u8,
192 operations: &mut [embedded_hal::i2c::blocking::Operation<'a>],
193 ) -> Result<(), Self::Error> {
194 let mut st = OpState::First;
195 let mut msgs = Vec::with_capacity(operations.len());
196 let mut it = operations.into_iter().peekable();
197
198 while let Some(op) = it.next() {
199 use embedded_hal::i2c::blocking::Operation;
200
201 msgs.push(match op {
202 Operation::Read(buffer) => {
203 let prev_was_read = st == OpState::WasRead;
204 st = OpState::WasRead;
205 iic_msg {
206 addr: (address as u16) << 1,
207 flags: IIC_M_RD
208 | if it.peek().is_some() { IIC_M_NOSTOP } else { 0 }
209 | if prev_was_read { IIC_M_NOSTART } else { 0 },
210 len: buffer.len() as u16,
211 buf: buffer as *const _ as *mut _,
212 }
213 },
214 Operation::Write(bytes) => {
215 let prev_was_write = st == OpState::WasWrite;
216 st = OpState::WasWrite;
217 iic_msg {
218 addr: (address as u16) << 1,
219 flags: IIC_M_WR
220 | if it.peek().is_some() { IIC_M_NOSTOP } else { 0 }
221 | if prev_was_write { IIC_M_NOSTART } else { 0 },
222 len: bytes.len() as u16,
223 buf: bytes as *const _ as *mut _,
224 }
225 },
226 });
227 }
228
229 rdwr(self.0, &msgs[..])
230 }
231}
232
233impl embedded_hal::i2c::blocking::TransactionalIter for I2cBus {
234 type Error = I2cError;
235
236 fn exec_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
237 where
238 O: IntoIterator<Item = embedded_hal::i2c::blocking::Operation<'a>>,
239 {
240 use embedded_hal::i2c::blocking::Transactional;
245 self.exec(address, &mut operations.into_iter().collect::<Vec<_>>())
246 }
247}
248
249const IIC_M_WR: u16 = 0x00;
250const IIC_M_RD: u16 = 0x01;
251const IIC_M_NOSTOP: u16 = 0x02;
252const IIC_M_NOSTART: u16 = 0x04;
253
254#[repr(C)]
255#[allow(non_camel_case_types)]
256struct iic_msg {
257 addr: u16,
258 flags: u16,
259 len: u16,
260 buf: *mut u8,
261}
262
263#[repr(C)]
264#[allow(non_camel_case_types)]
265struct iic_rdwr_data {
266 msgs: *const iic_msg,
267 nmsgs: u32,
268}
269
270fn rdwr(fd: RawFd, msgs: &[iic_msg]) -> Result<(), I2cError> {
271 let mut dat = iic_rdwr_data { msgs: msgs.as_ptr(), nmsgs: msgs.len() as u32 };
272 let res = unsafe {
273 libc::ioctl(fd, 0x80106906 , &mut dat as *mut _)
274 };
275 if res == -1 {
276 return Err(I2cError(io::Error::last_os_error()));
277 }
278 Ok(())
279}