diff --git a/can_converter_gui.py b/can_converter_gui.py index 5ee47e2..797d495 100644 --- a/can_converter_gui.py +++ b/can_converter_gui.py @@ -32,22 +32,42 @@ from PyQt5.QtGui import QFont, QTextCursor, QIcon # ============================================================================ class CANMessage: - """ESP32 CAN Logger의 CAN 메시지 구조체""" - STRUCT_FORMAT = ' '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}개의 파싱 오류 발생")