NRF52832-DFU-Bootloader源码详解

NRF52832-DFU-Bootloader源码详解

Bootloader源码:nRF5_SDK_15.0.0_a53641a\examples\dfu\secure_bootloader\pca10040_ble

 

Keil5中的C/C++中宏定义为:

APP_TIMER_V2 APP_TIMER_V2_RTC1_ENABLED BLE_STACK_SUPPORT_REQD BOARD_PCA10040 CONFIG_GPIO_AS_PINRESET FLOAT_ABI_HARD NRF52 NRF52832_XXAA NRF52_PAN_74 NRF_DFU_SETTINGS_VERSION=1 NRF_DFU_SVCI_ENABLED NRF_SD_BLE_API_VERSION=6 S132 SOFTDEVICE_PRESENT SVC_INTERFACE_CALL_AS_NORMAL_FUNCTION __HEAP_SIZE=0 uECC_ENABLE_VLI_API=0 uECC_OPTIMIZATION_LEVEL=3 uECC_SQUARE_FUNC=0 uECC_SUPPORT_COMPRESSED_POINT=0 uECC_VLI_NATIVE_LITTLE_ENDIAN=1

 

  1. main.c

ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);

这是将MBR区域(前0X1000)进行写保护, MBR是在FLASH中最靠前的一段程序。

ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE, false);这是将Bootloader程序区域进行写保护。

BOOTLOADER_START_ADDR由keil中的配置决定。BOOTLOADER_START_ADDR=0X70000

BOOTLOADER_SIZE = NRF_MBR_PARAMS_PAGE_ADDRESS-BOOTLOADER_START_ADDR

= 0X7E000 - 0X70000 = 0XE000

IRAM1的起始地址不能设置太小,得留够协议栈的RAM。

 

NRF_LOG_DEFAULT_BACKENDS_INIT();初始化RTT调试输出,此处是关闭的,空操作。

 

static void dfu_observer(nrf_dfu_evt_type_t evt_type)//这是DFU过程各种事件的回调函数。

nrf_bootloader_app_start();//如果不能进入升级处理流程,将会进入此函数,跳转到用户APP程序运行。

 

ret_val = nrf_bootloader_init(dfu_observer);//DFU升级最关键的函数就是这,dfu_observer是回调函数。

 

 

1、ret_val = nrf_dfu_settings_init(false);设置参数的初始化,进入此函数内部看看。

ret_code_t rc = nrf_dfu_flash_init(sd_irq_initialized);//此处是操作FLASH前的初始化。

NRF52832的FLASH操作有两种方式,一种是nrf_fstorage_sd,非阻塞方式, 一种是nrf_fstorage_nvmc,阻塞方式。

一般无协议栈时用nvmc方式,而有协议栈时用sd方式。如果已经初始化协议栈,仍使能nvmc方式,则程序可能会出现异常,具体原因还有待查找。此处因DFU程序还未初始化协议栈,所以使用的是nvmc方式。p_api_impl = &nrf_fstorage_nvmc;

memcpy((void*)&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t));

将FLASH中的设置参数复制到RAM中然后进行CRC校验,如果正确则设置参数有效,不需要初始化,否则进行设置参数的初始化。

 memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));

s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;只是设置了一个设置参数的版本号。

rc = nrf_dfu_settings_write(NULL); 此函数会将FLASH中的设置参数与刚才初始化的参数进行比对,如果一样则跳过, 否则先按页(4K)擦除,然后更新s_dfu_settings的CRC值,最后写入FALSH中。

  1. activation_result = nrf_bootloader_fw_activate();//检查bank1是否有固件待更新

 先了解下NRF52832的FLASH布局情况。DFU升级使用的是双区升级。

  

NRF52832的FLASH布局如上图,MBR就是最先运行的那部分程序,是厂家固化FLASH中,无法擦除的,大小固定为0X1000。softdevice紧跟其后,大小与协议栈的版本有关,s132_nrf52_6.0.0_softdevice就占用152K,application紧跟协议栈,超始地址为0X26000。

