Nordic nrf51 sdk sources. Mirrored from https://github.com/ARMmbed/nrf51-sdk.

Dependents:   nRF51822 nRF51822

Committer:
vcoubard
Date:
Thu Apr 07 17:37:56 2016 +0100
Revision:
28:041dac1366b2
Parent:
20:a90c48eb1d30
Child:
29:286940b7ee5a
Synchronized with git rev 012b8118
Author: Liyou Zhou
Pull in files from sdk 10.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vcoubard 28:041dac1366b2 1 /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
vcoubard 28:041dac1366b2 2 *
vcoubard 28:041dac1366b2 3 * The information contained herein is property of Nordic Semiconductor ASA.
vcoubard 28:041dac1366b2 4 * Terms and conditions of usage are described in detail in NORDIC
vcoubard 28:041dac1366b2 5 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
vcoubard 28:041dac1366b2 6 *
vcoubard 28:041dac1366b2 7 * Licensees are granted free, non-transferable use of the information. NO
vcoubard 28:041dac1366b2 8 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
vcoubard 28:041dac1366b2 9 * the file.
vcoubard 28:041dac1366b2 10 *
vcoubard 1:ebc0e0ef0a11 11 */
vcoubard 1:ebc0e0ef0a11 12
vcoubard 1:ebc0e0ef0a11 13 #include "dfu_app_handler.h"
vcoubard 1:ebc0e0ef0a11 14 #include <string.h>
vcoubard 1:ebc0e0ef0a11 15 #include "bootloader_util.h"
vcoubard 1:ebc0e0ef0a11 16 #include "nrf.h"
vcoubard 1:ebc0e0ef0a11 17 #include "nrf_sdm.h"
vcoubard 1:ebc0e0ef0a11 18 #include "ble_gatt.h"
vcoubard 1:ebc0e0ef0a11 19 #include "ble_gatts.h"
vcoubard 1:ebc0e0ef0a11 20 #include "app_error.h"
vcoubard 1:ebc0e0ef0a11 21 #include "dfu_ble_svc.h"
vcoubard 1:ebc0e0ef0a11 22 #include "device_manager.h"
vcoubard 1:ebc0e0ef0a11 23 #include "nrf_delay.h"
vcoubard 1:ebc0e0ef0a11 24
vcoubard 1:ebc0e0ef0a11 25 #define IRQ_ENABLED 0x01 /**< Field that identifies if an interrupt is enabled. */
vcoubard 1:ebc0e0ef0a11 26 #define MAX_NUMBER_INTERRUPTS 32 /**< Maximum number of interrupts available. */
vcoubard 1:ebc0e0ef0a11 27
vcoubard 1:ebc0e0ef0a11 28 static void dfu_app_reset_prepare(void); /**< Forward declaration of default reset handler. */
vcoubard 1:ebc0e0ef0a11 29 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 30 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 31 static dm_handle_t m_dm_handle; /**< Device Manager handle with instance IDs of current BLE connection. */
vcoubard 1:ebc0e0ef0a11 32
vcoubard 1:ebc0e0ef0a11 33
vcoubard 1:ebc0e0ef0a11 34 /**@brief Function for reset_prepare handler if the application has not registered a handler.
vcoubard 1:ebc0e0ef0a11 35 */
vcoubard 1:ebc0e0ef0a11 36 static void dfu_app_reset_prepare(void)
vcoubard 1:ebc0e0ef0a11 37 {
vcoubard 1:ebc0e0ef0a11 38 // Reset prepare should be handled by application.
vcoubard 1:ebc0e0ef0a11 39 // This function can be extended to include default handling if application does not implement
vcoubard 1:ebc0e0ef0a11 40 // own handler.
vcoubard 1:ebc0e0ef0a11 41 }
vcoubard 1:ebc0e0ef0a11 42
vcoubard 1:ebc0e0ef0a11 43
vcoubard 1:ebc0e0ef0a11 44 /**@brief Function for disabling all interrupts before jumping from bootloader to application.
vcoubard 1:ebc0e0ef0a11 45 */
vcoubard 1:ebc0e0ef0a11 46 static void interrupts_disable(void)
vcoubard 1:ebc0e0ef0a11 47 {
vcoubard 1:ebc0e0ef0a11 48 uint32_t interrupt_setting_mask;
vcoubard 1:ebc0e0ef0a11 49 uint32_t irq;
vcoubard 1:ebc0e0ef0a11 50
vcoubard 1:ebc0e0ef0a11 51 // Fetch the current interrupt settings.
vcoubard 1:ebc0e0ef0a11 52 interrupt_setting_mask = NVIC->ISER[0];
vcoubard 1:ebc0e0ef0a11 53
vcoubard 1:ebc0e0ef0a11 54 // Loop from interrupt 0 for disabling of all interrupts.
vcoubard 1:ebc0e0ef0a11 55 for (irq = 0; irq < MAX_NUMBER_INTERRUPTS; irq++)
vcoubard 1:ebc0e0ef0a11 56 {
vcoubard 1:ebc0e0ef0a11 57 if (interrupt_setting_mask & (IRQ_ENABLED << irq))
vcoubard 1:ebc0e0ef0a11 58 {
vcoubard 1:ebc0e0ef0a11 59 // The interrupt was enabled, hence disable it.
vcoubard 1:ebc0e0ef0a11 60 NVIC_DisableIRQ((IRQn_Type)irq);
vcoubard 1:ebc0e0ef0a11 61 }
vcoubard 1:ebc0e0ef0a11 62 }
vcoubard 1:ebc0e0ef0a11 63 }
vcoubard 1:ebc0e0ef0a11 64
vcoubard 1:ebc0e0ef0a11 65
vcoubard 1:ebc0e0ef0a11 66 /**@brief Function for providing peer information to DFU for re-establishing a bonded connection in
vcoubard 1:ebc0e0ef0a11 67 * DFU mode.
vcoubard 1:ebc0e0ef0a11 68 *
vcoubard 1:ebc0e0ef0a11 69 * @param[in] conn_handle Connection handle for the connection requesting DFU mode.
vcoubard 1:ebc0e0ef0a11 70 */
vcoubard 1:ebc0e0ef0a11 71 static void dfu_app_peer_data_set(uint16_t conn_handle)
vcoubard 1:ebc0e0ef0a11 72 {
vcoubard 1:ebc0e0ef0a11 73 uint32_t err_code;
vcoubard 1:ebc0e0ef0a11 74 dm_sec_keyset_t key_set;
vcoubard 1:ebc0e0ef0a11 75 uint32_t app_context_data = 0;
vcoubard 1:ebc0e0ef0a11 76 dm_application_context_t app_context;
vcoubard 1:ebc0e0ef0a11 77
vcoubard 1:ebc0e0ef0a11 78
vcoubard 1:ebc0e0ef0a11 79 /** [DFU bond sharing] */
vcoubard 1:ebc0e0ef0a11 80 err_code = dm_handle_get(conn_handle, &m_dm_handle);
vcoubard 1:ebc0e0ef0a11 81 if (err_code == NRF_SUCCESS)
vcoubard 1:ebc0e0ef0a11 82 {
vcoubard 1:ebc0e0ef0a11 83 err_code = dm_distributed_keys_get(&m_dm_handle, &key_set);
vcoubard 1:ebc0e0ef0a11 84 if (err_code == NRF_SUCCESS)
vcoubard 1:ebc0e0ef0a11 85 {
vcoubard 1:ebc0e0ef0a11 86 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 87
vcoubard 1:ebc0e0ef0a11 88 m_peer_data.addr = key_set.keys_central.p_id_key->id_addr_info;
vcoubard 1:ebc0e0ef0a11 89 m_peer_data.irk = key_set.keys_central.p_id_key->id_info;
vcoubard 1:ebc0e0ef0a11 90 m_peer_data.enc_key.enc_info = key_set.keys_periph.enc_key.p_enc_key->enc_info;
vcoubard 1:ebc0e0ef0a11 91 m_peer_data.enc_key.master_id = key_set.keys_periph.enc_key.p_enc_key->master_id;
vcoubard 1:ebc0e0ef0a11 92
vcoubard 1:ebc0e0ef0a11 93 err_code = dfu_ble_svc_peer_data_set(&m_peer_data);
vcoubard 1:ebc0e0ef0a11 94 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 95
vcoubard 1:ebc0e0ef0a11 96 app_context_data = (DFU_APP_ATT_TABLE_CHANGED << DFU_APP_ATT_TABLE_POS);
vcoubard 1:ebc0e0ef0a11 97 app_context.len = sizeof(app_context_data);
vcoubard 1:ebc0e0ef0a11 98 app_context.p_data = (uint8_t *)&app_context_data;
vcoubard 1:ebc0e0ef0a11 99 app_context.flags = 0;
vcoubard 1:ebc0e0ef0a11 100
vcoubard 1:ebc0e0ef0a11 101 err_code = dm_application_context_set(&m_dm_handle, &app_context);
vcoubard 1:ebc0e0ef0a11 102 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 103 }
vcoubard 1:ebc0e0ef0a11 104 else
vcoubard 1:ebc0e0ef0a11 105 {
vcoubard 1:ebc0e0ef0a11 106 // Keys were not available, thus we have a non-encrypted connection.
vcoubard 1:ebc0e0ef0a11 107 err_code = dm_peer_addr_get(&m_dm_handle, &m_peer_data.addr);
vcoubard 1:ebc0e0ef0a11 108 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 109
vcoubard 1:ebc0e0ef0a11 110 err_code = dfu_ble_svc_peer_data_set(&m_peer_data);
vcoubard 1:ebc0e0ef0a11 111 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 112 }
vcoubard 1:ebc0e0ef0a11 113 }
vcoubard 1:ebc0e0ef0a11 114 /** [DFU bond sharing] */
vcoubard 1:ebc0e0ef0a11 115 }
vcoubard 1:ebc0e0ef0a11 116
vcoubard 1:ebc0e0ef0a11 117
vcoubard 1:ebc0e0ef0a11 118 /**@brief Function for preparing the reset, disabling SoftDevice, and jumping to the bootloader.
vcoubard 1:ebc0e0ef0a11 119 *
vcoubard 1:ebc0e0ef0a11 120 * @param[in] conn_handle Connection handle for peer requesting to enter DFU mode.
vcoubard 1:ebc0e0ef0a11 121 */
vcoubard 1:ebc0e0ef0a11 122 static void bootloader_start(uint16_t conn_handle)
vcoubard 1:ebc0e0ef0a11 123 {
vcoubard 1:ebc0e0ef0a11 124 uint32_t err_code;
vcoubard 1:ebc0e0ef0a11 125 uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr);
vcoubard 1:ebc0e0ef0a11 126
vcoubard 1:ebc0e0ef0a11 127 err_code = sd_ble_gatts_sys_attr_get(conn_handle,
vcoubard 1:ebc0e0ef0a11 128 m_peer_data.sys_serv_attr,
vcoubard 1:ebc0e0ef0a11 129 &sys_serv_attr_len,
vcoubard 1:ebc0e0ef0a11 130 BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
vcoubard 1:ebc0e0ef0a11 131 if (err_code != NRF_SUCCESS)
vcoubard 1:ebc0e0ef0a11 132 {
vcoubard 1:ebc0e0ef0a11 133 // Any error at this stage means the system service attributes could not be fetched.
vcoubard 1:ebc0e0ef0a11 134 // This means the service changed indication cannot be sent in DFU mode, but connection
vcoubard 1:ebc0e0ef0a11 135 // is still possible to establish.
vcoubard 1:ebc0e0ef0a11 136 }
vcoubard 1:ebc0e0ef0a11 137
vcoubard 1:ebc0e0ef0a11 138 m_reset_prepare();
vcoubard 1:ebc0e0ef0a11 139
vcoubard 1:ebc0e0ef0a11 140 err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START);
vcoubard 1:ebc0e0ef0a11 141 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 142
vcoubard 1:ebc0e0ef0a11 143 err_code = sd_softdevice_disable();
vcoubard 1:ebc0e0ef0a11 144 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 145
vcoubard 1:ebc0e0ef0a11 146 err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR);
vcoubard 1:ebc0e0ef0a11 147 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 148
vcoubard 1:ebc0e0ef0a11 149 dfu_app_peer_data_set(conn_handle);
vcoubard 1:ebc0e0ef0a11 150
vcoubard 1:ebc0e0ef0a11 151 NVIC_ClearPendingIRQ(SWI2_IRQn);
vcoubard 1:ebc0e0ef0a11 152 interrupts_disable();
vcoubard 1:ebc0e0ef0a11 153 bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR);
vcoubard 1:ebc0e0ef0a11 154 }
vcoubard 1:ebc0e0ef0a11 155
vcoubard 1:ebc0e0ef0a11 156
vcoubard 1:ebc0e0ef0a11 157 void dfu_app_on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
vcoubard 1:ebc0e0ef0a11 158 {
vcoubard 1:ebc0e0ef0a11 159 switch (p_evt->ble_dfu_evt_type)
vcoubard 1:ebc0e0ef0a11 160 {
vcoubard 1:ebc0e0ef0a11 161 case BLE_DFU_START:
vcoubard 1:ebc0e0ef0a11 162 // Starting the bootloader - will cause reset.
vcoubard 1:ebc0e0ef0a11 163 bootloader_start(p_dfu->conn_handle);
vcoubard 1:ebc0e0ef0a11 164 break;
vcoubard 1:ebc0e0ef0a11 165
vcoubard 1:ebc0e0ef0a11 166 default:
vcoubard 1:ebc0e0ef0a11 167 {
vcoubard 1:ebc0e0ef0a11 168 // Unsupported event received from DFU Service.
vcoubard 1:ebc0e0ef0a11 169 // Send back BLE_DFU_RESP_VAL_NOT_SUPPORTED message to peer.
vcoubard 1:ebc0e0ef0a11 170 uint32_t err_code = ble_dfu_response_send(p_dfu,
vcoubard 1:ebc0e0ef0a11 171 BLE_DFU_START_PROCEDURE,
vcoubard 1:ebc0e0ef0a11 172 BLE_DFU_RESP_VAL_NOT_SUPPORTED);
vcoubard 1:ebc0e0ef0a11 173 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 174 }
vcoubard 1:ebc0e0ef0a11 175 break;
vcoubard 1:ebc0e0ef0a11 176 }
vcoubard 1:ebc0e0ef0a11 177 }
vcoubard 1:ebc0e0ef0a11 178
vcoubard 1:ebc0e0ef0a11 179
vcoubard 1:ebc0e0ef0a11 180 void dfu_app_reset_prepare_set(dfu_app_reset_prepare_t reset_prepare_func)
vcoubard 1:ebc0e0ef0a11 181 {
vcoubard 1:ebc0e0ef0a11 182 m_reset_prepare = reset_prepare_func;
vcoubard 1:ebc0e0ef0a11 183 }
vcoubard 1:ebc0e0ef0a11 184
vcoubard 1:ebc0e0ef0a11 185
vcoubard 1:ebc0e0ef0a11 186 void dfu_app_dm_appl_instance_set(dm_application_instance_t app_instance)
vcoubard 1:ebc0e0ef0a11 187 {
vcoubard 1:ebc0e0ef0a11 188 uint32_t err_code;
vcoubard 1:ebc0e0ef0a11 189
vcoubard 1:ebc0e0ef0a11 190 err_code = dm_application_instance_set(&app_instance, &m_dm_handle);
vcoubard 1:ebc0e0ef0a11 191 APP_ERROR_CHECK(err_code);
vcoubard 1:ebc0e0ef0a11 192 }