#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ ============================================================================= KT mBMS 3종 통합 펌웨어 패키지 생성 스크립트 (Unified Multi-FW Packager) ============================================================================= 기능: - 3종의 mBMS 펌웨어 이미지(V1, V2, V3)를 하나의 통합 .bin 파일로 병합 - 패키지 헤더(256 바이트)에 각 펌웨어의 타겟 HW 구분, 버전, 크기, CRC32, 체크섬(Sum32), 오프셋 메타데이터 패킹 - GUI(LFP_Manager_GL)에서 통합 bin 파일을 읽어 보드 버전 확인 및 자동 다운로드 지원 작성일자: 2026-10-23 """ import os import sys import struct # --------------------------------------------------------------------------- # 상 수 정 의 # --------------------------------------------------------------------------- MULTI_FW_MAGIC = 0x4D4D4657 # 'MMFW' (Multi mBMS FirmWare) HEADER_VERSION = 0x0001 # 헤더 버전 1.0 TOTAL_HEADER_SIZE = 256 # 전체 헤더 크기 (64B Master + 64B * 3 Entries) ENTRY_COUNT = 3 HW_TYPE_V1 = 0x11 # STM32F407 + BQ76PL455 + Relay HW_TYPE_V2 = 0x22 # HC32F460 + BQ76940 + FET HW_TYPE_V3 = 0x33 # HC32F460 + ADBMS1818 + FET POLYNOMIAL_CRC32 = 0x04C11DB7 # --------------------------------------------------------------------------- # CRC32 및 CheckSum 계산기 (GUI의 C# csMultiFwPackage와 100% 동일) # --------------------------------------------------------------------------- _crc_table = None def init_crc_table(): global _crc_table if _crc_table is not None: return _crc_table = [] for i in range(256): crc = (i << 24) & 0xFFFFFFFF for _ in range(8): if crc & 0x80000000: crc = ((crc << 1) ^ POLYNOMIAL_CRC32) & 0xFFFFFFFF else: crc = (crc << 1) & 0xFFFFFFFF _crc_table.append(crc) def calculate_crc32(data: bytes) -> int: init_crc_table() crc = 0 for b in data: idx = ((crc >> 24) ^ b) & 0xFF crc = (((crc << 8) & 0xFFFFFFFF) ^ _crc_table[idx]) & 0xFFFFFFFF return crc def calculate_checksum32(data: bytes) -> int: return sum(data) & 0xFFFFFFFF # --------------------------------------------------------------------------- # 패키지 빌더 # --------------------------------------------------------------------------- def build_multi_fw_package( v1_bin_path: str, v2_bin_path: str, v3_bin_path: str, output_bin_path: str, version: tuple = (4, 0, 0, 1), package_name: str = "mBMS_KT_UNIFIED_FW_V4.0.0.1" ): print("=" * 70) print(" KT mBMS 통합 펌웨어 패키지 생성 시작") print("=" * 70) # 1. 각 바이너리 파일 로드 (보드 버전 판별 규칙: x1xx -> V1, x2xx -> V2, x3xx -> V3) inputs = [ { "hw_type": HW_TYPE_V1, "hw_name": "HW1:STM32+PL455", # x1xx (V1) "path": v1_bin_path, "data": b"" }, { "hw_type": HW_TYPE_V2, "hw_name": "HW2:HC32+BQ76940", # x2xx (V2) "path": v2_bin_path, "data": b"" }, { "hw_type": HW_TYPE_V3, "hw_name": "HW3:HC32+ADBMS18", # x3xx (V3) "path": v3_bin_path, "data": b"" } ] for item in inputs: if not os.path.exists(item["path"]): raise FileNotFoundError(f"펌웨어 파일이 존재하지 않습니다: {item['path']}") with open(item["path"], "rb") as f: item["data"] = f.read() item["size"] = len(item["data"]) item["crc32"] = calculate_crc32(item["data"]) item["chksum"] = calculate_checksum32(item["data"]) item["filename"] = os.path.basename(item["path"]) print(f"[*] {item['hw_name']:<18}: {item['filename']} ({item['size']:,} bytes)") print(f" - CRC32: 0x{item['crc32']:08X}, CheckSum(Sum32): 0x{item['chksum']:08X}") # 2. 오프셋 계산 current_offset = TOTAL_HEADER_SIZE for item in inputs: item["offset"] = current_offset current_offset += item["size"] total_package_size = current_offset print("-" * 70) print(f"[*] 통합 헤더 크기 : {TOTAL_HEADER_SIZE} bytes") print(f"[*] 최종 패키지 크기 : {total_package_size:,} bytes") # 3. 마스터 헤더 (64 바이트) 패킹 # 구조: # Magic (4B, uint32) # HeaderVersion (2B, uint16) # ImageCount (2B, uint16) # TotalPackageSize (4B, uint32) # HeaderCrc32 (4B, uint32) - 임시 0 # PackageVer (4B, 4 bytes) # PackageName (32B, char[32]) # Reserved (12B, 12 bytes) pkg_ver_bytes = bytes([version[0], version[1], version[2], version[3]]) pkg_name_bytes = package_name.encode("ascii")[:31].ljust(32, b"\x00") reserved12 = b"\x00" * 12 master_header = struct.pack( "= TOTAL_HEADER_SIZE, "파일 크기가 헤더보다 작습니다." magic, hdr_ver, img_cnt, total_sz, hdr_crc = struct.unpack_from("