对比下协议栈s132_nrf52_6.0.0与s132_nrf52_5.0.0可以看出,MBR好像又是包含在协议栈中的。

Dfu bootloader的起始地址也不一定是0X78000,是可以调整的。而Dfu bootloader的起始地址前的3页(12K)是用户数据存储区。

Bootloader setting起始地址是0X7F000,大小0X1000,这是固定不变的。

MBR parameters 起始地址是0X7E000, 大小0X1000, 这也是固定不变的。

这样用户APP区大小为512-152-32-12=316K,再分为两个bank, bank0起始地址为:0X26000,保存的是最终的用户APP程序,bank1起始地址为bank0的结束地址,页对齐。Bank1在DFU升级时用来保存升级包数据,后续将会覆盖bank0。所以用户APP程序最大为158K。

进入到nrf_bootloader_fw_activate函数内部。

case NRF_DFU_BANK_VALID_APP: ret_val = app_activate();//bank1为有效的APP程序,则复制到bank0区域

case NRF_DFU_BANK_VALID_SD:ret_val = sd_activate();//bank1为有效的SD程序,则复制到协议栈起始地址0X1000处

case NRF_DFU_BANK_VALID_BL:ret_val = bl_activate();//bank1为有效的bootloader程序,则通过nrf_dfu_mbr_copy_bl函数来复制

case NRF_DFU_BANK_VALID_SD_BL:ret_val = sd_bl_activate();//bank1为有效的bootloader程序及SD程序,则先复制SD程序,后复制BOOT程序。

case NRF_DFU_BANK_INVALID://bank1无效

default:

return ACTIVATION_NONE; //则不处理,后续将跳转到用户APP程序。

 

nrf_dfu_bank_invalidate(p_bank);//清除bank1有效标志

ret_val = nrf_dfu_settings_write(flash_write_callback);//更新参数到FLASH中。下次重启将不会执行复制操作。

根据执行上面函数的返回值作相应处理:

case ACTIVATION_NONE:

initial_timeout = NRF_BL_DFU_INACTIVITY_TIMEOUT_MS;//DFU升级时间限定为120秒。

dfu_enter       = dfu_enter_check();//检查是否进入DFU升级

case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:

initial_timeout = NRF_BL_DFU_CONTINUATION_TIMEOUT_MS;

dfu_enter       = true;

//如果SD已更新,而bank0有效,则进入DFU升级,限时10秒。

case ACTIVATION_SUCCESS:

bootloader_reset();//前面从bank1的复制操作成功,软件复位。

case ACTIVATION_ERROR:

default:

return NRF_ERROR_INTERNAL;//出错将会产生软件复位

 

if (dfu_enter)//如果进入DFU升级流程

nrf_bootloader_wdt_init();//初始化看门狗

scheduler_init();//调度相关初始化

dfu_enter_flags_clear();//清除进入DFU的相关标志

//进入DFU的方式有:NRF_BL_DFU_ENTER_METHOD_GPREGRET根据电源备份寄存器的 //值, 按键NRF_BL_DFU_ENTER_METHOD_BUTTONLESS,复位键 //NRF_BL_DFU_ENTER_METHOD_PINRESET。

 

ret_val = nrf_dfu_init_user();//什么也没干。

nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout, inactivity_timeout);//开启超时定时器。

ret_val = nrf_dfu_init(dfu_observer);//DFU的初始化,与蓝牙相关,进入函数看看。

 

 

ret_val = nrf_dfu_transports_init(dfu_observer);//初始化蓝牙传输,调用函数ble_dfu_transport_init.进入函数查看。

err_code = nrf_balloc_init(&m_buffer_pool);//初始化内存池

err_code = ble_stack_init();//初始化协议栈

if (nrf_dfu_settings_adv_name_is_valid())

     err_code = nrf_dfu_settings_adv_name_copy(&m_adv_name);

