@@ -77,9 +77,13 @@ class BLFParseError(Exception):
77
77
# group name length, marker name length, description length
78
78
GLOBAL_MARKER_STRUCT = struct .Struct ("<LLL3xBLLL12x" )
79
79
80
+ # Metadata object type, 4 context-specific bytes, metadata length, 4 more
81
+ # context-specific bytes
82
+ METADATA_HEADER_STRUCT = struct .Struct ("<I4BI4B" )
80
83
81
84
CAN_MESSAGE = 1
82
85
LOG_CONTAINER = 10
86
+ METADATA = 65
83
87
CAN_ERROR_EXT = 73
84
88
CAN_MESSAGE2 = 86
85
89
GLOBAL_MARKER = 96
@@ -142,7 +146,12 @@ class BLFReader(BinaryIOMessageReader):
142
146
Iterator of CAN messages from a Binary Logging File.
143
147
144
148
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.
146
155
"""
147
156
148
157
file : BinaryIO
@@ -173,6 +182,10 @@ def __init__(
173
182
)
174
183
# Read rest of header
175
184
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
+
176
189
self ._tail = b""
177
190
self ._pos = 0
178
191
@@ -230,6 +243,8 @@ def _parse_data(self, data):
230
243
unpack_can_fd_64_msg = CAN_FD_MSG_64_STRUCT .unpack_from
231
244
can_fd_64_msg_size = CAN_FD_MSG_64_STRUCT .size
232
245
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
233
248
234
249
start_timestamp = self .start_timestamp
235
250
max_pos = len (data )
@@ -370,6 +385,24 @@ def _parse_data(self, data):
370
385
data = msg_data ,
371
386
channel = channel - 1 ,
372
387
)
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 ))
373
406
374
407
pos = next_pos
375
408
0 commit comments