如何实现蓝牙空中升级BLE OTA

如何实现BLE OTA?什么叫DFU?如何通过UART实现固件升级?又如何通过USB实现固件升级?怎么保证升级的安全性?什么叫双备份(dual bank)DFU?什么叫单备份(single bank)DFU?什么叫后台式(background)DFU?本文将对上述问题进行探讨。

1.概述

所谓DFU(Device Firmware Update),就是设备固件升级的意思,而OTA是DFU的一种类型,准确说,OTA的全称应该是OTA DFU,只不过大家为了方便起见,直接用OTA来指代固件空中升级(有时候大家也将OTA称为FOTA)。DFU除了可以通过无线方式(OTA)进行升级,也可以通过有线方式进行升级,比如通过UART,USB或者SPI通信接口来升级设备固件。

不管采用OTA方式还是有线通信方式,DFU包括后台式(background)和非后台式两种模式,目前的智能手机升级Android或者iOS系统都是采用background DFU方式,即新固件在后台悄悄下载,下载成功后,再提示用户升级,整个升级过程中对用户手机使用没有任何影响。而早先的功能机就是采用非后台式 DFU来升级操作系统的,即用户需要先长按某些按键进入bootloader模式,然后再进行升级,在升级过程中,手机的正常功能无法使用。Background DFU必须采用双备份(dual bank)模式进行升级,即老系统(老固件)和新系统(新固件)各占一块存储区,只有当新系统下载完成并校验成功后才会去升级老系统。而非后台式DFU可以采用dual bank或者single bank模式,dual bank的做法是升级时系统先进入bootloader,然后把新系统(新固件)下载下来并校验成功,然后再擦除老系统(老固件)并升级新系统,dual bank方式虽然牺牲了很多存储空间,但是换来了更好的升级体验。Single bank的做法是升级时系统也是先进入bootloader,然后立马把老系统擦除,然后直接把新系统下载到老系统区域,跟dual bank相比,single bank将大大节省Flash存储区域,在系统资源比较紧张的时候,推荐使用single bank方式。不管是single bank还是dual bank,升级过程出现问题后,都可以进行二次升级,都不会出现“变砖”情况。不过dual bank有一个好处,如果升级过程中出现问题或者新固件有问题,它还可以选择之前的老系统继续执行而不受其影响。而single bank碰到这种情况就只能一直待在bootloader中,然后等待二次或者多次升级,此时设备的正常功能就无法使用了,从用户使用这个角度来说,你也可以认为此时设备已经“变砖”了。可参考下面三个图来理解上述过程。

  

 

如果你是第一次接触Nordic nRF5 SDK,那么建议你先看一下这篇文章:开发你的第一个BLE应用程序—Blinky,或者看一下这一篇文章:手把手教你开发BLE数据透传应用程序,以建立Nordic nRF5 SDK的一些基本知识,然后再往下看以下章节。

2. Nordic nRF5 SDK DFU例程

Nordic 原生态SDK就提供了OTA(BLE)DFU,UART DFU,以及USB DFU例程,大家可以直接参考Nordic例程来实现自己的DFU。由于Nordic SDK版本很多,而且每个版本之间都或多或少有些差异,下面将分SDK版本来阐述Nordic每个版本SDK中如何实现OTA,至于UART DFU和USB DFU,这里就不再阐述了。感兴趣的同学可以参考Nordic nRF5 SDK v15.0.0如下目录:

UART serial DFU目录(nRF52832):nRF5_SDK_15.0.0_a53641a\examples\dfu\secure_bootloader\pca10040_uart\arm5_no_packs

USB serial DFU目录(nRF52840):

nRF5_SDK_15.0.0_a53641a\examples\dfu\secure_bootloader\pca10056_usb\arm5_no_packs

这里说明一下,目前Nordic只提供非后台式DFU例子,SDK中还没有后台式DFU例子(不过这个实现起来并不难,只要大家搞明白了里面的原理,自己开发起来会很快的),所以下面的论述都是基于非后台式DFU。另外,SDK9/10/11,Nordic只有明文DFU。从SDK12开始,Nordic 开始支持安全DFU(secure DFU)。所谓secure DFU,不是指升级时固件是加密的,而是指升级之前bootloader会先验证新固件的签名,只有验签通过后,才允许后续升级,此时的升级方式仍然是明文;验签失败,则拒绝后续升级。Secure DFU将杜绝黑客的恶意攻击,大大提高系统的安全性。