//如果setting中有广播名称则复制过来。

err_code = gap_params_init();//蓝牙通用连接参数初始化,如果setting中有蓝牙广播名称就用,没有就用默认的。设置最小最大连接间隔,从机延迟,超时时间。

 

err_code = ble_dfu_init(&m_dfu);//初始化设备固件更新服务

err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,

                                        &service_uuid,

                                        &(p_dfu->service_handle));

//增加基本服务0xFE59到协议栈,获取服务句柄service_handle。

 

err_code = sd_ble_uuid_vs_add(&base_uuid128, &p_dfu->uuid_type);

//加入一个服务UUID 128bit到协议栈,获取UUID类型到uuid_type

 

  err_code = dfu_pkt_char_add(p_dfu);

  //增加数据包特性到服务,可写,DFU的升级数据包及初始化包通过此特性传输。

 

err_code = dfu_ctrl_pt_add(p_dfu);

//增加控制特性到服务 可写,通知功能,DFU升级的控制,通过此特性传输,通知功能用作应答。

 

err_code = advertising_start();//蓝牙广播的初始化及启动广播

//nrf_dfu_transports_init

ret_val = nrf_dfu_req_handler_init(dfu_observer);

//此函数中先nrf_dfu_flash_init(true); FLASH操作用sd非阻塞方式, 然后初始化签名安全认证。如果已经接收了初始化数据包,则进行签名认证。

 

继续nrf_bootloader_init函数:

loop_forever(); // This function will never return.

//进入死循环,根据事件回调,循环喂看门狗

Else

ret_val = nrf_dfu_settings_additional_erase();//清除掉setting最后部分,广播名称,参数。

nrf_bootloader_app_start();//开始执行APP程序。

 

关于回调函数dfu_observer 

//此函数为 nrf_bootloader.c中的回调

static void dfu_observer(nrf_dfu_evt_type_t evt_type)

{

    switch (evt_type)

{

//创建初始化包传输即认为是DFU升级开始

        case NRF_DFU_EVT_DFU_STARTED://在on_cmd_obj_create_request中

//on_data_obj_execute_request每次接收到数据都会重启超时定时器

        case NRF_DFU_EVT_OBJECT_RECEIVED:

            LCD_Display_Updata_Cur();

            nrf_bootloader_dfu_inactivity_timer_restart(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS, inactivity_timeout);

            break;

        case NRF_DFU_EVT_DFU_COMPLETED:

        case NRF_DFU_EVT_DFU_ABORTED:

            bootloader_reset();

            break;

        default:

            break;

    }

 

    if (m_user_observer)

    {

        m_user_observer(evt_type);

    }

}

//nrf_bootloader.c中调用, 因 nrf_dfu_init 在nrf_dfu.c中被重写

ret_val = nrf_dfu_init(dfu_observer);

 

//nrf_dfu.c 重写nrf_dfu_init

uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)

{

    uint32_t ret_val;

 

//nrf_bootloader.c中的dfu_observer被用于nrf_dfu.c中的m_user_observer

    m_user_observer = observer;

 

    NRF_LOG_INFO("Entering DFU mode.");

 

    dfu_observer(NRF_DFU_EVT_DFU_INITIALIZED);

 

    // Initializing transports

    ret_val = nrf_dfu_transports_init(dfu_observer);

    if (ret_val != NRF_SUCCESS)

    {

        NRF_LOG_ERROR("Could not initalize DFU transport: 0x%08x", ret_val);

        return ret_val;

    }

 

    ret_val = nrf_dfu_req_handler_init(dfu_observer);

 

    return ret_val;

}

 

//此函数为nrf_dfu.c中的回调 dfu_observer,在 nrf_dfu_req_handler.c中被设置

ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer);

//nrf_dfu.c中dfu_observer被nrf_dfu_req_handler.c中的on_dfu_complete调用。

 

nrf_dfu.c  static void dfu_observer(nrf_dfu_evt_type_t event)

