Appiko
sensebe_ble.c
1 /*
2  * sensebe_ble.c : BLE Support file for SenseBe application
3  * Copyright (C) 2019 Appiko
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #include "nrf_nvic.h"
20 #include "ble.h"
21 #include "nrf_sdm.h"
22 #include "app_error.h"
23 #include "boards.h"
24 #include "stddef.h"
25 #include "common_util.h"
26 #include "nrf_util.h"
27 #include "sensebe_ble.h"
28 #include "log.h"
29 #include "evt_sd_handler.h"
30 #include "string.h"
31 
32 #if ISR_MANAGER == 1
33 #include "isr_manager.h"
34 #endif
35 
38 #define DEVICE_NAME_CHAR 'S','e','n','s','e','B','e'
39 const uint8_t device_name[] = { DEVICE_NAME_CHAR };
40 
41 
44 #define SENSEBE_UUID_COMPLETE 0x0a, 0xde, 0xfb, 0x07, 0x74, 0x83, 0x66, 0xb0, 0x0d, 0x48, 0xf5, 0x07, 0x60, 0xdc, 0x73, 0x3c
45 
47 #define SENSEBE_UUID_SERVICE 0xdc60
48 
50 #define SENSEBE_UUID_SYSINFO 0xdc61
51 
52 #define SENSEBE_UUID_CONFIG 0xdc62
53 
55 #define ADVERTISING_INTERVAL MSEC_TO_UNITS(500, UNIT_0_625_MS)
56 
57 #define MIN_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS)
58 
59 #define MAX_CONN_INTERVAL MSEC_TO_UNITS(500, UNIT_1_25_MS)
60 
61 #define SLAVE_LATENCY 0
62 
63 #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
64 
65 
66 
67 
69 uint8_t h_adv;
70 
72 uint16_t h_conn;
73 
75 uint16_t h_sensebe_service;
76 
79 ble_gatts_char_handles_t h_sysinfo_char;
80 
83 ble_gatts_char_handles_t h_config_char;
84 
86 void (* sensebe_ble_sd_evt)(ble_evt_t * evt);
88 void (* sensebe_config_t_update)(sensebe_config_t * cfg);
89 
90 sensebe_sysinfo curr_sysinfo;
91 
94 #if ISR_MANAGER == 1
95 void sensebe_ble_swi_Handler ()
96 #else
97 void SWI1_IRQHandler(void)
98 #endif
99 {
100 // log_printf("radio going down\n");
101 }
102 
110 static void ble_evt_handler(ble_evt_t * evt)
111 {
112  uint32_t err_code;
113  switch(evt->header.evt_id)
114  {
115  case BLE_GAP_EVT_CONNECTED:
116  h_conn = evt->evt.gap_evt.conn_handle;
117  break;
118  case BLE_GAP_EVT_DISCONNECTED:
119  h_conn = BLE_CONN_HANDLE_INVALID;
120  break;
121  case BLE_GATTS_EVT_WRITE:
122  {
123  sensebe_config_t * config =
124  (sensebe_config_t *) evt->evt.gatts_evt.params.write.data;
125  sensebe_config_t_update(config);
126  break;
127  }
128  case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
129  {
130  uint16_t mtu_val = BLE_GATT_ATT_MTU_DEFAULT;
131  err_code = sd_ble_gatts_exchange_mtu_reply(h_conn, mtu_val);
132  APP_ERROR_CHECK(err_code);
133  break;
134  }
135  case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
136  {
137  ble_gap_phys_t const phys = {
138  .rx_phys = BLE_GAP_PHY_AUTO,
139  .tx_phys = BLE_GAP_PHY_AUTO,
140  };
141 
142  err_code = sd_ble_gap_phy_update(h_conn, &phys);
143  APP_ERROR_CHECK(err_code);
144  break;
145  }
146  case BLE_GAP_EVT_PHY_UPDATE:
147  {
148  log_printf("Tx_get : %x Rx_get : %x Status : %x\n",
149  evt->evt.gap_evt.params.phy_update.tx_phy,
150  evt->evt.gap_evt.params.phy_update.rx_phy,
151  evt->evt.gap_evt.params.phy_update.status);
152  break;
153  }
154  }
155 
156  sensebe_ble_sd_evt(evt);
157 }
158 
164 static void soc_evt_handler(uint32_t evt_id)
165 {
166  log_printf("soc evt %x\n", evt_id);
167 }
168 
169 void sensebe_ble_init(void (*ble_sd_evt)(ble_evt_t * evt),
170  void (* config_update)(sensebe_config_t * cfg))
171 {
172  sensebe_ble_sd_evt = ble_sd_evt;
173  sensebe_config_t_update = config_update;
174 }
175 
177 {
178  if(h_conn != BLE_CONN_HANDLE_INVALID)
179  {
180  uint32_t err_code;
181  err_code = sd_ble_gap_disconnect(h_conn,
182  BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
183  APP_ERROR_CHECK(err_code);
184  }
185 }
186 
187 void sensebe_ble_update_sysinfo(sensebe_sysinfo * sysinfo)
188 {
189  uint32_t err_code;
190  ble_gatts_value_t val =
191  {
192  .len = sizeof(sensebe_sysinfo),
193  .offset = 0,
194  .p_value = (uint8_t *) sysinfo
195  };
196  err_code = sd_ble_gatts_value_set(h_conn,
197  h_sysinfo_char.value_handle, &val);
198  APP_ERROR_CHECK(err_code);
199 }
200 
201 void sensebe_ble_update_config(sensebe_config_t * config)
202 {
203  uint32_t err_code;
204  ble_gatts_value_t val =
205  {
206  .len = sizeof(sensebe_config_t),
207  .offset = 0,
208  .p_value = (uint8_t *) config
209  };
210  err_code = sd_ble_gatts_value_set(h_conn,
211  h_config_char.value_handle, &val);
212  APP_ERROR_CHECK(err_code);
213 }
214 
215 
217 {
218  uint32_t err_code;
219  const nrf_clock_lf_cfg_t cfg = BOARD_LFCLKSRC_STRUCT;
220 
221  err_code = sd_softdevice_enable(&cfg, app_error_fault_handler);
222  APP_ERROR_CHECK(err_code);
223 
224  uint32_t app_ram_start = 0x20001c00;
225  log_printf("Init %x", app_ram_start);
226  err_code = sd_ble_enable(&app_ram_start);
227  log_printf(" RAM needed %x\n", app_ram_start);
228  APP_ERROR_CHECK(err_code);
229 
230  evt_sd_handler_init(ble_evt_handler, soc_evt_handler);
231 
232  //So that the application wakes up after every radio activity
233  err_code = sd_radio_notification_cfg_set(
234  NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE,
235  NRF_RADIO_NOTIFICATION_DISTANCE_NONE);
236  APP_ERROR_CHECK(err_code);
237 
238  // Initialize Radio Notification software interrupt
239  err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
240  APP_ERROR_CHECK(err_code);
241 
242  err_code = sd_nvic_SetPriority(SWI1_IRQn, APP_IRQ_PRIORITY_LOWEST);
243  APP_ERROR_CHECK(err_code);
244 
245  err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
246  APP_ERROR_CHECK(err_code);
247 
248  h_conn = BLE_CONN_HANDLE_INVALID;
249 }
250 
252 {
253  uint32_t err_code;
254  ble_uuid_t ble_uuid;
255  uint8_t uuid_type;
256 
257  /**** Create the Sense Pi service *****/
258  ble_uuid128_t base_uuid = {{SENSEBE_UUID_COMPLETE}};
259  err_code = sd_ble_uuid_vs_add(&base_uuid, &uuid_type);
260  APP_ERROR_CHECK(err_code);
261 
262  ble_uuid.type = uuid_type;
263  ble_uuid.uuid = SENSEBE_UUID_SERVICE;
264 
265  err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
266  &ble_uuid, &h_sensebe_service);
267  APP_ERROR_CHECK(err_code);
268 
269  /**** Create the read-only characteristic *****/
270  ble_gatts_char_md_t char_md;
271  ble_gatts_attr_t attr_char_value;
272  ble_gatts_attr_md_t attr_md;
273 
274  memset(&char_md, 0, sizeof(char_md));
275 
276  char_md.char_props.read = 1;
277  char_md.char_props.write = 0;
278  char_md.p_char_user_desc = NULL;
279  char_md.p_char_pf = NULL;
280  char_md.p_user_desc_md = NULL;
281  char_md.p_cccd_md = NULL;
282  char_md.p_sccd_md = NULL;
283 
284  ble_uuid.type = uuid_type;
285  ble_uuid.uuid = (SENSEBE_UUID_SYSINFO);
286 
287  memset(&attr_md, 0, sizeof(attr_md));
288 
289  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
290  BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
291  attr_md.vloc = BLE_GATTS_VLOC_STACK;
292  attr_md.rd_auth = 0;
293  attr_md.wr_auth = 0;
294  attr_md.vlen = 0;
295 
296  memset(&attr_char_value, 0, sizeof(attr_char_value));
297 
298  attr_char_value.p_uuid = &ble_uuid;
299  attr_char_value.p_attr_md = &attr_md;
300  attr_char_value.init_len = sizeof(sensebe_sysinfo);
301  attr_char_value.init_offs = 0;
302  attr_char_value.max_len = sizeof(sensebe_sysinfo);
303  attr_char_value.p_value = NULL;
304 
305  err_code = sd_ble_gatts_characteristic_add(
306  h_sensebe_service, &char_md, &attr_char_value, &h_sysinfo_char);
307  APP_ERROR_CHECK(err_code);
308 
309  /**** Create the read-write characterisitc *****/
310  memset(&char_md, 0, sizeof(char_md));
311 
312  char_md.char_props.read = 1;
313  char_md.char_props.write = 1;
314  char_md.p_char_user_desc = NULL;
315  char_md.p_char_pf = NULL;
316  char_md.p_user_desc_md = NULL;
317  char_md.p_cccd_md = NULL;
318  char_md.p_sccd_md = NULL;
319 
320  ble_uuid.type = uuid_type;
321  ble_uuid.uuid = (SENSEBE_UUID_CONFIG);
322 
323  memset(&attr_md, 0, sizeof(attr_md));
324 
325  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
326  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
327  attr_md.vloc = BLE_GATTS_VLOC_STACK;
328  attr_md.rd_auth = 0;
329  attr_md.wr_auth = 0;
330  attr_md.vlen = 0;
331 
332  memset(&attr_char_value, 0, sizeof(attr_char_value));
333 
334  attr_char_value.p_uuid = &ble_uuid;
335  attr_char_value.p_attr_md = &attr_md;
336  attr_char_value.init_len = sizeof(sensebe_config_t);
337  attr_char_value.init_offs = 0;
338  attr_char_value.max_len = sizeof(sensebe_config_t);
339  attr_char_value.p_value = NULL;
340 
341  err_code = sd_ble_gatts_characteristic_add(
342  h_sensebe_service, &char_md, &attr_char_value,&h_config_char);
343  APP_ERROR_CHECK(err_code);
344 }
345 
347 {
348  uint32_t err_code;
349  ble_gap_conn_params_t gap_conn_params;
350  ble_gap_conn_sec_mode_t sec_mode;
351 
352  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
353 
354  err_code = sd_ble_gap_device_name_set(
355  &sec_mode, (const uint8_t *)device_name, sizeof(device_name));
356  APP_ERROR_CHECK(err_code);
357 
358  memset(&gap_conn_params, 0, sizeof(gap_conn_params));
359 
360  gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
361  gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
362  gap_conn_params.slave_latency = SLAVE_LATENCY;
363  gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
364 
365  err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
366  APP_ERROR_CHECK(err_code);
367 }
368 
369 void sensebe_ble_adv_init(sensebe_ble_adv_data_t * sensebe_ble_adv_data)
370 {
371  h_adv = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
372  uint32_t err_code;
373 
374  ble_gap_adv_data_t adv_payload;
375 
376  adv_payload.adv_data.p_data = sensebe_ble_adv_data->adv_data;
377  adv_payload.adv_data.len = sensebe_ble_adv_data->adv_len;
378 
379  adv_payload.scan_rsp_data.p_data = sensebe_ble_adv_data->scan_rsp_data;
380  adv_payload.scan_rsp_data.len = sensebe_ble_adv_data->scan_rsp_len;
381 
382  ble_gap_adv_params_t adv_params;
383 
384  memset(&adv_params, 0, sizeof(adv_params));
385 
386  //Set channel 37, 38 and 39 as advertising channels
387  memset(adv_params.channel_mask, 0, 5);
388 
389  //Set the advertising to timeout in 180s
390  adv_params.duration = BLE_GAP_ADV_TIMEOUT_LIMITED_MAX;
391 
392  //Any device can scan request and connect
393  adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
394 
395  //Period between sending advertising packets
396  adv_params.interval = ADVERTISING_INTERVAL;
397 
398  //Use 1Mbps physical layer to be backward compatible
399  adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
400 
401  //The advertisement would be unidirected connectable and scannable
402  adv_params.properties.type =
403  BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
404 
405  adv_params.p_peer_addr = NULL;
406  adv_params.scan_req_notification = 0;
407 
408  err_code = sd_ble_gap_adv_set_configure(&h_adv,
409  (ble_gap_adv_data_t const *)&adv_payload,
410  (ble_gap_adv_params_t const *) &adv_params);
411  APP_ERROR_CHECK(err_code);
412 }
413 
415 {
416  uint32_t err_code;
417  err_code = sd_ble_gap_adv_start(h_adv, BLE_CONN_CFG_TAG_DEFAULT);
418  APP_ERROR_CHECK(err_code);
419 }
420 
void sensebe_ble_update_sysinfo(sensebe_sysinfo *sysinfo)
Updates the characteristic that stores the sysinfo.
Definition: sensebe_ble.c:187
void sensebe_ble_stack_init(void)
Function for initializing the BLE stack by enabling the SoftDevice and the BLE event interrupt.
Definition: sensebe_ble.c:216
void sensebe_ble_service_init(void)
Create the Service and its characteristics for the SensePi device. There is a read-only characteristi...
Definition: sensebe_ble.c:251
void sensebe_ble_init(void(*ble_sd_evt)(ble_evt_t *evt), void(*config_update)(sensebe_config_t *cfg))
Initialize the handlers to pass the BLE SD events and the configuration received from the mobile app.
Definition: sensebe_ble.c:169
void evt_sd_handler_init(void(*ble_evt_handler)(ble_evt_t *ble_evt), void(*soc_evt_handler)(uint32_t soc_evt_id))
Initializes the SWI2 interrupt routine and stores the handlers for the BLE and SoC events.
#define BOARD_LFCLKSRC_STRUCT
Definition: bluey_1v1.h:122
void sensebe_ble_disconn(void)
Disconnect the current active connection, if already connected.
Definition: sensebe_ble.c:176
#define APP_ERROR_CHECK(ERR_CODE)
Macro calls error handler if the provided error code is not NRF_SUCCESS. The behavior of this call de...
Definition: app_error.h:55
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
Callback to be invoked in case of fault i.e. unrecoverable errors occurring within the application or...
Definition: app_error.c:55
void sensebe_ble_update_config(sensebe_config_t *config)
Updates the characteristic that stores the SensePi config.
Definition: sensebe_ble.c:201
void sensebe_ble_adv_start(void)
Function to start advertising.
Definition: sensebe_ble.c:414
void sensebe_ble_gap_params_init(void)
Generic Access Profile initialization. The device name, and the preferred connection parameters are s...
Definition: sensebe_ble.c:346
void sensebe_ble_adv_init(sensebe_ble_adv_data_t *sensebe_ble_adv_data)
Function to initializing the advertising.
Definition: sensebe_ble.c:369