243 lines
9.0 KiB
Python
243 lines
9.0 KiB
Python
import hashlib
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from crc import Calculator, Crc16
|
|
|
|
from tools.IntelHex import file_IntelHex_to_Bin, file_Bin_to_IntelHex
|
|
|
|
|
|
Header_Tag = {
|
|
'file_type': [0x00, 2], # 0 - 文件类型; 2byte
|
|
'file_version': [0x01, 2], # 1 - 文件版本; 2byte
|
|
'file_length': [0x02, 4], # 2 - 文件长度; 4byte
|
|
'md5': [0x03, 16], # 3 - 文件MD5; 16byte
|
|
'encrypt': [0x04, 1], # 4 - 加密算法; 1byte
|
|
'update_type': [0x05, 1], # 5 - 升级文件类别; 1byte
|
|
'update_spec': [0x06, 4], # 6 - 升级特征字; 4byte
|
|
'update_verison': [0x07, 4], # 7 - 升级版本号; 4byte
|
|
'update_date': [0x08, 3], # 8 - 升级版本日期; 3byte
|
|
'area_code': [0x09, 4], # 9 - 省份特征; 4byte
|
|
'uptate_str': [0x0A, -1, 64], # 10 - 升级段描述; less than 64byte
|
|
'device_str': [0x0D, -1, 64], # 13 - 设备特征描述; less than 64byte
|
|
'hex_name': [0xFF, -1, 80], # 255 - Hex文件名; less than 80byte
|
|
}
|
|
|
|
|
|
def file_encryption(buffer):
|
|
""" 文件加密算法 """
|
|
pwd_idx = 0
|
|
pwd = b'moc.mmocspot.www'
|
|
pwd = list(map(lambda x: (x - 0x30 + 0x100) % 0x100, pwd))
|
|
result = bytearray(len(buffer))
|
|
for i in range(len(buffer)):
|
|
k = i
|
|
k |= i >> 8
|
|
k |= i >> 16
|
|
k |= i >> 24
|
|
result[i] = buffer[i] ^ pwd[pwd_idx] ^ (k & 0xFF)
|
|
pwd_idx = (pwd_idx + 1) % len(pwd)
|
|
return result
|
|
|
|
|
|
def build_header(config: dict, len_max=512):
|
|
"""
|
|
基于配置参数, 生成文件信息头;
|
|
V1版本, 依据字典生成tag标签组;
|
|
"""
|
|
# 定义文件头
|
|
m_file_header = bytearray(len_max)
|
|
|
|
header_len = 11
|
|
tag_num = 0
|
|
for tag, value in config.items():
|
|
if tag in Header_Tag.keys():
|
|
if tag == 'hex_name' and len_max < 256:
|
|
""" 当文件头长度不足时, 跳过文件名标签 """
|
|
continue
|
|
elif Header_Tag[tag][1] == -1:
|
|
tag_len = min(len(value), Header_Tag[tag][2])
|
|
else:
|
|
tag_len = Header_Tag[tag][1]
|
|
tag_date = [Header_Tag[tag][0], tag_len] + value[:tag_len]
|
|
m_file_header[header_len: header_len + tag_len + 2] = bytearray(tag_date)
|
|
tag_num += 1
|
|
header_len += 2 + tag_len
|
|
m_file_header[0:8] = b"TOPSCOMM"
|
|
m_file_header[8] = ((header_len - 10) % 0x100)
|
|
m_file_header[9] = ((header_len - 10) // 0x100)
|
|
m_file_header[10] = tag_num
|
|
m_file_header[header_len] = sum(m_file_header[:header_len]) % 0x100
|
|
m_file_header[header_len+1] = sum(m_file_header[:header_len]) // 0x100
|
|
|
|
if header_len+2 > len_max:
|
|
return None
|
|
else:
|
|
return m_file_header
|
|
|
|
|
|
def build_header_lite(config: dict):
|
|
"""
|
|
基于配置参数, 生成文件信息头;
|
|
V2版本, 仅提供必要信息;
|
|
"""
|
|
# 定义文件头
|
|
m_file_header = bytearray(64)
|
|
m_file_header[0:4] = bytearray(config["update_verison"])
|
|
m_file_header[4:8] = bytearray(config["file_length"])
|
|
m_file_header[8:24] = bytearray(config["md5"])
|
|
|
|
return m_file_header
|
|
|
|
|
|
def build_header_new(config: dict):
|
|
"""
|
|
基于配置参数, 生成新版文件信息头;
|
|
V3版本, 依据新版格式填充数据;
|
|
"""
|
|
# 定义文件头
|
|
m_file_header = [0xFF] * 184
|
|
|
|
m_file_header[0:8] = list(b"TOPSCOMM")
|
|
m_file_header[8:10] = config['prod_type']
|
|
m_file_header[10:22] = config['prog_id'] + [0] * (12 - len(config['prog_id']))
|
|
if config['method_compress'] == True:
|
|
m_file_header[23] = 0x01
|
|
else:
|
|
m_file_header[23] = 0x00
|
|
|
|
if 'crc32' in config.keys():
|
|
m_file_header[22] = 0x00
|
|
m_file_header[24: 40] = config['crc32'] + [0x00] * 12
|
|
elif 'md5' in config.keys():
|
|
m_file_header[22] = 0x01
|
|
m_file_header[24: 40] = config['md5']
|
|
else:
|
|
raise Exception("Error, Unknown method verify.")
|
|
|
|
# 时间戳生成
|
|
time_now = datetime.now()
|
|
time_stamp = list(map(lambda x: int(x),
|
|
time_now.strftime("%Y-%m-%d-%H-%M").split('-')))
|
|
time_stamp.insert(1, time_stamp[0] // 0x100)
|
|
time_stamp[0] = time_stamp[0] % 0x100
|
|
m_file_header[40: 46] = time_stamp
|
|
|
|
m_file_header[46: 50] = config['file_length']
|
|
# Cpu1
|
|
m_file_header[50: 54] = [0x00] * 4
|
|
m_file_header[54: 70] = [0x00] * 16
|
|
# Cpu2
|
|
m_file_header[70: 74] = [0x00] * 4
|
|
m_file_header[74: 90] = [0x00] * 16
|
|
|
|
if config['prog_type'] == 'app':
|
|
m_file_header[90: 92] = [0x00, 0x00]
|
|
elif config['prog_type'] == 'boot':
|
|
m_file_header[90: 92] = [0x01, 0x00]
|
|
elif config['prog_type'] == 'diff':
|
|
m_file_header[90: 92] = [0x02, 0x00]
|
|
elif config['prog_type'] == 'font':
|
|
m_file_header[90: 92] = [0x03, 0x00]
|
|
elif config['prog_type'] == 'config':
|
|
m_file_header[90: 92] = [0x04, 0x00]
|
|
elif config['prog_type'] == 'data':
|
|
m_file_header[90: 92] = [0x05, 0x00]
|
|
elif config['prog_type'] == 'test':
|
|
m_file_header[90: 92] = [0x06, 0x00]
|
|
else:
|
|
raise Exception("Error, Unknown Program Type.")
|
|
|
|
m_file_header[92: 94] = config['area_code']
|
|
m_file_header[94: 158] = config['hex_name']
|
|
if 'upgrade_type' in config.keys():
|
|
m_file_header[158: 160] = config['upgrade_type']
|
|
m_file_header[160: 182] = [0x00] * 22
|
|
else:
|
|
m_file_header[158: 182] = [0x00] * 24
|
|
|
|
m_file_header = bytearray(m_file_header)
|
|
|
|
calculator = Calculator(Crc16.MODBUS)
|
|
code_crc16 = calculator.checksum(m_file_header[:-2])
|
|
m_file_header[182: 184] = [code_crc16 // 0x100, code_crc16 % 0x100]
|
|
|
|
return m_file_header
|
|
|
|
|
|
def parser_version_info(file_bin: bytearray, base_addr:int):
|
|
""" 解析Bin文件内的版本信息结构体 """
|
|
address_block = (file_bin[6] << 24) + (file_bin[7] << 16) + (file_bin[4] << 8) + file_bin[5]
|
|
address_block -= base_addr
|
|
address_block *= 2
|
|
|
|
offset = address_block
|
|
block_version = {}
|
|
block_version['name'] = file_bin[offset + 1 : offset + 64 : 2]
|
|
offset += 64
|
|
block_version['device'] = file_bin[offset + 1 : offset + 64 : 2]
|
|
offset += 64
|
|
block_version['factory'] = file_bin[offset + 1 : offset + 32 : 2]
|
|
offset += 32
|
|
block_version['hardware'] = file_bin[offset + 1 : offset + 64 : 2]
|
|
offset += 64
|
|
|
|
return block_version
|
|
|
|
def test1(fp: Path):
|
|
""" bin文件生成测试 """
|
|
file1 = Path(fp)
|
|
path1 = file1.parent / (file1.stem + ".bin")
|
|
data1 = file1.read_text()
|
|
data2 = file_IntelHex_to_Bin(data1, 0x3F0100)
|
|
path1.write_bytes(data2)
|
|
|
|
# 测试Bin到IntelHex
|
|
bin = Path(fp).read_bytes()
|
|
result = file_Bin_to_IntelHex(bin, 0x80000, memory_width=2)
|
|
(fp.parent / (fp.stem + ".hex")).write_text(result)
|
|
|
|
|
|
def test2():
|
|
""" 校验, 加密测试 """
|
|
# Header - Crc16
|
|
bin_offcial = Path(r"D:\WorkSpace\UserTool\SelfTool\FrameParser\test\p460\result\lamina_adapter_t1.dat")
|
|
data_offcial = bin_offcial.read_bytes()
|
|
byte_data = data_offcial[:182]
|
|
crc = data_offcial[182:184]
|
|
# data = "54 4F 50 53 43 4F 4D 4D 45 00 53 4C 43 50 30 30 31 00 00 00 00 00 01 00 B6 61 A8 73 BF 82 9E A7 4C 79 F6 BB 94 E2 A5 18 E8 07 05 18 0B 17 18 4C 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6C 61 6D 69 6E 61 5F 61 64 61 70 74 65 72 5F 6D 61 69 6E 02 00 00 00 00 20 10 53 06 00 00 00 00 80 A5 8F 02 00 00 00 00 EC 1F 40 00 00 00 00 00 00 00 00 00 00 00 00 00 7A CA 61 0A FD 7F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
|
|
# byte_data = list(map(lambda x: int(x, 16), data.split(' ')))
|
|
# crc = "99 CB"
|
|
calculator = Calculator(Crc16.MODBUS)
|
|
code_crc16 = calculator.checksum(bytearray(byte_data))
|
|
print(f"Result = {hex(code_crc16)}, Offcial Result = {crc}")
|
|
|
|
# File - md5
|
|
data_bin = '123456 123456 '.encode()
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(data_bin)
|
|
hash = md5_ctx.hexdigest()
|
|
# File - encrypt
|
|
buffer1 = data_bin[:]
|
|
buffer1_en = file_encryption(buffer1)
|
|
buffer2 = buffer1_en[:6] + buffer1[6:]
|
|
buffer2_de = file_encryption(buffer2)
|
|
pass
|
|
|
|
|
|
def task5():
|
|
""" 文件缓冲区对比测试 """
|
|
file_dat = Path(r"test\p280039\result\lamina_controller_dsp_t1.dat")
|
|
file_dat_buffer = Path(r"test\p280039\result\lamina_controller_dsp_buffer.bin")
|
|
file_dat_buffer.exists(), file_dat.exists()
|
|
data_dat = file_dat.read_bytes()
|
|
data_dat_buffer = file_dat_buffer.read_bytes()
|
|
for i in range(len(data_dat)):
|
|
if data_dat[i] != data_dat_buffer[2*i]:
|
|
print(f"Diff in {hex(i)}, Data: {data_dat[i]}!={data_dat_buffer[2*i]}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# path_bin = Path("F:\\Work\\FPGA\\Test\\Vivado\\test_update\\test_update.vitis\\upgrade_system\\Debug\\sd_card\\BOOT.BIN")
|
|
# GeneratePackage_Demo_Xilinx(path_bin)
|
|
pass
|