blob: 7a6c0fe981bd42b16be4d93d529fe2b73ed9ffb8 [file] [log] [blame]
Ravago Jones11472372023-03-04 15:57:56 -08001#include "frc971/can_logger/can_logger.h"
2
3namespace frc971 {
4namespace can_logger {
5
Maxwell Henderson0604e6f2024-01-15 15:24:44 -08006CanLogger::CanLogger(aos::ShmEventLoop *event_loop,
7 std::string_view channel_name,
Ravago Jones11472372023-03-04 15:57:56 -08008 std::string_view interface_name)
9 : fd_(socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)),
Maxwell Henderson0604e6f2024-01-15 15:24:44 -080010 frames_sender_(event_loop->MakeSender<CanFrame>(channel_name)) {
Ravago Jones11472372023-03-04 15:57:56 -080011 struct ifreq ifr;
12 strcpy(ifr.ifr_name, interface_name.data());
13 PCHECK(ioctl(fd_.get(), SIOCGIFINDEX, &ifr) == 0)
14 << "Failed to get index for interface " << interface_name;
15
16 int enable_canfd = true;
17 PCHECK(setsockopt(fd_.get(), SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd,
18 sizeof(enable_canfd)) == 0)
19 << "Failed to enable CAN FD";
20
21 struct sockaddr_can addr;
22 addr.can_family = AF_CAN;
23 addr.can_ifindex = ifr.ifr_ifindex;
24
25 PCHECK(bind(fd_.get(), reinterpret_cast<struct sockaddr *>(&addr),
26 sizeof(addr)) == 0)
27 << "Failed to bind socket to interface " << interface_name;
28
29 int recieve_buffer_size;
30 socklen_t opt_size = sizeof(recieve_buffer_size);
31 PCHECK(getsockopt(fd_.get(), SOL_SOCKET, SO_RCVBUF, &recieve_buffer_size,
32 &opt_size) == 0);
33 CHECK_EQ(opt_size, sizeof(recieve_buffer_size));
34 VLOG(0) << "CAN recieve bufffer is " << recieve_buffer_size << " bytes large";
35
Maxwell Henderson0604e6f2024-01-15 15:24:44 -080036 event_loop->epoll()->OnReadable(fd_, [this]() { Poll(); });
Ravago Jones11472372023-03-04 15:57:56 -080037}
38
39void CanLogger::Poll() {
40 VLOG(2) << "Polling";
41 int frames_read = 0;
42 while (ReadFrame()) {
43 frames_read++;
44 }
45 VLOG(1) << "Read " << frames_read << " frames to end of buffer";
46}
47
48bool CanLogger::ReadFrame() {
49 errno = 0;
50 struct canfd_frame frame;
51 ssize_t bytes_read = read(fd_.get(), &frame, sizeof(struct canfd_frame));
52
53 if (bytes_read < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
54 // There are no more frames sitting in the recieve buffer.
55 return false;
56 }
57
58 VLOG(2) << "Read " << bytes_read << " bytes";
59 PCHECK(bytes_read > 0);
60 PCHECK(bytes_read == static_cast<ssize_t>(CAN_MTU) ||
61 bytes_read == static_cast<ssize_t>(CANFD_MTU))
62 << "Incomplete can frame";
63
64 struct timeval tv;
65 PCHECK(ioctl(fd_.get(), SIOCGSTAMP, &tv) == 0)
66 << "Failed to get timestamp of CAN frame";
67
68 aos::Sender<CanFrame>::Builder builder = frames_sender_.MakeBuilder();
69
70 auto frame_data = builder.fbb()->CreateVector<uint8_t>(frame.data, frame.len);
71
72 CanFrame::Builder can_frame_builder = builder.MakeBuilder<CanFrame>();
73 can_frame_builder.add_can_id(frame.can_id);
Ravago Jones6f641762023-03-29 19:58:32 -070074 can_frame_builder.add_flags(frame.flags);
Ravago Jones11472372023-03-04 15:57:56 -080075 can_frame_builder.add_data(frame_data);
76 can_frame_builder.add_monotonic_timestamp_ns(
77 static_cast<std::chrono::nanoseconds>(
78 std::chrono::seconds(tv.tv_sec) +
79 std::chrono::microseconds(tv.tv_usec))
80 .count());
81
82 builder.CheckOk(builder.Send(can_frame_builder.Finish()));
83
84 return true;
85}
86
87} // namespace can_logger
88} // namespace frc971