生成Nordic DFU升级ZIP包和混合HEX烧录包以及使用python脚本实现自动打包

        Nordic的大部分蓝牙芯片,其打包方式都是差不多的,这里贴出我整理好的打zip升级包和hex混合烧录包的步骤,主要使用Nordic官方的打包工具nrfutil。打包的时候,有几个重要的东西,包括private key,bootloader等需要先准备好。

        nrfutil的所有合法的命令和参数都可以通过“nrfutil pkg generate --help”命令来查询。

        打dfu升级包使用 nrfutil pkg generate 命令,一个完整的示例命令如下:

.\nrfutil pkg generate --hw-version 52  --sd-req 0xAF --key-file private.key --application-version 1 --application mmc_w505.hex product_dfu.zip

        上述命令会生成一个名为 1227_2.zip 的dfu升级文件。其中,--hw-version 参数表示所使用的cpu类型(51/52),--sd-req 参数表示使用的softdevice的版本; --key-file 表示使用的秘钥文件;--application-version表示版本号,需要大于或者等于升级以前的版本,实际上这里可以永远写一个值不用变动;--application 表示用于升级的hex文件,最后1227_2.zip就是生成的target文件。

--hw-version 52  :51/52.
--application-version 1 :equal or greater than before.
--sd-req 0x8C  :use  "nrfutil pkg generate --help" to find out the value. (0x8C matched S132  3.0.0)

        打混合烧录包的话,需要先生成bootloader_settings.hex文件,然后将softdevice.hex、bootloader_settings.hex、原始的project hex文件以及bootloader等四个文件合并即可用于烧录。

        生成bootloader_settings.hex文件的示例命令如下:

.\nrfutil settings generate  --no-backup --family NRF52 --application mmc_w505.hex --application-version 0 --bootloader-version 0 --bl-settings-version 1 bootloader_setting.hex

        这里的话,backup没有什么意义,--family 表示使用的设备类型,需要具体到某一个型号,比如我们使用的是NRF52832QFAA就写NRF52,同为52832的另一个仅内置256kB Flash的版本NRF52832QFAB需要写NRF52QFAB;--application也是表示输入的project hex文件,--application-version 、--bootloader-version和--bl-settings-version表示各个初始的版本号,这里和上边的生成dfu的命令中的版本号是对应的,如果这里的版本号大于dfu的版本号,将无法升级。

--bl-settings-version: For SDK12 and SDK13 we only have same bootloader setting version = 1
--application-version and --bootloader-version: The initial version of application and bootloader of your choice. In this case I chose 0.
--family: Device family, match with your chip. If you have nRF52840 you have to use NRF52840 instead of NRF52.

        生成bootloader_settings.hex文件之后,就可以合并烧录包了。可以使用别的工具,也可以使用Nordic提供的合并工具 mergehex.exe。这个工具有一点简陋,一次最多只能合并三个文件,我们用于烧录的话,四个文件需要经过两次合并。

.\mergehex.exe -m s132_nrf52_6.1.0_softdevice.hex  s132_bootloader_15.2.hex bootloader_setting.hex -o temp.hex

.\mergehex.exe -m temp.hex  mmc_w505.hex  -o  product.hex

        这样操作起来挺麻烦的,我这里写了一个python脚本来帮助我完成打包。

        准备一个目录,将nrfutil和mergehex等打包工具以及bootloader,private key,softdevice等打包文件准备好,然后弄一个配置文件用于记录路径信息,命名为release_config.json:

{
    "buildAbsPath": "D:/WorkSpace/MCU/mmc_w505_15.2/mmc/pca10040/arm5_no_packs/_build",
    "projectPath": "D:/WorkSpace/MCU/mmc_w505_15.2",
    "releasePath": "../auto_release"
}

        这里主要记录了build文件路径,项目的工程路径(这个用于后边的git操作,暂未完成)以及打包好的文件存放的目录。

        然后,python脚本如下,我的运行环境是使用Anaconda3配置的python3.5,应该python3.6也是可以跑的,2.7的没有测试过,可能需要略微修改一些语法什么的。

        这里的操作有些繁琐,主要步骤是,解析目录下的release_config.json文件,然后得到项目的build路径,查找该路径下的mmc_w505.hex 文件,然后将其复制到当前目录,组织命令分别生成zip格式的dfu文件和hex格式的混合烧录文件。我们这个是体温计项目,初期的版本中,各个热敏电阻的档位没有直接写入到UICR中(稍后会有一文记录这个),所以暂时会根据不同的热敏电阻档位去生成不同的打包文件,所以这里的脚本要求输入两个参数,一个是固件版本号,一个是档位。比如使用如下命令:

python auto_release.py 0056 H

        这个命令会在上边配置的releasePath(../auto_release,父目录下的auto_release目录)中,生成一个release_0056的文件夹,然后在这个文件夹下生成一个dfu_release_0056_H.zip文件和一个product_release_0056_H.hex文件。此外,由于我们会同时打多个档位的包,这里也会同步生成一个release_0056的压缩文件,每生成一个新的档位,都会将同一个版本号不同档位的zip文件和hex文件压缩到一起。

        脚本内容如下:

#!/usr/bin/python

import sys
import os
from shutil import copyfile
import glob
import zipfile
import json

#
RELEASE_CONFIG = "release_config.json"

##########################################

# release package collect path.
RELEASE_PATH = "auto_release"

# file prefix str.
DFU_PRE = "dfu_release"
PRODUCT_PRE = "product_release"

# origin file.
INPUT_FILE = "mmc_w505.hex"
# temp merge file.
TEMP_MERGE_FILE = "temp_bootable.hex"
# temp bootloader setting file.
BOOTLOADER_SETTINGS_FILE = "bootloader_setting.hex"
# softdevice file
SOFT_DEVICE = "s132_nrf52_6.1.0_softdevice.hex"
# bootloader file
BOOTLOADER = "bl_512.hex"
HEX = ".hex"
ZIP = ".zip"
buildAbsPath = ""
projectPath = ""
releasePath = ""


def copy_build_file(srcDir):
    dst = os.path.dirname(os.path.abspath(__file__))
    print("execPath:"+dst)
    print("sourcePath:"+srcDir)
    if not os.path.exists(os.path.join(srcDir, INPUT_FILE)):
        return False
    copyfile(srcDir+"/"+INPUT_FILE, dst+"/"+INPUT_FILE)
    fs = os.listdir(srcDir)
    for f in fs:
        if(os.path.exists(os.path.join(srcDir, f)) and os.path.isfile(os.path.join(srcDir, f))):
            os.remove(os.path.join(srcDir, f))
    return True


def auto_release_check():
    global buildAbsPath
    global projectPath
    global releasePath
    if(os.path.exists(RELEASE_CONFIG)):
        with open(RELEASE_CONFIG, 'r') as file_read:
            json_str = json.load(file_read)
            buildAbsPath = json_str["buildAbsPath"]
            projectPath = json_str["projectPath"]
            releasePath = json_str["releasePath"]
            print("buildAbsPath:"+buildAbsPath)
            print("projectPath:"+projectPath)
            print("releasePath:"+releasePath)
            if(os.path.exists(buildAbsPath) and os.path.exists(projectPath) and os.path.exists(releasePath)):
                return True
    return False


def zip_all_release_file(path):

    # zip_path=path.split('/')[-1]
    if(os.path.exists(path+ZIP)):
        os.remove(path+ZIP)
    print("ZIP:"+path+ZIP)
    with zipfile.ZipFile(path+ZIP, 'w') as target:
        for i in os.walk(path):
            # print("walk:"+str(i))
            for n in i[2]:
                # print("walk  2:"+str(n))
                target.write(''.join((i[0], '/', n)), n)
    return


def create_path(path):
    if(not os.path.exists(path)):
        os.makedirs(path)
    return


def clear_temp_file():
    os.remove(BOOTLOADER_SETTINGS_FILE)
    os.remove(TEMP_MERGE_FILE)
    os.remove(INPUT_FILE)
    return


def create_dfu_zip_file(path, common_name):
    os.system("nrfutil.exe pkg generate --hw-version 52 --sd-req 0xAF --key-file private.key --application-version 1 --application  " +
              INPUT_FILE+" "+path+"/"+DFU_PRE+"_"+common_name+ZIP)
    return


def create_bootloader_setting_file(path, common_name):
    os.system("nrfutil.exe settings generate  --no-backup --family NRF52 --application "+INPUT_FILE +
              " --application-version 0 --bootloader-version 0 --bl-settings-version 1 "+BOOTLOADER_SETTINGS_FILE)
    return


def create_product_hex_file(path, common_name):
    os.system("mergehex.exe -m "+SOFT_DEVICE+" "+BOOTLOADER +
              " "+BOOTLOADER_SETTINGS_FILE+" -o "+TEMP_MERGE_FILE)
    os.system("mergehex.exe -m "+TEMP_MERGE_FILE+" "+INPUT_FILE +
              " -o "+path+"/"+PRODUCT_PRE+"_"+common_name+HEX)
    return


def run_release(argv):
    os.system('cls')  # clear screen
    print(argv)
    if len(argv) < 1:
        print("Error:need output version !")
        exit()
    elif len(argv) < 2:
        print("Warning:no ntc info!")
    else:
        if(auto_release_check()):
            if not copy_build_file(buildAbsPath):
                print("Error:the source hex file not exist!")
                return
        else:
            print("Error:config path not exist!")
            return

        ver_str = argv[0]
        path = releasePath+"/release_"+ver_str
        common_name = ver_str
        if(len(argv) > 1):
            ntc_index = argv[1]
            common_name = ver_str+"_"+ntc_index

        create_path(path)
        create_dfu_zip_file(path, common_name)
        create_bootloader_setting_file(path, common_name)
        create_product_hex_file(path, common_name)
        clear_temp_file()
        zip_all_release_file(path)
        return


# start application
if __name__ == "__main__":
    run_release(sys.argv[1:])

 

你可能感兴趣的:(#,BLE,物联网)