{

    switch (event)

    {

        case NRF_DFU_EVT_DFU_COMPLETED://所有固件传输完成

        {

#ifndef NRF_DFU_NO_TRANSPORT

            UNUSED_RETURN_VALUE(nrf_dfu_transports_close(NULL));//关闭连接

#endif

            break;

        }

        default:

            break;

    }

 

    /* Call user's observer if present. */

    if (m_user_observer)

    {

        m_user_observer(event);

    }

}

 

 

 

 

//所有固件传输完成执行

nrf_dfu_req_handler.c static void on_dfu_complete(nrf_fstorage_evt_t * p_evt)

{

    UNUSED_PARAMETER(p_evt);

 

    NRF_LOG_DEBUG("All flash operations have completed. DFU completed.");

 

    m_observer(NRF_DFU_EVT_DFU_COMPLETED);

}

 

 

nrf_dfu_req_handler.c static void on_data_obj_execute_request_sched(void * p_evt, uint16_t event_length)

{

    UNUSED_PARAMETER(event_length);

 

    nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);

 

    /* Wait for all buffers to be written in flash. */

    if (nrf_fstorage_is_busy(NULL))

    {

        ret_code_t ret = app_sched_event_put(p_req,

                                             sizeof(nrf_dfu_request_t),

                                             on_data_obj_execute_request_sched);

        if (ret != NRF_SUCCESS)

        {

            NRF_LOG_ERROR("Failed to schedule object execute: 0x%x.", ret);

        }

        return;

    }

 

    nrf_dfu_response_t res =

    {

        .request = NRF_DFU_OP_OBJECT_EXECUTE,

    };

 

    nrf_dfu_flash_callback_t dfu_settings_callback;

 

    /* 所有固件传输完成 */

    if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req)

    {

        NRF_LOG_DEBUG("Postvalidation of firmware image.");

 

        res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);

        res.result = ext_err_code_handle(res.result);

 

        /* Callback to on_dfu_complete() after updating the settings. */

        dfu_settings_callback = (nrf_dfu_flash_callback_t)(on_dfu_complete);//回调函数在保存后setting后执行

on_dfu_complete->nrf_dfu.c::dfu_observer(关闭连接)->nrf_bootloader::dfu_observer(重启)

    }

    else

    {

        res.result = NRF_DFU_RES_CODE_SUCCESS;

        /* No callback required. */

        dfu_settings_callback = NULL;

    }

 

    /* Provide response to transport */

    p_req->callback.response(&res, p_req->p_context);

 

    /* Store settings to flash if the whole image was received or if configured

     * to save progress information in flash.

     */

    if ((dfu_settings_callback != NULL) || NRF_DFU_SAVE_PROGRESS_IN_FLASH)

    {

        ret_code_t ret = nrf_dfu_settings_write(dfu_settings_callback);//升级完成需要恢复且保存setting

        UNUSED_RETURN_VALUE(ret);

    }

 

    NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", res.result);

}

 

 

 

 

 

 

蓝牙事件回调函数

Nrf_dfu_ble.c

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)

 

case BLE_GAP_EVT_CONNECTED: //建立连接后的处理

m_conn_handle = p_gap->conn_handle;//保存连接句柄

err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_gap_conn_params);//更新连接参数

case BLE_GAP_EVT_DISCONNECTED: //断开连接,自动广播

m_conn_handle = BLE_CONN_HANDLE_INVALID;//连接句柄无效

//数据包接收完成后会置位此标志,停止传输,不需要广播。

if (!(m_flags & DFU_BLE_RESETTING_SOON))     

err_code = advertising_start();

case BLE_GATTS_EVT_WRITE: //蓝牙特性值写操作

on_write(&m_dfu, p_ble_evt);

//只有是写数据包特性才处理

if (p_write_evt->handle != p_dfu->dfu_pkt_handles.value_handle)

//申请缓存池

uint8_t * p_balloc_buf = nrf_balloc_alloc(&m_buffer_pool);