Nordic nRF5 SDK软件架构跟其他家有点不一样,程序存储区最开始部分放得不是bootloader,而是蓝牙协议栈softdevice,bootloader则被nRF5 SDK放在程序存储区的最上面,整个存储区结构图如下所示:

 

根据升级时如何跳转到Bootloader,nRF5 SDK又将DFU分为按键式DFU和非按键式(Buttonless)DFU,所谓按键式DFU,就是上电时长按某个按键以进入bootloader模式。而buttonless DFU,就是整个DFU过程中设备端无任何人工干预,通过BLE指令方式让设备进入bootloader模式。

按键式DFU比较简单,你只需将softdevice和bootloader image烧入到设备中(application可烧可不烧),按住button4然后上电,设备就会自动进入bootloader模式,然后就可以通过nRF Connect或者nRF Toolbox对设备进行OTA了。一旦buttonless DFU例子从app跳到了bootloader,后续DFU升级过程就跟按键式DFU一模一样,所以如果你对按键式DFU操作过程中有什么不明白的地方,可以参考后面的buttonless DFU的说明,这里就不单独对按键式DFU操作过程进行说明了。

下面将对buttonless DFU实现过程按照SDK版本一一进行阐述,请选择你感兴趣的SDK版本进行阅读。下文的所有操作步骤所对应的脚本都放在百度云盘上,云盘链接如下所示

建议大家先把对应的脚本下下来,然后对着操作步骤去实现自己的DFU过程。

2.1 nRF5 SDK v15.0.0 OTA

SDK15既支持明文DFU又支持安全DFU(实际上是签名DFU),而且SDK15既可以实现OTA DFU,也可以实现基于UART或者USB通信的DFU。所谓签名DFU,就是bootloader中预先装载一个公钥,升级时,主机先发一个签名给bootloader,bootloader会对这个签名进行验签,验签通过才能继续DFU,否则拒绝DFU。SDK15 OTA DFU是基于例程ble_app_buttonless_dfu来实现的,而且SDK15只支持nRF52系列产品,它不支持nRF51系列产品,下面我们以nRF52832(开发板编号:PCA10040)为例,来阐述SDK15是如何实现OTA的。

nRF52832 OTA

请大家先到百度云盘下载压缩包:DFU/SDK15_0/ Script_SDK15_S132_nRF52832.rar”并解压,然后对照以下步骤进行操作:

1)     准备。请先执行如下的“build_all.bat”脚本(Windows系统),以生成相应的micro-ecc库(micro-ecc会用来对签名进行验签等安全功能)。请注意,欲成功执行build_all.bat,大家必须先安装好git和gcc编译器。如果你嫌麻烦,可以到百度云盘下载: micro-ecc_sdk14_15_newer.rar,然后覆盖相关文件,效果也是一样的。

 

然后请按照http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.tools%2Fdita%2Ftools%2Fnrfutil%2Fnrfutil_installing.html&cp=5_5_1安装最新版nrfutil,nrfutil安装有两种方式,一种是直接下载exe文件,一种是以Python的方式进行安装。

nrfutil.exe直接下载链接为:(注:如果大家不熟悉Python,推荐使用这种方式)

https://github.com/NordicSemiconductor/pc-nrfutil/releases记得把nrfutil.exe所在目录放在Windows环境变量中。

或者你按照如下步骤去安装nrfutil:

注:安装完Python2.7后,需要修改Windows path变量值,如果你安装了老版本nrfutil,请先把老版本所在的目录C:\Program Files (x86)\Nordic Semiconductor\nRFgo Studio从path变量中删除,然后添加这2个目录:C:\Python27;C:\Python27\Scripts;

  • 通过pip安装最新版的nrfutil,即打开Windows命令行工具CMD,输入如下命令:pip install nrfutil,即可以完成nrfutil的安装。
  • 安装完成后,在Windows命令行工具输入:nrfutil version,其版本应该在3.2.0以上。
  • 对于Windows用户,nrfutil运行需要几个特殊的DLL库,而这几个库有些Windows机器是没有的,如此,可往:https://www.microsoft.com/en-us/download/details.aspx?id=40784下载。

