添加升级文件生成模块;
This commit is contained in:
@@ -9,9 +9,22 @@ def trans_str_to_list(data: str) -> list:
|
||||
func_trans = lambda x: int(x, 16)
|
||||
return list(map(func_trans, data.strip().split(" ")))
|
||||
|
||||
def conv_int_to_array(num: int, big_end=False):
|
||||
""" 数值转字节数组 """
|
||||
result = [0, 0, 0, 0]
|
||||
if big_end:
|
||||
indexlist = reversed(range(len(result)))
|
||||
else:
|
||||
indexlist = range(len(result))
|
||||
|
||||
for i in indexlist:
|
||||
result[i] = int(num % 0x100)
|
||||
num //= 0x100
|
||||
return result
|
||||
|
||||
def display_hex(data, len) -> str:
|
||||
""" Hex字符表示 """
|
||||
data %= 2 ** (4 * len)
|
||||
result = "0" * len + hex(data)[2:]
|
||||
return "0x" + result[-len:].upper()
|
||||
|
||||
|
||||
222
source/utl_upgrade.py
Normal file
222
source/utl_upgrade.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# 升级包生成脚本
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from utl import conv_int_to_array
|
||||
|
||||
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_hex_to_bin(file_data, base_address, len_max=0xC000, conv_end=False):
|
||||
"""
|
||||
将Intel Hex格式文件转换为Bin格式;
|
||||
"""
|
||||
result = bytearray(len_max).replace(b'\x00', b'\xff')
|
||||
lines = file_data.split('\n')
|
||||
offset = 0
|
||||
max_address = 0
|
||||
for line in lines:
|
||||
if max_address >= len_max:
|
||||
raise("Bin file Oversize.")
|
||||
if line[0] == ':':
|
||||
checksum = sum([int(x, 16) * (15 * (~i & 0x01) + 1) for i, x in enumerate(line[1:])])
|
||||
if (checksum & 0x00FF) != 0:
|
||||
raise Exception('Hex file checksum error!')
|
||||
|
||||
if line[7:9] == '00':
|
||||
len = int(line[1:3], 16)
|
||||
address = offset + int(line[3:7], 16) - base_address
|
||||
address *= 2
|
||||
data = bytearray.fromhex(line[9:-2])
|
||||
if conv_end:
|
||||
for i in range(0, len, 2):
|
||||
t = data[i]
|
||||
data[i] = data[i+1]
|
||||
data[i+1] = t
|
||||
result[address:address+len] = data
|
||||
|
||||
if (address + len) > max_address:
|
||||
max_address = address + len
|
||||
elif line[7:9] == '01':
|
||||
break
|
||||
elif line[7:9] == '02':
|
||||
offset = int(line[9:-2], 16) * 2**16
|
||||
elif line[7:9] == '03':
|
||||
pass
|
||||
elif line[7:9] == '04': # 拓展地址偏移
|
||||
offset = int(line[9:-2], 16) * 2**16
|
||||
elif line[7:9] == '05':
|
||||
pass
|
||||
return result[:max_address]
|
||||
|
||||
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(data_bin: bytearray, config: dict, len_max=512):
|
||||
"""
|
||||
基于配置参数, 生成文件信息头;
|
||||
"""
|
||||
# 定义文件头
|
||||
m_file_header = bytearray(len_max)
|
||||
m_file_header[0:8] = b"TOPSCOMM"
|
||||
|
||||
header_len = 11
|
||||
tag_num = 0
|
||||
for tag, value in config.items():
|
||||
if tag in header_tag.keys():
|
||||
if 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[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 > 64:
|
||||
return None
|
||||
else:
|
||||
return m_file_header
|
||||
|
||||
def build_header1(data_bin: bytearray, config: dict):
|
||||
"""
|
||||
基于配置参数, 生成文件信息头; 基于新版本升级方案;
|
||||
"""
|
||||
# 定义文件头
|
||||
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 make_datafile(file_path: str, config: dict, header_len=512):
|
||||
""" 升级文件生成函数 """
|
||||
file_path = Path(file_path)
|
||||
file_data = file_path.read_text()
|
||||
data_bin = file_hex_to_bin(file_data, config['flash_addr'], len_max=config['flash_size'] * 2)
|
||||
md5_ctx = hashlib.md5()
|
||||
md5_ctx.update(data_bin)
|
||||
config['file_length'] = conv_int_to_array(len(data_bin))
|
||||
config["md5"] = list(md5_ctx.digest())
|
||||
if header_len > 256:
|
||||
config['hex_name'] = list(file_path.name.encode())[:80]
|
||||
|
||||
data_header = build_header(data_bin, config, header_len)
|
||||
if data_header is None:
|
||||
raise ("header tag oversize! ")
|
||||
data_encrypt = file_encryption(data_bin)
|
||||
return data_header, data_encrypt, data_bin
|
||||
|
||||
def make_datafile1(file_path: str, config: dict, header_len=512):
|
||||
""" 升级文件生成函数; 基于新版本方案 """
|
||||
file_path = Path(file_path)
|
||||
file_data = file_path.read_text()
|
||||
data_bin = file_hex_to_bin(file_data, config['flash_addr'], len_max=config['flash_size'] * 2)
|
||||
md5_ctx = hashlib.md5()
|
||||
md5_ctx.update(data_bin)
|
||||
|
||||
config['file_length'] = conv_int_to_array(len(data_bin), True)
|
||||
config["md5"] = list(md5_ctx.digest())
|
||||
if header_len > 256:
|
||||
config['hex_name'] = list(file_path.name.encode())[:80]
|
||||
|
||||
data_header = build_header1(data_bin, config)
|
||||
data_encrypt = file_encryption(data_bin)
|
||||
return data_header, data_encrypt, data_bin
|
||||
|
||||
def test1(fp):
|
||||
""" bin文件生成测试 """
|
||||
file1 = Path(fp)
|
||||
path1 = file1.parent / (file1.stem + ".bin")
|
||||
data1 = file1.read_text()
|
||||
data2 = file_hex_to_bin(data1, 0x3F0100)
|
||||
path1.write_bytes(data2)
|
||||
pass
|
||||
|
||||
def test2():
|
||||
""" md5校验, 加密测试 """
|
||||
data_bin = '123456 123456 '.encode()
|
||||
md5_ctx = hashlib.md5()
|
||||
md5_ctx.update(data_bin)
|
||||
hash = md5_ctx.hexdigest()
|
||||
buffer1 = data_bin[:]
|
||||
buffer1_en = file_encryption(buffer1)
|
||||
buffer2 = buffer1_en[:6] + buffer1[6:]
|
||||
buffer2_en = file_encryption(buffer2)
|
||||
pass
|
||||
|
||||
def test3():
|
||||
""" 完整升级包生成测试 """
|
||||
config = {
|
||||
# 'file_type': [0x43, 0x00], # 叠光DSP升级文件
|
||||
# 'file_version': [0x00, 0x00], # 文件版本-00
|
||||
# 'file_length': [], # 文件长度
|
||||
# 'md5': [], # 文件MD5
|
||||
'encrypt': [0x01], # 默认加密算法
|
||||
'update_type': [0x01], # APP升级
|
||||
# 'update_spec': [], # 升级特征字
|
||||
'update_verison': [0x01, 0x00, 0x00, 0x00], # 升级版本号; 4byte
|
||||
'update_date': [0x23, 0x12, 0x16], # 升级版本日期; 3byte
|
||||
# 'area_code': [], # 省份特征; 4byte
|
||||
# 'uptate_str': [], # 升级段描述; less than 64byte
|
||||
# 'device_str': [], # 设备特征描述; less than 64byte
|
||||
# 'hex_name': [], # Hex文件名; less than 80byte
|
||||
|
||||
# 文件结构信息
|
||||
'flash_addr': 0x3E8020, # 程序文件起始地址
|
||||
'flash_size': 0x005FC0, # 程序文件大小
|
||||
}
|
||||
file1 = Path("D:\WorkingProject\LightStackController\lamina_pvdc\Source\PVDC20\Debug\LAMINA_PVDC.hex")
|
||||
func_gen = [make_datafile, make_datafile1]
|
||||
func_para = [{'header_len':64}, {}]
|
||||
|
||||
count = 0
|
||||
for func, para in zip(func_gen, func_para):
|
||||
header, data_e, data_b = func(file1, config, **para)
|
||||
print(list(map(hex, header)))
|
||||
print(list(map(hex, data_e)))
|
||||
print(list(map(hex, data_b)))
|
||||
file2 = file1.parent / (file1.stem + f'_v{count}.dat')
|
||||
file2.write_bytes(header + data_b)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# test1()
|
||||
# test2()
|
||||
test3()
|
||||
pass
|
||||
Reference in New Issue
Block a user