blob: d3506726eec9ecbf97f07c546dcd5997fc49eaff [file] [log] [blame]
Ravago Jones11472372023-03-04 15:57:56 -08001#include "frc971/can_logger/can_logger.h"
2
Austin Schuh99f7c6a2024-06-25 22:07:44 -07003#include "absl/flags/flag.h"
Austin Schuhc41249a2024-02-28 20:58:12 -08004
Austin Schuh99f7c6a2024-06-25 22:07:44 -07005ABSL_FLAG(bool, poll, false,
6 "If true, poll the CAN bus every 100ms. If false, wake up for "
7 "each frame and publish it.");
8
9ABSL_FLAG(int32_t, priority, 10,
10 "If --poll is not set, set the realtime priority to this.");
11ABSL_FLAG(int32_t, affinity, -1, "If positive, pin to this core.");
Austin Schuhd8362d52024-03-16 12:59:37 -070012
Stephan Pleinesf63bde82024-01-13 15:59:33 -080013namespace frc971::can_logger {
Ravago Jones11472372023-03-04 15:57:56 -080014
Maxwell Henderson0604e6f2024-01-15 15:24:44 -080015CanLogger::CanLogger(aos::ShmEventLoop *event_loop,
16 std::string_view channel_name,
Ravago Jones11472372023-03-04 15:57:56 -080017 std::string_view interface_name)
Maxwell Henderson92b9d4e2024-02-13 20:21:08 -080018 : shm_event_loop_(event_loop),
19 fd_(socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)),
20 frames_sender_(shm_event_loop_->MakeSender<CanFrame>(channel_name)) {
Austin Schuh9bf8a6f2024-02-28 23:58:01 -080021 // TODO(max): Figure out a proper priority
Austin Schuh99f7c6a2024-06-25 22:07:44 -070022 if (!absl::GetFlag(FLAGS_poll)) {
23 shm_event_loop_->SetRuntimeRealtimePriority(absl::GetFlag(FLAGS_priority));
Austin Schuhd8362d52024-03-16 12:59:37 -070024 }
Austin Schuh99f7c6a2024-06-25 22:07:44 -070025 if (absl::GetFlag(FLAGS_affinity) >= 0) {
Austin Schuhd8362d52024-03-16 12:59:37 -070026 shm_event_loop_->SetRuntimeAffinity(
Austin Schuh99f7c6a2024-06-25 22:07:44 -070027 aos::MakeCpusetFromCpus({absl::GetFlag(FLAGS_affinity)}));
Austin Schuh9bf8a6f2024-02-28 23:58:01 -080028 }
Ravago Jones11472372023-03-04 15:57:56 -080029 struct ifreq ifr;
30 strcpy(ifr.ifr_name, interface_name.data());
31 PCHECK(ioctl(fd_.get(), SIOCGIFINDEX, &ifr) == 0)
32 << "Failed to get index for interface " << interface_name;
33
34 int enable_canfd = true;
35 PCHECK(setsockopt(fd_.get(), SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd,
36 sizeof(enable_canfd)) == 0)
37 << "Failed to enable CAN FD";
38
39 struct sockaddr_can addr;
40 addr.can_family = AF_CAN;
41 addr.can_ifindex = ifr.ifr_ifindex;
42
43 PCHECK(bind(fd_.get(), reinterpret_cast<struct sockaddr *>(&addr),
44 sizeof(addr)) == 0)
45 << "Failed to bind socket to interface " << interface_name;
46
47 int recieve_buffer_size;
48 socklen_t opt_size = sizeof(recieve_buffer_size);
49 PCHECK(getsockopt(fd_.get(), SOL_SOCKET, SO_RCVBUF, &recieve_buffer_size,
50 &opt_size) == 0);
51 CHECK_EQ(opt_size, sizeof(recieve_buffer_size));
52 VLOG(0) << "CAN recieve bufffer is " << recieve_buffer_size << " bytes large";
53
Austin Schuh99f7c6a2024-06-25 22:07:44 -070054 if (absl::GetFlag(FLAGS_poll)) {
Austin Schuhc41249a2024-02-28 20:58:12 -080055 aos::TimerHandler *timer_handler =
56 shm_event_loop_->AddTimer([this]() { Poll(); });
57 timer_handler->set_name("CAN logging Loop");
58 timer_handler->Schedule(event_loop->monotonic_now(), kPollPeriod);
59 } else {
60 shm_event_loop_->epoll()->OnReadable(fd_.get(), [this]() { Poll(); });
61 }
Ravago Jones11472372023-03-04 15:57:56 -080062}
63
64void CanLogger::Poll() {
65 VLOG(2) << "Polling";
66 int frames_read = 0;
67 while (ReadFrame()) {
68 frames_read++;
69 }
70 VLOG(1) << "Read " << frames_read << " frames to end of buffer";
71}
72
73bool CanLogger::ReadFrame() {
74 errno = 0;
75 struct canfd_frame frame;
76 ssize_t bytes_read = read(fd_.get(), &frame, sizeof(struct canfd_frame));
77
78 if (bytes_read < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
79 // There are no more frames sitting in the recieve buffer.
80 return false;
81 }
82
83 VLOG(2) << "Read " << bytes_read << " bytes";
84 PCHECK(bytes_read > 0);
85 PCHECK(bytes_read == static_cast<ssize_t>(CAN_MTU) ||
86 bytes_read == static_cast<ssize_t>(CANFD_MTU))
87 << "Incomplete can frame";
88
89 struct timeval tv;
90 PCHECK(ioctl(fd_.get(), SIOCGSTAMP, &tv) == 0)
91 << "Failed to get timestamp of CAN frame";
92
93 aos::Sender<CanFrame>::Builder builder = frames_sender_.MakeBuilder();
94
95 auto frame_data = builder.fbb()->CreateVector<uint8_t>(frame.data, frame.len);
96
97 CanFrame::Builder can_frame_builder = builder.MakeBuilder<CanFrame>();
98 can_frame_builder.add_can_id(frame.can_id);
Ravago Jones6f641762023-03-29 19:58:32 -070099 can_frame_builder.add_flags(frame.flags);
Ravago Jones11472372023-03-04 15:57:56 -0800100 can_frame_builder.add_data(frame_data);
James Kuszmaul22248e92024-02-23 16:46:51 -0800101 can_frame_builder.add_realtime_timestamp_ns(
102 std::chrono::duration_cast<std::chrono::nanoseconds>(
Ravago Jones11472372023-03-04 15:57:56 -0800103 std::chrono::seconds(tv.tv_sec) +
104 std::chrono::microseconds(tv.tv_usec))
105 .count());
106
107 builder.CheckOk(builder.Send(can_frame_builder.Finish()));
108
109 return true;
110}
111
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800112} // namespace frc971::can_logger