Toyomasa Watarai / nrf51-sdk

Fork of nrf51-sdk by Nordic Semiconductor

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?

UserRevisionLine numberNew 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 }