Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nrf51-sdk by
source/nordic_sdk/components/libraries/bootloader_dfu/dfu_app_handler.c@10:233fefd8162b, 2016-04-07 (annotated)
- Committer:
- vcoubard
- Date:
- Thu Apr 07 17:37:28 2016 +0100
- Revision:
- 10:233fefd8162b
- Parent:
- 1:ebc0e0ef0a11
- Child:
- 19:47192cb9def7
Synchronized with git rev daa4809a
Author: Liyou Zhou
Add license headers
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| vcoubard | 10:233fefd8162b | 1 | /* |
| vcoubard | 10:233fefd8162b | 2 | * Copyright (c) Nordic Semiconductor ASA |
| vcoubard | 10:233fefd8162b | 3 | * All rights reserved. |
| vcoubard | 10:233fefd8162b | 4 | * |
| vcoubard | 10:233fefd8162b | 5 | * Redistribution and use in source and binary forms, with or without modification, |
| vcoubard | 10:233fefd8162b | 6 | * are permitted provided that the following conditions are met: |
| vcoubard | 10:233fefd8162b | 7 | * |
| vcoubard | 10:233fefd8162b | 8 | * 1. Redistributions of source code must retain the above copyright notice, this |
| vcoubard | 10:233fefd8162b | 9 | * list of conditions and the following disclaimer. |
| vcoubard | 10:233fefd8162b | 10 | * |
| vcoubard | 10:233fefd8162b | 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this |
| vcoubard | 10:233fefd8162b | 12 | * list of conditions and the following disclaimer in the documentation and/or |
| vcoubard | 10:233fefd8162b | 13 | * other materials provided with the distribution. |
| vcoubard | 10:233fefd8162b | 14 | * |
| vcoubard | 10:233fefd8162b | 15 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of other |
| vcoubard | 10:233fefd8162b | 16 | * contributors to this software may be used to endorse or promote products |
| vcoubard | 10:233fefd8162b | 17 | * derived from this software without specific prior written permission. |
| vcoubard | 10:233fefd8162b | 18 | * |
| vcoubard | 10:233fefd8162b | 19 | * |
| vcoubard | 10:233fefd8162b | 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| vcoubard | 10:233fefd8162b | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| vcoubard | 10:233fefd8162b | 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| vcoubard | 10:233fefd8162b | 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| vcoubard | 10:233fefd8162b | 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| vcoubard | 10:233fefd8162b | 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| vcoubard | 10:233fefd8162b | 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| vcoubard | 10:233fefd8162b | 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| vcoubard | 10:233fefd8162b | 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| vcoubard | 10:233fefd8162b | 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| vcoubard | 10:233fefd8162b | 30 | * |
| vcoubard | 1:ebc0e0ef0a11 | 31 | */ |
| vcoubard | 1:ebc0e0ef0a11 | 32 | |
| vcoubard | 1:ebc0e0ef0a11 | 33 | #include "dfu_app_handler.h" |
| vcoubard | 1:ebc0e0ef0a11 | 34 | #include <string.h> |
| vcoubard | 1:ebc0e0ef0a11 | 35 | #include "bootloader_util.h" |
| vcoubard | 1:ebc0e0ef0a11 | 36 | #include "nrf.h" |
| vcoubard | 1:ebc0e0ef0a11 | 37 | #include "nrf_sdm.h" |
| vcoubard | 1:ebc0e0ef0a11 | 38 | #include "ble_gatt.h" |
| vcoubard | 1:ebc0e0ef0a11 | 39 | #include "ble_gatts.h" |
| vcoubard | 1:ebc0e0ef0a11 | 40 | #include "app_error.h" |
| vcoubard | 1:ebc0e0ef0a11 | 41 | #include "dfu_ble_svc.h" |
| vcoubard | 1:ebc0e0ef0a11 | 42 | #include "device_manager.h" |
| vcoubard | 1:ebc0e0ef0a11 | 43 | #include "nrf_delay.h" |
| vcoubard | 1:ebc0e0ef0a11 | 44 | |
| vcoubard | 1:ebc0e0ef0a11 | 45 | #define IRQ_ENABLED 0x01 /**< Field that identifies if an interrupt is enabled. */ |
| vcoubard | 1:ebc0e0ef0a11 | 46 | #define MAX_NUMBER_INTERRUPTS 32 /**< Maximum number of interrupts available. */ |
| vcoubard | 1:ebc0e0ef0a11 | 47 | |
| vcoubard | 1:ebc0e0ef0a11 | 48 | static void dfu_app_reset_prepare(void); /**< Forward declaration of default reset handler. */ |
| vcoubard | 1:ebc0e0ef0a11 | 49 | static dfu_app_reset_prepare_t m_reset_prepare = dfu_app_reset_prepare; /**< Callback function to application to prepare for system reset. Allows application to clean up service and memory before reset. */ |
| vcoubard | 1:ebc0e0ef0a11 | 50 | static dfu_ble_peer_data_t m_peer_data; /**< Peer data to be used for data exchange when resetting into DFU mode. */ |
| vcoubard | 1:ebc0e0ef0a11 | 51 | static dm_handle_t m_dm_handle; /**< Device Manager handle with instance IDs of current BLE connection. */ |
| vcoubard | 1:ebc0e0ef0a11 | 52 | |
| vcoubard | 1:ebc0e0ef0a11 | 53 | |
| vcoubard | 1:ebc0e0ef0a11 | 54 | /**@brief Function for reset_prepare handler if the application has not registered a handler. |
| vcoubard | 1:ebc0e0ef0a11 | 55 | */ |
| vcoubard | 1:ebc0e0ef0a11 | 56 | static void dfu_app_reset_prepare(void) |
| vcoubard | 1:ebc0e0ef0a11 | 57 | { |
| vcoubard | 1:ebc0e0ef0a11 | 58 | // Reset prepare should be handled by application. |
| vcoubard | 1:ebc0e0ef0a11 | 59 | // This function can be extended to include default handling if application does not implement |
| vcoubard | 1:ebc0e0ef0a11 | 60 | // own handler. |
| vcoubard | 1:ebc0e0ef0a11 | 61 | } |
| vcoubard | 1:ebc0e0ef0a11 | 62 | |
| vcoubard | 1:ebc0e0ef0a11 | 63 | |
| vcoubard | 1:ebc0e0ef0a11 | 64 | /**@brief Function for disabling all interrupts before jumping from bootloader to application. |
| vcoubard | 1:ebc0e0ef0a11 | 65 | */ |
| vcoubard | 1:ebc0e0ef0a11 | 66 | static void interrupts_disable(void) |
| vcoubard | 1:ebc0e0ef0a11 | 67 | { |
| vcoubard | 1:ebc0e0ef0a11 | 68 | uint32_t interrupt_setting_mask; |
| vcoubard | 1:ebc0e0ef0a11 | 69 | uint32_t irq; |
| vcoubard | 1:ebc0e0ef0a11 | 70 | |
| vcoubard | 1:ebc0e0ef0a11 | 71 | // Fetch the current interrupt settings. |
| vcoubard | 1:ebc0e0ef0a11 | 72 | interrupt_setting_mask = NVIC->ISER[0]; |
| vcoubard | 1:ebc0e0ef0a11 | 73 | |
| vcoubard | 1:ebc0e0ef0a11 | 74 | // Loop from interrupt 0 for disabling of all interrupts. |
| vcoubard | 1:ebc0e0ef0a11 | 75 | for (irq = 0; irq < MAX_NUMBER_INTERRUPTS; irq++) |
| vcoubard | 1:ebc0e0ef0a11 | 76 | { |
| vcoubard | 1:ebc0e0ef0a11 | 77 | if (interrupt_setting_mask & (IRQ_ENABLED << irq)) |
| vcoubard | 1:ebc0e0ef0a11 | 78 | { |
| vcoubard | 1:ebc0e0ef0a11 | 79 | // The interrupt was enabled, hence disable it. |
| vcoubard | 1:ebc0e0ef0a11 | 80 | NVIC_DisableIRQ((IRQn_Type)irq); |
| vcoubard | 1:ebc0e0ef0a11 | 81 | } |
| vcoubard | 1:ebc0e0ef0a11 | 82 | } |
| vcoubard | 1:ebc0e0ef0a11 | 83 | } |
| vcoubard | 1:ebc0e0ef0a11 | 84 | |
| vcoubard | 1:ebc0e0ef0a11 | 85 | |
| vcoubard | 1:ebc0e0ef0a11 | 86 | /**@brief Function for providing peer information to DFU for re-establishing a bonded connection in |
| vcoubard | 1:ebc0e0ef0a11 | 87 | * DFU mode. |
| vcoubard | 1:ebc0e0ef0a11 | 88 | * |
| vcoubard | 1:ebc0e0ef0a11 | 89 | * @param[in] conn_handle Connection handle for the connection requesting DFU mode. |
| vcoubard | 1:ebc0e0ef0a11 | 90 | */ |
| vcoubard | 1:ebc0e0ef0a11 | 91 | static void dfu_app_peer_data_set(uint16_t conn_handle) |
| vcoubard | 1:ebc0e0ef0a11 | 92 | { |
| vcoubard | 1:ebc0e0ef0a11 | 93 | uint32_t err_code; |
| vcoubard | 1:ebc0e0ef0a11 | 94 | dm_sec_keyset_t key_set; |
| vcoubard | 1:ebc0e0ef0a11 | 95 | uint32_t app_context_data = 0; |
| vcoubard | 1:ebc0e0ef0a11 | 96 | dm_application_context_t app_context; |
| vcoubard | 1:ebc0e0ef0a11 | 97 | |
| vcoubard | 1:ebc0e0ef0a11 | 98 | |
| vcoubard | 1:ebc0e0ef0a11 | 99 | /** [DFU bond sharing] */ |
| vcoubard | 1:ebc0e0ef0a11 | 100 | err_code = dm_handle_get(conn_handle, &m_dm_handle); |
| vcoubard | 1:ebc0e0ef0a11 | 101 | if (err_code == NRF_SUCCESS) |
| vcoubard | 1:ebc0e0ef0a11 | 102 | { |
| vcoubard | 1:ebc0e0ef0a11 | 103 | err_code = dm_distributed_keys_get(&m_dm_handle, &key_set); |
| vcoubard | 1:ebc0e0ef0a11 | 104 | if (err_code == NRF_SUCCESS) |
| vcoubard | 1:ebc0e0ef0a11 | 105 | { |
| vcoubard | 1:ebc0e0ef0a11 | 106 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 107 | |
| vcoubard | 1:ebc0e0ef0a11 | 108 | m_peer_data.addr = key_set.keys_central.p_id_key->id_addr_info; |
| vcoubard | 1:ebc0e0ef0a11 | 109 | m_peer_data.irk = key_set.keys_central.p_id_key->id_info; |
| vcoubard | 1:ebc0e0ef0a11 | 110 | m_peer_data.enc_key.enc_info = key_set.keys_periph.enc_key.p_enc_key->enc_info; |
| vcoubard | 1:ebc0e0ef0a11 | 111 | m_peer_data.enc_key.master_id = key_set.keys_periph.enc_key.p_enc_key->master_id; |
| vcoubard | 1:ebc0e0ef0a11 | 112 | |
| vcoubard | 1:ebc0e0ef0a11 | 113 | err_code = dfu_ble_svc_peer_data_set(&m_peer_data); |
| vcoubard | 1:ebc0e0ef0a11 | 114 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 115 | |
| vcoubard | 1:ebc0e0ef0a11 | 116 | app_context_data = (DFU_APP_ATT_TABLE_CHANGED << DFU_APP_ATT_TABLE_POS); |
| vcoubard | 1:ebc0e0ef0a11 | 117 | app_context.len = sizeof(app_context_data); |
| vcoubard | 1:ebc0e0ef0a11 | 118 | app_context.p_data = (uint8_t *)&app_context_data; |
| vcoubard | 1:ebc0e0ef0a11 | 119 | app_context.flags = 0; |
| vcoubard | 1:ebc0e0ef0a11 | 120 | |
| vcoubard | 1:ebc0e0ef0a11 | 121 | err_code = dm_application_context_set(&m_dm_handle, &app_context); |
| vcoubard | 1:ebc0e0ef0a11 | 122 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 123 | } |
| vcoubard | 1:ebc0e0ef0a11 | 124 | else |
| vcoubard | 1:ebc0e0ef0a11 | 125 | { |
| vcoubard | 1:ebc0e0ef0a11 | 126 | // Keys were not available, thus we have a non-encrypted connection. |
| vcoubard | 1:ebc0e0ef0a11 | 127 | err_code = dm_peer_addr_get(&m_dm_handle, &m_peer_data.addr); |
| vcoubard | 1:ebc0e0ef0a11 | 128 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 129 | |
| vcoubard | 1:ebc0e0ef0a11 | 130 | err_code = dfu_ble_svc_peer_data_set(&m_peer_data); |
| vcoubard | 1:ebc0e0ef0a11 | 131 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 132 | } |
| vcoubard | 1:ebc0e0ef0a11 | 133 | } |
| vcoubard | 1:ebc0e0ef0a11 | 134 | /** [DFU bond sharing] */ |
| vcoubard | 1:ebc0e0ef0a11 | 135 | } |
| vcoubard | 1:ebc0e0ef0a11 | 136 | |
| vcoubard | 1:ebc0e0ef0a11 | 137 | |
| vcoubard | 1:ebc0e0ef0a11 | 138 | /**@brief Function for preparing the reset, disabling SoftDevice, and jumping to the bootloader. |
| vcoubard | 1:ebc0e0ef0a11 | 139 | * |
| vcoubard | 1:ebc0e0ef0a11 | 140 | * @param[in] conn_handle Connection handle for peer requesting to enter DFU mode. |
| vcoubard | 1:ebc0e0ef0a11 | 141 | */ |
| vcoubard | 1:ebc0e0ef0a11 | 142 | static void bootloader_start(uint16_t conn_handle) |
| vcoubard | 1:ebc0e0ef0a11 | 143 | { |
| vcoubard | 1:ebc0e0ef0a11 | 144 | uint32_t err_code; |
| vcoubard | 1:ebc0e0ef0a11 | 145 | uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr); |
| vcoubard | 1:ebc0e0ef0a11 | 146 | |
| vcoubard | 1:ebc0e0ef0a11 | 147 | err_code = sd_ble_gatts_sys_attr_get(conn_handle, |
| vcoubard | 1:ebc0e0ef0a11 | 148 | m_peer_data.sys_serv_attr, |
| vcoubard | 1:ebc0e0ef0a11 | 149 | &sys_serv_attr_len, |
| vcoubard | 1:ebc0e0ef0a11 | 150 | BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); |
| vcoubard | 1:ebc0e0ef0a11 | 151 | if (err_code != NRF_SUCCESS) |
| vcoubard | 1:ebc0e0ef0a11 | 152 | { |
| vcoubard | 1:ebc0e0ef0a11 | 153 | // Any error at this stage means the system service attributes could not be fetched. |
| vcoubard | 1:ebc0e0ef0a11 | 154 | // This means the service changed indication cannot be sent in DFU mode, but connection |
| vcoubard | 1:ebc0e0ef0a11 | 155 | // is still possible to establish. |
| vcoubard | 1:ebc0e0ef0a11 | 156 | } |
| vcoubard | 1:ebc0e0ef0a11 | 157 | |
| vcoubard | 1:ebc0e0ef0a11 | 158 | m_reset_prepare(); |
| vcoubard | 1:ebc0e0ef0a11 | 159 | |
| vcoubard | 1:ebc0e0ef0a11 | 160 | err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START); |
| vcoubard | 1:ebc0e0ef0a11 | 161 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 162 | |
| vcoubard | 1:ebc0e0ef0a11 | 163 | err_code = sd_softdevice_disable(); |
| vcoubard | 1:ebc0e0ef0a11 | 164 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 165 | |
| vcoubard | 1:ebc0e0ef0a11 | 166 | err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR); |
| vcoubard | 1:ebc0e0ef0a11 | 167 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 168 | |
| vcoubard | 1:ebc0e0ef0a11 | 169 | dfu_app_peer_data_set(conn_handle); |
| vcoubard | 1:ebc0e0ef0a11 | 170 | |
| vcoubard | 1:ebc0e0ef0a11 | 171 | NVIC_ClearPendingIRQ(SWI2_IRQn); |
| vcoubard | 1:ebc0e0ef0a11 | 172 | interrupts_disable(); |
| vcoubard | 1:ebc0e0ef0a11 | 173 | bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR); |
| vcoubard | 1:ebc0e0ef0a11 | 174 | } |
| vcoubard | 1:ebc0e0ef0a11 | 175 | |
| vcoubard | 1:ebc0e0ef0a11 | 176 | |
| vcoubard | 1:ebc0e0ef0a11 | 177 | void dfu_app_on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) |
| vcoubard | 1:ebc0e0ef0a11 | 178 | { |
| vcoubard | 1:ebc0e0ef0a11 | 179 | switch (p_evt->ble_dfu_evt_type) |
| vcoubard | 1:ebc0e0ef0a11 | 180 | { |
| vcoubard | 1:ebc0e0ef0a11 | 181 | case BLE_DFU_START: |
| vcoubard | 1:ebc0e0ef0a11 | 182 | // Starting the bootloader - will cause reset. |
| vcoubard | 1:ebc0e0ef0a11 | 183 | bootloader_start(p_dfu->conn_handle); |
| vcoubard | 1:ebc0e0ef0a11 | 184 | break; |
| vcoubard | 1:ebc0e0ef0a11 | 185 | |
| vcoubard | 1:ebc0e0ef0a11 | 186 | default: |
| vcoubard | 1:ebc0e0ef0a11 | 187 | { |
| vcoubard | 1:ebc0e0ef0a11 | 188 | // Unsupported event received from DFU Service. |
| vcoubard | 1:ebc0e0ef0a11 | 189 | // Send back BLE_DFU_RESP_VAL_NOT_SUPPORTED message to peer. |
| vcoubard | 1:ebc0e0ef0a11 | 190 | uint32_t err_code = ble_dfu_response_send(p_dfu, |
| vcoubard | 1:ebc0e0ef0a11 | 191 | BLE_DFU_START_PROCEDURE, |
| vcoubard | 1:ebc0e0ef0a11 | 192 | BLE_DFU_RESP_VAL_NOT_SUPPORTED); |
| vcoubard | 1:ebc0e0ef0a11 | 193 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 194 | } |
| vcoubard | 1:ebc0e0ef0a11 | 195 | break; |
| vcoubard | 1:ebc0e0ef0a11 | 196 | } |
| vcoubard | 1:ebc0e0ef0a11 | 197 | } |
| vcoubard | 1:ebc0e0ef0a11 | 198 | |
| vcoubard | 1:ebc0e0ef0a11 | 199 | |
| vcoubard | 1:ebc0e0ef0a11 | 200 | void dfu_app_reset_prepare_set(dfu_app_reset_prepare_t reset_prepare_func) |
| vcoubard | 1:ebc0e0ef0a11 | 201 | { |
| vcoubard | 1:ebc0e0ef0a11 | 202 | m_reset_prepare = reset_prepare_func; |
| vcoubard | 1:ebc0e0ef0a11 | 203 | } |
| vcoubard | 1:ebc0e0ef0a11 | 204 | |
| vcoubard | 1:ebc0e0ef0a11 | 205 | |
| vcoubard | 1:ebc0e0ef0a11 | 206 | void dfu_app_dm_appl_instance_set(dm_application_instance_t app_instance) |
| vcoubard | 1:ebc0e0ef0a11 | 207 | { |
| vcoubard | 1:ebc0e0ef0a11 | 208 | uint32_t err_code; |
| vcoubard | 1:ebc0e0ef0a11 | 209 | |
| vcoubard | 1:ebc0e0ef0a11 | 210 | err_code = dm_application_instance_set(&app_instance, &m_dm_handle); |
| vcoubard | 1:ebc0e0ef0a11 | 211 | APP_ERROR_CHECK(err_code); |
| vcoubard | 1:ebc0e0ef0a11 | 212 | } |