//将蓝牙接收数据复制到用户内存空间。

memcpy(p_balloc_buf, p_write_evt->data, p_write_evt->len);

 nrf_dfu_request_t request =

    {

        .request      = NRF_DFU_OP_OBJECT_WRITE,//对象写操作,无应答

        .p_context    = p_dfu,

        .callback     =

        {

            .response = ble_dfu_req_handler_callback,//回调函数,用来应答

            .write    = on_flash_write,//写入FLASH

        }

    };

ret_code_t rc = nrf_dfu_req_handler_on_req(&request);//触发用户层的事件回调

调用nrf_dfu_req_handler_req_process,此函数后面详解。

 nrf_balloc_free(&m_buffer_pool, p_balloc_buf);释放内存池

case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST://更新当前的MTU值到手机端

//交换MTU请求,手机端发来一个MTU值,收到后比对是否小于MTU最大值247,如果小于,则去掉头部3字节,剩下的按4字节对齐,否则MTU值不变,最后应答当前的MTU值。

err_code = sd_ble_gatts_exchange_mtu_reply(m_conn_handle, mtu_reply);

 

case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST://数据长度更新请求

      ble_gap_data_length_params_t const dlp =

      {

           .max_rx_octets = BLE_GAP_DATA_LENGTH_AUTO,//自动数据长度

           .max_tx_octets = BLE_GAP_DATA_LENGTH_AUTO,//自动数据长度

      };

//启动或响应数据长度更新过程

      sd_ble_gap_data_length_update(p_ble_evt->evt.gatts_evt.conn_handle,

                                                     &dlp, NULL);                 

 

case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST://数据长度更新过程参数

NRF_LOG_DEBUG("Received BLE_GAP_EVT_DATA_LENGTH_UPDATE(%u, max_rx_time%u).",                           p_gap->params.data_length_update.effective_params.max_rx_octets,                           p_gap->params.data_length_update.effective_params.max_rx_time_us);

 

case BLE_GAP_EVT_SEC_PARAMS_REQUEST://请求提供安全参数

ble_gatts_value_t gatts_value =

      {

          .len     = BLE_CCCD_VALUE_LEN,//CCCD值长度2

           .p_value = (uint8_t*)&cccd

       };

//获取指定属性的值

err_code=sd_ble_gatts_value_get(m_conn_handle,                                               BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED,//服务改变特性 0X2A05

     &gatts_value);

//因未开启密码配对,应答不支持此功能

err_code=sd_ble_gap_sec_params_reply(m_conn_handle,                                                    BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,

                                NULL,

                                NULL);

 

case BLE_GAP_EVT_CONN_PARAM_UPDATE://连接参数已更新

ble_gap_conn_params_t const * p_conn =

                &p_gap->params.conn_param_update.conn_params;

             NRF_LOG_DEBUG("max_conn_interval: %d",p_conn->max_conn_interval);

        NRF_LOG_DEBUG("min_conn_interval: %d",p_conn->min_conn_interval);

NRF_LOG_DEBUG("slave_latency: %d",     p_conn->slave_latency);

NRF_LOG_DEBUG("conn_sup_timeout: %d",  p_conn->conn_sup_timeout);

 

case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST://连接参数更新请求 根据手机端的连接参数更新

//连接参数更新,将收到BLE_GAP_EVT_CONN_PARAM_UPDATE事件

err_code = sd_ble_gap_conn_param_update(m_conn_handle,

         &p_gap->params.conn_param_update_request.conn_params);

 

case BLE_GAP_EVT_PHY_UPDATE://PHY请求结果

NRF_LOG_DEBUG("Received BLE_GAP_EVT_PHY_UPDATE (RX:%d, TX:%d, status:%d)",

                          p_gap->params.phy_update.rx_phy,

                          p_gap->params.phy_update.tx_phy,

                          p_gap->params.phy_update.status);

 

