Skip to content

Commit be8103d

Browse files
committed
Add metadata object type
1 parent 5d62394 commit be8103d

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

can/io/blf.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ class BLFParseError(Exception):
7777
# group name length, marker name length, description length
7878
GLOBAL_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

8184
CAN_MESSAGE = 1
8285
LOG_CONTAINER = 10
86+
METADATA = 65
8387
CAN_ERROR_EXT = 73
8488
CAN_MESSAGE2 = 86
8589
GLOBAL_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

Comments
 (0)