수정
This commit is contained in:
@@ -32,22 +32,42 @@ from PyQt5.QtGui import QFont, QTextCursor, QIcon
|
||||
# ============================================================================
|
||||
|
||||
class CANMessage:
|
||||
"""ESP32 CAN Logger의 CAN 메시지 구조체"""
|
||||
STRUCT_FORMAT = '<QIB8s' # little-endian: uint64, uint32, uint8, 8*uint8
|
||||
STRUCT_SIZE = struct.calcsize(STRUCT_FORMAT)
|
||||
"""ESP32 CAN Logger의 CAN 메시지 구조체
|
||||
|
||||
def __init__(self, timestamp_us: int, can_id: int, dlc: int, data: bytes):
|
||||
펌웨어 구조체 (22 bytes, packed):
|
||||
uint64_t timestamp_us (8 bytes)
|
||||
uint32_t id (4 bytes)
|
||||
uint8_t dlc (1 byte)
|
||||
uint8_t flags (1 byte) ← RingBuffer 버전에서 추가 (EFF/RTR 보존)
|
||||
uint8_t data[8] (8 bytes)
|
||||
|
||||
구버전 (21 bytes, flags 없음):
|
||||
STRUCT_FORMAT_V1 = '<QIB8s'
|
||||
"""
|
||||
STRUCT_FORMAT = '<QIBb8s' # 22 bytes (현재 펌웨어 - flags 포함)
|
||||
STRUCT_FORMAT_V1 = '<QIB8s' # 21 bytes (구버전 - flags 없음)
|
||||
STRUCT_SIZE = struct.calcsize(STRUCT_FORMAT) # 22
|
||||
STRUCT_SIZE_V1 = struct.calcsize(STRUCT_FORMAT_V1) # 21
|
||||
|
||||
def __init__(self, timestamp_us: int, can_id: int, dlc: int, data: bytes, flags: int = 0):
|
||||
self.timestamp_us = timestamp_us
|
||||
self.can_id = can_id
|
||||
self.dlc = dlc
|
||||
self.flags = flags # bit7=EFF, bit6=RTR
|
||||
self.data = data[:dlc]
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes) -> 'CANMessage':
|
||||
"""바이너리 데이터에서 CANMessage 파싱"""
|
||||
timestamp_us, can_id, dlc, msg_data = struct.unpack(cls.STRUCT_FORMAT, data)
|
||||
return cls(timestamp_us, can_id, dlc, msg_data)
|
||||
|
||||
"""바이너리 데이터에서 CANMessage 파싱 (22/21 bytes 자동 감지)"""
|
||||
if len(data) == cls.STRUCT_SIZE:
|
||||
timestamp_us, can_id, dlc, flags, msg_data = struct.unpack(cls.STRUCT_FORMAT, data)
|
||||
return cls(timestamp_us, can_id, dlc, msg_data, flags)
|
||||
elif len(data) == cls.STRUCT_SIZE_V1:
|
||||
timestamp_us, can_id, dlc, msg_data = struct.unpack(cls.STRUCT_FORMAT_V1, data)
|
||||
return cls(timestamp_us, can_id, dlc, msg_data, 0)
|
||||
else:
|
||||
raise ValueError(f"Invalid data size: {len(data)} (expected 22 or 21)")
|
||||
|
||||
def __repr__(self):
|
||||
return f"CANMessage(id=0x{self.can_id:X}, dlc={self.dlc}, ts={self.timestamp_us})"
|
||||
# ============================================================================
|
||||
@@ -69,22 +89,40 @@ class CANBinToMDF:
|
||||
print(f" - 시그널 수: {sum(len(msg.signals) for msg in self.db.messages)}")
|
||||
|
||||
def read_bin_file(self, bin_path: str) -> List[CANMessage]:
|
||||
"""ESP32 CAN Logger의 bin 파일 읽기"""
|
||||
"""ESP32 CAN Logger의 bin 파일 읽기 (22/21 bytes 자동 감지)"""
|
||||
messages = []
|
||||
|
||||
with open(bin_path, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
|
||||
if not data:
|
||||
print(f"⚠️ 파일이 비어있습니다: {bin_path}")
|
||||
return messages
|
||||
|
||||
# 버전 자동 감지: 22 bytes(flags 포함) vs 21 bytes(구버전)
|
||||
# 파일 크기가 22의 배수면 신버전, 21의 배수면 구버전
|
||||
is_v2 = (len(data) % CANMessage.STRUCT_SIZE == 0)
|
||||
is_v1 = (len(data) % CANMessage.STRUCT_SIZE_V1 == 0)
|
||||
if is_v2:
|
||||
record_size = CANMessage.STRUCT_SIZE # 22
|
||||
print(f"✓ 펌웨어 버전: RingBuffer (22 bytes/record, flags 포함)")
|
||||
elif is_v1:
|
||||
record_size = CANMessage.STRUCT_SIZE_V1 # 21
|
||||
print(f"✓ 펌웨어 버전: 구버전 (21 bytes/record)")
|
||||
else:
|
||||
# 22 bytes 우선 시도
|
||||
record_size = CANMessage.STRUCT_SIZE
|
||||
print(f"⚠️ 파일 크기({len(data)})가 22/21의 배수가 아님, 22 bytes로 파싱 시도")
|
||||
|
||||
offset = 0
|
||||
while offset + CANMessage.STRUCT_SIZE <= len(data):
|
||||
msg_bytes = data[offset:offset + CANMessage.STRUCT_SIZE]
|
||||
while offset + record_size <= len(data):
|
||||
msg_bytes = data[offset:offset + record_size]
|
||||
try:
|
||||
msg = CANMessage.from_bytes(msg_bytes)
|
||||
messages.append(msg)
|
||||
except Exception as e:
|
||||
print(f"⚠️ 메시지 파싱 오류 at offset {offset}: {e}")
|
||||
|
||||
offset += CANMessage.STRUCT_SIZE
|
||||
offset += record_size
|
||||
|
||||
print(f"✓ bin 파일 읽기 완료: {bin_path}")
|
||||
print(f" - 총 메시지: {len(messages)}")
|
||||
@@ -286,7 +324,7 @@ class CANBinToCSV:
|
||||
print(f" - 시그널 수: {sum(len(msg.signals) for msg in self.db.messages)}")
|
||||
|
||||
def read_bin_file(self, bin_path: str) -> List[CANMessage]:
|
||||
"""ESP32 CAN Logger의 bin 파일 읽기"""
|
||||
"""ESP32 CAN Logger의 bin 파일 읽기 (22/21 bytes 자동 감지)"""
|
||||
messages = []
|
||||
|
||||
try:
|
||||
@@ -298,20 +336,33 @@ class CANBinToCSV:
|
||||
return messages
|
||||
|
||||
print(f" 파일 크기: {len(data)} bytes")
|
||||
|
||||
# 버전 자동 감지: 22 bytes(flags 포함) vs 21 bytes(구버전)
|
||||
is_v2 = (len(data) % CANMessage.STRUCT_SIZE == 0)
|
||||
is_v1 = (len(data) % CANMessage.STRUCT_SIZE_V1 == 0)
|
||||
if is_v2:
|
||||
record_size = CANMessage.STRUCT_SIZE
|
||||
print(f" 펌웨어 버전: RingBuffer (22 bytes/record)")
|
||||
elif is_v1:
|
||||
record_size = CANMessage.STRUCT_SIZE_V1
|
||||
print(f" 펌웨어 버전: 구버전 (21 bytes/record)")
|
||||
else:
|
||||
record_size = CANMessage.STRUCT_SIZE
|
||||
print(f"⚠️ 파일 크기가 22/21의 배수가 아님, 22 bytes로 파싱 시도")
|
||||
|
||||
offset = 0
|
||||
parse_errors = 0
|
||||
while offset + CANMessage.STRUCT_SIZE <= len(data):
|
||||
msg_bytes = data[offset:offset + CANMessage.STRUCT_SIZE]
|
||||
while offset + record_size <= len(data):
|
||||
msg_bytes = data[offset:offset + record_size]
|
||||
try:
|
||||
msg = CANMessage.from_bytes(msg_bytes)
|
||||
messages.append(msg)
|
||||
except Exception as e:
|
||||
parse_errors += 1
|
||||
if parse_errors <= 5: # 처음 5개 에러만 출력
|
||||
if parse_errors <= 5:
|
||||
print(f"⚠️ 메시지 파싱 오류 at offset {offset}: {e}")
|
||||
|
||||
offset += CANMessage.STRUCT_SIZE
|
||||
offset += record_size
|
||||
|
||||
if parse_errors > 5:
|
||||
print(f"⚠️ 총 {parse_errors}개의 파싱 오류 발생")
|
||||
|
||||
Reference in New Issue
Block a user