docs(cp02): add documentation for new firmware utilities
- Document bin_to_txt_converter.py for binary to text conversion - Document txt_to_bin_converter.py for text to binary conversion - Document merge_encrypted_firmware.py for encrypted firmware merging - Add usage examples for all three new tools
This commit is contained in:
parent
8f928a93e8
commit
40dcc0db8c
@ -71,6 +71,40 @@
|
|||||||
- 支持多种芯片 ID 的引导加载程序变体
|
- 支持多种芯片 ID 的引导加载程序变体
|
||||||
- 输出签名的二进制文件和相关 JSON 元数据
|
- 输出签名的二进制文件和相关 JSON 元数据
|
||||||
|
|
||||||
|
### bin_to_txt_converter.py
|
||||||
|
- **功能**: 将二进制文件转换为文本格式
|
||||||
|
- **用法**: `python3 bin_to_txt_converter.py <input.bin> [output.txt]`
|
||||||
|
- **描述**:
|
||||||
|
- 将二进制文件(如 IUM)转换为文本格式
|
||||||
|
- 按 4 字节块处理数据,转换为十六进制字符串
|
||||||
|
- 支持小端序字节序转换
|
||||||
|
- 输出文件包含 start/end 标记
|
||||||
|
- 未指定输出文件时自动生成文件名
|
||||||
|
|
||||||
|
### txt_to_bin_converter.py
|
||||||
|
- **功能**: 将文本格式转换回二进制文件
|
||||||
|
- **用法**: `python3 txt_to_bin_converter.py <input.txt> <output.bin>`
|
||||||
|
- **描述**:
|
||||||
|
- 将文本格式(如 ium11.txt)转换回二进制文件
|
||||||
|
- 处理 8 字符十六进制字符串为 4 字节整数
|
||||||
|
- 写入前 63 个完整的 4 字节值
|
||||||
|
- 第 64 个值仅写入第一个字节
|
||||||
|
- 跳过 start/end 标记行
|
||||||
|
|
||||||
|
### merge_encrypted_firmware.py
|
||||||
|
- **功能**: 合成已加密的固件和 IUM 为最终 programmer 固件
|
||||||
|
- **用法**: `python3 merge_encrypted_firmware.py <base.bin> <encrypted.bin> <ium.bin> -o <output.bin>`
|
||||||
|
- **描述**:
|
||||||
|
- 合并 Base firmware (16KB)、加密固件 (最大 119KB) 和 IUM storage (256 bytes)
|
||||||
|
- 固件布局:
|
||||||
|
- 0x0000 - 0x4000: Base firmware
|
||||||
|
- 0x4000 - 0x1DC00: 加密用户固件
|
||||||
|
- 0x1DC00 - 0x1DD00: IUM storage
|
||||||
|
- 0x1DD00 - 0x1DD10: Metadata (16 bytes)
|
||||||
|
- 自动生成 metadata(包含 blocks 和 last_block_size)
|
||||||
|
- 显示完整的内存布局和校验信息
|
||||||
|
- IUM storage 包含 CRC8 和 CRC16 校验
|
||||||
|
|
||||||
## 使用示例
|
## 使用示例
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -98,4 +132,12 @@
|
|||||||
python3 signer_new.py --firmware firmware.bin --output_dir ./output
|
python3 signer_new.py --firmware firmware.bin --output_dir ./output
|
||||||
python3 signer_new.py --bootloader bootloader.bin --output_dir ./output --enable_swd
|
python3 signer_new.py --bootloader bootloader.bin --output_dir ./output --enable_swd
|
||||||
python3 signer_new.py --firmware firmware.bin --bootloader bootloader.bin --output_dir ./output --boot_directly
|
python3 signer_new.py --firmware firmware.bin --bootloader bootloader.bin --output_dir ./output --boot_directly
|
||||||
|
|
||||||
|
# 二进制与文本格式转换
|
||||||
|
python3 bin_to_txt_converter.py ium.bin # 自动生成输出文件名
|
||||||
|
python3 bin_to_txt_converter.py ium.bin ium_converted.txt # 指定输出文件
|
||||||
|
python3 txt_to_bin_converter.py ium11.txt ium11.bin # 文本转二进制
|
||||||
|
|
||||||
|
# 合成加密固件
|
||||||
|
python3 merge_encrypted_firmware.py base.bin encrypted.bin ium.bin -o programmer.bin
|
||||||
```
|
```
|
||||||
100
CP02/bin_to_txt_converter.py
Executable file
100
CP02/bin_to_txt_converter.py
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Binary to Text Converter for IUM files
|
||||||
|
Converts .bin files to .txt format matching ium11.txt structure
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def bin_to_txt(bin_file_path, txt_file_path=None):
|
||||||
|
"""
|
||||||
|
Convert binary file to text format matching the ium11.txt structure
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bin_file_path (str): Path to input binary file
|
||||||
|
txt_file_path (str): Path to output text file (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Path to generated text file
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not os.path.exists(bin_file_path):
|
||||||
|
raise FileNotFoundError(f"Binary file not found: {bin_file_path}")
|
||||||
|
|
||||||
|
# Generate output filename if not provided
|
||||||
|
if txt_file_path is None:
|
||||||
|
base_name = os.path.splitext(bin_file_path)[0]
|
||||||
|
txt_file_path = f"{base_name}_converted.txt"
|
||||||
|
|
||||||
|
# Read binary file
|
||||||
|
try:
|
||||||
|
with open(bin_file_path, 'rb') as bin_file:
|
||||||
|
binary_data = bin_file.read()
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"Error reading binary file: {e}")
|
||||||
|
|
||||||
|
# Convert binary data to text format
|
||||||
|
try:
|
||||||
|
with open(txt_file_path, 'w') as txt_file:
|
||||||
|
# Write start marker
|
||||||
|
txt_file.write("start\n")
|
||||||
|
|
||||||
|
# Process binary data in 4-byte chunks (32-bit words)
|
||||||
|
for i in range(0, len(binary_data), 4):
|
||||||
|
chunk = binary_data[i:i+4]
|
||||||
|
|
||||||
|
# Pad with zeros if chunk is less than 4 bytes
|
||||||
|
if len(chunk) < 4:
|
||||||
|
chunk = chunk + b'\x00' * (4 - len(chunk))
|
||||||
|
|
||||||
|
# Convert to little-endian 32-bit hex value
|
||||||
|
hex_value = chunk[::-1].hex().upper() # Reverse bytes for little-endian
|
||||||
|
|
||||||
|
# Format as 8-character hex string
|
||||||
|
hex_value = hex_value.zfill(8)
|
||||||
|
|
||||||
|
# Write hex value
|
||||||
|
txt_file.write(f"{hex_value}\n")
|
||||||
|
|
||||||
|
# Write end marker
|
||||||
|
txt_file.write("end\n")
|
||||||
|
txt_file.write("\n")
|
||||||
|
|
||||||
|
return txt_file_path
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"Error writing text file: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to handle command line arguments"""
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python bin_to_txt_converter.py <input_bin_file> [output_txt_file]")
|
||||||
|
print("\nExample:")
|
||||||
|
print(" python bin_to_txt_converter.py ium11.bin")
|
||||||
|
print(" python bin_to_txt_converter.py ium11.bin ium11_converted.txt")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
bin_file_path = sys.argv[1]
|
||||||
|
txt_file_path = sys.argv[2] if len(sys.argv) > 2 else None
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_path = bin_to_txt(bin_file_path, txt_file_path)
|
||||||
|
print(f"Successfully converted {bin_file_path} to {output_path}")
|
||||||
|
|
||||||
|
# Show file sizes for verification
|
||||||
|
bin_size = os.path.getsize(bin_file_path)
|
||||||
|
txt_size = os.path.getsize(output_path)
|
||||||
|
print(f"Binary file size: {bin_size} bytes")
|
||||||
|
print(f"Text file size: {txt_size} bytes")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
139
CP02/merge_encrypted_firmware.py
Normal file
139
CP02/merge_encrypted_firmware.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
合成已加密的固件和 IUM 为最终 programmer 固件
|
||||||
|
|
||||||
|
固件布局:
|
||||||
|
0x0000 - 0x4000: Base firmware (16KB)
|
||||||
|
0x4000 - 0x1DC00: 加密后的用户固件 (最大 119KB)
|
||||||
|
0x1DC00 - 0x1DD00: IUM storage (256 bytes)
|
||||||
|
0x1DD00 - 0x1DD10: Metadata (16 bytes)
|
||||||
|
|
||||||
|
IUM Storage 结构 (256 bytes):
|
||||||
|
Bytes 0-252: Modified IUM (253 bytes)
|
||||||
|
Byte 253: CRC8
|
||||||
|
Bytes 254-255: CRC16 (little-endian)
|
||||||
|
|
||||||
|
用法:
|
||||||
|
python3 merge_encrypted_firmware.py base.bin encrypted.bin ium_storage.bin -o output.bin
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 常量定义
|
||||||
|
BASE_FIRMWARE_SIZE = 0x4000 # 16KB
|
||||||
|
USER_FIRMWARE_MAX_SIZE = 0x1DC00 # 119KB
|
||||||
|
IUM_STORAGE_SIZE = 0x100 # 256 bytes
|
||||||
|
METADATA_SIZE = 0x10 # 16 bytes
|
||||||
|
|
||||||
|
BASE_FIRMWARE_OFFSET = 0x0000
|
||||||
|
USER_FIRMWARE_OFFSET = 0x4000
|
||||||
|
IUM_OFFSET = 0x1DC00
|
||||||
|
METADATA_OFFSET = 0x1DD00
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='合成加密固件和IUM为最终programmer固件',
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog='''
|
||||||
|
示例:
|
||||||
|
%(prog)s base.bin encrypted_binary.bin ium.bin -o programmer.bin
|
||||||
|
|
||||||
|
输入文件说明:
|
||||||
|
base_firmware - Base firmware BIN 文件 (最大 16KB)
|
||||||
|
encrypted_binary - 已加密的固件 BIN 文件 (*_encrypted_binary.bin)
|
||||||
|
ium_storage - IUM storage 文件 (256 bytes, *_ium.bin)
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
parser.add_argument('base_firmware', help='Base firmware BIN 文件 (最大 16KB)')
|
||||||
|
parser.add_argument('encrypted_binary', help='已加密的固件 BIN 文件')
|
||||||
|
parser.add_argument('ium_storage', help='IUM storage 文件 (256 bytes)')
|
||||||
|
parser.add_argument('-o', '--output', required=True, help='输出文件路径')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# 检查文件是否存在
|
||||||
|
for filepath, name in [
|
||||||
|
(args.base_firmware, 'Base firmware'),
|
||||||
|
(args.encrypted_binary, 'Encrypted binary'),
|
||||||
|
(args.ium_storage, 'IUM storage')
|
||||||
|
]:
|
||||||
|
if not Path(filepath).exists():
|
||||||
|
print(f"错误: {name} 文件不存在: {filepath}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 读取文件
|
||||||
|
base_firmware = Path(args.base_firmware).read_bytes()
|
||||||
|
encrypted_binary = Path(args.encrypted_binary).read_bytes()
|
||||||
|
ium_storage = Path(args.ium_storage).read_bytes()
|
||||||
|
|
||||||
|
# 验证大小
|
||||||
|
if len(base_firmware) > BASE_FIRMWARE_SIZE:
|
||||||
|
print(f"错误: Base firmware 最大 {BASE_FIRMWARE_SIZE} bytes (16KB), 实际 {len(base_firmware)} bytes")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if len(encrypted_binary) > USER_FIRMWARE_MAX_SIZE:
|
||||||
|
print(f"错误: 加密固件最大 {USER_FIRMWARE_MAX_SIZE} bytes (119KB), 实际 {len(encrypted_binary)} bytes")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if len(ium_storage) != IUM_STORAGE_SIZE:
|
||||||
|
print(f"错误: IUM storage 必须是 {IUM_STORAGE_SIZE} bytes (256), 实际 {len(ium_storage)} bytes")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("合成 Programmer 固件:")
|
||||||
|
print(f" Base firmware: {args.base_firmware} ({len(base_firmware)} bytes)")
|
||||||
|
print(f" Encrypted binary: {args.encrypted_binary} ({len(encrypted_binary)} bytes)")
|
||||||
|
print(f" IUM storage: {args.ium_storage} ({len(ium_storage)} bytes)")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 创建输出缓冲区 (填充 0xFF)
|
||||||
|
total_size = METADATA_OFFSET + METADATA_SIZE
|
||||||
|
output = bytearray([0xFF] * total_size)
|
||||||
|
|
||||||
|
# 复制 base firmware (0x0000)
|
||||||
|
output[BASE_FIRMWARE_OFFSET:BASE_FIRMWARE_OFFSET + len(base_firmware)] = base_firmware
|
||||||
|
|
||||||
|
# 复制加密固件 (0x4000)
|
||||||
|
output[USER_FIRMWARE_OFFSET:USER_FIRMWARE_OFFSET + len(encrypted_binary)] = encrypted_binary
|
||||||
|
|
||||||
|
# 复制 IUM storage (0x1DC00)
|
||||||
|
output[IUM_OFFSET:IUM_OFFSET + IUM_STORAGE_SIZE] = ium_storage
|
||||||
|
|
||||||
|
# 生成 metadata
|
||||||
|
blocks = len(encrypted_binary) // 256
|
||||||
|
last_block_size = len(encrypted_binary) % 256
|
||||||
|
|
||||||
|
# Metadata 结构: uint16_t blocks, uint8_t last_block_size, uint8_t reserved[13]
|
||||||
|
metadata = struct.pack('<HB', blocks, last_block_size) + bytes(13)
|
||||||
|
output[METADATA_OFFSET:METADATA_OFFSET + METADATA_SIZE] = metadata
|
||||||
|
|
||||||
|
# 写入输出文件
|
||||||
|
Path(args.output).write_bytes(output)
|
||||||
|
|
||||||
|
# 解析 IUM storage 中的 CRC
|
||||||
|
ium_crc8 = ium_storage[253]
|
||||||
|
ium_crc16 = ium_storage[254] | (ium_storage[255] << 8)
|
||||||
|
|
||||||
|
print("固件结构:")
|
||||||
|
print(f" Base firmware: 0x{BASE_FIRMWARE_OFFSET:04X} - 0x{BASE_FIRMWARE_OFFSET + len(base_firmware):04X} ({len(base_firmware)} bytes)")
|
||||||
|
print(f" Encrypted binary: 0x{USER_FIRMWARE_OFFSET:04X} - 0x{USER_FIRMWARE_OFFSET + len(encrypted_binary):04X} ({len(encrypted_binary)} bytes)")
|
||||||
|
print(f" IUM storage: 0x{IUM_OFFSET:04X} - 0x{IUM_OFFSET + IUM_STORAGE_SIZE:04X} ({IUM_STORAGE_SIZE} bytes)")
|
||||||
|
print(f" Metadata: 0x{METADATA_OFFSET:04X} - 0x{METADATA_OFFSET + METADATA_SIZE:04X} ({METADATA_SIZE} bytes)")
|
||||||
|
print()
|
||||||
|
print("Metadata 信息:")
|
||||||
|
print(f" Blocks: {blocks}")
|
||||||
|
print(f" Last block size: {last_block_size} bytes")
|
||||||
|
print(f" Total size: {blocks * 256 + last_block_size} bytes")
|
||||||
|
print()
|
||||||
|
print("IUM 校验:")
|
||||||
|
print(f" CRC8: 0x{ium_crc8:02X}")
|
||||||
|
print(f" CRC16: 0x{ium_crc16:04X}")
|
||||||
|
print()
|
||||||
|
print(f"✓ 输出文件: {args.output} ({len(output)} bytes)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
45
CP02/txt_to_bin_converter.py
Normal file
45
CP02/txt_to_bin_converter.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
import re
|
||||||
|
|
||||||
|
def convert_txt_to_bin(txt_file, bin_file):
|
||||||
|
with open(txt_file, 'r', encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
with open(bin_file, 'wb') as f:
|
||||||
|
count = 0
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if line == 'start' or line == 'end' or not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if line contains only hex digits (8 characters)
|
||||||
|
if re.match(r'^[0-9A-Fa-f]{8}$', line):
|
||||||
|
hex_value = line
|
||||||
|
# Convert hex string to integer
|
||||||
|
int_value = int(hex_value, 16)
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
# Write first 63 complete 4-byte integers
|
||||||
|
if count <= 63:
|
||||||
|
f.write(struct.pack('<I', int_value))
|
||||||
|
# For the 64th value, only write the first byte
|
||||||
|
elif count == 64:
|
||||||
|
f.write(struct.pack('<I', int_value)[:1])
|
||||||
|
break
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: python txt_to_bin_converter.py <input.txt> <output.bin>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
txt_file = sys.argv[1]
|
||||||
|
bin_file = sys.argv[2]
|
||||||
|
|
||||||
|
try:
|
||||||
|
convert_txt_to_bin(txt_file, bin_file)
|
||||||
|
print(f"Successfully converted {txt_file} to {bin_file}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
Loading…
x
Reference in New Issue
Block a user