2)     通过nrfutil生成公私钥对。大家可以直接双击“key_generate.bat”以生成相应的私钥(priv.pem)和公钥(dfu_public_key.c)。大家务必要保存好私钥priv.pem,以后每个新image要升级时,都会先通过这个私钥对它进行签名,一旦priv.pem丢失或者被暴露,DFU将无法进行或者变得不安全。

3)     编译bootloader代码。将刚才的dfu_public_key.c取代目录nRF5_SDK_15.0.0_a53641a\examples\dfu下的同名文件,然后编译如下目录中的工程:

nRF5_SDK_15.0.0_a53641a\examples\dfu\secure_bootloader\pca10040_ble\arm5_no_packs,将hex改为:bootloader.hex

4)     编译application代码。请编译工程:nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral\ble_app_buttonless_dfu\pca10040\s132\arm5_no_packs,将hex修改为:app.hex

5)     生成bootloader settings page。Bootloader settings存储在Flash最后一个page,它将决定复位后芯片的行为,比如是进入DFU模式还是应用模式,同时它还包含image的CRC值和版本等信息。如果要求芯片复位后进入application,必须正确生成该bootloader settings hex,生成脚本见“settings_page_generate.bat”

6)     烧写softdevice,app和bootloader。请双击“mass_program.bat”来完成整个烧写过程

7)     生成新image对应的zip包。请双击“zip_generate.bat”,以生成SDK15_app_s132.zip,升级时,该zip包将会由云端下发到手机app中。

8)     将“SDK15_app_s132.zip”拷贝到手机上。安卓和苹果手机都可以通过微信的‘文件传输助手’拷过去,非常方便。请注意,手机nRF Connect和nRF Toolbox都支持DFU功能,苹果手机拷贝的时候可以随便选择其中一个app。

9)     使用nRF Connect或者nRF Toolbox来完成DFU过程。这里以nRF Connect为例来阐述整个升级过程

  • DK广播为Nordic_Buttonless,如下

 

  • 连接该设备,使能CCCD,并选择“DFU”

 

  • 选择升级用的zip包。有些安卓系统自带的文件浏览器会有问题,建议使用ES explorer来选择zip,如下:

 

 

  • 开始升级

  

  • 升级成功,设备将自动启动,此时你会看到新image已经在运行,广播名字也变成Nordic_new,如下:

 

后面我会以SDK15.0.0 ble_app_uart为例,详细阐述如何把ble_app_buttonless_dfu的DFU功能移植到ble_app_uart上,从而让ble_app_uart也具有DFU功能,有兴趣的的读者请参考第3章。

nRF52840 OTA

nRF52840 OTA过程与nRF52832非常相似,唯一不同的是选择pca10056目录,请下载百度云盘脚本“DFU/SDK15_0/ Script_SDK15_S140_nRF52840.rar”,然后按照上述52832的步骤来实现52840的OTA DFU。

2.2 nRF5 SDK v14.2.0 OTA

SDK14目前只支持安全DFU(实际上是签名DFU),所谓签名DFU,就是bootloader中预先装载一个公钥,升级时,主机先发一个签名给bootloader,bootloader会对这个签名进行验签,验签通过后才能继续DFU,否则拒绝DFU。SDK14既可以实现OTA DFU,也可以实现基于UART或者USB通信的DFU。SDK14 OTA DFU是基于例程ble_app_buttonless_dfu来实现的,而且SDK14只支持nRF52系列产品,它不支持nRF51系列产品,下面我们以nRF52832(开发板编号:PCA10040)为例,来阐述SDK14是如何实现OTA的。

nRF52832 OTA

请大家先到百度云盘下载压缩包:DFU/SDK14_2/ Script_SDK14_S132_nRF52832.rar”并解压,然后对照以下步骤进行操作:

1)     准备。请先执行如下的“build_all.bat”脚本(Windows系统),以生成相应的micro-ecc库(micro-ecc会用来对签名进行验签等安全功能)。请注意,欲成功执行build_all.bat,大家必须先安装好git和gcc编译器。如果你嫌麻烦,可以到百度云盘下载: micro-ecc_sdk14_15_newer.rar,然后覆盖相关文件,效果也是一样的。

然后请按照http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.tools%2Fdita%2Ftools%2Fnrfutil%2Fnrfutil_installing.html&cp=5_5_1安装最新版nrfutil,nrfutil安装有两种方式,一种是直接下载exe文件,一种是以Python的方式进行安装。

nrfutil.exe直接下载链接为:(注:如果大家不熟悉Python,推荐使用这种方式)

