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
dfu_app_handler.c
00001 /* 00002 * Copyright (c) Nordic Semiconductor ASA 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without modification, 00006 * are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * 00011 * 2. Redistributions in binary form must reproduce the above copyright notice, this 00012 * list of conditions and the following disclaimer in the documentation and/or 00013 * other materials provided with the distribution. 00014 * 00015 * 3. Neither the name of Nordic Semiconductor ASA nor the names of other 00016 * contributors to this software may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00021 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00023 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 00024 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 00027 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #include "dfu_app_handler.h " 00034 #include <string.h> 00035 #include "bootloader_util.h " 00036 #include "nrf.h" 00037 #include "nrf_sdm.h" 00038 #include "ble_gatt.h" 00039 #include "ble_gatts.h" 00040 #include "app_error.h " 00041 #include "dfu_ble_svc.h " 00042 #include "device_manager.h " 00043 #include "nrf_delay.h" 00044 00045 #define IRQ_ENABLED 0x01 /**< Field that identifies if an interrupt is enabled. */ 00046 #define MAX_NUMBER_INTERRUPTS 32 /**< Maximum number of interrupts available. */ 00047 00048 static void dfu_app_reset_prepare(void); /**< Forward declaration of default reset handler. */ 00049 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. */ 00050 static dfu_ble_peer_data_t m_peer_data; /**< Peer data to be used for data exchange when resetting into DFU mode. */ 00051 static dm_handle_t m_dm_handle; /**< Device Manager handle with instance IDs of current BLE connection. */ 00052 00053 00054 /**@brief Function for reset_prepare handler if the application has not registered a handler. 00055 */ 00056 static void dfu_app_reset_prepare(void) 00057 { 00058 // Reset prepare should be handled by application. 00059 // This function can be extended to include default handling if application does not implement 00060 // own handler. 00061 } 00062 00063 00064 /**@brief Function for disabling all interrupts before jumping from bootloader to application. 00065 */ 00066 static void interrupts_disable(void) 00067 { 00068 uint32_t interrupt_setting_mask; 00069 uint32_t irq; 00070 00071 // Fetch the current interrupt settings. 00072 interrupt_setting_mask = NVIC->ISER[0]; 00073 00074 // Loop from interrupt 0 for disabling of all interrupts. 00075 for (irq = 0; irq < MAX_NUMBER_INTERRUPTS; irq++) 00076 { 00077 if (interrupt_setting_mask & (IRQ_ENABLED << irq)) 00078 { 00079 // The interrupt was enabled, hence disable it. 00080 NVIC_DisableIRQ((IRQn_Type)irq); 00081 } 00082 } 00083 } 00084 00085 00086 /**@brief Function for providing peer information to DFU for re-establishing a bonded connection in 00087 * DFU mode. 00088 * 00089 * @param[in] conn_handle Connection handle for the connection requesting DFU mode. 00090 */ 00091 static void dfu_app_peer_data_set(uint16_t conn_handle) 00092 { 00093 uint32_t err_code; 00094 dm_sec_keyset_t key_set; 00095 uint32_t app_context_data = 0; 00096 dm_application_context_t app_context; 00097 00098 00099 /** [DFU bond sharing] */ 00100 err_code = dm_handle_get(conn_handle, &m_dm_handle); 00101 if (err_code == NRF_SUCCESS) 00102 { 00103 err_code = dm_distributed_keys_get(&m_dm_handle, &key_set); 00104 if (err_code == NRF_SUCCESS) 00105 { 00106 APP_ERROR_CHECK(err_code); 00107 00108 m_peer_data.addr = key_set.keys_central.p_id_key->id_addr_info; 00109 m_peer_data.irk = key_set.keys_central.p_id_key->id_info; 00110 m_peer_data.enc_key.enc_info = key_set.keys_periph.enc_key.p_enc_key->enc_info; 00111 m_peer_data.enc_key.master_id = key_set.keys_periph.enc_key.p_enc_key->master_id; 00112 00113 err_code = dfu_ble_svc_peer_data_set(&m_peer_data); 00114 APP_ERROR_CHECK(err_code); 00115 00116 app_context_data = (DFU_APP_ATT_TABLE_CHANGED << DFU_APP_ATT_TABLE_POS); 00117 app_context.len = sizeof(app_context_data); 00118 app_context.p_data = (uint8_t *)&app_context_data; 00119 app_context.flags = 0; 00120 00121 err_code = dm_application_context_set(&m_dm_handle, &app_context); 00122 APP_ERROR_CHECK(err_code); 00123 } 00124 else 00125 { 00126 // Keys were not available, thus we have a non-encrypted connection. 00127 err_code = dm_peer_addr_get(&m_dm_handle, &m_peer_data.addr); 00128 APP_ERROR_CHECK(err_code); 00129 00130 err_code = dfu_ble_svc_peer_data_set(&m_peer_data); 00131 APP_ERROR_CHECK(err_code); 00132 } 00133 } 00134 /** [DFU bond sharing] */ 00135 } 00136 00137 00138 /**@brief Function for preparing the reset, disabling SoftDevice, and jumping to the bootloader. 00139 * 00140 * @param[in] conn_handle Connection handle for peer requesting to enter DFU mode. 00141 */ 00142 static void bootloader_start(uint16_t conn_handle) 00143 { 00144 uint32_t err_code; 00145 uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr); 00146 00147 err_code = sd_ble_gatts_sys_attr_get(conn_handle, 00148 m_peer_data.sys_serv_attr, 00149 &sys_serv_attr_len, 00150 BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); 00151 if (err_code != NRF_SUCCESS) 00152 { 00153 // Any error at this stage means the system service attributes could not be fetched. 00154 // This means the service changed indication cannot be sent in DFU mode, but connection 00155 // is still possible to establish. 00156 } 00157 00158 m_reset_prepare(); 00159 00160 err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START); 00161 APP_ERROR_CHECK(err_code); 00162 00163 err_code = sd_softdevice_disable(); 00164 APP_ERROR_CHECK(err_code); 00165 00166 err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR); 00167 APP_ERROR_CHECK(err_code); 00168 00169 dfu_app_peer_data_set(conn_handle); 00170 00171 NVIC_ClearPendingIRQ(SWI2_IRQn ); 00172 interrupts_disable(); 00173 bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR); 00174 } 00175 00176 00177 void dfu_app_on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) 00178 { 00179 switch (p_evt->ble_dfu_evt_type) 00180 { 00181 case BLE_DFU_START: 00182 // Starting the bootloader - will cause reset. 00183 bootloader_start(p_dfu->conn_handle); 00184 break; 00185 00186 default: 00187 { 00188 // Unsupported event received from DFU Service. 00189 // Send back BLE_DFU_RESP_VAL_NOT_SUPPORTED message to peer. 00190 uint32_t err_code = ble_dfu_response_send(p_dfu, 00191 BLE_DFU_START_PROCEDURE, 00192 BLE_DFU_RESP_VAL_NOT_SUPPORTED); 00193 APP_ERROR_CHECK(err_code); 00194 } 00195 break; 00196 } 00197 } 00198 00199 00200 void dfu_app_reset_prepare_set(dfu_app_reset_prepare_t reset_prepare_func) 00201 { 00202 m_reset_prepare = reset_prepare_func; 00203 } 00204 00205 00206 void dfu_app_dm_appl_instance_set(dm_application_instance_t app_instance) 00207 { 00208 uint32_t err_code; 00209 00210 err_code = dm_application_instance_set(&app_instance, &m_dm_handle); 00211 APP_ERROR_CHECK(err_code); 00212 }
Generated on Tue Jul 12 2022 14:11:19 by
