1use std::mem;
37use std::io;
38use std::ops::Index;
39use std::{os::raw::{c_char, c_int, c_void}};
40
41use chrono::Duration;
42
43#[allow(invalid_value)]
44
45const AF_CAN: c_int = 29;
47const PF_CAN: c_int = 29;
48pub const EFF_FLAG: u32 = 0x80000000;
62pub const RTR_FLAG: u32 = 0x40000000;
64pub const ERR_FLAG: u32 = 0x20000000;
66pub const SFF_MASK: u32 = 0x000007ff;
68pub const EFF_MASK: u32 = 0x1fffffff;
70pub const ERR_MASK: u32 = 0x1fffffff;
72pub const ERR_MASK_ALL: u32 = ERR_MASK;
74pub const ERR_MASK_NONE: u32 = 0;
76
77pub struct Can {
81 fd: c_int,
82}
83impl Can
84{
85 pub fn open(ifname: &str) -> Result<Can, io::Error> {
87 unsafe {
88 if ifname.len() > 16 {
89 return Err(io::Error::new(io::ErrorKind::Other, "No such device"));
90 }
91 let fd = libc::socket(PF_CAN, libc::SOCK_RAW, libc::CAN_RAW);
92 let mut uaddr = mem::MaybeUninit::<libc::sockaddr_can>::uninit();
93 let mut addr = uaddr.as_mut_ptr();
94 (*addr).can_family = AF_CAN as u16;
95 let mut cifname = [0 as c_char; 17];
96 for (i, ch) in ifname.chars().enumerate() {
97 cifname[i] = ch as c_char;
98 }
99 (*addr).can_ifindex = libc::if_nametoindex(&cifname as *const c_char) as i32;
100 if (*addr).can_ifindex == 0 {
101 return Err(io::Error::last_os_error());
102 }
103 let can = Can { fd: fd };
104 {
105 let timestamp_on: c_int = 1;
106 if libc::setsockopt(can.fd, libc::SOL_SOCKET, libc::SO_TIMESTAMP, ×tamp_on as *const c_int as *const c_void, mem::size_of::<c_int>() as u32 + 2) < 0 {
107 return Err(io::Error::last_os_error());
108 }
109 }
110 {
111 let opt_on: c_int = 1;
112 libc::setsockopt(can.fd, libc::SOL_CAN_RAW, libc::CAN_RAW_FD_FRAMES, &opt_on as *const c_int as *const c_void, mem::size_of::<c_int>() as u32);
113 }
114 if libc::bind(can.fd, addr as *const libc::sockaddr_can as *const libc::sockaddr, mem::size_of::<libc::sockaddr_can>() as u32) != 0 {
115 return Err(io::Error::last_os_error());
116 }
117 Ok(can)
118 }
119 }
120 pub fn recv(&self, msg: &mut Msg) -> Result<(), io::Error> {
123 unsafe {
124 msg.reset();
125 let nbytes = libc::recvmsg(self.fd, mem::transmute(&msg.msg), 0);
126 if nbytes < 0 {
127 return Err(io::Error::last_os_error());
128 }
129 }
130 Ok(())
131 }
132}
133impl Drop for Can {
134 fn drop(&mut self) {
135 unsafe {
136 if self.fd != 0 {
137 libc::close(self.fd);
138 }
139 self.fd = 0;
140 }
141 }
142}
143struct CanData<T> {
144 can: Can,
145 user_data: T,
146}
147pub struct Msg {
149 msg: libc::msghdr,
150 addr: libc::sockaddr_can,
151 iov: libc::iovec,
152 frame: libc::canfd_frame,
153 ctrlmsg: [u8; unsafe { libc::CMSG_SPACE(mem::size_of::<libc::timeval>() as u32) +
154 libc::CMSG_SPACE(3 * mem::size_of::<libc::timespec>() as u32) +
155 libc::CMSG_SPACE(mem::size_of::<u32>() as u32) } as usize],
156}
157impl Msg {
158 pub fn new() -> Box<Msg> {
162 unsafe {
163 let ucm = mem::MaybeUninit::<Msg>::uninit();
164 let mut msg = Box::<Msg>::new(mem::transmute(ucm));
165 msg.msg.msg_iovlen = 1;
166 msg.iov.iov_base = mem::transmute(&(*msg).frame);
167 msg.msg.msg_name = mem::transmute(&(*msg).addr);
168 msg.msg.msg_iov = mem::transmute(&(*msg).iov);
169 msg.msg.msg_control = mem::transmute(&(*msg).ctrlmsg[0]);
170 msg.reset();
171 msg
172 }
173 }
174 fn reset(&mut self) {
175 self.msg.msg_iovlen = 1;
176 self.iov.iov_len = mem::size_of::<libc::canfd_frame>();
177 self.msg.msg_namelen = mem::size_of::<libc::sockaddr_can>() as u32;
178 self.msg.msg_controllen = mem::size_of_val(&self.ctrlmsg);
179 self.msg.msg_flags = 0;
180 }
181 pub fn can_id(&self) -> u32 {
183 self.frame.can_id
184 }
185 pub fn len(&self) -> u8 {
187 self.frame.len
188 }
189 pub fn flags(&self) -> u8 {
191 self.frame.flags
192 }
193 pub fn timestamp(&self) -> io::Result<Duration> {
195 unsafe {
196 let mut cmsg = libc::CMSG_FIRSTHDR(&self.msg);
197 loop {
198 if cmsg.is_null() || (*cmsg).cmsg_level != libc::SOL_SOCKET {
199 break
200 }
201 match (*cmsg).cmsg_type {
202 libc::SO_TIMESTAMP => {
203 let tv = libc::CMSG_DATA(cmsg) as *const libc::timeval;
204 return Ok(Duration::milliseconds(((*tv).tv_sec * 1000000000 + (*tv).tv_usec * 1000) as i64));
205 }
206 libc::SO_TIMESTAMPING => {
207 let ts = libc::CMSG_DATA(cmsg) as *const libc::timespec;
208 return Ok(Duration::milliseconds(((*ts).tv_sec * 1000000000 + (*ts).tv_nsec) as i64));
209 }
210 _ => {
211 }
212 };
213 cmsg = libc::CMSG_NXTHDR(&self.msg, cmsg);
214 }
215 }
216 Err(io::Error::new(io::ErrorKind::Unsupported, "timestamps aren't supported"))
217 }
218}
219impl Index<usize> for Msg {
220 type Output = u8;
221 fn index(&self, index: usize) -> &u8 {
222 &self.frame.data[index]
223 }
224}
225pub struct CanGroup<T> {
227 fd_epoll: c_int,
228 cans: Vec<CanData<T>>,
229 events: Vec<libc::epoll_event>,
230 msg: Box<Msg>,
231}
232impl<T> CanGroup<T> {
233 pub fn new() -> CanGroup<T> {
235 unsafe {
236 CanGroup::<T> {
237 fd_epoll: libc::epoll_create(1),
238 cans: Vec::new(),
239 events: Vec::new(),
240 msg: Msg::new(),
241 }
242 }
243 }
244 pub fn add(&mut self, can: Can, user_data: T) -> io::Result<()> {
246 unsafe {
247 for i in 0..self.events.len() {
248 if libc::epoll_ctl(self.fd_epoll, libc::EPOLL_CTL_DEL, self.cans[i].can.fd, 0 as *mut libc::epoll_event) != 0 {
249 return Err(io::Error::last_os_error());
250 }
251 }
252 self.cans.push(CanData { can: can, user_data: user_data });
253 self.events.push(mem::transmute(mem::MaybeUninit::<libc::epoll_event>::uninit()));
254 for i in 0..self.events.len() {
255 self.events[i].events = libc::EPOLLIN as u32;
256 self.events[i].u64 = self.cans.last().unwrap() as *const _ as u64;
257 let eptr = self.events.as_mut_ptr();
258 if libc::epoll_ctl(self.fd_epoll, libc::EPOLL_CTL_ADD, self.cans[i].can.fd, eptr.add(i)) != 0 {
259 return Err(io::Error::last_os_error());
260 }
261 }
262 }
263 Ok(())
264 }
265 pub fn next(&mut self, timeout: Duration, on_recv: fn(&Box<Msg>, &T)) -> Result<bool, io::Error> {
272 unsafe {
273 let mut no_timeout = false;
274 let num_events = libc::epoll_wait(self.fd_epoll, self.events.as_mut_ptr(), self.events.len() as i32, timeout.num_milliseconds() as i32);
275 if num_events == -1 {
276 return Err(io::Error::last_os_error());
277 }
278 if num_events > 0 {
279 no_timeout = true;
280 for i in 0..num_events {
281 let can_data = self.events[i as usize].u64 as *mut CanData<T>;
282 (*can_data).can.recv(&mut self.msg)?;
283 on_recv(&self.msg, &(*can_data).user_data);
284 }
285 }
286 Ok(no_timeout)
287 }
288 }
289}
290impl<T> Drop for CanGroup<T> {
291 fn drop(&mut self) {
292 unsafe {
293 if self.fd_epoll != 0 {
294 libc::close(self.fd_epoll);
295 }
296 self.fd_epoll = 0;
297 }
298 }
299}
300
301#[cfg(test)]
302fn on_recv(msg: &Box<Msg>, _user_data: &u64) {
303 println!("timestamp: {:?}", msg.timestamp());
304 print!("received CAN frame (id: {}): ", msg.can_id());
305 for i in 0..msg.len() {
306 print!("{} ", msg[i as usize]);
307 }
308 println!("");
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 #[test]
315 fn it_works() {
316 let can = Can::open("vcan0").unwrap();
317 let mut cg = CanGroup::<u64>::new();
318 cg.add(can, 0).unwrap();
319 match cg.next(Duration::milliseconds(-1), on_recv) {
320 Ok(no_timeout) => if !no_timeout { panic!("timeout"); },
321 Err(_) => panic!("error"),
322 }
323 }
324}
325