541 lines
24 KiB
Python
541 lines
24 KiB
Python
import time
|
|
import warnings
|
|
import hashlib
|
|
from math import ceil
|
|
from tqdm import tqdm
|
|
from pathlib import Path
|
|
|
|
from . import tools
|
|
from .tools import ByteConv, IntelHex
|
|
from .function import protocols, file_upgrade
|
|
from .DeviceSerial import DeviceSerial
|
|
|
|
ParamMap_LaminaAdapter = {
|
|
# 1 - Hex
|
|
# 2 - Int16
|
|
# 3 - lnt32
|
|
# 4 - str
|
|
# 5 - addr
|
|
# 6 - float
|
|
# 8 - func_callback
|
|
0x00: ["硬件版本识别电压", 2, 1000],
|
|
0x01: ["输出电容电电压", 2, 10],
|
|
0x02: ["参考电压", 2, 10],
|
|
|
|
0x0E: ["故障字1", 1],
|
|
0x0F: ["故障字2", 1],
|
|
0x10: ["MPPT工作状态", 1],
|
|
0x11: ["系统工作状态", 1],
|
|
0x12: ["系统工作模式", 1],
|
|
0x13: ["输入电压", 2, 10],
|
|
0x14: ["电感电流", 2, 100],
|
|
0x15: ["12V电压", 2, 10],
|
|
0x16: ["输出电压", 2, 10],
|
|
0x17: ["输入电流", 2, 100],
|
|
0x18: ["温度1", 2, 10],
|
|
0x19: ["温度2", 2, 10],
|
|
0x1A: ["输入功率", 3, 1000],
|
|
0x1C: ["设备温度", 2, 10],
|
|
0x1D: ["开关机状态", 1],
|
|
0x1E: ["电池电压", 2, 10],
|
|
0x1F: ["并机功率限值", 3, 1000],
|
|
0x21: ["输出限功率电压阈值", 2, 10],
|
|
|
|
0x50: ["启停控制命令" , 2],
|
|
0x51: ["故障清除命令" , 2],
|
|
0x52: ["参数还原命令" , 2],
|
|
0x53: ["设备复位命令" , 2],
|
|
0x54: ["主动故障命令" , 2],
|
|
0x55: ["短时停机命令" , 2],
|
|
|
|
0x5E: ["抖动频率上限", 2, 100],
|
|
0x5F: ["抖动频率下限", 2, 100],
|
|
0x60: ["光伏通道使能", 1],
|
|
0x61: ["最小启动输入电压", 2, 10],
|
|
0x62: ["最大启动输入电压", 2, 10],
|
|
0x63: ["最小停止输入电压", 2, 10],
|
|
0x64: ["最大停止输入电压", 2, 10],
|
|
0x65: ["最小MPPT电压", 2, 10],
|
|
0x66: ["最大MPPT电压", 2, 10],
|
|
0x67: ["最小启动输出电压", 2, 10],
|
|
0x68: ["最大启动输出电压", 2, 10],
|
|
0x69: ["最小停止输出电压", 2, 10],
|
|
0x6A: ["最大停止输出电压", 2, 10],
|
|
0x6B: ["输入过压保护值", 2, 10],
|
|
0x6C: ["输出过压保护值", 2, 10],
|
|
0x6D: ["输出欠压保护值", 2, 10],
|
|
0x6E: ["电感过流保护值", 2, 100],
|
|
0x6F: ["输入过流保护值", 2, 100],
|
|
0x70: ["最小电感电流限值", 2, 100],
|
|
0x71: ["最大电感电流限值", 2, 100],
|
|
0x72: ["浮充电压阈值", 2, 10],
|
|
0x73: ["三点法中间阈值", 2, 10],
|
|
0x74: ["恒压充电电压", 2, 10],
|
|
0x75: ["过温故障值", 2, 10],
|
|
0x76: ["过温告警值", 2, 10],
|
|
0x77: ["温度恢复值", 2, 10],
|
|
0x78: ["最低满载电压", 2, 10],
|
|
0x79: ["最高满载电压", 2, 10],
|
|
0x7A: ["输入过载保护值", 3, 1000],
|
|
0x7C: ["最小功率限值", 3, 1000],
|
|
0x7E: ["最大功率限值", 3, 1000],
|
|
0x80: ["最大功率限值存储值", 3, 1000],
|
|
0x82: ["载波通信地址", 5, 3],
|
|
0x85: ["电压环out_max", 2, 100],
|
|
0x86: ["电压环out_min", 2, 100],
|
|
0x87: ["电流环out_max", 2, 100],
|
|
0x88: ["电流环out_min", 2, 100],
|
|
0x89: ["MPPT扰动系数k_d_vin", 2, 100],
|
|
0x8A: ["dmin", 2, 1000],
|
|
0x8B: ["dmax", 2, 1000],
|
|
0x8C: ["扫描电压偏移scanvolt_offset", 2, 10],
|
|
0x8D: ["电压环Kp", 3, 100000],
|
|
0x8F: ["电压环Ki", 3, 100000],
|
|
0x91: ["电流环Kp", 3, 100000],
|
|
0x93: ["电流环Ki", 3, 100000],
|
|
0x95: ["日志级别", 1],
|
|
0x96: ["日志输出方式", 1],
|
|
0x97: ["采样校准volt_in_a", 2, 1000],
|
|
0x98: ["采样校准volt_in_b", 2, 100],
|
|
0x99: ["采样校准volt_out_a", 2, 1000],
|
|
0x9A: ["采样校准volt_out_b", 2, 100],
|
|
0x9B: ["采样校准curr_in_a", 2, 1000],
|
|
0x9C: ["采样校准curr_in_b", 2, 100],
|
|
0x9D: ["采样校准curr_induc_a", 2, 1000],
|
|
0x9E: ["采样校准curr_induc_b", 2, 100],
|
|
0x9F: ["采样校准volt_12V_a", 2, 1000],
|
|
0xA0: ["采样校准volt_12V_b", 2, 100],
|
|
0xA1: ["温度补偿temp1_b", 2, 10],
|
|
0xA2: ["温度补偿temp2_b", 2, 10],
|
|
0xA3: ["系统工作模式", 2],
|
|
0xA4: ["电感电流给定值curr_set", 2, 100],
|
|
0xA5: ["抖动频率上限", 2, 100],
|
|
0xA6: ["抖动频率下限", 2, 100],
|
|
0xA7: ["电池电压判断限值", 2, 10],
|
|
0xA8: ["MPPT追踪模式", 1],
|
|
0xA9: ["ADC参考电压", 2, 1000],
|
|
0xAA: ["硬件版本", 1],
|
|
0xAB: ["保留", 1],
|
|
0xAC: ["保留", 1],
|
|
0xAD: ["保留", 1],
|
|
0xAE: ["保留", 1],
|
|
0xAF: ["保留", 1],
|
|
0xB0: ["版本", 4, 16],
|
|
0x100: ["版本(ODM)", 4, 16],
|
|
0x110: ["型号", 4, 16],
|
|
0x120: ["载波芯片地址", 4, 16],
|
|
0x130: ["厂商", 4, 8],
|
|
0x138: ["保留", 4, 8],
|
|
0x140: ["保留", 4, 16],
|
|
0x150: ["保留", 4, 16],
|
|
0x160: ["硬件", 4, 16],
|
|
0x170: ["SN", 4, 16],
|
|
0x180: ["MES", 4, 16],
|
|
0x190: ["Datetime", 4, 16],
|
|
0x1A0: ["事件记录1", 8, 16],
|
|
0x1B0: ["事件记录2", 8, 16],
|
|
0x1C0: ["事件记录3", 8, 16],
|
|
0x1D0: ["事件记录4", 8, 16],
|
|
0x1E0: ["事件记录5", 8, 16],
|
|
0x1F0: ["事件记录6", 8, 16],
|
|
0x200: ["事件记录-Log", 8, 16],
|
|
}
|
|
|
|
MemoryMap_SLCP001 = {
|
|
'image_size': 0x100000, # 镜像文件大小
|
|
'app_size': 0x040000, # 应用程序大小
|
|
'boot_size': 0x010000, # Boot程序大小
|
|
|
|
'boot_addr': 0x000000, # Boot程序地址
|
|
'main_addr': 0x010000, # main程序地址
|
|
'back_addr': 0x0BC000, # back程序地址
|
|
'main_header': 0x0FC000, # main信息地址
|
|
'back_header': 0x0FE000, # back信息地址
|
|
}
|
|
MemoryMap_460 = {
|
|
'image_size': 0x058000, # 镜像文件大小
|
|
'app_size': 0x024000, # 应用程序大小
|
|
'boot_size': 0x010000, # Boot程序大小
|
|
|
|
'boot_addr': 0x000000, # Boot程序地址
|
|
'main_addr': 0x00C000, # main程序地址
|
|
'back_addr': 0x030000, # back程序地址
|
|
'main_header': 0x054000, # main信息地址
|
|
'back_header': 0x056000, # back信息地址
|
|
}
|
|
|
|
class LaminaAdapter(DeviceSerial):
|
|
""" 叠光适配器\优化器
|
|
使用继承方式实现功能
|
|
"""
|
|
def __init__(self, com_name,
|
|
addr_645=[0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA],
|
|
addr_modbus=0x01, type_dev='SLCP101', **kwargs):
|
|
""" 调用超类实现函数初始化 """
|
|
super().__init__(com_name,
|
|
callbacks=(lambda : protocols.make_frame_dlt645(self.block),
|
|
lambda frame: protocols.check_frame_dlt645(frame, self.block)),
|
|
**kwargs)
|
|
|
|
self.device = type_dev
|
|
match type_dev:
|
|
case 'SLCP001':
|
|
self.make_package = lambda *args, **kwargs: GeneratePackage('SLCP001', *args, **kwargs)
|
|
self.make_image = lambda *args, **kwargs: GenerateImage('SLCP001', *args, **kwargs)
|
|
case 'SLCP101':
|
|
self.make_package = lambda *args, **kwargs: GeneratePackage('SLCP101', *args, **kwargs)
|
|
self.make_image = lambda *args, **kwargs: GenerateImage('SLCP101', *args, **kwargs)
|
|
case 'SLCP102':
|
|
self.make_package = lambda *args, **kwargs: GeneratePackage('SLCP102', *args, **kwargs)
|
|
self.make_image = lambda *args, **kwargs: GenerateImage('SLCP102', *args, **kwargs)
|
|
case 'DLSY001':
|
|
self.make_package = lambda *args, **kwargs: GeneratePackage('DLSY001', *args, **kwargs)
|
|
self.make_image = lambda *args, **kwargs: GenerateImage('DLSY001', *args, **kwargs)
|
|
case _:
|
|
self.make_package = None
|
|
self.make_image = None
|
|
|
|
self.block = {
|
|
'addr' : addr_645,
|
|
'type' : 'modbus',
|
|
'data' : {
|
|
'addr_dev' : addr_modbus,
|
|
'data_define': ParamMap_LaminaAdapter,
|
|
},
|
|
}
|
|
|
|
def frame_read(self, daddr=0x60, dlen=0x50) -> bool:
|
|
""" 通用参数读取 """
|
|
self.block['data']['type'] = 'read'
|
|
self.block['data']['data_addr'] = daddr
|
|
self.block['data']['data_len'] = dlen
|
|
return self._transfer_data()
|
|
|
|
def frame_write(self, daddr, dlen=1, dval=None) -> bool:
|
|
""" 通用参数写入 """
|
|
if daddr in self.block['data']['data_define'].keys():
|
|
param_define = self.block['data']['data_define'][daddr]
|
|
else:
|
|
param_define = [f'未知参数{daddr}', 1]
|
|
match param_define[1]:
|
|
case 1 | 2:
|
|
return self.frame_write_one(daddr, 0 if dval is None else dval)
|
|
case 3:
|
|
return self.frame_write_dual(daddr, 0 if dval is None else dval)
|
|
case 4 | 5 | 6:
|
|
return self.frame_write_str(daddr, [] if dval is None else dval)
|
|
case 6 | 7 | 8:
|
|
type_param_define = next(v for k, v in protocols.modbus_map.items() if v == param_define[1])
|
|
warnings.warn(f"DataType unsupport write: {type_param_define}")
|
|
return False
|
|
case _:
|
|
return self.frame_write_one(daddr, 0 if dval is None else dval)
|
|
|
|
def frame_write_one(self, daddr=0x85, dval=-900) -> bool:
|
|
self.block['data']['type'] = 'write_one'
|
|
self.block['data']['data_addr'] = daddr
|
|
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
|
self.block['data']['data_val'] = int(dval * item_coff)
|
|
return self._transfer_data()
|
|
|
|
def frame_write_dual(self, daddr=0x91, dval=600) -> bool:
|
|
self.block['data']['type'] = 'write_dual'
|
|
self.block['data']['data_addr'] = daddr
|
|
item_coff = self.block['data']['data_define'][daddr][2] if len(self.block['data']['data_define'][daddr]) > 2 else 1
|
|
self.block['data']['data_val'] = int(dval * item_coff)
|
|
return self._transfer_data()
|
|
|
|
def frame_write_str(self, daddr=0x82, dval=[0x06, 0x05, 0x04, 0x03, 0x02, 0x01]) -> bool:
|
|
self.block['data']['type'] = 'write_str'
|
|
self.block['data']['data_addr'] = daddr
|
|
self.block['data']['data_val'] = dval
|
|
return self._transfer_data()
|
|
|
|
def frame_read_log(self, step='next') -> bool:
|
|
self.block['data']['type'] = 'log'
|
|
self.block['data']['step'] = step
|
|
return self._transfer_data()
|
|
|
|
def frame_update(self, path_file: Path, makefile: bool = False, savefile: bool = False, **kwargs) -> bool:
|
|
""" 程序升级
|
|
注意: 在使用单板升级测试时, 需要关闭低电压检测功能, 否则无法启动升级流程;
|
|
|
|
"""
|
|
param_saved = self.flag_print, self.retry, self.time_out
|
|
self.flag_print = False
|
|
try:
|
|
status = 'init' # 初始化
|
|
if not path_file.exists():
|
|
raise Exception("工程编译目标文件不存在.")
|
|
if makefile and self.make_package is not None:
|
|
self.block['data']['file'] = self.make_package(path_file, **kwargs)
|
|
if savefile:
|
|
path_file.parent.joinpath(path_file.stem + '.dat').write_bytes(self.block['data']['file'])
|
|
else:
|
|
self.block['data']['file'] = path_file.read_bytes()
|
|
|
|
self.block['data']['type'] = 'update'
|
|
self.block['data']['header_offset'] = 184
|
|
|
|
status = 'start' # 启动帧
|
|
self.block['data']['step'] = 'start'
|
|
self.block['data']['index'] = 0
|
|
assert self._transfer_data()
|
|
|
|
self.block["data"]['file_block_size'] = self.output['upgrade']['length']
|
|
# 避免接收到延迟返回报文
|
|
time.sleep(self.time_out)
|
|
|
|
status = 'trans' # 文件传输
|
|
self.retry = 3
|
|
self.time_out = 1.5
|
|
self.block["data"]['step'] = 'trans'
|
|
self.block['data']['index'] = 0
|
|
frame_total = ceil((len(self.block["data"]['file']) - self.block['data']['header_offset']) / self.block["data"]['file_block_size'])
|
|
for idx in tqdm(range(frame_total), desc="File Transmitting"):
|
|
self.block["data"]['index'] = idx
|
|
assert self._transfer_data()
|
|
|
|
status = 'end' # 结束升级
|
|
self.time_out = 1
|
|
self.block["data"]['step'] = 'end'
|
|
self.block["data"]['index'] += 1
|
|
assert self._transfer_data()
|
|
except Exception as ex:
|
|
""" 通用异常处理 """
|
|
self.flag_print, self.retry, self.time_out = param_saved
|
|
report = f'Upgrade Fail: {status}'
|
|
report += f', Frame in {self.block["data"]["index"]}' if status == 'trans' else ''
|
|
report += f'\n Error by {ex}' if not isinstance(ex, AssertionError) else ''
|
|
print(report)
|
|
return False
|
|
|
|
self.flag_print, self.retry, self.time_out = param_saved
|
|
time.sleep(6)
|
|
self.frame_read(0x100, 0x20)
|
|
return True
|
|
|
|
|
|
def GeneratePackage(type_dev: str, path_hex: Path, **kwargs) -> bytearray:
|
|
""" 生成升级包 """
|
|
upgrade_backup = kwargs['upgrade_backup'] if 'upgrade_backup' in kwargs.keys() else None
|
|
|
|
config = {
|
|
'prod_type': [0x45, 0x00], # 产品类型
|
|
'method_compress': False, # 文件压缩
|
|
'prog_id': list(type_dev.encode('ascii')), # 程序识别号
|
|
'prog_type': 'app', # 程序类型
|
|
'area_code': [0x00, 0x00], # 地区
|
|
}
|
|
match type_dev:
|
|
case 'SLCP001':
|
|
MemoryMap = MemoryMap_SLCP001
|
|
case 'SLCP101':
|
|
MemoryMap = MemoryMap_460
|
|
case 'SLCP102':
|
|
MemoryMap = MemoryMap_460
|
|
case 'DLSY001':
|
|
MemoryMap = MemoryMap_460
|
|
case _:
|
|
raise Exception("Unknow device.")
|
|
|
|
bin_main = IntelHex.file_IntelHex_to_Bin(path_hex.read_text(), len_max=MemoryMap['app_size'])
|
|
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_main)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
config['hex_name'] = list(path_hex.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
if upgrade_backup:
|
|
config['prog_id'][:4] = b'BACK'
|
|
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
print("Package generated successfully.")
|
|
print(f"File name: {path_hex.name}")
|
|
print(f"File Info:")
|
|
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
|
|
# 组装镜像
|
|
Image = [0xFF] * (len(main_header) + len(encrypt_main))
|
|
offset_image = 0
|
|
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
offset_image += len(main_header)
|
|
Image[offset_image: offset_image + len(encrypt_main)] = encrypt_main
|
|
|
|
# 额外处理
|
|
if 'output_bin' in kwargs.keys() and kwargs['output_bin']:
|
|
(path_hex / (path_hex.stem + '.bin')).write_bytes(bin_main)
|
|
|
|
if 'output_dat' in kwargs.keys() and kwargs['output_dat']:
|
|
(path_hex / (path_hex.stem + '.dat')).write_bytes(bytearray(Image))
|
|
|
|
return bytearray(Image)
|
|
|
|
def GenerateImage(type_dev: str, path_boot: Path, path_main: Path, path_back: Path, **kwargs) ->bytearray:
|
|
""" 镜像生成 """
|
|
config = {
|
|
'prod_type': [0x45, 0x00], # 产品类型
|
|
'method_compress': False, # 文件压缩
|
|
'prog_id': list(type_dev.encode('ascii')), # 程序识别号
|
|
'prog_type': 'app', # 程序类型
|
|
'area_code': [0x00, 0x00], # 地区
|
|
}
|
|
match type_dev:
|
|
case 'SLCP001':
|
|
MemoryMap = MemoryMap_SLCP001
|
|
case 'SLCP101':
|
|
MemoryMap = MemoryMap_460
|
|
case 'SLCP102':
|
|
MemoryMap = MemoryMap_460
|
|
case 'DLSY001':
|
|
MemoryMap = MemoryMap_460
|
|
case _:
|
|
raise Exception("Unknow device.")
|
|
|
|
bin_boot = IntelHex.file_IntelHex_to_Bin(path_boot.read_text(), len_max=MemoryMap['boot_size'])
|
|
bin_main = IntelHex.file_IntelHex_to_Bin(path_main.read_text(), len_max=MemoryMap['app_size'])
|
|
bin_back = IntelHex.file_IntelHex_to_Bin(path_back.read_text(), len_max=MemoryMap['app_size'])
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_main)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
config['hex_name'] = list(path_main.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_back)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_back))
|
|
config['hex_name'] = list(path_back.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
config['prog_id'][:4] = b'BACK'
|
|
if (back_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
# 组装镜像
|
|
Image = [0xFF] * MemoryMap['image_size']
|
|
Image[MemoryMap['boot_addr']: MemoryMap['boot_addr'] + len(bin_boot)] = bin_boot
|
|
Image[MemoryMap['main_addr']: MemoryMap['main_addr'] + len(bin_main)] = bin_main
|
|
Image[MemoryMap['back_addr']: MemoryMap['back_addr'] + len(bin_back)] = bin_back
|
|
Image[MemoryMap['main_header']: MemoryMap['main_header'] + len(main_header)] = main_header
|
|
Image[MemoryMap['back_header']: MemoryMap['back_header'] + len(back_header)] = back_header
|
|
|
|
# Log打印
|
|
print("Merge Image generated successfully.")
|
|
print(f"Main File:")
|
|
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
print(f"Back File:")
|
|
print(f"\t header_length={len(back_header)}, bin_length={len(bin_back)}[{hex(len(bin_back))}]")
|
|
|
|
# 额外文件
|
|
if 'output_header' in kwargs.keys() and kwargs['output_header']:
|
|
(path_main.parent / (path_main.stem + '.header')).write_bytes(main_header)
|
|
(path_back.parent / (path_back.stem + '.header')).write_bytes(back_header)
|
|
if 'output_bin' in kwargs.keys() and kwargs['output_bin']:
|
|
(path_main.parent / (path_main.stem + '.bin')).write_bytes(bin_main)
|
|
(path_back.parent / (path_back.stem + '.bin')).write_bytes(bin_back)
|
|
if 'output_encrypt' in kwargs.keys() and kwargs['output_encrypt']:
|
|
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
encrypt_back = file_upgrade.file_encryption(bin_back)
|
|
(path_main.parent / (path_main.stem + '.encrypt')).write_bytes(encrypt_main)
|
|
(path_back.parent / (path_back.stem + '.encrypt')).write_bytes(encrypt_back)
|
|
|
|
return bytearray(Image)
|
|
|
|
|
|
def GeneratePackage_DLSY001_p460(path_hex: Path):
|
|
""" 叠光优化器-460平台版本 生成升级包 """
|
|
config = {
|
|
'prod_type': [0x45, 0x00], # 产品类型
|
|
'method_compress': False, # 文件压缩
|
|
'prog_id': list(b"DLSY001"), # 程序识别号
|
|
'prog_type': 'app', # 程序类型
|
|
'area_code': [0x00, 0x00], # 地区
|
|
}
|
|
bin_main = IntelHex.file_IntelHex_to_Bin(path_hex.read_text(), len_max=0x024000)
|
|
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_main)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
config['hex_name'] = list(path_hex.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
print("Package generated successfully.")
|
|
print(f"File name: {path_hex.name}")
|
|
print(f"File Info:")
|
|
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
|
|
# 组装镜像
|
|
Image = [0xFF] * (len(main_header) + len(encrypt_main))
|
|
offset_image = 0
|
|
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
offset_image += len(main_header)
|
|
Image[offset_image: offset_image + len(encrypt_main)] = encrypt_main
|
|
|
|
return bytearray(Image), bin_main
|
|
|
|
|
|
def GenerateImage_DLSY001_p460(path_boot: Path, path_main: Path, path_back: Path):
|
|
""" 叠光优化器-460平台版本 镜像生成 """
|
|
config = {
|
|
'prod_type': [0x45, 0x00], # 产品类型
|
|
'method_compress': False, # 文件压缩
|
|
'prog_id': list(b"DLSY001"), # 程序识别号
|
|
'prog_type': 'app', # 程序类型
|
|
'area_code': [0x00, 0x00], # 地区
|
|
}
|
|
bin_boot = IntelHex.file_IntelHex_to_Bin(path_boot.read_text(), len_max=0x00C000)
|
|
bin_main = IntelHex.file_IntelHex_to_Bin(path_main.read_text(), len_max=0x024000)
|
|
bin_back = IntelHex.file_IntelHex_to_Bin(path_back.read_text(), len_max=0x024000)
|
|
encrypt_main = file_upgrade.file_encryption(bin_main)
|
|
encrypt_back = file_upgrade.file_encryption(bin_back)
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_main)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_main))
|
|
config['hex_name'] = list(path_main.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
if (main_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
md5_ctx = hashlib.md5()
|
|
md5_ctx.update(bin_back)
|
|
config["md5"] = list(md5_ctx.digest())
|
|
config['file_length'] = ByteConv.conv_int_to_array(len(bin_back))
|
|
config['hex_name'] = list(path_back.name.encode())[:64]
|
|
config['hex_name'] += [0] * (64 - len(config['hex_name']))
|
|
if (back_header:=file_upgrade.build_header_new(config)) is None:
|
|
raise Exception("Header tag oversize. ")
|
|
|
|
print("Merge Image generated successfully.")
|
|
print(f"Main File:")
|
|
print(f"\t header_length={len(main_header)}, bin_length={len(bin_main)}[{hex(len(bin_main))}]")
|
|
print(f"Back File:")
|
|
print(f"\t header_length={len(back_header)}, bin_length={len(bin_back)}[{hex(len(bin_back))}]")
|
|
|
|
# 组装镜像
|
|
Image = [0xFF] * 0x058000
|
|
offset_image = 0
|
|
Image[offset_image: offset_image + len(bin_boot)] = bin_boot
|
|
offset_image = 0x00C000
|
|
Image[offset_image: offset_image + len(bin_main)] = bin_main
|
|
offset_image = 0x030000
|
|
Image[offset_image: offset_image + len(bin_back)] = bin_back
|
|
offset_image = 0x054000
|
|
Image[offset_image: offset_image + len(main_header)] = main_header
|
|
offset_image = 0x056000
|
|
Image[offset_image: offset_image + len(back_header)] = back_header
|
|
|
|
return bytearray(Image), main_header, back_header
|