https://github.com/NordicSemiconductor/pc-nrfutil/releases记得把nrfutil.exe所在目录放在Windows环境变量中。

或者你按照如下步骤去安装nrfutil:

注:安装完Python2.7后,需要修改Windows path变量值,如果你安装了老版本nrfutil,请先把老版本所在的目录C:\Program Files (x86)\Nordic Semiconductor\nRFgo Studio从path变量中删除,然后添加这2个目录:C:\Python27;C:\Python27\Scripts;

  • 通过pip安装最新版的nrfutil,即打开Windows命令行工具CMD,输入如下命令:pip install nrfutil,即可以完成nrfutil的安装。
  • 安装完成后,在Windows命令行工具输入:nrfutil version,其版本应该在3.2.0以上。
  • 对于Windows用户,nrfutil运行需要几个特殊的DLL库,而这几个库有些Windows机器是没有的,如此,可往:https://www.microsoft.com/en-us/download/details.aspx?id=40784下载。

2)     通过nrfutil生成公私钥对。大家可以直接双击“key_generate.bat”以生成相应的私钥(priv.pem)和公钥(dfu_public_key.c)。大家务必要保存好私钥priv.pem,以后每个新image要升级时,都会先通过这个私钥对它进行签名,一旦priv.pem丢失或者被暴露DFU将无法进行或者变得不安全

3)     编译bootloader代码。将刚才的dfu_public_key.c取代目录nRF5_SDK_14.2.0_17b948a\examples\dfu\dfu_req_handling下的同名文件,然后编译如下目录中的工程:

nRF5_SDK_14.2.0_17b948a\examples\dfu\bootloader_secure_ble\pca10040\arm5_no_packs,将hex改为:bootloader.hex

4)     编译application代码。请编译工程:nRF5_SDK_14.2.0_17b948a\examples\ble_peripheral\ble_app_buttonless_dfu\pca10040\s132\arm5_no_packs,将hex修改为:app.hex

5)     生成bootloader settings page。Bootloader settings存储在Flash最后一个page,它将决定复位后芯片的行为,比如是进入DFU模式还是应用模式,同时它还包含image的CRC值和版本等信息。如果要求芯片复位后进入application,必须正确生成该bootloader settings hex,生成脚本见“settings_page_generate.bat”

6)     烧写softdevice,app和bootloader。请双击“mass_program.bat”来完成整个烧写过程

7)     生成新image对应的zip包。请双击“zip_generate.bat”,以生成SDK14_app_s132.zip,升级时,该zip包将会由云端下发到手机app中。

8)     将“SDK14_app_s132.zip”拷贝到手机上。安卓和苹果手机都可以通过微信的‘文件传输助手’拷过去,非常方便。请注意,手机nRF Connect和nRF Toolbox都支持DFU功能,苹果手机拷贝的时候可以随便选择其中一个app。

9)     使用nRF Connect或者nRF Toolbox来完成DFU过程。这里以nRF Connect为例来阐述整个升级过程

  • DK广播为Nordic_Buttonless,如下

 

  • 连接该设备,使能CCCD,并选择“DFU”

 

  • 选择升级用的zip包。有些安卓系统自带的文件浏览器会有问题,建议使用ES explorer来选择zip,如下: 

 

  • 开始升级

 

  • 升级成功,设备将自动启动,此时你会看到新image已经在运行,广播名字也变成Nordic_new,如下:

 

后面我们会以SDK15.0.0 ble_app_uart为例,详细阐述如何把ble_app_buttonless_dfu的DFU功能移植到ble_app_uart上,从而让ble_app_uart也具有DFU功能,有兴趣的的读者请参考第3章。注意:SDK14.2.0 DFU原理跟SDK15.0.0一模一样,大家可以依葫芦画瓢,完成SDK14.2.0的DFU移植工作。

2.3 nRF5 SDK v12.3.0 OTA

SDK12目前只支持安全DFU(实际上是签名DFU),所谓签名DFU,就是bootloader中预先装载一个公钥,升级时,主机先发一个签名给bootloader,bootloader会对这个签名进行验签,验签通过后才能继续DFU,否则拒绝DFU。SDK12只有OTA DFU例子,而没有基于串口的DFU例程。SDK12 OTA DFU是基于例程ble_app_buttonless_dfu来实现的,而且SDK12同时支持nRF52832以及nRF51系列产品,下面我们以nRF52832(开发板编号:PCA10040)为例,来详细阐述SDK12是如何实现OTA的。

