pretty good
This commit is contained in:
105
analyzer/protocols/decoders/can_bus.py
Normal file
105
analyzer/protocols/decoders/can_bus.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
CAN Bus decoder for Chapter 10 data types
|
||||
Supports Controller Area Network Bus (0x78)
|
||||
"""
|
||||
|
||||
import struct
|
||||
from typing import Dict, Any, Optional
|
||||
from .base import DataTypeDecoder, DecodedPayload
|
||||
|
||||
|
||||
class CANBusDecoder(DataTypeDecoder):
|
||||
"""Decoder for CAN Bus type (0x78)"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.data_type_base = 0x78
|
||||
self.data_type_name = "CAN Bus"
|
||||
self.supported_formats = [0x78]
|
||||
|
||||
def can_decode(self, data_type: int) -> bool:
|
||||
return data_type == 0x78
|
||||
|
||||
def get_data_type_name(self, data_type: int) -> str:
|
||||
return "Controller Area Network Bus"
|
||||
|
||||
def decode(self, payload: bytes, ch10_header: Dict[str, Any]) -> Optional[DecodedPayload]:
|
||||
"""Decode CAN Bus payload"""
|
||||
decoded_data = {}
|
||||
errors = []
|
||||
|
||||
# Parse IPH
|
||||
iph = self._parse_intra_packet_header(payload)
|
||||
if iph:
|
||||
decoded_data.update(iph)
|
||||
data_start = iph['data_start']
|
||||
else:
|
||||
data_start = 0
|
||||
errors.append("Failed to parse intra-packet header")
|
||||
|
||||
# Parse CAN messages
|
||||
messages = []
|
||||
offset = data_start
|
||||
|
||||
while offset + 16 <= len(payload):
|
||||
can_header = self._safe_unpack('<IIII', payload, offset)
|
||||
if not can_header:
|
||||
break
|
||||
|
||||
can_timestamp, can_id_flags, data_length, reserved = can_header
|
||||
|
||||
# Parse CAN ID and flags
|
||||
can_id = can_id_flags & 0x1FFFFFFF
|
||||
extended_id = bool(can_id_flags & 0x80000000)
|
||||
remote_frame = bool(can_id_flags & 0x40000000)
|
||||
error_frame = bool(can_id_flags & 0x20000000)
|
||||
|
||||
message = {
|
||||
'timestamp': can_timestamp,
|
||||
'can_id': f'0x{can_id:x}',
|
||||
'extended_id': extended_id,
|
||||
'remote_frame': remote_frame,
|
||||
'error_frame': error_frame,
|
||||
'data_length': data_length
|
||||
}
|
||||
|
||||
# Extract CAN data
|
||||
can_data_start = offset + 16
|
||||
if can_data_start + data_length <= len(payload):
|
||||
can_data = payload[can_data_start:can_data_start + data_length]
|
||||
message['data'] = can_data.hex()
|
||||
message['data_bytes'] = list(can_data)
|
||||
else:
|
||||
message['data_error'] = 'Data extends beyond payload'
|
||||
|
||||
messages.append(message)
|
||||
offset = can_data_start + max(data_length, 8) # CAN frames are padded to 8 bytes
|
||||
|
||||
if len(messages) >= 100: # Limit output size
|
||||
break
|
||||
|
||||
decoded_data['can_messages'] = messages
|
||||
decoded_data['message_count'] = len(messages)
|
||||
|
||||
# Statistics
|
||||
if messages:
|
||||
extended_count = sum(1 for msg in messages if msg['extended_id'])
|
||||
remote_count = sum(1 for msg in messages if msg['remote_frame'])
|
||||
error_count = sum(1 for msg in messages if msg['error_frame'])
|
||||
|
||||
decoded_data['statistics'] = {
|
||||
'extended_frames': extended_count,
|
||||
'remote_frames': remote_count,
|
||||
'error_frames': error_count,
|
||||
'standard_frames': len(messages) - extended_count
|
||||
}
|
||||
|
||||
return DecodedPayload(
|
||||
data_type=0x78,
|
||||
data_type_name="Controller Area Network Bus",
|
||||
format_version=0,
|
||||
decoded_data=decoded_data,
|
||||
raw_payload=payload,
|
||||
errors=errors,
|
||||
metadata={'decoder': 'CANBusDecoder'}
|
||||
)
|
||||
Reference in New Issue
Block a user