@@ -833,6 +833,8 @@ class Pdu(object):
833833 Whereas a PDU is the same than a frame on CAN bus, at flexray a frame may consist of
834834 multiple PDUs (a bit like multiple signal layout for multiplexed can frames).
835835 This class is only used for flexray busses.
836+ Note: since container-pdus are supported for arxml, this class is also used for arxml (but only
837+ for sub-pdus of container-pdus).
836838 """
837839
838840 name = attr .ib (default = "" ) # type: str
@@ -844,6 +846,8 @@ class Pdu(object):
844846 signals = attr .ib (factory = list ) # type: typing.MutableSequence[Signal]
845847 signalGroups = attr .ib (factory = list ) # type: typing.MutableSequence[SignalGroup]
846848 cycle_time = attr .ib (default = 0 ) # type: int
849+ # offset is used for arxml, sub-pdu inside a static-container-pdu
850+ offset_bytes = attr .ib (default = 0 ) # type: int
847851
848852 def add_signal (self , signal ):
849853 # type: (Signal) -> Signal
@@ -1491,20 +1495,35 @@ def unpack(self, data: bytes,
14911495 f"Received message 0x{ msg_id :04X} with wrong data size: { rx_length } instead of { self .size } " )
14921496
14931497 if self .is_pdu_container :
1498+ # note: PDU-Container without header is possible for ARXML-Container-PDUs with NO-HEADER
1499+ # that mean this are not dynamic Container-PDUs rather than static ones. (each sub-pdu has
1500+ # a fixed offset in the container)
1501+ header_signals = []
14941502 header_id_signal = self .signal_by_name ("Header_ID" )
14951503 header_dlc_signal = self .signal_by_name ("Header_DLC" )
1496- if header_id_signal is None or header_dlc_signal is None :
1497- raise DecodingConatainerPdu (
1498- 'Received message 0x{:08X} without Header_ID or '
1499- 'Header_DLC signal' .format (self .arbitration_id .id )
1500- )
1504+
1505+ if header_id_signal is not None :
1506+ header_signals .append (header_id_signal )
1507+ _header_id_signal_size = header_id_signal .size
1508+ else :
1509+ _header_id_signal_size = 0
1510+ if header_dlc_signal is not None :
1511+ header_signals .append (header_dlc_signal )
1512+ _header_dlc_signal_size = header_dlc_signal .size
1513+ else :
1514+ _header_dlc_signal_size = 0
15011515 # TODO: may be we need to check that ID/DLC signals are contiguous
1502- header_size = header_id_signal .size + header_dlc_signal .size
1516+ if len (header_signals ) > 0 and len (header_signals ) != 2 :
1517+ raise DecodingContainerPdu (
1518+ 'Received message 0x{:08X} with incorrect Header-Defintiion. '
1519+ 'Header_ID signal or Header_DLC is missing' .format (self .arbitration_id .id )
1520+ )
1521+ header_size = _header_id_signal_size + _header_dlc_signal_size
15031522 little , big = self .bytes_to_bitstrings (data )
15041523 size = self .size * 8
15051524 return_dict = dict ({"pdus" : []})
15061525 # decode signal which are not in PDUs
1507- signals = [s for s in self .signals if s not in [ header_id_signal , header_dlc_signal ] ]
1526+ signals = [s for s in self .signals if s not in header_signals ]
15081527 if signals :
15091528 unpacked = self .bitstring_to_signal_list (signals , big , little , size )
15101529 for s , v in zip (signals , unpacked ):
@@ -1527,20 +1546,52 @@ def unpack(self, data: bytes,
15271546 return_dict [s .name ] = []
15281547 return_dict [s .name ].append (DecodedSignal (v , s ))
15291548 pdu = self .pdu_by_id (pdu_id )
1549+ offset = header_id_signal .start_bit if header_id_signal is not None else 0
1550+ no_header_next_pdu_idx = 0
1551+ # decode as long as there is data left to decode (if there is a header), or as long as there are sub-pdus
1552+ # left to decode (in case of static-container without pdu-headers)
1553+ while (offset + header_size ) < size and no_header_next_pdu_idx < len (self .pdus ):
1554+ if len (header_signals ) > 0 :
1555+ unpacked = self .bitstring_to_signal_list (
1556+ header_signals ,
1557+ big [offset :offset + header_size ],
1558+ little [size - offset - header_size :size - offset ],
1559+ header_size
1560+ )
1561+ offset += header_size
1562+ pdu_id = unpacked [0 ]
1563+ pdu_dlc = unpacked [1 ]
1564+ for s , v in zip (header_signals , unpacked ):
1565+ if s .name not in return_dict :
1566+ return_dict [s .name ] = []
1567+ return_dict [s .name ].append (DecodedSignal (v , s ))
1568+ pdu = self .pdu_by_id (pdu_id )
1569+ else :
1570+ # if there is no pdu-header, then we have a static container-pdu
1571+ # we have to loop all sub-pdus and set the offset to the offset of the PDU
1572+ # note: order of processing sub-PDUs is not important, even if the sub-PDUs are not ordered
1573+ # by the pdu-offset (we just set the offset correct to the actual processed sub-PDU)
1574+ pdu = self .pdus [no_header_next_pdu_idx ]
1575+ no_header_next_pdu_idx += 1
1576+ pdu_dlc = pdu .size
1577+ offset = pdu .offset_bytes * 8
1578+ decode_size_bits = pdu_dlc * 8
15301579 if pdu is None :
15311580 return_dict ['pdus' ].append (None )
15321581 else :
15331582 unpacked = self .bitstring_to_signal_list (
15341583 pdu .signals ,
1535- big [offset :offset + pdu_dlc * 8 ],
1536- little [size - offset - pdu_dlc * 8 :size - offset ],
1537- pdu_dlc * 8
1584+ big [offset :offset + decode_size_bits ],
1585+ little [size - offset - decode_size_bits :size - offset ],
1586+ decode_size_bits
15381587 )
15391588 pdu_dict = dict ()
15401589 for s , v in zip (pdu .signals , unpacked ):
15411590 pdu_dict [s .name ] = DecodedSignal (v , s )
15421591 return_dict ["pdus" ].append ({pdu .name : pdu_dict })
1543- offset += (pdu_dlc * 8 )
1592+ if len (header_signals ) > 0 :
1593+ # if there is a pdu-header, we have to set the offset to the start of the next pdu
1594+ offset += decode_size_bits
15441595 return return_dict
15451596 else :
15461597 little , big = self .bytes_to_bitstrings (data )
0 commit comments