HELLO,大家好,好久不见,最近太忙了, 几个月没有更新文章了。

最近在项目开发过程中,做每个项目的bootloader升级时,就得修订对应的头部打包脚本,或者是有界面的打包工具,都需要把对应的厂商、项目相关的信息手动输入,每打包一次,需要手动输入一次这些项目相关的数据,太麻烦了!!!

本文,将使用python+配置文件的方式,自动读取源bin文件并自动生成可定制化的带头部的目的文件。

废话不多说,见我72变。

  • 首先, 需要编写配置文件,我提供一个配置文件案例: 将其保存为xxxx.headconfig

注意文件名字不重要,后缀名一定需要是.headconfig

具体怎么增加填充修订xxxx.headconfig,如下文件,请自行填充。

hello, 这是自动打包头部的工具,请按照项目属性进行配置.
首先,我们需要配置编译生成的输出的文件名【可带编译路径】:
======================================================
0、>>testota.bin>>
然后,我们需要设置升级文件头部信息,请按照项目属性进行配置.
================升级文件头部配置起始====================
================请按规定修订定制值======================
1、厂商ID:8字节
##XXXX1234##
2、产品规格:8字节
##XXXX5678##
3、硬件版本号:3字节
##V001##
4、固件版本号:3字节
##V001##
5、...
================升级文件头部配置结束====================
最后,我们需要设置输出文件名信息,请按照项目属性进行配置.
================输出文件名配置起始======================
================请按规定修订定制值======================
1、项目名称:
@@XXX123@@
2、硬件版本号
@@V100@@
3、固件版本号
@@V100@@
4、...
================输出文件名配置结束======================
再见

  • 其次,编写python解析该文件,具体代码我直接给出:
  • 测试环境为windows

import crcmod
import re
import os
import sys
# 方法1, 与方法2效果一致
cr16_xmodem = crcmod.predefined.mkCrcFun('modbus')
# 方法2, 与方法1效果一致
# cr16_xmodem = crcmod.mkCrcFun(0x18005, initCrc=0xFFFF, rev=True, xorOut=0x0000)
# print(hex(cr16_xmodem(bytearray(data))))
header_mes = []
out_bin = []
in_bin = []
# 厂商ID:8字节
# 产品规格:8字节
# 硬件版本号:4字节
# 固件版本号:4字节
head_conf_len = [8, 8, 4, 4]
HEADER_LENGTH = 64
TOOLS_VERSION = 'V1.0.0'
print('')
print('**************************科学防疫,健康生活**************************')
print('* *')
print('**************************自动打包头部工具***************************')
print('* *')
print('**************************工具版本号:%s%s' % (TOOLS_VERSION,'**************************'))
str_update_pat = re.compile(r'\##(.*)\##')
str_outpath_pat = re.compile(r'\@@(.*)\@@')
str_in_bin_path_pat = re.compile(r'\>>(.*)\>>')
# 提取文件夹下的地址+文件名
def file_name(file_dir, file_pat):
L = []
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == file_pat:
L.append(os.path.join(root, file))
return L
# 获取头部配置文件
config_path_list = file_name('.', '.headconfig')
config_path = ''
for conf in config_path_list:
config_path += conf.strip();
print('头部配置文件:%s' % conf)
if (len(config_path_list) != 1):
print('头部配置文件不存在或者存在多份!')
os.system('cmd')
sys.exit(1)
with open(config_path, 'rt', encoding='utf8') as conf:
configs = conf.readlines()
for line in configs:
header_mes += str_update_pat.findall(line)
out_bin += str_outpath_pat.findall(line)
in_bin += str_in_bin_path_pat.findall(line)
# 拼接头部填充值
header_mes_str = ''
header_mes_one_len = []
for line in header_mes:
header_mes_one_len.append(len(line.strip()))
header_mes_str += line
# 拼接输出文件名
out_bin_path = ''
for line in out_bin:
out_bin_path += line.strip() + '-'
# 拼接输入文件名
in_bin_path = ''
for line in in_bin:
in_bin_path += line.strip()
out_bin_path = out_bin_path.rstrip('-')
out_bin_path += '-UP.bin'
print('头部数据:%s' % header_mes_str)
print('输出文件名:%s' % out_bin_path)
print('输入文件路径:%s' % (in_bin_path))
if header_mes_one_len != head_conf_len:
print('头部配置不符合规范,请检查头部配置!')
os.system('cmd')
sys.exit(2)
if(os.path.exists(in_bin_path) != True):
print('输入文件不存在!')
os.system('cmd')
sys.exit(3)
try:
srcbin_len = os.path.getsize(in_bin_path)
with open(in_bin_path, 'rb') as sf:
srcbin = sf.read()
except UnicodeError:
print('文件编码出错!')
else:
print('源文件的长度:%d' % srcbin_len)
srcbin_crc = cr16_xmodem(srcbin)
print('源文件CRC值:', hex(srcbin_crc))
header_mes = list(header_mes_str.encode('utf-8'))
srcbin_len_bytes = int(srcbin_len).to_bytes(4, byteorder='big', signed=False)
for i in range(len(srcbin_len_bytes)):
header_mes.append(srcbin_len_bytes[i])
srcbin_crc_bytes = int(srcbin_crc).to_bytes(2, byteorder='big', signed=False)
for i in range(len(srcbin_crc_bytes)):
header_mes.append(srcbin_crc_bytes[i])
header_mes_crc = cr16_xmodem(bytearray(header_mes))
print('头部CRC【填充0xFF前】:', hex(header_mes_crc))
head_mes_crc_bytes = int(header_mes_crc).to_bytes(2, byteorder='big', signed=False)
for i in range(len(head_mes_crc_bytes)):
header_mes.append(head_mes_crc_bytes[i])
print('填充前头部的长度:%d' % (len(header_mes)))
for i in range(len(header_mes), HEADER_LENGTH):
header_mes.append(0xFF)
print('填充后头部的长度:%d' % (len(header_mes)))
with open(out_bin_path, 'wb') as out:
out.write(bytearray(header_mes))
out.write(bytearray(srcbin))
with open(out_bin_path, 'rb') as rout:
outbin_file = rout.read()
outbin_len = os.path.getsize(out_bin_path)
print('填充头部后的输出文件长度:%d' % outbin_len)
print('填充头部后的输出文件CRC:', hex(cr16_xmodem(outbin_file)))
if ((srcbin_len + HEADER_LENGTH) != outbin_len):
print('**************************头部填充失败了**************************')
else:
print('**************************头部填充成功了**************************')
print('')
os.system('cmd')

  • 为了能在没有安装python环境的电脑上运行,此处将python脚本进行打包成exe文件:

//将保留打印输出调试信息
pyinstaller -F --clean auto_add_header.py
//如果不保留打印调试信息
pyinstaller -F -w --clean auto_add_header.py
//可以修改exe文件图标,一定需要是.ico文件
pyinstaller -F -i test.ico auto_add_header.py

  • 可以在dist文件夹下生成auto_add_header.exe文件
  • 准备好test.bin, head_mes.headconfig, auto_add_header.exe,双击auto_add_header.exe文件, 会有如下输出:

如果头部配置文件输入不符合规范,如:

执行窗口会有如下输出:

好了,差不多了,工具拿走不谢!

最后,希望大家科学防疫,健康生活!!!