nRF52832 OTA

请大家先到百度云盘下载压缩包:DFU/SDK12_3/ Script_SDK12_S132_nRF52832.rar”并解压,然后对照以下步骤进行操作:

1)     准备。请先到百度云盘下载: micro-ecc_sdk12.rar,然后覆盖如下目录:

 

然后请按照http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.tools%2Fdita%2Ftools%2Fnrfutil%2Fnrfutil_installing.html&cp=5_5_1安装最新版nrfutil,nrfutil安装有两种方式,一种是直接下载exe文件,一种是以Python的方式进行安装。

nrfutil.exe直接下载链接为:(注:如果大家不熟悉Python,推荐使用这种方式)

https://github.com/NordicSemiconductor/pc-nrfutil/releases记得把nrfutil.exe所在目录放在Windows环境变量中。

或者你按照如下步骤去安装nrfutil:

注:安装完Python2.7后,需要修改Windows path变量值,如果你安装了老版本nrfutil,请先把老版本所在的目录C:\Program Files (x86)\Nordic Semiconductor\nRFgo Studio从path变量中删除,然后添加这2个目录:C:\Python27;C:\Python27\Scripts;

  • 通过pip安装最新版的nrfutil,即打开Windows命令行工具CMD,输入如下命令:pip install nrfutil,即可以完成nrfutil的安装。
  • 安装完成后,在Windows命令行工具输入:nrfutil version,其版本应该在3.2.0以上。
  • 对于Windows用户,nrfutil运行需要几个特殊的DLL库,而这几个库有些Windows机器是没有的,如此,可往:https://www.microsoft.com/en-us/download/details.aspx?id=40784下载。

2)     通过nrfutil生成公私钥对。大家可以直接双击“key_generate.bat”以生成相应的私钥(priv.pem)和公钥(dfu_public_key.c)。大家务必要保存好私钥priv.pem,以后每个新image要升级时,都会先通过这个私钥对它进行签名,一旦priv.pem丢失或者被暴露DFU将无法进行或者变得不安全

3)     编译bootloader代码。将刚才的dfu_public_key.c取代目录nRF5_SDK_12.3.0_d7731ad\examples\dfu\bootloader_secure下的同名文件,然后编译如下目录中的工程:

nRF5_SDK_12.3.0_d7731ad\examples\dfu\bootloader_secure\pca10040\arm5_no_packs,将hex改为:bootloader.hex

4)     编译application代码。请编译工程:nRF5_SDK_12.3.0_d7731ad\examples\ble_peripheral\experimental_ble_app_buttonless_dfu\pca10040\s132\arm5_no_packs,将hex修改为:app.hex

5)     生成bootloader settings page。Bootloader settings存储在Flash最后一个page,它将决定复位后芯片的行为,比如是进入DFU模式还是应用模式,同时它还包含image的CRC值和版本等信息。如果要求芯片复位后进入application,必须正确生成该bootloader settings hex,生成脚本见“settings_page_generate.bat”

6)     烧写softdevice,app和bootloader。请双击“mass_program.bat”来完成整个烧写过程。请注意,在烧写前,请把app.hex倒数第3行和倒数第4行删除,因为bootloader.hex也包含一模一样的内容,会导致merge的时候hex定义冲突,如下:

 

或者编译application的时候,把如下语句注掉:

 

7)     生成新image对应的zip包。请双击“zip_generate.bat”,以生成SDK12_app_s132.zip,升级时,该zip包将会由云端下发到手机app中。

8)     将“SDK12_app_s132.zip”拷贝到手机上。安卓和苹果手机都可以通过微信的‘文件传输助手’拷过去,非常方便。请注意,手机nRF Connect和nRF Toolbox都支持DFU功能,苹果手机拷贝的时候可以随便选择其中一个app。

9)     使用nRF Connect或者nRF Toolbox来完成DFU过程。这里以nRF Connect为例来阐述整个升级过程

  • DK广播为Nordic_Buttonless,如下

 

  • 连接该设备,使能CCCD,并选择“DFU”

 

  • 选择升级用的zip包。有些安卓系统自带的文件浏览器会有问题,建议使用ES explorer来选择zip,如下:

 

  • 开始升级

 

  • 升级成功,设备将自动启动,此时你会看到新image已经在运行,广播名字也变成Nordic_new,如下:

 

