1use ffi;
10use core::{I2CDevice, I2CBus};
11use std::error::Error;
12use std::path::Path;
13use std::fs::File;
14use std::fmt;
15use nix;
16use std::io;
17use std::fs::OpenOptions;
18use std::io::prelude::*;
19use std::os::unix::prelude::*;
20
21pub use core::{I2CMsgFlags, I2CMsg};
23
24pub struct LinuxI2CDevice {
25 devfile: File,
26 slave_address: u16,
27}
28
29pub struct LinuxI2CBus {
30 devfile: File,
31}
32
33#[derive(Debug)]
34pub enum LinuxI2CError {
35 Nix(nix::Error),
36 Io(io::Error),
37}
38
39impl From<nix::Error> for LinuxI2CError {
40 fn from(e: nix::Error) -> Self {
41 LinuxI2CError::Nix(e)
42 }
43}
44
45impl From<io::Error> for LinuxI2CError {
46 fn from(e: io::Error) -> Self {
47 LinuxI2CError::Io(e)
48 }
49}
50
51impl From<LinuxI2CError> for io::Error {
52 fn from(e: LinuxI2CError) -> io::Error {
53 match e {
54 LinuxI2CError::Io(e) => e,
55 LinuxI2CError::Nix(e) => {
56 match e {
57 nix::Error::Sys(e) => io::Error::from_raw_os_error(e as i32),
58 e => {
59 io::Error::new(io::ErrorKind::InvalidInput, format!("{:?}", e))
60 }
61 }
62 }
63 }
64 }
65}
66
67impl fmt::Display for LinuxI2CError {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 match *self {
70 LinuxI2CError::Nix(ref e) => fmt::Display::fmt(e, f),
71 LinuxI2CError::Io(ref e) => fmt::Display::fmt(e, f),
72 }
73 }
74}
75
76impl Error for LinuxI2CError {
77 fn description(&self) -> &str {
78 match *self {
79 LinuxI2CError::Io(ref e) => e.description(),
80 LinuxI2CError::Nix(ref e) => e.description(),
81 }
82 }
83
84 fn cause(&self) -> Option<&Error> {
85 match *self {
86 LinuxI2CError::Io(ref e) => Some(e),
87 LinuxI2CError::Nix(ref e) => Some(e),
88 }
89 }
90}
91
92impl AsRawFd for LinuxI2CDevice {
93 fn as_raw_fd(&self) -> RawFd {
94 self.devfile.as_raw_fd()
95 }
96}
97
98impl AsRawFd for LinuxI2CBus {
99 fn as_raw_fd(&self) -> RawFd {
100 self.devfile.as_raw_fd()
101 }
102}
103
104impl LinuxI2CDevice {
105 pub fn new<P: AsRef<Path>>(path: P,
107 slave_address: u16)
108 -> Result<LinuxI2CDevice, LinuxI2CError> {
109 let file = OpenOptions::new()
110 .read(true)
111 .write(true)
112 .open(path)?;
113 let mut device = LinuxI2CDevice {
114 devfile: file,
115 slave_address: 0, };
117 device.set_slave_address(slave_address)?;
118 Ok(device)
119 }
120
121 pub fn set_slave_address(&mut self, slave_address: u16) -> Result<(), LinuxI2CError> {
133 ffi::i2c_set_slave_address(self.as_raw_fd(), slave_address)?;
134 self.slave_address = slave_address;
135 Ok(())
136 }
137}
138
139impl I2CDevice for LinuxI2CDevice {
140 type Error = LinuxI2CError;
141
142 fn read(&mut self, data: &mut [u8]) -> Result<(), LinuxI2CError> {
144 self.devfile.read(data).map_err(From::from).map(drop)
145 }
146
147 fn write(&mut self, data: &[u8]) -> Result<(), LinuxI2CError> {
149 self.devfile.write(data).map_err(From::from).map(drop)
150 }
151
152 fn smbus_write_quick(&mut self, bit: bool) -> Result<(), LinuxI2CError> {
154 ffi::i2c_smbus_write_quick(self.as_raw_fd(), bit).map_err(From::from)
155 }
156
157 fn smbus_read_byte(&mut self) -> Result<u8, LinuxI2CError> {
163 ffi::i2c_smbus_read_byte(self.as_raw_fd()).map_err(From::from)
164 }
165
166 fn smbus_write_byte(&mut self, value: u8) -> Result<(), LinuxI2CError> {
171 ffi::i2c_smbus_write_byte(self.as_raw_fd(), value).map_err(From::from)
172 }
173
174 fn smbus_read_byte_data(&mut self, register: u8) -> Result<u8, LinuxI2CError> {
178 ffi::i2c_smbus_read_byte_data(self.as_raw_fd(), register).map_err(From::from)
179 }
180
181 fn smbus_write_byte_data(&mut self, register: u8, value: u8) -> Result<(), LinuxI2CError> {
185 ffi::i2c_smbus_write_byte_data(self.as_raw_fd(), register, value).map_err(From::from)
186 }
187
188 fn smbus_read_word_data(&mut self, register: u8) -> Result<u16, LinuxI2CError> {
190 ffi::i2c_smbus_read_word_data(self.as_raw_fd(), register).map_err(From::from)
191 }
192
193 fn smbus_write_word_data(&mut self, register: u8, value: u16) -> Result<(), LinuxI2CError> {
195 ffi::i2c_smbus_write_word_data(self.as_raw_fd(), register, value).map_err(From::from)
196 }
197
198 fn smbus_process_word(&mut self, register: u8, value: u16) -> Result<u16, LinuxI2CError> {
200 ffi::i2c_smbus_process_call(self.as_raw_fd(), register, value).map_err(From::from)
201 }
202
203 fn smbus_read_block_data(&mut self, register: u8) -> Result<Vec<u8>, LinuxI2CError> {
209 ffi::i2c_smbus_read_block_data(self.as_raw_fd(), register).map_err(From::from)
210 }
211
212 fn smbus_read_i2c_block_data(&mut self, register: u8, len: u8) -> Result<Vec<u8>, LinuxI2CError> {
214 ffi::i2c_smbus_read_i2c_block_data(self.as_raw_fd(), register, len).map_err(From::from)
215 }
216
217 fn smbus_write_block_data(&mut self, register: u8, values: &[u8]) -> Result<(), LinuxI2CError> {
223 ffi::i2c_smbus_write_block_data(self.as_raw_fd(), register, values).map_err(From::from)
224 }
225
226 fn smbus_write_i2c_block_data(&mut self, register: u8, values: &[u8]) -> Result<(), LinuxI2CError> {
228 ffi::i2c_smbus_write_i2c_block_data(self.as_raw_fd(), register, values).map_err(From::from)
229 }
230
231 fn smbus_process_block(&mut self, register: u8, values: &[u8]) -> Result<Vec<u8>, LinuxI2CError> {
234 ffi::i2c_smbus_process_call_block(self.as_raw_fd(), register, values).map_err(From::from)
235 }
236}
237
238impl LinuxI2CBus {
239 pub fn new<P: AsRef<Path>>(path: P)
241 -> Result<LinuxI2CBus, LinuxI2CError> {
242 let file = OpenOptions::new()
243 .read(true)
244 .write(true)
245 .open(path)?;
246 let bus = LinuxI2CBus {
247 devfile: file,
248 };
249 Ok(bus)
250 }
251}
252
253impl I2CBus for LinuxI2CBus {
254 type Error = LinuxI2CError;
255
256 fn rdwr(&mut self, msgs: &mut Vec<I2CMsg>) -> Result<i32, LinuxI2CError> {
258 ffi::i2c_rdwr_read_write(self.as_raw_fd(), msgs).map_err(From::from)
259 }
260}