extern crate hex;
extern crate itertools;
extern crate libc;
extern crate nix;
pub mod dump;
use libc::{c_int, c_short, c_void, c_uint, socket, SOCK_RAW, close, bind, sockaddr, read, write,
setsockopt, SOL_SOCKET, SO_RCVTIMEO, timeval, EINPROGRESS, SO_SNDTIMEO};
use itertools::Itertools;
use std::{error, fmt, io, time};
use std::mem::size_of;
use nix::net::if_::if_nametoindex;
pub trait ShouldRetry {
fn should_retry(&self) -> bool;
}
impl ShouldRetry for io::Error {
fn should_retry(&self) -> bool {
match self.kind() {
io::ErrorKind::WouldBlock => true,
io::ErrorKind::Other => {
if let Some(i) = self.raw_os_error() {
i == EINPROGRESS
} else {
false
}
}
_ => false,
}
}
}
impl<E: fmt::Debug> ShouldRetry for io::Result<E> {
fn should_retry(&self) -> bool {
if let &Err(ref e) = self {
e.should_retry()
} else {
false
}
}
}
const AF_CAN: c_int = 29;
const PF_CAN: c_int = 29;
const CAN_RAW: c_int = 1;
pub const EFF_FLAG: u32 = 0x80000000;
pub const RTR_FLAG: u32 = 0x40000000;
pub const ERR_FLAG: u32 = 0x20000000;
pub const SFF_MASK: u32 = 0x000007ff;
pub const EFF_MASK: u32 = 0x1fffffff;
pub const ERR_MASK: u32 = 0x1fffffff;
#[cfg(target_pointer_width = "64")]
fn c_timeval_new(t: time::Duration) -> timeval {
timeval {
tv_sec: t.as_secs() as i64,
tv_usec: (t.subsec_nanos() / 1000) as i64,
}
}
#[cfg(target_pointer_width = "32")]
fn c_timeval_new(t: time::Duration) -> timeval {
timeval {
tv_sec: t.as_secs() as i32,
tv_usec: (t.subsec_nanos() / 1000) as i32,
}
}
#[derive(Debug)]
#[repr(C)]
struct CANAddr {
_af_can: c_short,
if_index: c_int, rx_id: u32,
tx_id: u32,
}
#[derive(Debug)]
pub enum CANSocketOpenError {
LookupError(nix::Error),
IOError(io::Error),
}
impl fmt::Display for CANSocketOpenError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CANSocketOpenError::LookupError(ref e) => write!(f, "CAN Device not found: {}", e),
CANSocketOpenError::IOError(ref e) => write!(f, "IO: {}", e),
}
}
}
impl error::Error for CANSocketOpenError {
fn description(&self) -> &str {
match *self {
CANSocketOpenError::LookupError(_) => "can device not found",
CANSocketOpenError::IOError(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
CANSocketOpenError::LookupError(ref e) => Some(e),
CANSocketOpenError::IOError(ref e) => Some(e),
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum ConstructionError {
IDTooLarge,
TooMuchData,
}
impl fmt::Display for ConstructionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConstructionError::IDTooLarge => write!(f, "CAN ID too large"),
ConstructionError::TooMuchData => {
write!(f, "Payload is larger than CAN maximum of 8 bytes")
}
}
}
}
impl error::Error for ConstructionError {
fn description(&self) -> &str {
match *self {
ConstructionError::IDTooLarge => "can id too large",
ConstructionError::TooMuchData => "too much data",
}
}
}
impl From<nix::Error> for CANSocketOpenError {
fn from(e: nix::Error) -> CANSocketOpenError {
CANSocketOpenError::LookupError(e)
}
}
impl From<io::Error> for CANSocketOpenError {
fn from(e: io::Error) -> CANSocketOpenError {
CANSocketOpenError::IOError(e)
}
}
pub struct CANSocket {
fd: c_int,
}
impl CANSocket {
pub fn open(ifname: &str) -> Result<CANSocket, CANSocketOpenError> {
let if_index = try!(if_nametoindex(ifname));
CANSocket::open_if(if_index)
}
pub fn open_if(if_index: c_uint) -> Result<CANSocket, CANSocketOpenError> {
let addr = CANAddr {
_af_can: AF_CAN as c_short,
if_index: if_index as c_int,
rx_id: 0, tx_id: 0, };
let sock_fd;
unsafe {
sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
}
if sock_fd == -1 {
return Err(CANSocketOpenError::from(io::Error::last_os_error()));
}
let bind_rv;
unsafe {
let sockaddr_ptr = &addr as *const CANAddr;
bind_rv = bind(sock_fd,
sockaddr_ptr as *const sockaddr,
size_of::<CANAddr>() as u32);
}
if bind_rv == -1 {
let e = io::Error::last_os_error();
unsafe {
close(sock_fd);
}
return Err(CANSocketOpenError::from(e));
}
Ok(CANSocket { fd: sock_fd })
}
fn close(&mut self) -> io::Result<()> {
unsafe {
let rv = close(self.fd);
if rv != -1 {
return Err(io::Error::last_os_error());
}
}
Ok(())
}
pub fn set_read_timeout(&self, duration: time::Duration) -> io::Result<()> {
let rv = unsafe {
let tv = c_timeval_new(duration);
let tv_ptr: *const timeval = &tv as *const timeval;
setsockopt(self.fd,
SOL_SOCKET,
SO_RCVTIMEO,
tv_ptr as *const c_void,
size_of::<timeval>() as u32)
};
if rv != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn set_write_timeout(&self, duration: time::Duration) -> io::Result<()> {
let rv = unsafe {
let tv = c_timeval_new(duration);
let tv_ptr: *const timeval = &tv as *const timeval;
setsockopt(self.fd,
SOL_SOCKET,
SO_SNDTIMEO,
tv_ptr as *const c_void,
size_of::<timeval>() as u32)
};
if rv != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn read_frame(&self) -> io::Result<CANFrame> {
let mut frame = CANFrame {
_id: 0,
_data_len: 0,
_pad: 0,
_res0: 0,
_res1: 0,
_data: [0; 8],
};
let read_rv = unsafe {
let frame_ptr = &mut frame as *mut CANFrame;
read(self.fd, frame_ptr as *mut c_void, size_of::<CANFrame>())
};
if read_rv as usize != size_of::<CANFrame>() {
return Err(io::Error::last_os_error());
}
Ok(frame)
}
pub fn write_frame(&self, frame: &CANFrame) -> io::Result<()> {
let write_rv = unsafe {
let frame_ptr = frame as *const CANFrame;
write(self.fd, frame_ptr as *const c_void, size_of::<CANFrame>())
};
if write_rv as usize != size_of::<CANFrame>() {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
impl Drop for CANSocket {
fn drop(&mut self) {
self.close().ok(); }
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CANFrame {
_id: u32,
_data_len: u8,
_pad: u8,
_res0: u8,
_res1: u8,
_data: [u8; 8],
}
impl CANFrame {
pub fn new(id: u32, data: &[u8], rtr: bool, err: bool) -> Result<CANFrame, ConstructionError> {
let mut _id = id;
if data.len() > 8 {
return Err(ConstructionError::TooMuchData);
}
if id > EFF_MASK {
return Err(ConstructionError::IDTooLarge);
}
if id > SFF_MASK {
_id |= EFF_FLAG;
}
if rtr {
_id |= RTR_FLAG;
}
if err {
_id |= ERR_FLAG;
}
let mut full_data = [0; 8];
for (n, c) in data.iter().enumerate() {
full_data[n] = *c;
}
Ok(CANFrame {
_id: _id,
_data_len: data.len() as u8,
_pad: 0,
_res0: 0,
_res1: 0,
_data: full_data,
})
}
#[inline(always)]
pub fn id(&self) -> u32 {
if self.is_extended() {
self._id & EFF_MASK
} else {
self._id & SFF_MASK
}
}
#[inline(always)]
pub fn err(&self) -> u32 {
return self._id & ERR_MASK;
}
#[inline(always)]
pub fn is_extended(&self) -> bool {
self._id & EFF_FLAG != 0
}
#[inline(always)]
pub fn is_error(&self) -> bool {
self._id & ERR_FLAG != 0
}
#[inline(always)]
pub fn is_rtr(&self) -> bool {
self._id & RTR_FLAG != 0
}
#[inline(always)]
pub fn data(&self) -> &[u8] {
&self._data[..(self._data_len as usize)]
}
}
impl fmt::UpperHex for CANFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(f, "{:X}#", self.id()));
let mut parts = self.data().iter().map(|v| format!("{:02X}", v));
let sep = if f.alternate() { " " } else { " " };
write!(f, "{}", parts.join(sep))
}
}