@@ -77,9 +77,13 @@ class BLFParseError(Exception):
7777# group name length, marker name length, description length
7878GLOBAL_MARKER_STRUCT = struct .Struct ("<LLL3xBLLL12x" )
7979
80+ # Metadata object type, 4 context-specific bytes, metadata length, 4 more
81+ # context-specific bytes
82+ METADATA_HEADER_STRUCT = struct .Struct ("<I4BI4B" )
8083
8184CAN_MESSAGE = 1
8285LOG_CONTAINER = 10
86+ METADATA = 65
8387CAN_ERROR_EXT = 73
8488CAN_MESSAGE2 = 86
8589GLOBAL_MARKER = 96
@@ -142,7 +146,12 @@ class BLFReader(BinaryIOMessageReader):
142146 Iterator of CAN messages from a Binary Logging File.
143147
144148 Only CAN messages and error frames are supported. Other object types are
145- silently ignored.
149+ silently ignored. Metadata objects are parsed into `self.metadata` when
150+ they are encountered while iterating.
151+
152+ Metadata are a list of tuples containing the parsed metadata objects. The
153+ interpretation of this data is context-specific and out of scope of the
154+ BLFReader class.
146155 """
147156
148157 file : BinaryIO
@@ -173,6 +182,10 @@ def __init__(
173182 )
174183 # Read rest of header
175184 self .file .read (header [1 ] - FILE_HEADER_STRUCT .size )
185+
186+ # Metadata is appended when type 65 is encountered while iterating
187+ self .metadata = []
188+
176189 self ._tail = b""
177190 self ._pos = 0
178191
@@ -230,6 +243,8 @@ def _parse_data(self, data):
230243 unpack_can_fd_64_msg = CAN_FD_MSG_64_STRUCT .unpack_from
231244 can_fd_64_msg_size = CAN_FD_MSG_64_STRUCT .size
232245 unpack_can_error_ext = CAN_ERROR_EXT_STRUCT .unpack_from
246+ metadata_header = METADATA_HEADER_STRUCT .unpack_from
247+ metadata_header_size = METADATA_HEADER_STRUCT .size
233248
234249 start_timestamp = self .start_timestamp
235250 max_pos = len (data )
@@ -370,6 +385,24 @@ def _parse_data(self, data):
370385 data = msg_data ,
371386 channel = channel - 1 ,
372387 )
388+ elif obj_type == METADATA :
389+ # When we encounter a metadata object, parse it and save it in
390+ # self.metadata and continue looping for a message to return
391+ (
392+ mdobj_type ,
393+ b0 , b1 , b2 , b3 ,
394+ mdsize ,
395+ b4 , b5 , b6 , b7
396+ ) = metadata_header (data , pos )
397+ # Context-specific data
398+ mdcontext = bytearray ([b0 , b1 , b2 , b3 , b4 , b5 , b6 , b7 ])
399+ # Read until the end of the block rather than using the
400+ # untrusted size bytes
401+ mdstring = data [pos + metadata_header_size :next_pos ]
402+ # Append the metadata block, including the size bytes read
403+ # from the header. Caller can determine what to do if there's
404+ # a mismatch
405+ self .metadata .append ((mdobj_type , mdcontext , mdsize , mdstring ))
373406
374407 pos = next_pos
375408
0 commit comments