前言:在nordic的BLE程序中添加DFU服务比DFU的搭建要简单许多了,基本跟着流程走就能让自己的应用程序实现无线DFU
1.在要添加DFU服务的工程中添加DFU源码
nRF5_SDK_15.2.0_9412b96\components\ble\ble_services\ble_dfu\ble_dfu.c
nRF5_SDK_15.2.0_9412b96\components\ble\ble_services\ble_dfu\ble_dfu_bonded.c
nRF5_SDK_15.2.0_9412b96\components\ble\ble_services\ble_dfu\ble_dfu_unbonded.c
nRF5_SDK_15.2.0_9412b96\components\libraries\bootloader\dfu\nrf_dfu_svci.c
2.添加头文件路径
..\Libraries\components\libraries\svc
..\Libraries\components\libraries\bootloader
..\Libraries\components\libraries\bootloader\dfu
..\Libraries\components\libraries\bootloader\ble_dfu
..\Libraries\components\ble\ble_services\ble_dfu
..\Libraries\components\softdevice\mbr\nrf52832\headers
3.添加宏
1)BLE_SETTINGS_ACCESS_ONLY
2)NRF_DFU_SVCI_ENABLED
3)NRF_DFU_TRANSPORT_BLE=1
4.修改sdk_config.h文件
1)使能DFU模块
#ifndef BLE_DFU_ENABLED
#define BLE_DFU_ENABLED 1
#endif
2)修改使用的自定义UUID数量,每添加一个都要修改工程中RAM的开始地址和使用大小,1个UUID占用的RAM大小为0x10
#ifndef NRF_SDH_BLE_VS_UUID_COUNT
#define NRF_SDH_BLE_VS_UUID_COUNT 2
#endif
根据实际使用的自定义UUID个数修改
1.包含头文件
#include "nrf_power.h"
#include "nrf_bootloader_info.h"
#include "nrf_dfu_ble.h"
#include "ble_dfu.h"
#include "nrf_dfu_ble_svci_bond_sharing.h"
#include "nrf_svci_async_function.h"
#include "nrf_svci_async_handler.h"
2.在初始化服务函数里面初始化DFU服务
//获取广播配置参数
static void advertising_config_get(ble_adv_modes_config_t * p_config)
{
memset(p_config, 0, sizeof(ble_adv_modes_config_t));
p_config->ble_adv_fast_enabled = true;
p_config->ble_adv_fast_interval = APP_ADV_INTERVAL;
p_config->ble_adv_fast_timeout = APP_ADV_DURATION;
}
//断开连接
static void disconnect(uint16_t conn_handle, void * p_context)
{
UNUSED_PARAMETER(p_context);
ret_code_t err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_WARNING("Failed to disconnect connection. Connection handle: %d Error: %d", conn_handle, err_code);
}
else
{
NRF_LOG_DEBUG("Disconnected connection handle %d", conn_handle);
}
}
//DFU回调函数
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
{
ret_code_t err_code;
switch (event)
{ //在进入bootloader执行DFU前的准备工作
case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
//防止设备断开连接时进行广播
ble_adv_modes_config_t config;
advertising_config_get(&config);
config.ble_adv_on_disconnect_disabled = true;
ble_advertising_modes_config_set(&m_advertising, &config);
// 断开当前的所有连接
uint32_t conn_count = ble_conn_state_for_each_connected(disconnect, NULL);
NRF_LOG_INFO("Disconnected %d links.", conn_count);
case BLE_DFU_EVT_BOOTLOADER_ENTER:
NRF_LOG_INFO("Device will enter bootloader mode.");
break;
case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously.");
break;
case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
NRF_LOG_ERROR("Request to send a response to client failed.");
APP_ERROR_CHECK(false);
break;
default:
NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless.");
break;
}
}
static void dfu_s_init(void)
{
uint32_t err_code;
ble_dfu_buttonless_init_t dfus_init = {0};
//注册DFU回调函数
dfus_init.evt_handler = ble_dfu_evt_handler;
//初始化DFU
err_code = ble_dfu_buttonless_init(&dfus_init);
APP_ERROR_CHECK(err_code);
}
static void services_init(void)
{
//初始化DFU服务
dfu_s_init();
}
3.注册协议栈状态监视者
//协议栈状态发送改变时会调用此函数
static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context)
{
if (state == NRF_SDH_EVT_STATE_DISABLED)
{
//在复位之前禁用协议栈,并告知bootloader启动时跳过CRC
nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);
//进入system off模式
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
}
}
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) =
{
.handler = buttonless_dfu_sdh_state_observer,
};
至此,实现在自己编写的BLE程序中添加DFU服务的流程介绍完毕