use ffi;
use core::I2CDevice;
use std::error::Error;
use std::path::Path;
use std::fs::File;
use std::fmt;
use nix;
use std::io;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::os::unix::prelude::*;
pub struct LinuxI2CDevice {
devfile: File,
slave_address: u16,
}
#[derive(Debug)]
pub enum LinuxI2CError {
Nix(nix::Error),
Io(io::Error),
}
impl From<nix::Error> for LinuxI2CError {
fn from(e: nix::Error) -> Self {
LinuxI2CError::Nix(e)
}
}
impl From<io::Error> for LinuxI2CError {
fn from(e: io::Error) -> Self {
LinuxI2CError::Io(e)
}
}
impl From<LinuxI2CError> for io::Error {
fn from(e: LinuxI2CError) -> io::Error {
match e {
LinuxI2CError::Io(e) => e,
LinuxI2CError::Nix(e) => {
match e {
nix::Error::Sys(e) => io::Error::from_raw_os_error(e as i32),
e => {
io::Error::new(io::ErrorKind::InvalidInput, format!("{:?}", e))
}
}
}
}
}
}
impl fmt::Display for LinuxI2CError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LinuxI2CError::Nix(ref e) => fmt::Display::fmt(e, f),
LinuxI2CError::Io(ref e) => fmt::Display::fmt(e, f),
}
}
}
impl Error for LinuxI2CError {
fn description(&self) -> &str {
match *self {
LinuxI2CError::Io(ref e) => e.description(),
LinuxI2CError::Nix(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&Error> {
match *self {
LinuxI2CError::Io(ref e) => Some(e),
LinuxI2CError::Nix(ref e) => Some(e),
}
}
}
impl AsRawFd for LinuxI2CDevice {
fn as_raw_fd(&self) -> RawFd {
self.devfile.as_raw_fd()
}
}
impl LinuxI2CDevice {
pub fn new<P: AsRef<Path>>(path: P,
slave_address: u16)
-> Result<LinuxI2CDevice, LinuxI2CError> {
let file = OpenOptions::new()
.read(true)
.write(true)
.open(path)?;
let mut device = LinuxI2CDevice {
devfile: file,
slave_address: 0, };
device.set_slave_address(slave_address)?;
Ok(device)
}
pub fn set_slave_address(&mut self, slave_address: u16) -> Result<(), LinuxI2CError> {
ffi::i2c_set_slave_address(self.as_raw_fd(), slave_address)?;
self.slave_address = slave_address;
Ok(())
}
}
impl I2CDevice for LinuxI2CDevice {
type Error = LinuxI2CError;
fn read(&mut self, data: &mut [u8]) -> Result<(), LinuxI2CError> {
self.devfile.read(data).map_err(From::from).map(drop)
}
fn write(&mut self, data: &[u8]) -> Result<(), LinuxI2CError> {
self.devfile.write(data).map_err(From::from).map(drop)
}
fn smbus_write_quick(&mut self, bit: bool) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_quick(self.as_raw_fd(), bit).map_err(From::from)
}
fn smbus_read_byte(&mut self) -> Result<u8, LinuxI2CError> {
ffi::i2c_smbus_read_byte(self.as_raw_fd()).map_err(From::from)
}
fn smbus_write_byte(&mut self, value: u8) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_byte(self.as_raw_fd(), value).map_err(From::from)
}
fn smbus_read_byte_data(&mut self, register: u8) -> Result<u8, LinuxI2CError> {
ffi::i2c_smbus_read_byte_data(self.as_raw_fd(), register).map_err(From::from)
}
fn smbus_write_byte_data(&mut self, register: u8, value: u8) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_byte_data(self.as_raw_fd(), register, value).map_err(From::from)
}
fn smbus_read_word_data(&mut self, register: u8) -> Result<u16, LinuxI2CError> {
ffi::i2c_smbus_read_word_data(self.as_raw_fd(), register).map_err(From::from)
}
fn smbus_write_word_data(&mut self, register: u8, value: u16) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_word_data(self.as_raw_fd(), register, value).map_err(From::from)
}
fn smbus_process_word(&mut self, register: u8, value: u16) -> Result<u16, LinuxI2CError> {
ffi::i2c_smbus_process_call(self.as_raw_fd(), register, value).map_err(From::from)
}
fn smbus_read_block_data(&mut self, register: u8) -> Result<Vec<u8>, LinuxI2CError> {
ffi::i2c_smbus_read_block_data(self.as_raw_fd(), register).map_err(From::from)
}
fn smbus_read_i2c_block_data(&mut self, register: u8, len: u8) -> Result<Vec<u8>, LinuxI2CError> {
ffi::i2c_smbus_read_i2c_block_data(self.as_raw_fd(), register, len).map_err(From::from)
}
fn smbus_write_block_data(&mut self, register: u8, values: &[u8]) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_block_data(self.as_raw_fd(), register, values).map_err(From::from)
}
fn smbus_write_i2c_block_data(&mut self, register: u8, values: &[u8]) -> Result<(), LinuxI2CError> {
ffi::i2c_smbus_write_i2c_block_data(self.as_raw_fd(), register, values).map_err(From::from)
}
fn smbus_process_block(&mut self, register: u8, values: &[u8]) -> Result<Vec<u8>, LinuxI2CError> {
ffi::i2c_smbus_process_call_block(self.as_raw_fd(), register, values).map_err(From::from)
}
}