nRF51系列 OTA

nRF51822 OTA过程与nRF52832非常相似,唯一不同的是选择pca10028目录,请下载百度云盘脚本“DFU/SDK12_3/ Script_SDK12_S130_nRF51.rar”,然后按照上述52832的步骤来实现51822的OTA DFU。

后面我们会以SDK15.0.0 ble_app_uart为例,详细阐述如何把ble_app_buttonless_dfu的DFU功能移植到ble_app_uart上,从而让ble_app_uart也具有DFU功能,有兴趣的的读者请参考第3章。注意:SDK12.3.0 DFU原理跟SDK15.0.0非常相似,大家可以依葫芦画瓢,完成SDK12.3.0的DFU移植工作。

2.4 nRF5 SDK v11.0.0 OTA

SDK11使用的是明文OTA DFU,其DFU是基于例程ble_app_hrs来实现的,并同时支持nRF52832和nRF51系列。下面以nRF52832为例来阐述DFU过程。

nRF52832 OTA

请大家先到百度云盘下载压缩包:DFU/SDK11_0/ Script_SDK11_S132_nRF52.rar”并解压,然后对照以下步骤进行操作:

1)       编译bootloader代码,请编译目录“nRF5_SDK_11.0.0_89a8197\examples\dfu\bootloader\pca10040\dual_bank_ble_s132\arm5_no_packs”中的工程,将hex改为bootloader.hex

2)       编译app,请编译目录“nRF5_SDK_11.0.0_89a8197\examples\ble_peripheral\ble_app_hrs\pca10040\s132_with_dfu\arm5_no_packs”中的工程,将hex改为app.hex

3)       将softdevice,bootloader和app三者同时下载到设备中,另外我们还需要在Flash中写一个app有效标志位,从而上电后程序直接跑到app执行,而不是停留在bootloader中不出来。我已经把相关烧写脚本:mass_program.bat放在百度云盘中,大家直接双击就可以完成本步操作。

4)       将新image打包成一个zip包。除了包含新image,该zip包还包含一些配置信息。升级时,zip包会通过云端下发到手机端app,手机端app再把zip包传给蓝牙设备以进行固件升级。请使用老版本nrfutil(版本号0.3.0)来生成该升级包(注:老版本nrfutil在目录“C:\Program Files (x86)\Nordic Semiconductor\nRFgo Studio”中)。我已经把相关生成脚本zip_generate.bat放在百度云盘上,大家直接双击就可以完成本步操作,并生成SDK11_app_s132.zip。

5)       把上述的‘SDK11_app_s132.zip’拷到手机中,安卓和苹果手机都可以通过微信的‘文件传输助手’拷过去,非常方便。注:手机nRF Connect和nRF Toolbox都支持DFU功能,苹果手机拷贝的时候可以随便选择其中一个app。

6)       使用nRF Connect或者nRF Toolbox来完成DFU过程。这里以nRF Connect为例来阐述整个升级过程。

  • DK广播为Nordic_HRM

 

  • 连接该设备,并使能CCCD,然后选择“DFU”

 

  • 选择升级用的zip包。有些安卓系统自带的文件浏览器会有问题,建议使用ES explorer来选择zip,如下:

 

 

  • 开始升级

 

  • 升级成功,设备将自动启动,此时你会看到新image已经在运行,广播名字也变成Nordic_HRM_new,如下:

 

 

nRF51系列OTA

nRF51822 OTA DFU实现过程跟上述的nRF52832基本上一模一样,唯一不同的是选择pca10028目录,我已把相关脚本打包并放在百度云盘中,请直接下载“DFU/SDK11_0/ Script_SDK11_S130_nRF51.rar”,来实现nRF51系列 OTA。

如果你的应用是基于SDK11开发的,并且需要集成DFU功能,请参考上述例子ble_app_hrs来移植DFU功能,主要工作包括两部分:一把BLE_DFU_APP_SUPPORT这个宏包括的所有代码拷到你的工程中,二如果你的设备支持bonding的话,还需把Device manager相关代码也拷到你的工程中,如此即可完成DFU功能的移植。

3. 给ble_app_uart加上OTA功能

