#![allow(dead_code)]
#![allow(non_camel_case_types)]
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use nix;
use std::io::Cursor;
use std::mem;
use std::os::unix::prelude::*;
use std::ptr;
pub type I2CError = nix::Error;
#[repr(C)]
pub struct i2c_msg {
pub(crate) addr: u16,
pub(crate) flags: u16,
pub(crate) len: u16,
pub(crate) buf: *const u8,
}
bitflags! {
struct I2CFunctions: u32 {
const I2C_FUNC_I2C = 0x0000_0001;
const I2C_FUNC_10BIT_ADDR = 0x0000_0002;
const I2C_FUNC_PROTOCOL_MANGLING = 0x0000_0004; const I2C_FUNC_SMBUS_PEC = 0x0000_0008;
const I2C_FUNC_NOSTART = 0x0000_0010; const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x0000_8000; const I2C_FUNC_SMBUS_QUICK = 0x0001_0000;
const I2C_FUNC_SMBUS_READ_BYTE = 0x0002_0000;
const I2C_FUNC_SMBUS_WRITE_BYTE = 0x0004_0000;
const I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x0008_0000;
const I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x0010_0000;
const I2C_FUNC_SMBUS_READ_WORD_DATA = 0x0020_0000;
const I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x0040_0000;
const I2C_FUNC_SMBUS_PROC_CALL = 0x0080_0000;
const I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x0100_0000;
const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x0200_0000;
const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x0400_0000; const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x0800_0000; const I2C_FUNC_SMBUS_BYTE = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE.bits);
const I2C_FUNC_SMBUS_BYTE_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE_DATA.bits);
const I2C_FUNC_SMBUS_WORD_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_WORD_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_WORD_DATA.bits);
const I2C_FUNC_SMBUS_BLOCK_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BLOCK_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits);
const I2C_FUNC_SMBUS_I2C_BLOCK = (I2CFunctions::I2C_FUNC_SMBUS_READ_I2C_BLOCK.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_I2C_BLOCK.bits);
const I2C_FUNC_SMBUS_EMUL = (I2CFunctions::I2C_FUNC_SMBUS_QUICK.bits |
I2CFunctions::I2C_FUNC_SMBUS_BYTE.bits |
I2CFunctions::I2C_FUNC_SMBUS_BYTE_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WORD_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_PROC_CALL.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_I2C_BLOCK.bits |
I2CFunctions::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)]
pub struct i2c_smbus_ioctl_data {
read_write: u8,
command: u8,
size: u32,
data: *mut i2c_smbus_data,
}
#[repr(C)]
pub struct i2c_rdwr_ioctl_data {
msgs: *mut i2c_msg,
nmsgs: u32,
}
mod ioctl {
pub use super::i2c_rdwr_ioctl_data;
pub use super::i2c_smbus_ioctl_data;
use super::{I2C_PEC, I2C_RDWR, I2C_SLAVE, I2C_SLAVE_FORCE, I2C_SMBUS};
ioctl_write_int_bad!(set_i2c_slave_address, I2C_SLAVE);
ioctl_write_int_bad!(set_i2c_slave_address_force, I2C_SLAVE_FORCE);
ioctl_write_int_bad!(set_smbus_pec, I2C_PEC);
ioctl_write_ptr_bad!(i2c_smbus, I2C_SMBUS, i2c_smbus_ioctl_data);
ioctl_write_ptr_bad!(i2c_rdwr, I2C_RDWR, i2c_rdwr_ioctl_data);
}
pub fn i2c_set_slave_address(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
unsafe {
ioctl::set_i2c_slave_address(fd, i32::from(slave_address))?;
}
Ok(())
}
pub fn i2c_set_slave_address_force(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
unsafe {
ioctl::set_i2c_slave_address_force(fd, i32::from(slave_address))?;
}
Ok(())
}
pub fn i2c_set_smbus_pec(fd: RawFd, enable: bool) -> Result<(), nix::Error> {
unsafe {
ioctl::set_smbus_pec(fd, i32::from(enable))?;
}
Ok(())
}
unsafe fn i2c_smbus_access(
fd: RawFd,
read_write: I2CSMBusReadWrite,
command: u8, size: I2CSMBusSize,
data: *mut i2c_smbus_data,
) -> Result<(), I2CError> {
let args = i2c_smbus_ioctl_data {
read_write: read_write as u8,
command,
size: size as u32,
data,
};
ioctl::i2c_smbus(fd, &args).map(drop)
}
#[inline]
pub fn i2c_smbus_write_quick(fd: RawFd, bit: bool) -> Result<(), I2CError> {
let read_write = if bit {
I2CSMBusReadWrite::I2C_SMBUS_READ
} else {
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();
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();
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;
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
&mut data,
)
}
}
#[inline]
pub fn i2c_smbus_read_word_data(fd: RawFd, register: u8) -> Result<u16, I2CError> {
let mut data = i2c_smbus_data::empty();
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();
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_WORD_DATA,
&mut data,
)
}
}
#[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();
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();
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;
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]
fn copy_to_i2c_block_data(values: &[u8], max_size: usize) -> i2c_smbus_data {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > max_size {
max_size
} else {
values.len()
};
data.block[0] = len as u8;
data.block[1..=len].copy_from_slice(&values[..len]);
data
}
#[inline]
pub fn i2c_smbus_write_block_data(fd: RawFd, register: u8, values: &[u8]) -> Result<(), I2CError> {
let mut data = copy_to_i2c_block_data(values, 32);
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data,
)
}
}
#[inline]
pub fn i2c_smbus_write_i2c_block_data(
fd: RawFd,
register: u8,
values: &[u8],
) -> Result<(), I2CError> {
let mut data = copy_to_i2c_block_data(values, 32);
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
&mut data,
)
}
}
#[inline]
pub fn i2c_smbus_process_call_block(
fd: RawFd,
register: u8,
values: &[u8],
) -> Result<Vec<u8>, I2CError> {
let mut data = copy_to_i2c_block_data(values, 31);
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_PROC_CALL,
&mut data,
)?;
};
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}
#[inline]
pub fn i2c_rdwr(fd: RawFd, values: &mut [i2c_msg]) -> Result<u32, I2CError> {
let i2c_data = i2c_rdwr_ioctl_data {
msgs: values.as_mut_ptr(),
nmsgs: values.len() as u32,
};
let n;
unsafe {
n = ioctl::i2c_rdwr(fd, &i2c_data)?;
}
Ok(n as u32)
}