Appiko
sensepi_ble.c
1 /*
2  * sensepi_ble.c : BLE Support file for SensePi 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 "sensepi_ble.h"
28 #include "log.h"
29 #include "evt_sd_handler.h"
30 #include "string.h"
31 
34 #define DEVICE_NAME_CHAR 'S','e','n','s','e','P','i'
35 const uint8_t device_name[] = { DEVICE_NAME_CHAR };
36 
37 
40 #define SENSEPI_UUID_COMPLETE 0x0a, 0xde, 0xfb, 0x07, 0x74, 0x83, 0x66, 0xb0, 0x0d, 0x48, 0xf5, 0x07, 0x50, 0xdc, 0x73, 0x3c
41 
43 #define SENSEPI_UUID_SERVICE 0xdc50
44 
46 #define SENSEPI_UUID_SYSINFO 0xdc51
47 
48 #define SENSEPI_UUID_CONFIG 0xdc52
49 
51 #define ADVERTISING_INTERVAL MSEC_TO_UNITS(500, UNIT_0_625_MS)
52 
53 #define MIN_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS)
54 
55 #define MAX_CONN_INTERVAL MSEC_TO_UNITS(500, UNIT_1_25_MS)
56 
57 #define SLAVE_LATENCY 0
58 
59 #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
60 
61 
62 
63 
65 uint8_t h_adv;
66 
68 uint16_t h_conn;
69 
71 uint16_t h_sensepi_service;
72 
75 ble_gatts_char_handles_t h_sysinfo_char;
76 
79 ble_gatts_char_handles_t h_config_char;
80 
82 void (* sensepi_ble_sd_evt)(ble_evt_t * evt);
84 void (* sensepi_config_t_update)(sensepi_config_t * cfg);
85 
86 sensepi_sysinfo curr_sysinfo;
87 
90 void SWI1_IRQHandler(void)
91 {
92 // log_printf("radio going down\n");
93 }
94 
102 static void ble_evt_handler(ble_evt_t * evt)
103 {
104  uint32_t err_code;
105  switch(evt->header.evt_id)
106  {
107  case BLE_GAP_EVT_CONNECTED:
108  h_conn = evt->evt.gap_evt.conn_handle;
109  break;
110  case BLE_GAP_EVT_DISCONNECTED:
111  h_conn = BLE_CONN_HANDLE_INVALID;
112  break;
113  case BLE_GATTS_EVT_WRITE:
114  {
115  sensepi_config_t * config =
116  (sensepi_config_t *) evt->evt.gatts_evt.params.write.data;
117  sensepi_config_t_update(config);
118  break;
119  }
120  case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
121  {
122  uint16_t mtu_val = BLE_GATT_ATT_MTU_DEFAULT;
123  err_code = sd_ble_gatts_exchange_mtu_reply(h_conn, mtu_val);
124  APP_ERROR_CHECK(err_code);
125  break;
126  }
127  case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
128  {
129  ble_gap_phys_t const phys = {
130  .rx_phys = BLE_GAP_PHY_AUTO,
131  .tx_phys = BLE_GAP_PHY_AUTO,
132  };
133 
134  err_code = sd_ble_gap_phy_update(h_conn, &phys);
135  APP_ERROR_CHECK(err_code);
136  break;
137  }
138  case BLE_GAP_EVT_PHY_UPDATE:
139  {
140  log_printf("Tx_get : %x Rx_get : %x Status : %x\n",
141  evt->evt.gap_evt.params.phy_update.tx_phy,
142  evt->evt.gap_evt.params.phy_update.rx_phy,
143  evt->evt.gap_evt.params.phy_update.status);
144  break;
145  }
146  }
147 
148  sensepi_ble_sd_evt(evt);
149 }
150 
156 static void soc_evt_handler(uint32_t evt_id)
157 {
158  log_printf("soc evt %x\n", evt_id);
159 }
160 
161 void sensepi_ble_init(void (*ble_sd_evt)(ble_evt_t * evt),
162  void (* config_update)(sensepi_config_t * cfg))
163 {
164  sensepi_ble_sd_evt = ble_sd_evt;
165  sensepi_config_t_update = config_update;
166 }
167 
169 {
170  if(h_conn != BLE_CONN_HANDLE_INVALID)
171  {
172  uint32_t err_code;
173  err_code = sd_ble_gap_disconnect(h_conn,
174  BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
175  APP_ERROR_CHECK(err_code);
176  }
177 }
178 
179 void sensepi_ble_update_sysinfo(sensepi_sysinfo * sysinfo)
180 {
181  uint32_t err_code;
182  ble_gatts_value_t val =
183  {
184  .len = sizeof(sensepi_sysinfo),
185  .offset = 0,
186  .p_value = (uint8_t *) sysinfo
187  };
188  err_code = sd_ble_gatts_value_set(h_conn,
189  h_sysinfo_char.value_handle, &val);
190  APP_ERROR_CHECK(err_code);
191 }
192 
193 void sensepi_ble_update_config(sensepi_config_t * config)
194 {
195  uint32_t err_code;
196  ble_gatts_value_t val =
197  {
198  .len = sizeof(sensepi_config_t),
199  .offset = 0,
200  .p_value = (uint8_t *) config
201  };
202  err_code = sd_ble_gatts_value_set(h_conn,
203  h_config_char.value_handle, &val);
204  APP_ERROR_CHECK(err_code);
205 }
206 
207 
209 {
210  uint32_t err_code;
211  const nrf_clock_lf_cfg_t cfg = BOARD_LFCLKSRC_STRUCT;
212 
213  err_code = sd_softdevice_enable(&cfg, app_error_fault_handler);
214  APP_ERROR_CHECK(err_code);
215 
216  uint32_t app_ram_start = 0x20001c00;
217  log_printf("Init %x", app_ram_start);
218  err_code = sd_ble_enable(&app_ram_start);
219  log_printf(" RAM needed %x\n", app_ram_start);
220  APP_ERROR_CHECK(err_code);
221 
222  evt_sd_handler_init(ble_evt_handler, soc_evt_handler);
223 
224  //So that the application wakes up after every radio activity
225  err_code = sd_radio_notification_cfg_set(
226  NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE,
227  NRF_RADIO_NOTIFICATION_DISTANCE_NONE);
228  APP_ERROR_CHECK(err_code);
229 
230  // Initialize Radio Notification software interrupt
231  err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
232  APP_ERROR_CHECK(err_code);
233 
234  err_code = sd_nvic_SetPriority(SWI1_IRQn, APP_IRQ_PRIORITY_LOWEST);
235  APP_ERROR_CHECK(err_code);
236 
237  err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
238  APP_ERROR_CHECK(err_code);
239 
240  h_conn = BLE_CONN_HANDLE_INVALID;
241 }
242 
244 {
245  uint32_t err_code;
246  ble_uuid_t ble_uuid;
247  uint8_t uuid_type;
248 
249  /**** Create the Sense Pi service *****/
250  ble_uuid128_t base_uuid = {{SENSEPI_UUID_COMPLETE}};
251  err_code = sd_ble_uuid_vs_add(&base_uuid, &uuid_type);
252  APP_ERROR_CHECK(err_code);
253 
254  ble_uuid.type = uuid_type;
255  ble_uuid.uuid = SENSEPI_UUID_SERVICE;
256 
257  err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
258  &ble_uuid, &h_sensepi_service);
259  APP_ERROR_CHECK(err_code);
260 
261  /**** Create the read-only characteristic *****/
262  ble_gatts_char_md_t char_md;
263  ble_gatts_attr_t attr_char_value;
264  ble_gatts_attr_md_t attr_md;
265 
266  memset(&char_md, 0, sizeof(char_md));
267 
268  char_md.char_props.read = 1;
269  char_md.char_props.write = 0;
270  char_md.p_char_user_desc = NULL;
271  char_md.p_char_pf = NULL;
272  char_md.p_user_desc_md = NULL;
273  char_md.p_cccd_md = NULL;
274  char_md.p_sccd_md = NULL;
275 
276  ble_uuid.type = uuid_type;
277  ble_uuid.uuid = (SENSEPI_UUID_SYSINFO);
278 
279  memset(&attr_md, 0, sizeof(attr_md));
280 
281  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
282  BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
283  attr_md.vloc = BLE_GATTS_VLOC_STACK;
284  attr_md.rd_auth = 0;
285  attr_md.wr_auth = 0;
286  attr_md.vlen = 0;
287 
288  memset(&attr_char_value, 0, sizeof(attr_char_value));
289 
290  attr_char_value.p_uuid = &ble_uuid;
291  attr_char_value.p_attr_md = &attr_md;
292  attr_char_value.init_len = sizeof(sensepi_sysinfo);
293  attr_char_value.init_offs = 0;
294  attr_char_value.max_len = sizeof(sensepi_sysinfo);
295  attr_char_value.p_value = NULL;
296 
297  err_code = sd_ble_gatts_characteristic_add(
298  h_sensepi_service, &char_md, &attr_char_value, &h_sysinfo_char);
299  APP_ERROR_CHECK(err_code);
300 
301  /**** Create the read-write characterisitc *****/
302  memset(&char_md, 0, sizeof(char_md));
303 
304  char_md.char_props.read = 1;
305  char_md.char_props.write = 1;
306  char_md.p_char_user_desc = NULL;
307  char_md.p_char_pf = NULL;
308  char_md.p_user_desc_md = NULL;
309  char_md.p_cccd_md = NULL;
310  char_md.p_sccd_md = NULL;
311 
312  ble_uuid.type = uuid_type;
313  ble_uuid.uuid = (SENSEPI_UUID_CONFIG);
314 
315  memset(&attr_md, 0, sizeof(attr_md));
316 
317  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
318  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
319  attr_md.vloc = BLE_GATTS_VLOC_STACK;
320  attr_md.rd_auth = 0;
321  attr_md.wr_auth = 0;
322  attr_md.vlen = 0;
323 
324  memset(&attr_char_value, 0, sizeof(attr_char_value));
325 
326  attr_char_value.p_uuid = &ble_uuid;
327  attr_char_value.p_attr_md = &attr_md;
328  attr_char_value.init_len = sizeof(sensepi_config_t);
329  attr_char_value.init_offs = 0;
330  attr_char_value.max_len = sizeof(sensepi_config_t);
331  attr_char_value.p_value = NULL;
332 
333  err_code = sd_ble_gatts_characteristic_add(
334  h_sensepi_service, &char_md, &attr_char_value,&h_config_char);
335  APP_ERROR_CHECK(err_code);
336 }
337 
339 {
340  uint32_t err_code;
341  ble_gap_conn_params_t gap_conn_params;
342  ble_gap_conn_sec_mode_t sec_mode;
343 
344  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
345 
346  err_code = sd_ble_gap_device_name_set(
347  &sec_mode, (const uint8_t *)device_name, sizeof(device_name));
348  APP_ERROR_CHECK(err_code);
349 
350  memset(&gap_conn_params, 0, sizeof(gap_conn_params));
351 
352  gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
353  gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
354  gap_conn_params.slave_latency = SLAVE_LATENCY;
355  gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
356 
357  err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
358  APP_ERROR_CHECK(err_code);
359 }
360 
361 void sensepi_ble_adv_init(sensepi_ble_adv_data_t * sensepi_ble_adv_data)
362 {
363  h_adv = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
364  uint32_t err_code;
365 
366  ble_gap_adv_data_t adv_payload;
367 
368  adv_payload.adv_data.p_data = sensepi_ble_adv_data->adv_data;
369  adv_payload.adv_data.len = sensepi_ble_adv_data->adv_len;
370 
371  adv_payload.scan_rsp_data.p_data = sensepi_ble_adv_data->scan_rsp_data;
372  adv_payload.scan_rsp_data.len = sensepi_ble_adv_data->scan_rsp_len;
373 
374  ble_gap_adv_params_t adv_params;
375 
376  memset(&adv_params, 0, sizeof(adv_params));
377 
378  //Set channel 37, 38 and 39 as advertising channels
379  memset(adv_params.channel_mask, 0, 5);
380 
381  //Set the advertising to timeout in 180s
382  adv_params.duration = BLE_GAP_ADV_TIMEOUT_LIMITED_MAX;
383 
384  //Any device can scan request and connect
385  adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
386 
387  //Period between sending advertising packets
388  adv_params.interval = ADVERTISING_INTERVAL;
389 
390  //Use 1Mbps physical layer to be backward compatible
391  adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
392 
393  //The advertisement would be unidirected connectable and scannable
394  adv_params.properties.type =
395  BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
396 
397  adv_params.p_peer_addr = NULL;
398  adv_params.scan_req_notification = 0;
399 
400  err_code = sd_ble_gap_adv_set_configure(&h_adv,
401  (ble_gap_adv_data_t const *)&adv_payload,
402  (ble_gap_adv_params_t const *) &adv_params);
403  APP_ERROR_CHECK(err_code);
404 }
405 
407 {
408  uint32_t err_code;
409  err_code = sd_ble_gap_adv_start(h_adv, BLE_CONN_CFG_TAG_DEFAULT);
410  APP_ERROR_CHECK(err_code);
411 }
412 
void sensepi_ble_update_sysinfo(sensepi_sysinfo *sysinfo)
Updates the characteristic that stores the sysinfo.
Definition: sensepi_ble.c:179
void sensepi_ble_gap_params_init(void)
Generic Access Profile initialization. The device name, and the preferred connection parameters are s...
Definition: sensepi_ble.c:338
void sensepi_ble_stack_init(void)
Function for initializing the BLE stack by enabling the SoftDevice and the BLE event interrupt.
Definition: sensepi_ble.c:208
void sensepi_ble_adv_start(void)
Function to start advertising.
Definition: sensepi_ble.c:406
void sensepi_ble_service_init(void)
Create the Service and its characteristics for the SensePi device. There is a read-only characteristi...
Definition: sensepi_ble.c:243
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.
void sensepi_ble_init(void(*ble_sd_evt)(ble_evt_t *evt), void(*config_update)(sensepi_config_t *cfg))
Initialize the handlers to pass the BLE SD events and the configuration received from the mobile app.
Definition: sensepi_ble.c:161
void sensepi_ble_update_config(sensepi_config_t *config)
Updates the characteristic that stores the SensePi config.
Definition: sensepi_ble.c:193
#define BOARD_LFCLKSRC_STRUCT
Definition: bluey_1v1.h:122
#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 sensepi_ble_disconn(void)
Disconnect the current active connection, if already connected.
Definition: sensepi_ble.c:168
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 sensepi_ble_adv_init(sensepi_ble_adv_data_t *sensepi_ble_adv_data)
Function to initializing the advertising.
Definition: sensepi_ble.c:361