case BLE_GAP_EVT_PHY_UPDATE_REQUEST:

ble_gap_phys_t const phys =

       {

           .rx_phys = BLE_GAP_PHY_AUTO,//自动PHY

           .tx_phys = BLE_GAP_PHY_AUTO,//自动PHY

       };

//启动或响应PHY更新过程

err_code = sd_ble_gap_phy_update(p_gap->conn_handle, &phys);

 

case BLE_GATTS_EVT_TIMEOUT: //对方应答超时

//如果是ATT协议超时

if(p_ble_evt->evt.gatts_evt.params.timeout.src==BLE_GATT_TIMEOUT_SRC_PROTOCO)

err_code=sd_ble_gap_disconnect(m_conn_handle,                                                  BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);//远程断开连接

 

case BLE_EVT_USER_MEM_REQUEST://用户内存请求

err_code = sd_ble_user_mem_reply(m_conn_handle, NULL);//申请用户内存块

 

case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST://写请求操作(从应用程序请求写入授权)

//此处是控制属性的入口,用来控制升级过程。读写授权请求, 前提是使能了通知。

if (p_ble_evt->evt.gatts_evt.params.authorize_request.type//不是无效类型

                != BLE_GATTS_AUTHORIZE_TYPE_INVALID)

if (on_rw_authorize_req(&m_dfu, p_ble_evt))//GATT层面的自动应答

err_code=on_ctrl_pt_write(&m_dfu,                           &(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write));

on_ctrl_pt_write函数后面详解

 

case BLE_GAP_EVT_SEC_INFO_REQUEST://请求提供安全信息

//应答安全信息

err_code = sd_ble_gap_sec_info_reply(p_gap->conn_handle, p_enc_info, p_id_info, NULL);

 

case BLE_GAP_EVT_CONN_SEC_UPDATE://安全连接已更新

case BLE_GATTS_EVT_SYS_ATTR_MISSING://永久性系统属性访问挂起

//初始化永久系统属性信息

err_code = sd_ble_gatts_sys_attr_set(p_gap->conn_handle, NULL, 0, 0);

 

 

static void nrf_dfu_req_handler_req_process(nrf_dfu_request_t * p_req)

 

switch (p_req->request)

 

case NRF_DFU_OP_PROTOCOL_VERSION:// DFU协议版本消息功能

on_protocol_version_request(p_req, &response);

//如果支持上传DFU协议版本, 则应答DFU协议版本号1,否则应答不支持的操 作 NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED实际好像并未应答这些数据

case NRF_DFU_OP_HARDWARE_VERSION://硬件版本号

on_hw_version_request(p_req, &response);

//硬件信息包括:硬件部分,硬件变量,ROM大小,RAM大小,ROM页数,

//实际好像并未应答这些数据

case NRF_DFU_OP_FIRMWARE_VERSION://固件版本,实际好像并未应答这些数据

on_fw_version_request(p_req, &response);

case NRF_DFU_OP_PING: //实际好像并未应答这些数据

on_ping_request(p_req, &response);

case NRF_DFU_OP_RECEIPT_NOTIF_SET://接收通知的设置 无额外数据应答

on_prn_set_request(p_req, &response);

case NRF_DFU_OP_MTU_GET://获取MTU大小  p_res->mtu.size

on_mtu_get_request(p_req, &response);

case NRF_DFU_OP_ABORT://中止DFU程序

on_abort_request(p_req, &response);

//当前程序只有下面5种情况才会处理,其它情况只应答3个数据

    case NRF_DFU_OP_OBJECT_CREATE:   //创建    

    case NRF_DFU_OP_OBJECT_SELECT: //选择

    case NRF_DFU_OP_OBJECT_WRITE: //写

    case NRF_DFU_OP_OBJECT_EXECUTE: //执行

case NRF_DFU_OP_CRC_GET: //获取CRC值

response_ready = nrf_dfu_obj_op(p_req, &response);

default:break;

if (response_ready)//应答

