blob: 5282d13deca45c1db76c5be53b18df53eeb02ff1 [file] [log] [blame]
Ravago Jones09067de2023-03-29 18:44:43 -07001#include "frc971/can_logger/asc_logger.h"
2
3#include <linux/can.h>
4
Stephan Pleinesf63bde82024-01-13 15:59:33 -08005namespace frc971::can_logger {
Ravago Jones09067de2023-03-29 18:44:43 -07006
7AscLogger::AscLogger(aos::EventLoop *event_loop, const std::string &filename)
8 : output_(filename), event_loop_(event_loop) {
9 CHECK(output_);
10 event_loop->MakeWatcher(
11 "/can", [this](const CanFrame &frame) { HandleFrame(frame); });
12}
13
14void AscLogger::HandleFrame(const CanFrame &frame) {
James Kuszmaul22248e92024-02-23 16:46:51 -080015 if (!first_frame_realtime_) {
16 aos::realtime_clock::time_point time(
17 std::chrono::nanoseconds(frame.realtime_timestamp_ns()));
Ravago Jones09067de2023-03-29 18:44:43 -070018
James Kuszmaul22248e92024-02-23 16:46:51 -080019 first_frame_realtime_ = time;
Ravago Jones09067de2023-03-29 18:44:43 -070020
21 WriteHeader(output_, event_loop_->realtime_now());
22 }
23
24 WriteFrame(output_, frame);
25}
26
27void AscLogger::WriteHeader(std::ostream &file,
28 aos::realtime_clock::time_point start_time) {
29 file << "date " << start_time << "\n";
30 file << "base hex timetamps absolute\n";
31 file << "no internal events logged\n";
32}
33
34namespace {
35
36static const unsigned char len2dlc[] = {
37 0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
38 9, 9, 9, 9, /* 9 - 12 */
39 10, 10, 10, 10, /* 13 - 16 */
40 11, 11, 11, 11, /* 17 - 20 */
41 12, 12, 12, 12, /* 21 - 24 */
42 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
43 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
44 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
45 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
46 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
47
48/* map the sanitized data length to an appropriate data length code */
49unsigned char can_fd_len2dlc(unsigned char len) {
50 if (len > 64) return 0xF;
51
52 return len2dlc[len];
53}
54
55#define ASC_F_RTR 0x00000010
56#define ASC_F_FDF 0x00001000
57#define ASC_F_BRS 0x00002000
58#define ASC_F_ESI 0x00004000
59
60} // namespace
61
62void AscLogger::WriteFrame(std::ostream &file, const CanFrame &frame) {
James Kuszmaul22248e92024-02-23 16:46:51 -080063 aos::realtime_clock::time_point frame_timestamp(
64 std::chrono::nanoseconds(frame.realtime_timestamp_ns()));
Ravago Jones09067de2023-03-29 18:44:43 -070065
66 std::chrono::duration<double> time(frame_timestamp -
James Kuszmaul22248e92024-02-23 16:46:51 -080067 first_frame_realtime_.value());
Ravago Jones09067de2023-03-29 18:44:43 -070068
69 // TODO: maybe this should not be hardcoded
70 const int device_id = 1;
71
72 // EFF/SFF is set in the MSB
73 bool is_extended_frame_format = frame.can_id() & CAN_EFF_FLAG;
74
75 uint32_t id_mask = is_extended_frame_format ? CAN_EFF_MASK : CAN_SFF_MASK;
76 int id = frame.can_id() & id_mask;
77
78 // data length code
79 int dlc = can_fd_len2dlc(frame.data()->size());
80
81 const uint8_t flags = frame.flags();
82
83 uint32_t asc_flags = 0;
84
85 // Mark it as a CAN FD Frame
86 asc_flags = ASC_F_FDF;
87
88 // Pass through the bit rate switch flag
89 // indicates that it used a second bitrate for payload data
90 if (flags & CANFD_BRS) {
91 asc_flags |= ASC_F_BRS;
92 }
93
94 // ESI is the error state indicator of the transmitting node
95 if (flags & CANFD_ESI) {
96 asc_flags |= ASC_F_ESI;
97 }
98
99 file << std::fixed << time.count() << " ";
100
101 file << "CANFD ";
102
103 file << std::setfill(' ') << std::setw(3) << std::right << device_id << " ";
104
105 file << "Rx ";
106
107 std::stringstream formatted_id;
108 formatted_id << std::hex << std::uppercase << std::setfill('0') << id
109 << std::dec;
110 if (is_extended_frame_format) {
111 formatted_id << "x";
112 }
113
114 file << std::setfill(' ') << std::setw(11) << formatted_id.str();
115 file << " ";
116
117 file << ((flags & CANFD_BRS) ? '1' : '0') << " ";
118 file << ((flags & CANFD_ESI) ? '1' : '0') << " ";
119
120 file << std::hex << std::nouppercase << dlc << std::dec << " ";
121
122 // actual data length
123 file << std::setfill(' ') << std::setw(2) << frame.data()->size();
124
125 file << std::hex << std::uppercase;
126 for (uint8_t byte : *frame.data()) {
127 file << " " << std::setfill('0') << std::setw(2) << static_cast<int>(byte);
128 }
129 file << std::dec;
130
131 // these are hardcoded in log2asc too, I don't know why
132 file << " 130000 130 ";
133 file << std::setfill(' ') << std::setw(8) << std::hex << asc_flags
134 << std::dec;
135 file << " 0 0 0 0 0";
136
137 file << "\n";
138}
139
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800140} // namespace frc971::can_logger