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