#![deny(missing_docs)]
#![doc(html_root_url = "http://arcnmx.github.io/i2c-linux-rs/")]
#[macro_use]
extern crate bitflags;
extern crate resize_slice;
extern crate i2c_linux_sys as i2c;
#[cfg(feature = "i2c")]
extern crate i2c as i2c_gen;
#[cfg(feature = "udev")]
extern crate udev;
use std::time::Duration;
use std::path::Path;
use std::os::unix::io::{AsRawFd, IntoRawFd, FromRawFd, RawFd};
use std::io::{self, Read, Write};
use std::fs::{File, OpenOptions};
use std::{mem, cmp, iter};
use resize_slice::ResizeSlice;
pub use i2c::{SmbusReadWrite as ReadWrite, Functionality};
#[cfg(feature = "udev")]
mod enumerate;
#[cfg(feature = "udev")]
pub use enumerate::Enumerator;
#[cfg(feature = "i2c")]
mod i2c_impl;
pub enum Message<'a> {
Read {
address: u16,
data: &'a mut [u8],
flags: ReadFlags,
},
Write {
address: u16,
data: &'a [u8],
flags: WriteFlags,
},
}
impl<'a> Message<'a> {
pub fn len(&self) -> usize {
match *self {
Message::Read { ref data, .. } => data.len(),
Message::Write { ref data, .. } => data.len(),
}
}
pub fn address(&self) -> u16 {
match *self {
Message::Read { address, .. } => address,
Message::Write { address, .. } => address,
}
}
}
bitflags! {
#[derive(Default)]
pub struct ReadFlags: u16 {
const TENBIT_ADDR = i2c::I2C_M_TEN;
const RECEIVE_LEN = i2c::I2C_M_RECV_LEN;
const NACK = i2c::I2C_M_NO_RD_ACK;
const REVERSE_RW = i2c::I2C_M_REV_DIR_ADDR;
const NO_START = i2c::I2C_M_NOSTART;
const STOP = i2c::I2C_M_STOP;
}
}
bitflags! {
#[derive(Default)]
pub struct WriteFlags: u16 {
const TENBIT_ADDR = i2c::I2C_M_TEN;
const IGNORE_NACK = i2c::I2C_M_IGNORE_NAK;
const REVERSE_RW = i2c::I2C_M_REV_DIR_ADDR;
const NO_START = i2c::I2C_M_NOSTART;
const STOP = i2c::I2C_M_STOP;
}
}
pub struct I2c<I> {
inner: I,
message_buffer: Box<[i2c::i2c_msg; i2c::I2C_RDWR_IOCTL_MAX_MSGS]>,
address: Option<u16>,
address_10bit: bool,
functionality: Option<Functionality>,
}
impl I2c<File> {
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Self> {
OpenOptions::new().read(true).write(true)
.open(p).map(Self::new)
}
}
impl<I> I2c<I> {
pub fn new(device: I) -> Self {
I2c {
inner: device,
message_buffer: Box::new(unsafe { mem::zeroed() }),
address: None,
address_10bit: false,
functionality: None,
}
}
pub fn into_inner(self) -> I {
self.inner
}
pub fn inner_ref(&self) -> &I {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut I {
&mut self.inner
}
}
impl<I: AsRawFd> AsRawFd for I2c<I> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
impl<I: IntoRawFd> IntoRawFd for I2c<I> {
fn into_raw_fd(self) -> RawFd {
self.inner.into_raw_fd()
}
}
impl FromRawFd for I2c<File> {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::new(File::from_raw_fd(fd))
}
}
impl<I: AsRawFd> I2c<I> {
fn update_functionality(&mut self) -> Option<Functionality> {
if let Some(func) = self.functionality.clone() {
Some(func)
} else {
let functionality = self.i2c_functionality().ok();
self.functionality = functionality.clone();
functionality
}
}
pub fn i2c_set_retries(&self, value: usize) -> io::Result<()> {
i2c::i2c_set_retries(self.as_raw_fd(), value)
}
pub fn i2c_set_timeout(&self, duration: Duration) -> io::Result<()> {
let value = duration.as_secs() as usize * 1000 + duration.subsec_nanos() as usize / 1000000;
i2c::i2c_set_timeout_ms(self.as_raw_fd(), value as _)
}
pub fn smbus_set_slave_address(&mut self, address: u16, tenbit: bool) -> io::Result<()> {
if let Some(func) = self.update_functionality() {
if func.contains(Functionality::TENBIT_ADDR) || tenbit {
i2c::i2c_set_slave_address_10bit(self.as_raw_fd(), tenbit)?;
}
}
let res = i2c::i2c_set_slave_address(self.as_raw_fd(), address, false);
if res.is_ok() {
self.address = Some(address);
self.address_10bit = tenbit;
}
res
}
pub fn smbus_set_pec(&self, pec: bool) -> io::Result<()> {
i2c::i2c_pec(self.as_raw_fd(), pec)
}
pub fn i2c_functionality(&self) -> io::Result<Functionality> {
i2c::i2c_get_functionality(self.as_raw_fd())
}
pub fn i2c_transfer_flags(&self) -> io::Result<(ReadFlags, WriteFlags)> {
let func = self.i2c_functionality()?;
let (mut read, mut write) = (ReadFlags::empty(), WriteFlags::empty());
if func.contains(Functionality::PROTOCOL_MANGLING) {
read.set(ReadFlags::NACK, true);
read.set(ReadFlags::REVERSE_RW, true);
read.set(ReadFlags::STOP, true);
write.set(WriteFlags::IGNORE_NACK, true);
write.set(WriteFlags::REVERSE_RW, true);
write.set(WriteFlags::STOP, true);
}
if func.contains(Functionality::NO_START) {
read.set(ReadFlags::NO_START, true);
write.set(WriteFlags::NO_START, true);
}
if func.contains(Functionality::TENBIT_ADDR) {
read.set(ReadFlags::TENBIT_ADDR, true);
write.set(WriteFlags::TENBIT_ADDR, true);
}
Ok((read, write))
}
pub fn i2c_transfer(&mut self, messages: &mut [Message]) -> io::Result<()> {
assert!(messages.len() <= self.message_buffer.len());
self.message_buffer.iter_mut().zip(messages.iter_mut())
.for_each(|(out, msg)| *out = match *msg {
Message::Read { address, ref mut data, flags } => i2c::i2c_msg {
addr: address,
flags: i2c::Flags::from_bits_truncate(flags.bits()) | i2c::Flags::RD,
len: data.len() as _,
buf: data.as_mut_ptr(),
},
Message::Write { address, ref data, flags } => i2c::i2c_msg {
addr: address,
flags: i2c::Flags::from_bits_truncate(flags.bits()),
len: data.len() as _,
buf: data.as_ptr() as *mut _,
},
});
let res = unsafe {
i2c::i2c_rdwr(self.as_raw_fd(), &mut self.message_buffer[..messages.len()])?;
};
self.message_buffer.iter().zip(messages.iter_mut())
.for_each(|(msg, out)| match *out {
Message::Read { ref mut data, .. } => data.resize_to(msg.len as usize),
Message::Write { .. } => (),
});
Ok(res)
}
pub fn smbus_write_quick(&mut self, value: ReadWrite) -> io::Result<()> {
i2c::i2c_smbus_write_quick(self.as_raw_fd(), value)
}
pub fn smbus_read_byte(&mut self) -> io::Result<u8> {
i2c::i2c_smbus_read_byte(self.as_raw_fd())
}
pub fn smbus_write_byte(&mut self, value: u8) -> io::Result<()> {
i2c::i2c_smbus_write_byte(self.as_raw_fd(), value)
}
pub fn smbus_read_byte_data(&mut self, command: u8) -> io::Result<u8> {
i2c::i2c_smbus_read_byte_data(self.as_raw_fd(), command)
}
pub fn smbus_write_byte_data(&mut self, command: u8, value: u8) -> io::Result<()> {
i2c::i2c_smbus_write_byte_data(self.as_raw_fd(), command, value)
}
pub fn smbus_read_word_data(&mut self, command: u8) -> io::Result<u16> {
i2c::i2c_smbus_read_word_data(self.as_raw_fd(), command)
}
pub fn smbus_write_word_data(&mut self, command: u8, value: u16) -> io::Result<()> {
i2c::i2c_smbus_write_word_data(self.as_raw_fd(), command, value)
}
pub fn smbus_process_call(&mut self, command: u8, value: u16) -> io::Result<u16> {
i2c::i2c_smbus_process_call(self.as_raw_fd(), command, value)
}
pub fn smbus_read_block_data(&mut self, command: u8, value: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(value.len(), i2c::I2C_SMBUS_BLOCK_MAX);
i2c::i2c_smbus_read_block_data(self.as_raw_fd(), command, &mut value[..len])
}
pub fn smbus_write_block_data(&mut self, command: u8, value: &[u8]) -> io::Result<()> {
i2c::i2c_smbus_write_block_data(self.as_raw_fd(), command, value)
}
pub fn smbus_block_process_call(&mut self, command: u8, write: &[u8], read: &mut [u8]) -> io::Result<usize> {
let read_len = cmp::min(read.len(), i2c::I2C_SMBUS_BLOCK_MAX);
i2c::i2c_smbus_block_process_call(self.as_raw_fd(), command, write, &mut read[..read_len])
}
pub fn i2c_read_block_data(&mut self, command: u8, value: &mut [u8]) -> io::Result<usize> {
if let Some(func) = self.update_functionality() {
if !func.contains(Functionality::SMBUS_READ_I2C_BLOCK) || value.len() > i2c::I2C_SMBUS_BLOCK_MAX {
if func.contains(Functionality::I2C) {
if let Some(address) = self.address {
let mut msgs = [
Message::Write {
address: address,
data: &[command],
flags: if self.address_10bit { WriteFlags::TENBIT_ADDR } else { WriteFlags::default() },
},
Message::Read {
address: address,
data: value,
flags: if self.address_10bit { ReadFlags::TENBIT_ADDR } else { ReadFlags::default() },
},
];
return self.i2c_transfer(&mut msgs)
.map(|_| msgs[1].len())
}
}
}
}
let len = cmp::min(value.len(), i2c::I2C_SMBUS_BLOCK_MAX);
i2c::i2c_smbus_read_i2c_block_data(self.as_raw_fd(), command, &mut value[..len])
}
pub fn i2c_write_block_data(&mut self, command: u8, value: &[u8]) -> io::Result<()> {
if let Some(func) = self.update_functionality() {
if !func.contains(Functionality::SMBUS_WRITE_I2C_BLOCK) || value.len() > i2c::I2C_SMBUS_BLOCK_MAX {
if func.contains(Functionality::I2C) {
if let Some(address) = self.address {
let flags = if self.address_10bit { WriteFlags::TENBIT_ADDR } else { WriteFlags::default() };
return if func.contains(Functionality::NO_START) {
self.i2c_transfer(&mut [
Message::Write {
address: address,
data: &[command],
flags: flags,
},
Message::Write {
address: address,
data: value,
flags: flags | WriteFlags::NO_START,
},
])
} else {
self.i2c_transfer(&mut [
Message::Write {
address: address,
data: &iter::once(command).chain(value.iter().cloned()).collect::<Vec<_>>(),
flags: flags,
},
])
}
} else {
}
}
}
}
i2c::i2c_smbus_write_i2c_block_data(self.as_raw_fd(), command, value)
}
}
impl<I: Read> Read for I2c<I> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl<I: Write> Write for I2c<I> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}