mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-28 07:47:02 -05:00
* Add Vector Binary Logging Format pattern * Combine object header extensions into single type --------- Co-authored-by: Nik <werwolv98@gmail.com>
534 lines
17 KiB
Rust
534 lines
17 KiB
Rust
|
|
|
|
// 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");
|
|
|