ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ble_dfu_unbonded.c
Go to the documentation of this file.
1 
41 #include <stdint.h>
42 #include <stdbool.h>
43 #include <stddef.h>
44 #include "nrf_dfu_ble_svci_bond_sharing.h"
45 #include "nordic_common.h"
46 #include "nrf_error.h"
47 #include "ble_dfu.h"
48 #include "nrf_log.h"
49 #include "nrf_sdh_soc.h"
50 #if NRF_MODULE_ENABLED(BLE_DFU)
51 
52 #if (!NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
53 
54 #define NRF_DFU_ADV_NAME_MAX_LENGTH (20)
55 
56 
57 void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
58 uint32_t nrf_dfu_svci_vector_table_set(void);
59 uint32_t nrf_dfu_svci_vector_table_unset(void);
60 
62 NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_ADV_NAME, nrf_dfu_set_adv_name, nrf_dfu_adv_name_t);
63 
64 // Register SoC observer for the Buttonless Secure DFU service
65 NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
66 
67 ble_dfu_buttonless_t * mp_dfu = NULL;
68 static nrf_dfu_adv_name_t m_adv_name;
69 
70 
79 static uint32_t set_adv_name(nrf_dfu_adv_name_t * p_adv_name)
80 {
81  uint32_t err_code;
82 
83  if (mp_dfu->is_waiting_for_svci)
84  {
85  return DFU_RSP_BUSY;
86  }
87 
88  err_code = nrf_dfu_set_adv_name(p_adv_name);
89  if (err_code == NRF_SUCCESS)
90  {
91  // The request was accepted.
92  mp_dfu->is_waiting_for_svci = true;
93  }
94  else if (err_code == NRF_ERROR_FORBIDDEN)
95  {
96  NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the advertising name. "\
97  "The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the advertising name.");
98  }
99 
100  return err_code;
101 }
102 
103 
106 static uint32_t enter_bootloader()
107 {
108  uint32_t err_code;
109 
110  if (mp_dfu->is_waiting_for_svci)
111  {
112  // We have an ongoing async operation. Entering bootloader mode is not possible at this time.
113  err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
114  if (err_code != NRF_SUCCESS)
115  {
116  mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
117  }
118  return NRF_SUCCESS;
119  }
120 
121  // Set the flag indicating that we expect DFU mode.
122  // This will be handled on acknowledgement of the characteristic indication.
123  mp_dfu->is_waiting_for_reset = true;
124 
125  err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
126  if (err_code != NRF_SUCCESS)
127  {
128  mp_dfu->is_waiting_for_reset = false;
129  }
130 
131  return err_code;
132 }
133 
134 
135 uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
136 {
137  VERIFY_PARAM_NOT_NULL(p_dfu);
138 
139  mp_dfu = p_dfu;
140 
141  return NRF_SUCCESS;
142 }
143 
144 
145 uint32_t ble_dfu_buttonless_async_svci_init(void)
146 {
147  uint32_t ret_val;
148  CRITICAL_REGION_ENTER();
149  ret_val = nrf_dfu_svci_vector_table_set();
150 
151  if(NRF_SUCCESS == ret_val)
152  {
153  ret_val = nrf_dfu_set_adv_name_init();
154 
155  if(NRF_SUCCESS == ret_val)
156  {
157  ret_val = nrf_dfu_svci_vector_table_unset();
158  }
159  }
160  CRITICAL_REGION_EXIT();
161  return ret_val;
162 }
163 
164 
165 void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
166 {
167  uint32_t err_code;
168 
169  if (!nrf_dfu_set_adv_name_is_initialized())
170  {
171  return;
172  }
173 
174  err_code = nrf_dfu_set_adv_name_on_sys_evt(sys_evt);
175  if (err_code == NRF_ERROR_INVALID_STATE)
176  {
177  // The system event is not from an operation started by buttonless DFU.
178  // No action is taken, and nothing is reported.
179  }
180  else if (err_code == NRF_SUCCESS)
181  {
182  // The async operation is finished.
183  // Set the flag indicating that we are waiting for indication response
184  // to activate the reset.
185  mp_dfu->is_waiting_for_svci = false;
186 
187  // Report back the positive response
188  err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_SUCCESS);
189  if (err_code != NRF_SUCCESS)
190  {
191  mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
192  }
193  }
194  else
195  {
196  // Invalid error code reported back.
197  mp_dfu->is_waiting_for_svci = false;
198 
199  err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_BUSY);
200  if (err_code != NRF_SUCCESS)
201  {
202  mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
203  }
204 
205  // Report the failure to enter DFU mode
206  mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
207  }
208 }
209 
210 
211 uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
212 {
213  ble_add_char_params_t add_char_params;
214 
215  memset(&add_char_params, 0, sizeof(add_char_params));
216  add_char_params.uuid = BLE_DFU_BUTTONLESS_CHAR_UUID;
217  add_char_params.uuid_type = p_dfu->uuid_type;
218  add_char_params.char_props.indicate = 1;
219  add_char_params.char_props.write = 1;
220  add_char_params.is_defered_write = true;
221  add_char_params.is_var_len = true;
222  add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
223 
224  add_char_params.cccd_write_access = SEC_OPEN;
225  add_char_params.write_access = SEC_OPEN;
226  add_char_params.read_access = SEC_OPEN;
227 
228  return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char);
229 }
230 
231 
232 void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
233 {
234  uint32_t err_code;
235  ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
236 
237  // Start executing the control point write operation
238  /*lint -e415 -e416 -save "Out of bounds access"*/
239  switch (p_evt_write->data[0])
240  {
241  case DFU_OP_ENTER_BOOTLOADER:
242  err_code = enter_bootloader();
243  if (err_code == NRF_SUCCESS)
244  {
245  rsp_code = DFU_RSP_SUCCESS;
246  }
247  else if (err_code == NRF_ERROR_BUSY)
248  {
249  rsp_code = DFU_RSP_BUSY;
250  }
251  break;
252 
253  case DFU_OP_SET_ADV_NAME:
254  if( (p_evt_write->data[1] > NRF_DFU_ADV_NAME_MAX_LENGTH)
255  || (p_evt_write->data[1] == 0))
256  {
257  // New advertisement name too short or too long.
258  rsp_code = DFU_RSP_ADV_NAME_INVALID;
259  }
260  else
261  {
262  memcpy(m_adv_name.name, &p_evt_write->data[2], p_evt_write->data[1]);
263  m_adv_name.len = p_evt_write->data[1];
264  err_code = set_adv_name(&m_adv_name);
265  if (err_code == NRF_SUCCESS)
266  {
267  rsp_code = DFU_RSP_SUCCESS;
268  }
269  }
270  break;
271 
272  default:
273  rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
274  break;
275  }
276  /*lint -restore*/
277 
278 
279  // Report back in case of error
280  if (rsp_code != DFU_RSP_SUCCESS)
281  {
282  err_code = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0], rsp_code);
283  if (err_code != NRF_SUCCESS)
284  {
285  mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
286 
287  }
288  // Report the error to the main application
289  mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
290  }
291 }
292 
293 uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
294 {
295  uint32_t err_code;
296 
297  // Indicate to main app that DFU mode is starting.
298  mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
299 
300  err_code = ble_dfu_buttonless_bootloader_start_finalize();
301  return err_code;
302 }
303 
304 #endif // NRF_DFU_BOTTONLESS_SUPPORT_BOND
305 #endif // Module enabled
#define BLE_DFU_SOC_OBSERVER_PRIO
Definition: sdk_config.h:12474