p_req->callback.response(&response,p_req->p_context);//ble_dfu_req_handler_callback

 

static bool nrf_dfu_obj_op(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)

 

static nrf_dfu_obj_type_t current_object = NRF_DFU_OBJ_TYPE_COMMAND;//静态变量初始化

if ( (p_req->request == NRF_DFU_OP_OBJECT_SELECT)//选择请求的对象在object_type

    || (p_req->request == NRF_DFU_OP_OBJECT_CREATE))//创建请求的对象在object_type

current_object = (nrf_dfu_obj_type_t)(p_req->select.object_type);

switch (current_object)

    {

        case NRF_DFU_OBJ_TYPE_COMMAND://初始化包相关

            nrf_dfu_command_req(p_req, p_res);

            break;

 

        case NRF_DFU_OBJ_TYPE_DATA://升级数据包相关

            response_ready = nrf_dfu_data_req(p_req, p_res);

            break;

}

 

//初始化包相关处理

static void nrf_dfu_command_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)

switch (p_req->request)

case NRF_DFU_OP_OBJECT_CREATE:

//为传输初始化包做准备,设置包大小到setting中。

on_cmd_obj_create_request(p_req, p_res);

case NRF_DFU_OP_CRC_GET:

//应答初始化包在setting中的偏移及CRC值

on_cmd_obj_crc_request(p_req, p_res);

case NRF_DFU_OP_OBJECT_WRITE:

//保存初始化包到setting中,但是不应答。

on_cmd_obj_write_request(p_req, p_res);

case NRF_DFU_OP_OBJECT_EXECUTE:

//签名及版名校验,并获取升级包的大小及存储地址。将当前setting(包含初始化包数据)保存

on_cmd_obj_execute_request(p_req, p_res);

case NRF_DFU_OP_OBJECT_SELECT:

//应答对象信息包含最大对象大小、偏移量和到目前为止整个对象的CRC32

on_cmd_obj_select_request(p_req, p_res);

 

升级数据包相关处理

static bool nrf_dfu_data_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)

switch (p_req->request)

case NRF_DFU_OP_OBJECT_SELECT:

//选择升级包传输对象,应答最大字节数4K,偏移量(已传输数据量)及CRC值

on_data_obj_select_request(p_req, p_res);

 

case NRF_DFU_OP_OBJECT_CREATE:

on_data_obj_create_request(p_req, p_res);

//必须已接收到初始化包,才能创建升级包单包传输。单包传输最大为4K,可分为多个小包传输。此处先擦除一页,等待接收数据。应答成功

case NRF_DFU_OP_OBJECT_WRITE:

on_data_obj_write_request(p_req, p_res);//保存接收数据到FLASH,bank1中。不需要应答。

case NRF_DFU_OP_CRC_GET:

//应答接收数据的偏移量及CRC值,客户端会进行校验。

 on_data_obj_crc_request(p_req, p_res);

case NRF_DFU_OP_OBJECT_EXECUTE:

//校验接收数据总量是否正确,

response_ready = on_data_obj_execute_request(p_req, p_res);

如果升级包全部接收完毕,调用 nrf_dfu_validation_post_data_execute(m_firmware_start_addr,m_firmware_size_req);

进行固件hash值验证,如果是APP,则bank1有效,并更新大小及CRC,清除升级进度数据,清除初始化包数据。并调用回调函数on_dfu_complete,关闭连接,并软件复位。

如果升级包未接收完,则应答执行成功。

DFU升级流程为:

  1. 进入bootloader,判断相应标志,决定是否等待DFU升级。
  2. 清相关标志,等待DFU升级,接收初始化包,进行签名校验。
  3. 接收升级包存入bank1。
  4. 接收完成,软件复位。
  5. 进入bootloader,检查bank1是否有有效的APP固件,有则复制到bank0.
  6. 清除bank1有效标志,软件复位。
  7. 进入bootloader,跳转到bank0的APP程序运行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值