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