-
-
Notifications
You must be signed in to change notification settings - Fork 282
Expand file tree
/
Copy pathblf.hexpat
More file actions
533 lines (474 loc) · 16.7 KB
/
blf.hexpat
File metadata and controls
533 lines (474 loc) · 16.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
// Pattern for binary logging files (Vector BLF)
// References used for writing this:
// https://python-can.readthedocs.io/en/stable/_modules/can/io/blf.html
// https://bitbucket.org/tobylorenz/vector_blf
#pragma magic [ 4C 4F 47 47 ] @ 0x00
#pragma description Vector BLF Frame Logging Files
#pragma array_limit 4194304
#pragma pattern_limit 4294967296
#pragma endian little
import hex.dec;
import std.io;
import type.magic;
enum object_type : u32 {
unknown = 0, //< unknown object
can_message = 1, //< CAN message object
can_error = 2, //< CAN error frame object
can_overload = 3, //< CAN overload frame object
can_statistic = 4, //< CAN driver statistics object
app_trigger = 5, //< application trigger object
env_integer = 6, //< environment integer object
env_double = 7, //< environment double object
env_string = 8, //< environment string object
env_data = 9, //< environment data object
log_container = 10, //< container object
lin_message = 11, //< LIN message object
lin_crc_error = 12, //< LIN CRC error object
lin_dlc_info = 13, //< LIN DLC info object
lin_rcv_error = 14, //< LIN receive error object
lin_snd_error = 15, //< LIN send error object
lin_slv_timeout = 16, //< LIN slave timeout object
lin_sched_modch = 17, //< LIN scheduler mode change object
lin_syn_error = 18, //< LIN sync error object
lin_baudrate = 19, //< LIN baudrate event object
lin_sleep = 20, //< LIN sleep mode event object
lin_wakeup = 21, //< LIN wakeup event object
most_spy = 22, //< MOST spy message object
most_ctrl = 23, //< MOST control message object
most_lightlock = 24, //< MOST light lock object
most_statistic = 25, //< MOST statistic object
flexray_data = 29, //< FLEXRAY data object
flexray_sync = 30, //< FLEXRAY sync object
can_driver_error = 31, //< CAN driver error object
most_pkt = 32, //< MOST Packet
most_pkt2 = 33, //< MOST Packet including original timestamp
most_hwmode = 34, //< MOST hardware mode event
most_reg = 35, //< MOST register data (various chips)
most_genreg = 36, //< MOST register data (MOST register)
most_netstate = 37, //< MOST NetState event
most_datalost = 38, //< MOST data lost
most_trigger = 39, //< MOST trigger
flexray_cycle = 40, //< FLEXRAY V6 start cycle object
flexray_message = 41, //< FLEXRAY V6 message object
lin_checksum_info = 42, //< LIN checksum info event object
lin_spike_event = 43, //< LIN spike event object
can_driver_sync = 44, //< CAN driver hardware sync
flexray_status = 45, //< FLEXRAY status event object
gps_event = 46, //< GPS event object
flexray_error = 47, //< FLEXRAY error event object
flexray_status = 48, //< FLEXRAY status event object
flexray_startcycle = 49, //< FLEXRAY start cycle event object
flexray_rcv_message = 50, //< FLEXRAY receive message event object
realtime_clock = 51, //< Realtime clock object
lin_statistic = 54, //< LIN statistic event object
j1708_message = 55, //< J1708 message object
j1708_virtual_message = 56, //< J1708 message object with more than 21 data bytes
lin_message2 = 57, //< LIN frame object - extended
lin_snd_error2 = 58, //< LIN transmission error object - extended
lin_syn_error2 = 59, //< LIN sync error object - extended
lin_crc_error2 = 60, //< LIN checksum error object - extended
lin_crv_error2 = 61, //< LIN receive error object
lin_wakeup2 = 62, //< LIN wakeup event object - extended
lin_spike_event2 = 63, //< LIN spike event object - extended
lin_long_dom_sig = 64, //< LIN long dominant signal object
app_text = 65, //< text object
flexray_rcvmessage_ex = 66, //< FLEXRAY receive message ex event object
most_statistic_ex = 67, //< MOST extended statistic event
most_txlight = 68, //< MOST TxLight event
most_alloctab = 69, //< MOST Allocation table event
most_stress = 70, //< MOST Stress event
ethernet_frame = 71, //< Ethernet frame object
sys_variable = 72, //< system variable object
can_error_ext = 73, //< CAN error frame object (extended)
can_driver_error_ext = 74, //< CAN driver error object (extended)
lin_long_dom_sig2 = 75, //< LIN long dominant signal object - extended
most_150_message = 76, //< MOST150 Control channel message
most_150_pkt = 77, //< MOST150 Asynchronous channel message
most_ethernet_pkt = 78, //< MOST Ethernet channel message
most_150_message_fragment = 79, //< Partial transmitted MOST50/150 Control channel message
most_150_pkt_fragment = 80, //< Partial transmitted MOST50/150 data packet on asynchronous channel
most_ethernet_pkt_fragment = 81, //< Partial transmitted MOST Ethernet packet on asynchronous channel
most_system_event = 82, //< Event for various system states on MOST
most_150_alloctab = 83, //< MOST50/150 Allocation table event
most_50_message = 84, //< MOST50 Control channel message
most_50_pkg = 85, //< MOST50 Asynchronous channel message
can_message2 = 86, //< CAN message object - extended
lin_unexpected_wakeup = 87,
lin_short_or_slow_response = 88,
lin_disturbance_event = 89,
serial_event = 90,
overrun_error = 91, //< driver overrun event
event_comment = 92,
wlan_frame = 93,
wlan_statistic = 94,
most_ecl = 95, //< MOST Electrical Control Line event
global_marker = 96,
afdx_frame = 97,
afdx_statistic = 98,
kline_statusevent = 99, //< E.g. wake-up pattern
can_fd_message = 100, //< CAN FD message object
can_fd_message_64 = 101, //< CAN FD message object
ethernet_rx_error = 102, //< Ethernet RX error object
ethernet_status = 103, //< Ethernet status object
can_fd_error_64 = 104, //< CAN FD Error Frame object
lin_short_or_slow_response2 = 105,
afdx_status = 106, //< AFDX status object
afdx_bus_statistic = 107, //< AFDX line-dependent busstatistic object
afdx_error_event = 109, //< AFDX asynchronous error event
a429_error = 110, //< A429 error object
a429_status = 111, //< A429 status object
a429_bus_statistic = 112, //< A429 busstatistic object
a429_message = 113, //< A429 Message
ethernet_statistic = 114, //< Ethernet statistic object
restore_point_container = 115, //< Restore point container, use unknown
test_structure = 118, //< Event for test execution flow
diag_request_information = 119, //< Event for correct interpretation of diagnostic requests
ethernet_frame_ex = 120, //< Ethernet packet extended object
ethernet_frame_forwarded = 121, //< Ethernet packet forwarded object
ethernet_error_ex = 122, //< Ethernet error extended object
ethernet_error_forwarded = 123, //< Ethernet error forwarded object
function_bus = 124, //< FunctionBus object
data_lost_begin = 125, //< Data lost begin
data_lost_end = 126, //< Data lost end
water_mark_event = 127, //< Watermark event
trigger_condition = 128, //< Trigger Condition event
can_setting_changed = 129, //< CAN Settings Changed object
distributed_object_member = 130, //< Distributed object member (communication setup)
attribute_event = 131, //< ATTRIBUTE event (communication setup)
};
bitfield can_msg_flags {
is_tx : 1;
padding : 4;
nerr : 1;
wu : 1;
rtr : 1;
};
struct can_msg {
u16 channel;
can_msg_flags flags;
u8 dlc;
u32 id;
u8 data[8];
};
struct can_msg2 {
u16 channel;
can_msg_flags flags;
u8 dlc;
u32 id;
auto struct_len = 2 + 1 + 1 + 4 + 4 + 1 + 1 + 2; // TODO: Alternative way of doing this?
u8 data[parent.header.object_size - parent.header.header_size - struct_len];
// The frame length in nanoseconds
u32 frame_length;
// Total number of bits of the CAN frame
u8 bit_count;
padding[1];
padding[2];
};
bitfield can_fd_msg_flags {
edl : 1; //< Extended data length
brs : 1; //< Bit rate switch
esi : 1; //< Error state indicator
padding : 5;
};
fn format_can_fd_dlc(u8 dlc) {
if (dlc > 8)
return 8 + (dlc - 8) * 4;
return dlc;
};
struct can_fd_msg {
u16 channel;
u8 flags;
u8 dlc [[format("format_can_fd_dlc")]];
u32 id;
// The frame length in nanoseconds
u32 frame_length;
u8 arbitration_bit_count;
can_fd_msg_flags fd_flags;
u8 valid_data_bytes;
padding[1];
padding[4];
u8 data[64];
padding[4];
};
bitfield can_fd_msg_64_flags {
padding : 2;
nerr : 1;
hv_wake_up : 1;
remote_frame : 1;
padding : 1;
tx_ack : 1;
tx_req : 1;
padding : 1;
srr : 1;
r0 : 1;
r1 : 1;
edl : 1; //< Extended data length
brs : 1; //< Bit rate switch
esi : 1; //< Error state indicator
padding : 2;
burst : 1;
padding : 13;
};
struct can_bitrate_cfg {
u8 quartz_frequency;
u8 prescaler;
u8 btl_cycles;
u8 sampling_point;
};
struct can_fd_msg_64 {
u8 channel;
u8 dlc [[format("format_can_fd_dlc")]];
u8 valid_data_bytes;
u8 tx_count;
u32 id;
u32 frame_length;
can_fd_msg_64_flags flags;
can_bitrate_cfg arbitration_bitrate;
can_bitrate_cfg data_bitrate;
u32 brs_time_offset;
u32 crc_time_offset;
u16 bit_length;
u8 direction;
u8 data_offset;
u32 crc;
u8 data[valid_data_bytes];
};
fn format_bus_load(u16 bus_load) {
return std::format("{}%", float(bus_load) / 100.f);
};
struct can_statistic {
u16 channel;
// Bus load in 1/100 percent
u16 bus_load [[format("format_bus_load")]];
u32 standard_data_frames;
u32 extended_data_frames;
u32 standard_remote_frames;
u32 extended_remote_frames;
u32 error_frames;
u32 overload_frames;
u32 reserved;
};
struct can_driver_error {
u16 channel;
u8 tx_errors;
u8 rx_errors;
u32 error_code;
};
enum app_text_source : u32 {
comment = 0,
database_info = 1,
metadata = 2,
};
enum database_bus_type : u8 {
can = 1,
lin = 5,
most = 6,
flexray = 7,
j1708 = 9,
ethernet = 10,
wlan = 13,
afdx = 14,
};
bitfield app_text_database_info {
version : 8;
channel_num : 8;
database_bus_type bus_type : 8;
is_can_fd : 1;
padding : 7;
};
struct app_text {
app_text_source source;
if (source == 1)
app_text_database_info database_info;
else
padding[4]; // TODO: This is not necessarily padding, there's data here
u32 text_length;
padding[4];
char text[text_length];
};
// No idea what this is or does
struct restore_point_container {
u8 rpc[14];
u16 data_len;
u8 data[data_len];
};
enum compression_method : u16 {
no_compression = 0,
zlib = 2,
};
// The following section contains all of the decompressed data at once
std::mem::Section decompressed_data = std::mem::create_section("Decompressed data");
// This section is used only for decompressing data
std::mem::Section zlib_decompress_result = std::mem::create_section("zlib decompress result");
struct log_container {
u64 container_begin = $;
compression_method compression_method;
padding[2];
padding[4];
u32 uncompressed_size;
padding[4];
if (compression_method == compression_method::zlib) {
std::mem::set_section_size(zlib_decompress_result, uncompressed_size);
// Create a pattern that defines the compressed array data
auto compressed_byte_len = parent.header.object_size - parent.header.header_size - ($ - container_begin);
u8 compressed[compressed_byte_len];
if (uncompressed_size != 0)
padding[parent.header.object_size % 4]; // Idk, the format wants this... for some reason
std::assert(hex::dec::zlib_decompress(compressed, zlib_decompress_result) == compressed_byte_len,
"zlib decompress needs to succeed");
// Copy the decompressed data to the end of the section
std::mem::copy_section_to_section(zlib_decompress_result, 0,
decompressed_data, std::mem::get_section_size(decompressed_data),
std::mem::get_section_size(zlib_decompress_result));
} else if (compression_method == compression_method::no_compression) {
u8 data[uncompressed_size];
std::mem::copy_value_to_section(data, decompressed_data, std::mem::get_section_size(decompressed_data));
} else {
std::assert(false, "Invalid/unknown compression method");
}
};
enum object_flags : u32 {
// Timestamps are stored with a unit of 10us (10 microseconds)
time_10_us = 1,
// Timestamps are stored with a unit of 1ns (1 nanosecond)
time_1_ns = 2,
};
enum timestamp_status : u8 {
// Means original timestamps are valid
orig = 0x01,
// Timestamp is generated by software (1) or by hardware (0)
swhw = 0x02,
user = 0x10,
};
struct obj_header_ext {
object_flags flags;
if (parent.header.header_version == 1)
u16 client_index;
else if (parent.header.header_version == 2) {
timestamp_status timestamp_status;
padding[1];
}
u16 object_version;
u64 object_timestamp;
if (parent.header.header_version == 2)
u64 original_timestamp;
};
struct obj_header {
type::Magic<"LOBJ"> magic; // 4C 4F 42 4A
u16 header_size;
u16 header_version;
u32 object_size;
object_type object_type;
std::assert(header_version == 1 || header_version == 2, "Invalid/unknown header version");
};
struct obj_struct {
auto object_begin = $;
obj_header header [[inline]];
if (header.object_type == object_type::log_container) {
// Log containers seem to never include additional V1 or V2 headers
log_container log [[inline]];
} else {
obj_header_ext ext_header [[inline]];
match(header.object_type) {
(object_type::can_message): {
can_msg message [[inline]];
}
(object_type::can_statistic): {
can_statistic statistics [[inline]];
}
(object_type::can_driver_error): {
can_driver_error errors [[inline]];
}
(object_type::can_message2): {
can_msg2 message [[inline]];
}
(object_type::can_fd_message): {
can_fd_msg message [[inline]];
}
(object_type::can_fd_message_64): {
can_fd_msg_64 message [[inline]];
padding[header.object_size - ($ - object_begin)]; // TODO: This pattern doesn't support the extra data for this object
}
(object_type::app_text): {
app_text text [[inline]];
padding[header.object_size % 4];
}
(object_type::restore_point_container): {
restore_point_container rpc [[inline]];
}
(_): u8 bytes[header.object_size - header.header_size];
}
}
};
enum application_id : u8 {
unknown = 0,
canalyzer = 1,
canoe = 2,
canstress = 3,
canlog = 4,
canape = 5,
cancasexl = 6,
vlconfig = 7,
porsche_logger = 200,
caetec_logger = 201,
vector_net_sim = 202,
ipetronik_logger = 203,
rtpk = 204,
piketec = 205,
sparks = 206,
};
fn format_api_version(u32 api_version) {
return std::format("{}.{}.{}",
api_version / 1000000,
(api_version % 1000000) / 1000,
(api_version % 1000) / 100);
};
// Mostly just the zlib compression levels, but with some extras
enum compression_level : u8 {
no_compression = 0,
best_speed = 1,
default_compression = 6,
best_compression = 9,
// This means that the file contains only log containers, usually compressed at level 6
default_container_compression = 10,
};
struct timestamp {
u16 year;
u16 month;
u16 day_of_week;
u16 day;
u16 hour;
u16 minute;
u16 second;
u16 millisecond;
} [[format("format_timestamp")]];
fn format_timestamp(timestamp ts) {
return std::format("{}-{}-{}_{}-{}-{}",
ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second);
};
struct file_header {
type::Magic<"LOGG"> magic; // 4C 4F 47 47
u32 header_length;
u32 api_version [[format("format_api_version")]];
application_id app_id;
compression_level compression_level;
u8 app_major;
u8 app_minor;
u64 file_length;
u64 uncompressed_length;
u32 object_count;
u32 application_build;
timestamp start_timestamp;
timestamp stop_timestamp;
u64 restore_point_offset; // ?
} [[inline]];
struct file_layout {
file_header header;
padding[header.header_length - sizeof(header)];
obj_struct objects[while($ < std::mem::size())];
// Decode all objects from the zlib compressed data
if (std::mem::get_section_size(decompressed_data) != 0)
obj_struct decompressed_objects[header.object_count] @ 0x00 in decompressed_data;
} [[inline]];
file_layout file @ 0x00;
std::assert_warn(std::mem::size() == file.header.file_length, "file size mismatch");