i2cdev/
linux.rs

1// Copyright 2015, Paul Osborne <osbpau@gmail.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option.  This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use core::{I2CDevice, I2CTransfer};
10use ffi;
11use nix;
12use std::error::Error;
13use std::fmt;
14use std::fs::File;
15use std::fs::OpenOptions;
16use std::io;
17use std::io::prelude::*;
18use std::marker::PhantomData;
19use std::os::unix::prelude::*;
20use std::path::Path;
21
22// Expose these core structs from this module
23pub use core::I2CMessage;
24
25/// Concrete linux I2C device
26pub struct LinuxI2CDevice {
27    devfile: File,
28    slave_address: u16,
29    pec: bool,
30}
31
32/// Linux I2C bus
33pub struct LinuxI2CBus {
34    devfile: File,
35}
36
37/// Linux I2C errors
38#[derive(Debug)]
39pub enum LinuxI2CError {
40    /// Errno from a failing `libc` call. Sourced  from [`nix`].
41    ///
42    /// To interpret this value [`nix::errno::from_i32`] should be used.
43    ///
44    /// The [`Error`] implementation will not return a source
45    /// for this variant, like the [`Error`] implementation of the underlying `nix` error.
46    ///
47    /// [`nix`]: https://docs.rs/nix/latest/nix/
48    /// [`nix::errno::from_i32`]: https://docs.rs/nix/latest/nix/errno/fn.from_i32.html
49    /// [`Error`]: https://doc.rust-lang.org/std/error/trait.Error.html
50    Errno(i32),
51    /// Input/output error
52    Io(io::Error),
53}
54
55impl From<nix::Error> for LinuxI2CError {
56    fn from(e: nix::Error) -> Self {
57        LinuxI2CError::Errno(e as i32)
58    }
59}
60
61impl From<io::Error> for LinuxI2CError {
62    fn from(e: io::Error) -> Self {
63        LinuxI2CError::Io(e)
64    }
65}
66
67impl From<LinuxI2CError> for io::Error {
68    fn from(e: LinuxI2CError) -> io::Error {
69        match e {
70            LinuxI2CError::Io(e) => e,
71            LinuxI2CError::Errno(e) => io::Error::from_raw_os_error(e),
72        }
73    }
74}
75
76impl fmt::Display for LinuxI2CError {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        match *self {
79            LinuxI2CError::Errno(e) => {
80                let error = nix::Error::from_i32(e);
81                fmt::Display::fmt(&error, f)
82            }
83            LinuxI2CError::Io(ref e) => fmt::Display::fmt(e, f),
84        }
85    }
86}
87
88impl Error for LinuxI2CError {
89    fn cause(&self) -> Option<&dyn Error> {
90        match *self {
91            LinuxI2CError::Io(ref e) => Some(e),
92            LinuxI2CError::Errno(_) => None,
93        }
94    }
95}
96
97impl AsRawFd for LinuxI2CDevice {
98    fn as_raw_fd(&self) -> RawFd {
99        self.devfile.as_raw_fd()
100    }
101}
102
103impl AsRawFd for LinuxI2CBus {
104    fn as_raw_fd(&self) -> RawFd {
105        self.devfile.as_raw_fd()
106    }
107}
108
109impl LinuxI2CDevice {
110    /// Create a new I2CDevice for the specified path
111    pub fn new<P: AsRef<Path>>(
112        path: P,
113        slave_address: u16,
114    ) -> Result<LinuxI2CDevice, LinuxI2CError> {
115        let file = OpenOptions::new().read(true).write(true).open(path)?;
116        let mut device = LinuxI2CDevice {
117            devfile: file,
118            slave_address: 0, // will be set later
119            pec: false,
120        };
121        device.set_slave_address(slave_address)?;
122        device.set_smbus_pec(false)?;
123        Ok(device)
124    }
125
126    /// Create a new I2CDevice for the specified path, without checking if the
127    /// device is bound to a driver
128    ///
129    /// # Safety
130    /// Using this can seriously confuse the original driver, and may cause all
131    /// future communication to perform the wrong operations and/or return wrong results.
132    pub unsafe fn force_new<P: AsRef<Path>>(
133        path: P,
134        slave_address: u16,
135    ) -> Result<LinuxI2CDevice, LinuxI2CError> {
136        let file = OpenOptions::new().read(true).write(true).open(path)?;
137        let mut device = LinuxI2CDevice {
138            devfile: file,
139            slave_address: 0, // will be set later
140            pec: false,
141        };
142        device.force_set_slave_address(slave_address)?;
143        device.set_smbus_pec(false)?;
144        Ok(device)
145    }
146
147    /// Set the slave address for this device
148    ///
149    /// Typically the address is expected to be 7-bits but 10-bit addresses
150    /// may be supported by the kernel driver in some cases.  Little validation
151    /// is done in Rust as the kernel is good at making sure things are valid.
152    ///
153    /// Note that if you have created a device using
154    /// `I2Device::new(...)` it is not necesasry to call this method
155    /// (it is done internally).  Calling this method is only
156    /// necessary if you need to change the slave device and you do
157    /// not want to create a new device.
158    pub fn set_slave_address(&mut self, slave_address: u16) -> Result<(), LinuxI2CError> {
159        ffi::i2c_set_slave_address(self.as_raw_fd(), slave_address)?;
160        self.slave_address = slave_address;
161        Ok(())
162    }
163
164    /// Set the slave address for this device, even if it is already in use
165    /// by a driver
166    ///
167    /// This is private; use `force_new` instead.
168    unsafe fn force_set_slave_address(&mut self, slave_address: u16) -> Result<(), LinuxI2CError> {
169        ffi::i2c_set_slave_address_force(self.as_raw_fd(), slave_address)?;
170        self.slave_address = slave_address;
171        Ok(())
172    }
173
174    /// Enable/Disable PEC support for this device
175    ///
176    /// Used only for SMBus transactions.  This request only has an effect if the
177    /// the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
178    /// doesn't have any effect.
179    pub fn set_smbus_pec(&mut self, enable: bool) -> Result<(), LinuxI2CError> {
180        ffi::i2c_set_smbus_pec(self.as_raw_fd(), enable)?;
181        self.pec = enable;
182        Ok(())
183    }
184}
185
186impl I2CDevice for LinuxI2CDevice {
187    type Error = LinuxI2CError;
188
189    /// Read data from the device to fill the provided slice
190    fn read(&mut self, data: &mut [u8]) -> Result<(), LinuxI2CError> {
191        self.devfile.read_exact(data).map_err(From::from).map(drop)
192    }
193
194    /// Write the provided buffer to the device
195    fn write(&mut self, data: &[u8]) -> Result<(), LinuxI2CError> {
196        self.devfile.write(data).map_err(From::from).map(drop)
197    }
198
199    /// This sends a single bit to the device, at the place of the Rd/Wr bit
200    fn smbus_write_quick(&mut self, bit: bool) -> Result<(), LinuxI2CError> {
201        ffi::i2c_smbus_write_quick(self.as_raw_fd(), bit).map_err(From::from)
202    }
203
204    /// Read a single byte from a device, without specifying a device register
205    ///
206    /// Some devices are so simple that this interface is enough; for
207    /// others, it is a shorthand if you want to read the same register as in
208    /// the previous SMBus command.
209    fn smbus_read_byte(&mut self) -> Result<u8, LinuxI2CError> {
210        ffi::i2c_smbus_read_byte(self.as_raw_fd()).map_err(From::from)
211    }
212
213    /// Write a single byte to a sdevice, without specifying a device register
214    ///
215    /// This is the opposite operation as smbus_read_byte.  As with read_byte,
216    /// no register is specified.
217    fn smbus_write_byte(&mut self, value: u8) -> Result<(), LinuxI2CError> {
218        ffi::i2c_smbus_write_byte(self.as_raw_fd(), value).map_err(From::from)
219    }
220
221    /// Read a single byte from a device, from a designated register
222    ///
223    /// The register is specified through the Comm byte.
224    fn smbus_read_byte_data(&mut self, register: u8) -> Result<u8, LinuxI2CError> {
225        ffi::i2c_smbus_read_byte_data(self.as_raw_fd(), register).map_err(From::from)
226    }
227
228    /// Write a single byte to a specific register on a device
229    ///
230    /// The register is specified through the Comm byte.
231    fn smbus_write_byte_data(&mut self, register: u8, value: u8) -> Result<(), LinuxI2CError> {
232        ffi::i2c_smbus_write_byte_data(self.as_raw_fd(), register, value).map_err(From::from)
233    }
234
235    /// Read 2 bytes form a given register on a device
236    fn smbus_read_word_data(&mut self, register: u8) -> Result<u16, LinuxI2CError> {
237        ffi::i2c_smbus_read_word_data(self.as_raw_fd(), register).map_err(From::from)
238    }
239
240    /// Write 2 bytes to a given register on a device
241    fn smbus_write_word_data(&mut self, register: u8, value: u16) -> Result<(), LinuxI2CError> {
242        ffi::i2c_smbus_write_word_data(self.as_raw_fd(), register, value).map_err(From::from)
243    }
244
245    /// Select a register, send 16 bits of data to it, and read 16 bits of data
246    fn smbus_process_word(&mut self, register: u8, value: u16) -> Result<u16, LinuxI2CError> {
247        ffi::i2c_smbus_process_call(self.as_raw_fd(), register, value).map_err(From::from)
248    }
249
250    /// Read a block of up to 32 bytes from a device
251    ///
252    /// The actual number of bytes available to read is returned in the count
253    /// byte.  This code returns a correctly sized vector containing the
254    /// count bytes read from the device.
255    fn smbus_read_block_data(&mut self, register: u8) -> Result<Vec<u8>, LinuxI2CError> {
256        ffi::i2c_smbus_read_block_data(self.as_raw_fd(), register).map_err(From::from)
257    }
258
259    /// Read a block of up to 32 bytes from a device via i2c_smbus_i2c_read_block_data
260    fn smbus_read_i2c_block_data(
261        &mut self,
262        register: u8,
263        len: u8,
264    ) -> Result<Vec<u8>, LinuxI2CError> {
265        ffi::i2c_smbus_read_i2c_block_data(self.as_raw_fd(), register, len).map_err(From::from)
266    }
267
268    /// Write a block of up to 32 bytes to a device
269    ///
270    /// The opposite of the Block Read command, this writes up to 32 bytes to
271    /// a device, to a designated register that is specified through the
272    /// Comm byte. The amount of data is specified in the Count byte.
273    fn smbus_write_block_data(&mut self, register: u8, values: &[u8]) -> Result<(), LinuxI2CError> {
274        ffi::i2c_smbus_write_block_data(self.as_raw_fd(), register, values).map_err(From::from)
275    }
276
277    /// Write a block of up to 32 bytes from a device via i2c_smbus_i2c_write_block_data
278    fn smbus_write_i2c_block_data(
279        &mut self,
280        register: u8,
281        values: &[u8],
282    ) -> Result<(), LinuxI2CError> {
283        ffi::i2c_smbus_write_i2c_block_data(self.as_raw_fd(), register, values).map_err(From::from)
284    }
285
286    /// Select a register, send 1 to 31 bytes of data to it, and reads
287    /// 1 to 31 bytes of data from it.
288    fn smbus_process_block(
289        &mut self,
290        register: u8,
291        values: &[u8],
292    ) -> Result<Vec<u8>, LinuxI2CError> {
293        ffi::i2c_smbus_process_call_block(self.as_raw_fd(), register, values).map_err(From::from)
294    }
295}
296
297impl<'a> I2CTransfer<'a> for LinuxI2CDevice {
298    type Error = LinuxI2CError;
299    type Message = LinuxI2CMessage<'a>;
300
301    /// Issue the provided sequence of I2C transactions
302    fn transfer(&mut self, messages: &'a mut [Self::Message]) -> Result<u32, LinuxI2CError> {
303        let msg_type = |flag: u16| flag & I2CMessageFlags::READ.bits();
304        let mut prev_msg_type = None;
305        for msg in messages.iter_mut() {
306            msg.addr = self.slave_address;
307
308            let cur_msg_type = msg_type(msg.flags);
309            if prev_msg_type
310                .map(|prev| prev == cur_msg_type)
311                .unwrap_or_default()
312            {
313                msg.flags |= I2CMessageFlags::NO_START.bits();
314            } else {
315                prev_msg_type = Some(cur_msg_type);
316            }
317        }
318        ffi::i2c_rdwr(self.as_raw_fd(), messages).map_err(From::from)
319    }
320}
321
322impl LinuxI2CBus {
323    /// Create a new LinuxI2CBus for the specified path
324    pub fn new<P: AsRef<Path>>(path: P) -> Result<LinuxI2CBus, LinuxI2CError> {
325        let file = OpenOptions::new().read(true).write(true).open(path)?;
326        let bus = LinuxI2CBus { devfile: file };
327        Ok(bus)
328    }
329}
330
331pub use ffi::i2c_msg as LinuxI2CMessage;
332
333impl<'a> I2CTransfer<'a> for LinuxI2CBus {
334    type Error = LinuxI2CError;
335    type Message = LinuxI2CMessage<'a>;
336
337    /// Issue the provided sequence of I2C transactions
338    fn transfer(&mut self, msgs: &'a mut [Self::Message]) -> Result<u32, LinuxI2CError> {
339        ffi::i2c_rdwr(self.as_raw_fd(), msgs).map_err(From::from)
340    }
341}
342
343bitflags! {
344    /// Various flags used by the i2c_rdwr ioctl on Linux. For details, see
345    /// https://www.kernel.org/doc/Documentation/i2c/i2c-protocol
346    ///
347    /// In general, these are for special cases and should not be needed
348    pub struct I2CMessageFlags: u16 {
349        /// Use ten bit addressing on this message
350        const TEN_BIT_ADDRESS = 0x0010;
351        /// Read data, from slave to master
352        const READ = 0x0001;
353        /// Force an I2C stop condition on this message
354        const STOP = 0x8000;
355        /// Avoid sending an I2C start condition on this message
356        const NO_START = 0x4000;
357        /// If you need to invert a 'read' command bit to a 'write'
358        const INVERT_COMMAND = 0x2000;
359        /// Force this message to ignore I2C negative acknowlegements
360        const IGNORE_NACK = 0x1000;
361        /// Force message to ignore acknowledgement
362        const IGNORE_ACK = 0x0800;
363        /// Allow the client to specify how many bytes it will send
364        const USE_RECEIVE_LENGTH = 0x0400;
365    }
366}
367
368impl<'a> I2CMessage<'a> for LinuxI2CMessage<'a> {
369    fn read(data: &'a mut [u8]) -> LinuxI2CMessage<'a> {
370        Self {
371            addr: 0, // will be filled later
372            flags: I2CMessageFlags::READ.bits(),
373            len: data.len() as u16,
374            buf: data.as_ptr(),
375            _p: PhantomData,
376        }
377    }
378
379    fn write(data: &'a [u8]) -> LinuxI2CMessage<'a> {
380        Self {
381            addr: 0, // will be filled later
382            flags: I2CMessageFlags::empty().bits(),
383            len: data.len() as u16,
384            buf: data.as_ptr(),
385            _p: PhantomData,
386        }
387    }
388}
389
390impl<'a> LinuxI2CMessage<'a> {
391    /// Set the target device address for the message
392    pub fn with_address(self, slave_address: u16) -> Self {
393        Self {
394            addr: slave_address,
395            flags: self.flags,
396            len: self.len,
397            buf: self.buf,
398            _p: PhantomData,
399        }
400    }
401
402    /// Set optional message flags
403    pub fn with_flags(self, flags: I2CMessageFlags) -> Self {
404        Self {
405            addr: self.addr,
406            flags: flags.bits(),
407            len: self.len,
408            buf: self.buf,
409            _p: PhantomData,
410        }
411    }
412}