#[cfg(target_os = "linux")]
pub(crate) mod linux {
use crate::error::{Error, Result};
use std::io;
use std::os::raw::{c_int, c_void};
pub const AF_CAN: c_int = 29;
pub const PF_CAN: c_int = AF_CAN;
pub const SOCK_RAW: c_int = 3;
pub const CAN_RAW: c_int = 1;
pub const CAN_RAW_FD_FRAMES: c_int = 5;
pub const SOL_CAN_RAW: c_int = 101;
pub const F_GETFL: c_int = 3;
pub const F_SETFL: c_int = 4;
pub const O_NONBLOCK: c_int = 2048;
pub const SIOCGIFINDEX: u64 = 0x8933;
pub const CANFD_MTU: usize = 72;
pub const CANFD_BRS: u8 = 0x01;
pub const CAN_EFF_FLAG: u32 = 0x80000000;
pub const CAN_EFF_MASK: u32 = 0x1FFFFFFF;
#[repr(C)]
pub struct Ifreq {
pub ifr_name: [i8; 16],
pub ifr_ifindex: c_int,
pub _padding: [u8; 20],
}
#[repr(C)]
pub struct SockAddrCan {
pub can_family: u16,
pub can_ifindex: i32,
pub rx_id: u32,
pub tx_id: u32,
}
#[repr(C)]
pub struct CanFdFrameRaw {
pub can_id: u32,
pub len: u8,
pub flags: u8,
pub _res0: u8,
pub _res1: u8,
pub data: [u8; 64],
}
impl Default for CanFdFrameRaw {
fn default() -> Self {
CanFdFrameRaw {
can_id: 0,
len: 0,
flags: 0,
_res0: 0,
_res1: 0,
data: [0; 64],
}
}
}
extern "C" {
pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int;
pub fn bind(sockfd: c_int, addr: *const c_void, addrlen: u32) -> c_int;
pub fn close(fd: c_int) -> c_int;
pub fn read(fd: c_int, buf: *mut c_void, count: usize) -> isize;
pub fn write(fd: c_int, buf: *const c_void, count: usize) -> isize;
pub fn setsockopt(
sockfd: c_int,
level: c_int,
optname: c_int,
optval: *const c_void,
optlen: u32,
) -> c_int;
pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int;
pub fn ioctl(fd: c_int, request: u64, ...) -> c_int;
}
pub fn get_ifindex(interface: &str) -> Result<i32> {
let mut ifr = Ifreq {
ifr_name: [0; 16],
ifr_ifindex: 0,
_padding: [0; 20],
};
let name_bytes = interface.as_bytes();
let copy_len = std::cmp::min(name_bytes.len(), 15);
for (i, &b) in name_bytes[..copy_len].iter().enumerate() {
ifr.ifr_name[i] = b as i8;
}
let sock = unsafe { socket(AF_CAN, SOCK_RAW, CAN_RAW) };
if sock < 0 {
return Err(Error::Io(io::Error::last_os_error()));
}
let ret = unsafe { ioctl(sock, SIOCGIFINDEX, &mut ifr) };
unsafe { close(sock) };
if ret < 0 {
return Err(Error::DeviceNotFound(interface.to_string()));
}
Ok(ifr.ifr_ifindex)
}
#[allow(clippy::field_reassign_with_default)]
pub fn frame_to_raw(frame: &moteus_protocol::CanFdFrame, disable_brs: bool) -> CanFdFrameRaw {
let mut padded = frame.clone();
padded.pad_to_dlc();
let mut raw = CanFdFrameRaw::default();
raw.can_id = padded.arbitration_id;
if padded.arbitration_id > 0x7FF {
raw.can_id |= CAN_EFF_FLAG;
}
raw.len = padded.size;
if padded.brs_enabled() && !disable_brs {
raw.flags |= CANFD_BRS;
}
raw.data[..padded.size as usize].copy_from_slice(&padded.data[..padded.size as usize]);
raw
}
pub fn frame_from_raw(raw: &CanFdFrameRaw) -> moteus_protocol::CanFdFrame {
let mut frame = moteus_protocol::CanFdFrame::new();
frame.arbitration_id = raw.can_id & CAN_EFF_MASK;
frame.size = raw.len;
frame.data[..raw.len as usize].copy_from_slice(&raw.data[..raw.len as usize]);
if raw.flags & CANFD_BRS != 0 {
frame.set_brs(true);
}
frame.set_fdcan(true);
frame
}
}