extern crate hex;
extern crate itertools;
extern crate libc;
extern crate nix;
extern crate try_from;
mod err;
pub use err::{CANError, CANErrorDecodingFailure};
pub mod dump;
#[cfg(test)]
mod tests;
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, time_t,
suseconds_t, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use itertools::Itertools;
use std::{error, fmt, io, time};
use std::mem::size_of;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
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;
const SOL_CAN_BASE: c_int = 100;
const SOL_CAN_RAW: c_int = SOL_CAN_BASE + CAN_RAW;
const CAN_RAW_FILTER: c_int = 1;
const CAN_RAW_ERR_FILTER: c_int = 2;
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;
fn c_timeval_new(t: time::Duration) -> timeval {
timeval {
tv_sec: t.as_secs() as time_t,
tv_usec: (t.subsec_nanos() / 1000) as suseconds_t,
}
}
#[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)
}
}
#[derive(Debug)]
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_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let oldfl = unsafe { fcntl(self.fd, F_GETFL) };
if oldfl == -1 {
return Err(io::Error::last_os_error());
}
let newfl = if nonblocking {
oldfl | O_NONBLOCK
} else {
oldfl & !O_NONBLOCK
};
let rv = unsafe { fcntl(self.fd, F_SETFL, newfl) };
if rv != 0 {
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(())
}
pub fn write_frame_insist(&self, frame: &CANFrame) -> io::Result<()> {
loop {
match self.write_frame(frame) {
Ok(v) => return Ok(v),
Err(e) => {
if !e.should_retry() {
return Err(e);
}
}
}
}
}
pub fn set_filter(&self, filters: &[CANFilter]) -> io::Result<()> {
let rv = if filters.len() < 1 {
unsafe { setsockopt(self.fd, SOL_CAN_RAW, CAN_RAW_FILTER, 0 as *const c_void, 0) }
} else {
unsafe {
let filters_ptr = &filters[0] as *const CANFilter;
setsockopt(self.fd,
SOL_CAN_RAW,
CAN_RAW_FILTER,
filters_ptr as *const c_void,
(size_of::<CANFilter>() * filters.len()) as u32)
}
};
if rv != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[inline(always)]
pub fn filter_drop_all(&self) -> io::Result<()> {
self.set_filter(&[])
}
pub fn filter_accept_all(&self) -> io::Result<()> {
self.set_filter(&[CANFilter::new(0, 0).unwrap()])
}
#[inline(always)]
pub fn set_error_filter(&self, mask: u32) -> io::Result<()> {
let rv = unsafe {
setsockopt(self.fd,
SOL_CAN_RAW,
CAN_RAW_ERR_FILTER,
(&mask as *const u32) as *const c_void,
size_of::<u32>() as u32)
};
if rv != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[inline(always)]
pub fn error_filter_drop_all(&self) -> io::Result<()> {
self.set_error_filter(0)
}
#[inline(always)]
pub fn error_filter_accept_all(&self) -> io::Result<()> {
self.set_error_filter(ERR_MASK)
}
}
impl AsRawFd for CANSocket {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl FromRawFd for CANSocket {
unsafe fn from_raw_fd(fd: RawFd) -> CANSocket {
CANSocket { fd: fd }
}
}
impl IntoRawFd for CANSocket {
fn into_raw_fd(self) -> RawFd {
self.fd
}
}
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)]
}
#[inline(always)]
pub fn error(&self) -> Result<CANError, CANErrorDecodingFailure> {
CANError::from_frame(self)
}
}
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))
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct CANFilter {
_id: u32,
_mask: u32,
}
impl CANFilter {
pub fn new(id: u32, mask: u32) -> Result<CANFilter, ConstructionError> {
Ok(CANFilter {
_id: id,
_mask: mask,
})
}
}