Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 1 | #include "frc971/can_logger/can_logger.h" |
| 2 | |
Austin Schuh | c41249a | 2024-02-28 20:58:12 -0800 | [diff] [blame] | 3 | DEFINE_bool(poll, false, |
| 4 | "If true, poll the CAN bus every 100ms. If false, wake up for " |
| 5 | "each frame and publish it."); |
| 6 | |
Austin Schuh | d8362d5 | 2024-03-16 12:59:37 -0700 | [diff] [blame^] | 7 | DEFINE_int32(priority, 10, |
| 8 | "If --poll is not set, set the realtime priority to this."); |
| 9 | DEFINE_int32(affinity, -1, "If positive, pin to this core."); |
| 10 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame] | 11 | namespace frc971::can_logger { |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 12 | |
Maxwell Henderson | 0604e6f | 2024-01-15 15:24:44 -0800 | [diff] [blame] | 13 | CanLogger::CanLogger(aos::ShmEventLoop *event_loop, |
| 14 | std::string_view channel_name, |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 15 | std::string_view interface_name) |
Maxwell Henderson | 92b9d4e | 2024-02-13 20:21:08 -0800 | [diff] [blame] | 16 | : shm_event_loop_(event_loop), |
| 17 | fd_(socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)), |
| 18 | frames_sender_(shm_event_loop_->MakeSender<CanFrame>(channel_name)) { |
Austin Schuh | 9bf8a6f | 2024-02-28 23:58:01 -0800 | [diff] [blame] | 19 | // TODO(max): Figure out a proper priority |
| 20 | if (!FLAGS_poll) { |
Austin Schuh | d8362d5 | 2024-03-16 12:59:37 -0700 | [diff] [blame^] | 21 | shm_event_loop_->SetRuntimeRealtimePriority(FLAGS_priority); |
| 22 | } |
| 23 | if (FLAGS_affinity >= 0) { |
| 24 | shm_event_loop_->SetRuntimeAffinity( |
| 25 | aos::MakeCpusetFromCpus({FLAGS_affinity})); |
Austin Schuh | 9bf8a6f | 2024-02-28 23:58:01 -0800 | [diff] [blame] | 26 | } |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 27 | struct ifreq ifr; |
| 28 | strcpy(ifr.ifr_name, interface_name.data()); |
| 29 | PCHECK(ioctl(fd_.get(), SIOCGIFINDEX, &ifr) == 0) |
| 30 | << "Failed to get index for interface " << interface_name; |
| 31 | |
| 32 | int enable_canfd = true; |
| 33 | PCHECK(setsockopt(fd_.get(), SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, |
| 34 | sizeof(enable_canfd)) == 0) |
| 35 | << "Failed to enable CAN FD"; |
| 36 | |
| 37 | struct sockaddr_can addr; |
| 38 | addr.can_family = AF_CAN; |
| 39 | addr.can_ifindex = ifr.ifr_ifindex; |
| 40 | |
| 41 | PCHECK(bind(fd_.get(), reinterpret_cast<struct sockaddr *>(&addr), |
| 42 | sizeof(addr)) == 0) |
| 43 | << "Failed to bind socket to interface " << interface_name; |
| 44 | |
| 45 | int recieve_buffer_size; |
| 46 | socklen_t opt_size = sizeof(recieve_buffer_size); |
| 47 | PCHECK(getsockopt(fd_.get(), SOL_SOCKET, SO_RCVBUF, &recieve_buffer_size, |
| 48 | &opt_size) == 0); |
| 49 | CHECK_EQ(opt_size, sizeof(recieve_buffer_size)); |
| 50 | VLOG(0) << "CAN recieve bufffer is " << recieve_buffer_size << " bytes large"; |
| 51 | |
Austin Schuh | c41249a | 2024-02-28 20:58:12 -0800 | [diff] [blame] | 52 | if (FLAGS_poll) { |
| 53 | aos::TimerHandler *timer_handler = |
| 54 | shm_event_loop_->AddTimer([this]() { Poll(); }); |
| 55 | timer_handler->set_name("CAN logging Loop"); |
| 56 | timer_handler->Schedule(event_loop->monotonic_now(), kPollPeriod); |
| 57 | } else { |
| 58 | shm_event_loop_->epoll()->OnReadable(fd_.get(), [this]() { Poll(); }); |
| 59 | } |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | void CanLogger::Poll() { |
| 63 | VLOG(2) << "Polling"; |
| 64 | int frames_read = 0; |
| 65 | while (ReadFrame()) { |
| 66 | frames_read++; |
| 67 | } |
| 68 | VLOG(1) << "Read " << frames_read << " frames to end of buffer"; |
| 69 | } |
| 70 | |
| 71 | bool CanLogger::ReadFrame() { |
| 72 | errno = 0; |
| 73 | struct canfd_frame frame; |
| 74 | ssize_t bytes_read = read(fd_.get(), &frame, sizeof(struct canfd_frame)); |
| 75 | |
| 76 | if (bytes_read < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
| 77 | // There are no more frames sitting in the recieve buffer. |
| 78 | return false; |
| 79 | } |
| 80 | |
| 81 | VLOG(2) << "Read " << bytes_read << " bytes"; |
| 82 | PCHECK(bytes_read > 0); |
| 83 | PCHECK(bytes_read == static_cast<ssize_t>(CAN_MTU) || |
| 84 | bytes_read == static_cast<ssize_t>(CANFD_MTU)) |
| 85 | << "Incomplete can frame"; |
| 86 | |
| 87 | struct timeval tv; |
| 88 | PCHECK(ioctl(fd_.get(), SIOCGSTAMP, &tv) == 0) |
| 89 | << "Failed to get timestamp of CAN frame"; |
| 90 | |
| 91 | aos::Sender<CanFrame>::Builder builder = frames_sender_.MakeBuilder(); |
| 92 | |
| 93 | auto frame_data = builder.fbb()->CreateVector<uint8_t>(frame.data, frame.len); |
| 94 | |
| 95 | CanFrame::Builder can_frame_builder = builder.MakeBuilder<CanFrame>(); |
| 96 | can_frame_builder.add_can_id(frame.can_id); |
Ravago Jones | 6f64176 | 2023-03-29 19:58:32 -0700 | [diff] [blame] | 97 | can_frame_builder.add_flags(frame.flags); |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 98 | can_frame_builder.add_data(frame_data); |
James Kuszmaul | 22248e9 | 2024-02-23 16:46:51 -0800 | [diff] [blame] | 99 | can_frame_builder.add_realtime_timestamp_ns( |
| 100 | std::chrono::duration_cast<std::chrono::nanoseconds>( |
Ravago Jones | 1147237 | 2023-03-04 15:57:56 -0800 | [diff] [blame] | 101 | std::chrono::seconds(tv.tv_sec) + |
| 102 | std::chrono::microseconds(tv.tv_usec)) |
| 103 | .count()); |
| 104 | |
| 105 | builder.CheckOk(builder.Send(can_frame_builder.Finish())); |
| 106 | |
| 107 | return true; |
| 108 | } |
| 109 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame] | 110 | } // namespace frc971::can_logger |