20
20
from typing import Any , BinaryIO , Generator , List , Optional , Tuple , Union , cast
21
21
22
22
from ..message import Message
23
+ from ..ethernetframe import EthernetFrame
24
+ from ..unknownmessage import UnknownMessage
25
+ from ..ethernetframeext import EthernetFrameExt
23
26
from ..typechecking import StringPathLike
24
27
from ..util import channel2int , dlc2len , len2dlc
25
28
from .generic import BinaryIOMessageReader , FileIOMessageWriter
@@ -76,14 +79,27 @@ class BLFParseError(Exception):
76
79
# group name length, marker name length, description length
77
80
GLOBAL_MARKER_STRUCT = struct .Struct ("<LLL3xBLLL12x" )
78
81
82
+ # sourceAddress, channel, destinationAddress, dir, type, tpid, tci, payloadLength, reservedEthernetFrame
83
+ ETHERNET_FRAME_STRUCT = struct .Struct ("<6sH6sHHHHHQ" )
84
+ # after this, max 1500 data bytes of payload follows (ethernet header not included)
85
+
86
+ # structLength, flags, channel, hardwareChannel, frameduration, framechecksum, dir, frameLength, framehandle, reservedEthernetFrameEx
87
+ ETHERNET_FRAME_EX_STRUCT = struct .Struct ("<HHHHQLHHLL" )
88
+ # after this follows up to 1612 bytes of frameData containing: Ethernet header + Ethernet payload
79
89
80
90
CAN_MESSAGE = 1
81
91
LOG_CONTAINER = 10
92
+ ETHERNET_FRAME = 71
82
93
CAN_ERROR_EXT = 73
83
94
CAN_MESSAGE2 = 86
84
95
GLOBAL_MARKER = 96
85
96
CAN_FD_MESSAGE = 100
86
97
CAN_FD_MESSAGE_64 = 101
98
+ ETHERNET_FRAME_EX = 120 # < Ethernet packet extended object
99
+ # Related ethernet containers not yet supported:
100
+ # ETHERNET_FRAME_FORWARDED = 121 # < Ethernet packet forwarded object
101
+ # ETHERNET_ERROR_EX = 122 # < Ethernet error extended object
102
+ # ETHERNET_ERROR_FORWARDED = 123 # < Ethernet error forwarded object
87
103
88
104
NO_COMPRESSION = 0
89
105
ZLIB_DEFLATE = 2
@@ -100,7 +116,7 @@ class BLFParseError(Exception):
100
116
101
117
102
118
def timestamp_to_systemtime (timestamp : float ) -> TSystemTime :
103
- if timestamp is None or timestamp < 631152000 :
119
+ if timestamp is None :
104
120
# Probably not a Unix timestamp
105
121
return 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
106
122
t = datetime .datetime .fromtimestamp (round (timestamp , 3 ))
@@ -167,7 +183,7 @@ def __init__(
167
183
self ._tail = b""
168
184
self ._pos = 0
169
185
170
- def __iter__ (self ) -> Generator [Message , None , None ]:
186
+ def __iter__ (self ) -> Generator [Union [ Message , UnknownMessage , EthernetFrame , EthernetFrameExt ] , None , None ]:
171
187
while True :
172
188
data = self .file .read (OBJ_HEADER_BASE_STRUCT .size )
173
189
if not data :
@@ -196,7 +212,7 @@ def __iter__(self) -> Generator[Message, None, None]:
196
212
yield from self ._parse_container (data )
197
213
self .stop ()
198
214
199
- def _parse_container (self , data ) :
215
+ def _parse_container (self , data : bytes ) -> Generator [ Union [ Message , UnknownMessage , EthernetFrame , EthernetFrameExt ], None , None ] :
200
216
if self ._tail :
201
217
data = b"" .join ((self ._tail , data ))
202
218
try :
@@ -207,7 +223,7 @@ def _parse_container(self, data):
207
223
# Save the remaining data that could not be processed
208
224
self ._tail = data [self ._pos :]
209
225
210
- def _parse_data (self , data ) :
226
+ def _parse_data (self , data : bytes ) -> Generator [ Union [ Message , UnknownMessage , EthernetFrame , EthernetFrameExt ], None , None ] :
211
227
"""Optimized inner loop by making local copies of global variables
212
228
and class members and hardcoding some values."""
213
229
unpack_obj_header_base = OBJ_HEADER_BASE_STRUCT .unpack_from
@@ -221,6 +237,10 @@ def _parse_data(self, data):
221
237
unpack_can_fd_64_msg = CAN_FD_MSG_64_STRUCT .unpack_from
222
238
can_fd_64_msg_size = CAN_FD_MSG_64_STRUCT .size
223
239
unpack_can_error_ext = CAN_ERROR_EXT_STRUCT .unpack_from
240
+ unpack_ethernet_frame = ETHERNET_FRAME_STRUCT .unpack_from
241
+ ethernet_frame_msg_size = ETHERNET_FRAME_STRUCT .size
242
+ unpack_ethernet_frame_ex = ETHERNET_FRAME_EX_STRUCT .unpack_from
243
+ ethernet_ext_msg_size = ETHERNET_FRAME_EX_STRUCT .size
224
244
225
245
start_timestamp = self .start_timestamp
226
246
max_pos = len (data )
@@ -351,6 +371,70 @@ def _parse_data(self, data):
351
371
data = data [pos : pos + valid_bytes ],
352
372
channel = channel - 1 ,
353
373
)
374
+ elif obj_type == ETHERNET_FRAME :
375
+ members = unpack_ethernet_frame (data , pos )
376
+ (
377
+ sourceAddress ,
378
+ channel ,
379
+ destinationAddress ,
380
+ direction ,
381
+ frameType ,
382
+ tpid ,
383
+ tci ,
384
+ payloadLength ,
385
+ _
386
+ ) = members
387
+
388
+ pos += ethernet_frame_msg_size
389
+ yield EthernetFrame (
390
+ timestamp = timestamp ,
391
+ source_address = sourceAddress ,
392
+ channel = channel ,
393
+ destination_address = destinationAddress ,
394
+ direction = direction ,
395
+ ether_type = frameType ,
396
+ tpid = tpid ,
397
+ tci = tci ,
398
+ payloadLength = payloadLength ,
399
+ data = data [pos : pos + payloadLength ]
400
+ )
401
+
402
+ elif obj_type == ETHERNET_FRAME_EX :
403
+ members = unpack_ethernet_frame_ex (data , pos )
404
+ (
405
+ structLength ,
406
+ flags ,
407
+ channel ,
408
+ hardwareChannel ,
409
+ frameDuration ,
410
+ frameChecksum ,
411
+ direction ,
412
+ frameLength ,
413
+ frameHandle ,
414
+ _
415
+ ) = members
416
+
417
+ pos += ethernet_ext_msg_size
418
+ yield EthernetFrameExt (
419
+ timestamp = timestamp ,
420
+ struct_length = structLength ,
421
+ flags = flags ,
422
+ channel = channel ,
423
+ hardware_channel = hardwareChannel ,
424
+ duration = frameDuration ,
425
+ checksum = frameChecksum ,
426
+ handle = frameHandle ,
427
+ length = frameLength ,
428
+ direction = direction ,
429
+ data = data [pos : pos + frameLength ]
430
+ )
431
+
432
+ else :
433
+ yield UnknownMessage (
434
+ objectType = obj_type ,
435
+ timestamp = timestamp ,
436
+ data = data [pos : next_pos ]
437
+ )
354
438
355
439
pos = next_pos
356
440
@@ -443,13 +527,50 @@ def _write_header(self, filesize):
443
527
self .file .write (b"\x00 " * (FILE_HEADER_SIZE - FILE_HEADER_STRUCT .size ))
444
528
445
529
def on_message_received (self , msg ):
530
+
531
+ if isinstance (msg , UnknownMessage ):
532
+ data = msg .data
533
+ self ._add_object (msg .objectType , data , msg .timestamp )
534
+ return
535
+
446
536
channel = channel2int (msg .channel )
447
537
if channel is None :
448
538
channel = self .channel
449
539
else :
450
540
# Many interfaces start channel numbering at 0 which is invalid
451
541
channel += 1
452
542
543
+ if isinstance (msg , EthernetFrameExt ):
544
+ data = ETHERNET_FRAME_EX_STRUCT .pack (
545
+ msg .struct_length ,
546
+ msg .flags ,
547
+ channel ,
548
+ msg .hardware_channel if msg .hardware_channel is not None else 0 ,
549
+ msg .duration if msg .duration is not None else 0 ,
550
+ msg .checksum if msg .checksum is not None else 0 ,
551
+ msg .direction if msg .direction is not None else 0 ,
552
+ len (msg .data ),
553
+ msg .handle ,
554
+ 0 , # reservedEthernetFrameEx
555
+ )
556
+ self ._add_object (ETHERNET_FRAME_EX , data + msg .data , msg .timestamp )
557
+ return
558
+
559
+ if isinstance (msg , EthernetFrame ):
560
+ data = ETHERNET_FRAME_STRUCT .pack (
561
+ msg .source_address ,
562
+ channel ,
563
+ msg .destination_address ,
564
+ msg .direction ,
565
+ msg .type ,
566
+ msg .tpid ,
567
+ msg .tci ,
568
+ len (msg .data ),
569
+ 0 , # reservedEthernetFrame
570
+ )
571
+ self ._add_object (ETHERNET_FRAME , data + msg .data , msg .timestamp )
572
+ return
573
+
453
574
arb_id = msg .arbitration_id
454
575
if msg .is_extended_id :
455
576
arb_id |= CAN_MSG_EXT
0 commit comments