#![allow(dead_code)]
#![allow(non_camel_case_types)]
use nix;
use std::mem;
use std::ptr;
use std::io::Cursor;
use std::os::unix::prelude::*;
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
pub type I2CError = nix::Error;
bitflags! {
flags I2CMsgFlags: u16 {
const I2C_M_TEN = 0x0010,
const I2C_M_RD = 0x0001,
const I2C_M_STOP = 0x8000,
const I2C_M_NOSTART = 0x4000,
const I2C_M_REV_DIR_ADDR = 0x2000,
const I2C_M_IGNORE_NAK = 0x1000,
const I2C_M_NO_RD_ACK = 0x0800,
const I2C_M_RECV_LEN = 0x0400,
}
}
#[repr(C)]
struct i2c_msg {
addr: u16,
flags: u16,
len: u16,
buf: *mut u8,
}
bitflags! {
flags I2CFunctions: u32 {
const I2C_FUNC_I2C = 0x00000001,
const I2C_FUNC_10BIT_ADDR = 0x00000002,
const I2C_FUNC_PROTOCOL_MANGLING = 0x00000004,
const I2C_FUNC_SMBUS_PEC = 0x00000008,
const I2C_FUNC_NOSTART = 0x00000010,
const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x00008000,
const I2C_FUNC_SMBUS_QUICK = 0x00010000,
const I2C_FUNC_SMBUS_READ_BYTE = 0x00020000,
const I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000,
const I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000,
const I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000,
const I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000,
const I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000,
const I2C_FUNC_SMBUS_PROC_CALL = 0x00800000,
const I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000,
const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000,
const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000,
const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000,
const I2C_FUNC_SMBUS_BYTE = (I2C_FUNC_SMBUS_READ_BYTE.bits |
I2C_FUNC_SMBUS_WRITE_BYTE.bits),
const I2C_FUNC_SMBUS_BYTE_DATA = (I2C_FUNC_SMBUS_READ_BYTE_DATA.bits |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA.bits),
const I2C_FUNC_SMBUS_WORD_DATA = (I2C_FUNC_SMBUS_READ_WORD_DATA.bits |
I2C_FUNC_SMBUS_WRITE_WORD_DATA.bits),
const I2C_FUNC_SMBUS_BLOCK_DATA = (I2C_FUNC_SMBUS_READ_BLOCK_DATA.bits |
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits),
const I2C_FUNC_SMBUS_I2C_BLOCK = (I2C_FUNC_SMBUS_READ_I2C_BLOCK.bits |
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK.bits),
const I2C_FUNC_SMBUS_EMUL = (I2C_FUNC_SMBUS_QUICK.bits |
I2C_FUNC_SMBUS_BYTE.bits |
I2C_FUNC_SMBUS_BYTE_DATA.bits |
I2C_FUNC_SMBUS_WORD_DATA.bits |
I2C_FUNC_SMBUS_PROC_CALL.bits |
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits |
I2C_FUNC_SMBUS_I2C_BLOCK.bits |
I2C_FUNC_SMBUS_PEC.bits),
}
}
const I2C_SMBUS_BLOCK_MAX: u8 = 32;
#[repr(C)]
struct i2c_smbus_data {
block: [u8; (I2C_SMBUS_BLOCK_MAX + 2) as usize],
}
impl i2c_smbus_data {
fn empty() -> i2c_smbus_data {
unsafe { mem::zeroed() }
}
}
#[repr(u8)]
enum I2CSMBusReadWrite {
I2C_SMBUS_READ = 1,
I2C_SMBUS_WRITE = 0,
}
#[repr(u32)]
enum I2CSMBusSize {
I2C_SMBUS_QUICK = 0,
I2C_SMBUS_BYTE = 1,
I2C_SMBUS_BYTE_DATA = 2,
I2C_SMBUS_WORD_DATA = 3,
I2C_SMBUS_PROC_CALL = 4,
I2C_SMBUS_BLOCK_DATA = 5,
I2C_SMBUS_I2C_BLOCK_BROKEN = 6,
I2C_SMBUS_BLOCK_PROC_CALL = 7, I2C_SMBUS_I2C_BLOCK_DATA = 8,
}
const I2C_RETRIES: u16 = 0x0701;
const I2C_TIMEOUT: u16 = 0x0702;
const I2C_SLAVE: u16 = 0x0703;
const I2C_SLAVE_FORCE: u16 = 0x0706;
const I2C_TENBIT: u16 = 0x0704;
const I2C_FUNCS: u16 = 0x0705;
const I2C_RDWR: u16 = 0x0707;
const I2C_PEC: u16 = 0x0708;
const I2C_SMBUS: u16 = 0x0720;
const I2C_RDRW_IOCTL_MAX_MSGS: u8 = 42;
#[repr(C)]
struct i2c_smbus_ioctl_data {
read_write: u8,
command: u8,
size: u32,
data: *mut i2c_smbus_data,
}
#[repr(C)]
struct i2c_rdwr_ioctl_data {
msgs: *mut i2c_msg,
nmsgs: u32,
}
ioctl!(bad ioctl_set_i2c_slave_address with I2C_SLAVE);
ioctl!(bad ioctl_i2c_smbus with I2C_SMBUS);
pub fn i2c_set_slave_address(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
try!(unsafe {
ioctl_set_i2c_slave_address(fd, slave_address as *mut u8)
});
Ok(())
}
unsafe fn i2c_smbus_access(fd: RawFd,
read_write: I2CSMBusReadWrite,
command: u8, size: I2CSMBusSize,
data: *mut i2c_smbus_data)
-> Result<(), I2CError> {
let mut args = i2c_smbus_ioctl_data {
read_write: read_write as u8,
command: command,
size: size as u32,
data: data,
};
let p_args: *mut u8 = mem::transmute(&mut args);
ioctl_i2c_smbus(fd, p_args).map(drop)
}
#[inline]
pub fn i2c_smbus_write_quick(fd: RawFd, bit: bool) -> Result<(), I2CError> {
let read_write = match bit {
true => I2CSMBusReadWrite::I2C_SMBUS_READ,
false => I2CSMBusReadWrite::I2C_SMBUS_WRITE,
};
unsafe {
i2c_smbus_access(fd,
read_write,
0,
I2CSMBusSize::I2C_SMBUS_QUICK,
ptr::null_mut())
}
}
#[inline]
pub fn i2c_smbus_read_byte(fd: RawFd) -> Result<u8, I2CError> {
let mut data = i2c_smbus_data::empty();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
0,
I2CSMBusSize::I2C_SMBUS_BYTE,
&mut data)
});
Ok(data.block[0])
}
#[inline]
pub fn i2c_smbus_write_byte(fd: RawFd, value: u8) -> Result<(), I2CError> {
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
value,
I2CSMBusSize::I2C_SMBUS_BYTE,
ptr::null_mut())
}
}
#[inline]
pub fn i2c_smbus_read_byte_data(fd: RawFd, register: u8) -> Result<u8, I2CError> {
let mut data = i2c_smbus_data::empty();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
&mut data)
});
Ok(data.block[0])
}
#[inline]
pub fn i2c_smbus_write_byte_data(fd: RawFd, register: u8, value: u8) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
data.block[0] = value;
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
&mut data)
});
Ok(())
}
#[inline]
pub fn i2c_smbus_read_word_data(fd: RawFd, register: u8) -> Result<u16, I2CError> {
let mut data = i2c_smbus_data::empty();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_WORD_DATA,
&mut data)
});
Ok(Cursor::new(&data.block[..])
.read_u16::<NativeEndian>()
.unwrap())
}
#[inline]
pub fn i2c_smbus_write_word_data(fd: RawFd, register: u8, value: u16) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
Cursor::new(&mut data.block[..])
.write_u16::<NativeEndian>(value)
.unwrap();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_WORD_DATA,
&mut data)
});
Ok(())
}
#[inline]
pub fn i2c_smbus_process_call(fd: RawFd, register: u8, value: u16) -> Result<u16, I2CError> {
let mut data = i2c_smbus_data::empty();
Cursor::new(&mut data.block[..])
.write_u16::<NativeEndian>(value)
.unwrap();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_PROC_CALL,
&mut data)
});
Ok(Cursor::new(&data.block[..])
.read_u16::<NativeEndian>()
.unwrap())
}
#[inline]
pub fn i2c_smbus_read_block_data(fd: RawFd, register: u8) -> Result<Vec<u8>, I2CError> {
let mut data = i2c_smbus_data::empty();
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data)
});
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}
pub fn i2c_smbus_read_i2c_block_data(fd: RawFd, register: u8, len: u8) -> Result<Vec<u8>, I2CError> {
let mut data = i2c_smbus_data::empty();
data.block[0] = len;
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
&mut data)
});
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}
#[inline]
pub fn i2c_smbus_write_block_data(fd: RawFd, register: u8, values: &[u8]) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > 32 {
32
} else {
values.len()
};
data.block[0] = len as u8;
for i in 1..(len + 1) {
data.block[i] = values[i - 1];
}
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data)
});
Ok(())
}
#[inline]
pub fn i2c_smbus_write_i2c_block_data(fd: RawFd,
register: u8,
values: &[u8])
-> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > 32 {
32
} else {
values.len()
};
data.block[0] = len as u8;
for i in 1..(len + 1) {
data.block[i] = values[i - 1];
}
try!(unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
&mut data)
});
Ok(())
}