为了让ble_app_uart具有DFU功能,有2种做法,一是把NUS服务移植到ble_app_buttonless_dfu中,这种方法相对来说更简单,但不利于理解DFU的移植原理;二是把DFU服务移植到ble_app_uart中,我们现以第2种做法来详细阐述如何在SDK15.0.0中把DFU服务移植到ble_app_uart中。

3.1 正常连接OTA(无bonding)

1)     打开如下工程:nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral\ble_app_uart\pca10040\s132\arm5_no_packs

2)     添加DFU服务。代码如下:

#ifdef DFU_SUPPORT

    ble_dfu_buttonless_init_t dfus_init = {0};

    // Initialize the async SVCI interface to bootloader.

    err_code = ble_dfu_buttonless_async_svci_init();

    APP_ERROR_CHECK(err_code); 

    dfus_init.evt_handler = ble_dfu_evt_handler; 

    err_code = ble_dfu_buttonless_init(&dfus_init);

    APP_ERROR_CHECK(err_code);

#endif

定义ble_dfu_evt_handler,大家只要按照要求来,就没问题,这里就不贴代码了。

Nordic对每一个模块都有一个编译总开关,因此还需到sdk_config.h中使能DFU模块,如下:

#ifndef BLE_DFU_ENABLED

#define BLE_DFU_ENABLED 1

#endif
 

// <q> NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS  - Buttonless DFU supports bonds.

 
#ifndef NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS

#define NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS 0

#endif

3)     修改softdevice配置。现在整个应用包括2个vs_uuid:NUS和DFU,相应地ATT table size也要变大,然后应用程序RAM起始地址也需要跟着变,如下(注:这里的attr_tab_size设置得稍稍偏大):

// <o> NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE - Attribute Table size in bytes. The size must be a multiple of 4.

#ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE

#define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1600

#endif

 

// <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs.

#ifndef NRF_SDH_BLE_VS_UUID_COUNT

#define NRF_SDH_BLE_VS_UUID_COUNT 2

#endif

修改应用程序RAM起始地址,如下:

 

4)     添加上述函数涉及到的文件,宏定义及包含相关目录。首先添加如下DFU目录及相关文件:

 

在define中添加这些宏:DEBUG DFU_SUPPORT BL_SETTINGS_ACCESS_ONLY NRF_DFU_SVCI_ENABLED NRF_DFU_TRANSPORT_BLE=1,其中DEBUG宏只是为了调试方便而设置的,跟DFU本身无关。DFU_SUPPORT是我用来控制我添加的DFU代码的,删掉DFU_SUPPORT,将不编译所有DFU有关代码。其余的宏都是系统自带的,如果要支持DFU,也是必须要定义的。

 

然后包含如下目录:

 

5)     在main.c中添加如下头文件定义:

#ifdef DFU_SUPPORT

#include "ble_dfu.h"

#endif

6)     在跳转到bootloader之前,如果你想做一些专门的代码处理,比如完成pending的Flash操作,比如关闭某些模块,那么你可以注册一个app_shutdown_handler来做这些工作。(注:这一步不是必须的,是可选的!)

NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0);

7)     编译工程,将hex改为“app.hex”

8)     按照2.1节“nRF5 SDK v15.0.0 OTA”步骤来执行OTA过程,你会发现ble_app_uart已经具备DFU功能了。我已把OTA过程所有步骤打成一个包:Script_SDK15_S132_NUS_NoBonding.rar,大家可以到百度云盘去下载。

3.2 bonding连接OTA

我们在3.1节基础上,再加上bonding功能,以让ble_app_uart同时支持DFU和bonding。

1)     打开3.1节的工程

2)     添加如下文件:

 

3)     在main函数中添加peer_manager_init,定义如下:

static void peer_manager_init()

{

    ble_gap_sec_params_t sec_param;

    ret_code_t           err_code;

 

    err_code = pm_init();

    APP_ERROR_CHECK(err_code);

 

    memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));

 

    // Security parameters to be used for all security procedures.

    sec_param.bond           = SEC_PARAM_BOND;

    sec_param.mitm           = SEC_PARAM_MITM;

    sec_param.lesc           = SEC_PARAM_LESC;

    sec_param.keypress       = SEC_PARAM_KEYPRESS;

    sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;

    sec_param.oob            = SEC_PARAM_OOB;

    sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;

    sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;

    sec_param.kdist_own.enc  = 1;

    sec_param.kdist_own.id   = 1;

    sec_param.kdist_peer.enc = 1;

    sec_param.kdist_peer.id  = 1;

 

    err_code = pm_sec_params_set(&sec_param);

    APP_ERROR_CHECK(err_code);

 

    err_code = pm_register(pm_evt_handler);

    APP_ERROR_CHECK(err_code);

}

然后将上面新出现的符号定义一一拷贝过来,这里不再赘述

4)     修改advertising_start定义,增加删除bonding信息功能(如果你不需要这个功能,也可以不改)

static void advertising_start(bool erase_bonds)
{
    if (erase_bonds == true)
    {
        delete_bonds();
        // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
    }
    else
    {
        uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);

        NRF_LOG_DEBUG("advertising is started");
    }
}

5)     修改allow_repairing = true,这一步也是可选的。allow_repairing = true的好处是,当手机端的bonding信息被用户误删掉了,设备会允许这台手机的第二次配对bonding请求。如果allow_repairing = false,在这种情况下,就会拒绝手机的第二次配对请求,以提高安全性。

6)     在main.c文件开头,包含如下头文件:

#include "peer_manager.h"

7)     在ble_evt_handler中删除BLE_GAP_EVT_SEC_PARAMS_REQUEST分支,因为这个分支在peer_manager模块中已经进行处理了,这里再处理一次,会产生异常:

//        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:

//            // Pairing not supported

//            err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);

//            APP_ERROR_CHECK(err_code);

//            break;

8)     将ble_nus.c文件从\components目录中拷出来,放在自己工程目录下,因为我们接下来需要对它进行修改,后续项目直接引用自己的ble_nus,而不要再引用components目录下的原始文件了。将TX characteristic的CCCD写属性从open改为加密,这样将自动触发手机端的bonding请求,修改代码如下:

BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);

9)     修改sdk_config.h文件,需要修改多个地方,如下:

#define PEER_MANAGER_ENABLED 1

#define FDS_ENABLED 1

#define NRF_SDH_BLE_SERVICE_CHANGED 1

#define NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS 0

请注意NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS可以为0,也可以为1,两种情况下,DFU成功后,bonding信息都可以保持。两者的区别是,当NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS为0,进入DFU模式后,bootloader将用普通模式跟手机相连,这种方式兼容性好,可靠性高,但安全等级稍低;当NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS为1时,bootloader将共享application的bonding信息,也就是说,哪怕进入bootloader模式,设备还是跟手机处于bonding状态,这种方式安全级别比较高,但容易产生兼容性问题,极端情况下,如果DFU过程中用户把手机端的bonding信息删除,系统将会变砖,而且无法恢复。推荐将NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS设为0,以获得最好的兼容性和可靠性。

 

如果你在应用中把NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS设为1,那么还需要添加ble_dfu_bonded.c文件,如下:

 

而且,如果NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS设为1,那么bootloader代码也就不能采用默认配置,请修改bootloader工程中的sdk_config.h如下宏定义,然后重新编译生成新的bootloader hex。

#define NRF_DFU_BLE_REQUIRES_BONDS 1

#define NRF_SDH_BLE_SERVICE_CHANGED 1

10)  在C/C++ define里面定义“BONDING_SUPPORT”宏。

11)  编译工程,将hex改为app.hex

12)  按照2.1节“nRF5 SDK v15.0.0 OTA”步骤来执行OTA过程,不过如下几点需要注意:

    • 在nRF Connect中勾选“keep bond information”选项,如下:

 

    • 当你使能CCCD的时候,手机将会自动与设备进行bonding,如下

 

    • DFU升级成功后,设备将会与手机自动重连,此时需点击“Refresh services”,以获得设备最新服务列表,如下:

 

上述代码工程我已打包成:OTA_ble_app_uart_SDK15_0_0.rar,另外三种DFU模式对应的脚本,我也打成了包,其中没有bonding对应Script_SDK15_S132_NUS_NoBonding.rar,application单独bonding对应Script_SDK15_S132_NUS_Bonding_SUPPORTS_BONDS_0.rar,application和bootloader同时bonding对应Script_SDK15_S132_NUS_Bonding_SUPPORTS_BONDS_1.rar,请大家到百度云盘目录DFU\ble_app_uart中下载。代码工程解压缩到nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral这个目录下,就可以直接编译和运行。

猜你喜欢

转载自www.cnblogs.com/iini/p/9314246.html
OTA