ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_nrf5_sdk15_communication_ble_advertising.c
Go to the documentation of this file.
1 
10 #if RUUVI_NRF5_SDK15_ADV_ENABLED
11 
12 #include "ruuvi_driver_error.h"
13 #include "ruuvi_nrf5_sdk15_error.h"
17 #include "ruuvi_interface_log.h"
18 #include "nordic_common.h"
19 #include "nrf_ble_scan.h"
20 #include "nrf_nvic.h"
21 #include "nrf_queue.h"
22 #include "nrf_soc.h"
23 #include "nrf_sdh.h"
24 #include "nrf_sdh_ble.h"
25 #include "ble_advdata.h"
26 #include "ble_types.h"
27 #include "sdk_errors.h"
28 #include "nrf_log.h"
29 
30 #include <stdint.h>
31 
32 #ifndef RUUVI_NRF5_SDK15_ADV_LOG_LEVEL
33 #define LOG_LEVEL RI_LOG_LEVEL_INFO
34 #else
35 #define LOG_LEVEL RUUVI_NRF5_SDK15_ADV_LOG_LEVEL
36 #endif
37 static inline void LOG (const char * const msg)
38 {
39  ri_log (LOG_LEVEL, msg);
40 }
41 
42 static inline void LOGD (const char * const msg)
43 {
45 }
46 
47 static inline void LOGI (const char * const msg)
48 {
50 }
51 
52 static inline void LOGW (const char * const msg)
53 {
55 }
56 
57 static inline void LOGE (const char * const msg)
58 {
60 }
61 
62 #define DEFAULT_ADV_INTERVAL_MS (1010U)
63 #define MIN_ADV_INTERVAL_MS (100U)
64 #define MAX_ADV_INTERVAL_MS (10000U)
65 #define NONEXTENDED_ADV_MAX_LEN (24U)
66 
67 #define APP_BLE_OBSERVER_PRIO 3U
68 NRF_BLE_SCAN_DEF (m_scan);
69 
70 typedef struct
71 {
72  uint8_t adv_data[RUUVI_NRF5_SDK15_ADV_LENGTH];
73  uint8_t scan_data[RUUVI_NRF5_SDK15_SCAN_LENGTH];
74  ble_gap_adv_data_t data;
75  ble_gap_adv_params_t params;
76  int8_t tx_pwr;
77 } advertisement_t;
78 
80 NRF_QUEUE_DEF (advertisement_t, m_adv_queue, RUUVI_NRF5_SDK15_ADV_QUEUE_LENGTH,
81  NRF_QUEUE_MODE_NO_OVERFLOW);
83 NRF_QUEUE_DEF (ri_comm_message_t, m_scan_queue, RUUVI_NRF5_SDK15_SCAN_QUEUE_LENGTH,
84  NRF_QUEUE_MODE_NO_OVERFLOW);
85 
86 static uint16_t
87 m_advertisement_interval_ms;
88 static uint16_t m_manufacturer_id;
89 static ri_comm_channel_t *
90 m_channel;
91 static int8_t m_tx_power;
92 static bool m_scannable;
93 static ble_gap_conn_sec_mode_t m_security;
95 static char m_name[NONEXTENDED_ADV_MAX_LEN];
97 static bool m_advertise_nus;
98 static ri_adv_type_t m_type;
99 static ri_radio_channels_t m_radio_channels;
100 static bool m_is_rx_le_1m_phy_enabled;
101 static bool m_is_rx_le_2m_phy_enabled;
102 static bool m_is_rx_le_coded_phy_enabled;
103 static uint8_t m_max_adv_length = 0;
104 
106 static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
108 static bool m_advertisement_is_init = false;
110 static bool m_advertising = false;
112 static bool m_include_service_uuid = false;
114 static uint16_t m_service_uuid = 0xFC98;
115 
117 #if RUUVI_NRF5_SDK15_GATT_ENABLED
118 #include "ble_nus.h"
119 static ble_uuid_t m_adv_uuids[] =
120 {
121  {BLE_UUID_NUS_SERVICE, BLE_UUID_TYPE_VENDOR_BEGIN}
122 };
123 #endif
124 
125 static rd_status_t prepare_tx()
126 {
127  ret_code_t nrf_code = NRF_SUCCESS;
128 
129  // XXX: Use atomic compare-and-swap
130  if (!nrf_queue_is_empty (&m_adv_queue) && !m_advertising)
131  {
132  static advertisement_t adv;
133  nrf_queue_pop (&m_adv_queue, &adv);
134  // Pointers have been invalidated in queuing, refresh.
135  adv.data.adv_data.p_data = adv.adv_data;
136 
137  if (adv.data.scan_rsp_data.len > 0)
138  {
139  adv.data.scan_rsp_data.p_data = adv.scan_data;
140  }
141 
142  nrf_code |= sd_ble_gap_adv_set_configure (&m_adv_handle,
143  &adv.data,
144  &adv.params);
145  nrf_code |= sd_ble_gap_tx_power_set (BLE_GAP_TX_POWER_ROLE_ADV,
146  m_adv_handle,
147  adv.tx_pwr);
148  nrf_code |= sd_ble_gap_adv_start (m_adv_handle,
150 
151  if (NRF_SUCCESS == nrf_code)
152  {
153  m_advertising = true;
154  }
155  else
156  {
157  // Recursion depth is limited to depth of m_adv_queue.
158  prepare_tx();
159  }
160  }
161 
162  return ruuvi_nrf5_sdk15_to_ruuvi_error (nrf_code);
163 }
164 
166 static void notify_adv_stop (const ri_comm_evt_t evt)
167 {
168  m_advertising = false; // Runs at highest app interrupt level, no need for atomic.
169 
170  if ( (NULL != m_channel) && (NULL != m_channel->on_evt))
171  {
172  m_channel->on_evt (evt, NULL, 0);
173  }
174 }
175 
176 // Register a handler for advertisement events.
177 static void ble_advertising_on_ble_evt_isr (ble_evt_t const * p_ble_evt, void * p_context)
178 {
179  switch (p_ble_evt->header.evt_id)
180  {
181  case BLE_GAP_EVT_CONNECTED:
182  nrf_queue_reset (&m_adv_queue);
183 
184  if (CONNECTABLE_SCANNABLE == m_type)
185  {
186  m_type = NONCONNECTABLE_SCANNABLE;
187  }
188 
189  if (CONNECTABLE_NONSCANNABLE == m_type)
190  {
192  }
193 
194  notify_adv_stop (RI_COMM_ABORTED);
195  break;
196 
197  case BLE_GAP_EVT_DISCONNECTED:
198  nrf_queue_reset (&m_adv_queue);
199  notify_adv_stop (RI_COMM_ABORTED);
200  break;
201 
202  // Upon terminated advertising (time-out), start next and notify application TX complete.
203  case BLE_GAP_EVT_ADV_SET_TERMINATED:
204  notify_adv_stop (RI_COMM_SENT);
205  prepare_tx();
206  break;
207 
208  default:
209  break;
210  }
211 }
212 
213 typedef struct ble_adv_mac_addr_str_t
214 {
215 #if RI_LOG_ENABLED
216  char buf[BLE_MAC_ADDRESS_LENGTH * 2 + (BLE_MAC_ADDRESS_LENGTH - 1) + 1];
217 #else
218  char buf[1];
219 #endif
220 } ble_adv_mac_addr_str_t;
221 
222 static ble_adv_mac_addr_str_t ble_adv_mac_addr_to_str (const uint8_t * const p_mac)
223 {
224  ble_adv_mac_addr_str_t mac_addr_str = {0};
225 #if RI_LOG_ENABLED
226  snprintf (mac_addr_str.buf, sizeof (mac_addr_str.buf),
227  "%02x:%02x:%02x:%02x:%02x:%02x",
228  p_mac[5], p_mac[4], p_mac[3], p_mac[2], p_mac[1], p_mac[0]);
229 #endif
230  return mac_addr_str;
231 }
232 
233 
234 NRF_SDH_BLE_OBSERVER (m_ble_observer, APP_BLE_OBSERVER_PRIO,
235  ble_advertising_on_ble_evt_isr, NULL);
236 
237 // Register a handler for scan events.
238 static void on_advertisement (scan_evt_t const * p_scan_evt)
239 {
240  switch (p_scan_evt->scan_evt_id)
241  {
242  case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
243  LOGI ("Scan timeout\r\n");
244  m_channel->on_evt (RI_COMM_TIMEOUT,
245  NULL, 0);
246  break;
247 
248  // Data which matches the configured filter - todo
249  case NRF_BLE_SCAN_EVT_FILTER_MATCH:
250  LOGD ("Matching data\r\n");
251  // p_scan_evt->params.filter_match.p_adv_report; // Data should be here
252  break;
253 
254  // All the data, pass to application
255  case NRF_BLE_SCAN_EVT_NOT_FOUND:
256  LOGD ("Unknown data\r\n");
257 
258  if ( (NULL != m_channel) && (NULL != m_channel->on_evt))
259  {
261  ri_radio_get_modulation (&modulation);
262 
263  if ( (RI_RADIO_BLE_1MBPS == modulation) && (!m_is_rx_le_1m_phy_enabled)
264  && (BLE_GAP_PHY_1MBPS == p_scan_evt->params.p_not_found->primary_phy)
265  && (BLE_GAP_PHY_NOT_SET == p_scan_evt->params.p_not_found->secondary_phy))
266  {
267  NRF_LOG_INFO (
268  "on_advertisement: 1M PHY disabled, discard adv from "
269  "addr=%s: len=%d, primary_phy=%d, secondary_phy=%d, chan=%d",
270  ble_adv_mac_addr_to_str (p_scan_evt->params.p_not_found->peer_addr.addr).buf,
271  p_scan_evt->params.p_not_found->data.len,
272  p_scan_evt->params.p_not_found->primary_phy,
273  p_scan_evt->params.p_not_found->secondary_phy,
274  p_scan_evt->params.p_not_found->ch_index);
275  break;
276  }
277 
278  // Send advertisement report
279  ri_adv_scan_t scan;
280  const uint8_t max_len = m_max_adv_length ? m_max_adv_length : sizeof (scan.data);
281 
282  if (p_scan_evt->params.p_not_found->data.len > max_len)
283  {
284  NRF_LOG_WARNING ("on_advertisement: discard adv from addr=%s: len=%d is too long (>%d)",
285  ble_adv_mac_addr_to_str (p_scan_evt->params.p_not_found->peer_addr.addr).buf,
286  p_scan_evt->params.p_not_found->data.len,
287  max_len);
288  break;
289  }
290 
291  const bool is_coded_phy = (RI_RADIO_BLE_125KBPS == modulation) ? true : false;
292  NRF_LOG_INFO (
293  "on_advertisement: recv adv from addr=%s: len=%d, "
294  "is_coded_phy=%d, primary_phy=%d, secondary_phy=%d, chan=%d",
295  ble_adv_mac_addr_to_str (p_scan_evt->params.p_not_found->peer_addr.addr).buf,
296  p_scan_evt->params.p_not_found->data.len,
297  is_coded_phy,
298  p_scan_evt->params.p_not_found->primary_phy,
299  p_scan_evt->params.p_not_found->secondary_phy,
300  p_scan_evt->params.p_not_found->ch_index);
301  scan.addr[0] = p_scan_evt->params.p_not_found->peer_addr.addr[5];
302  scan.addr[1] = p_scan_evt->params.p_not_found->peer_addr.addr[4];
303  scan.addr[2] = p_scan_evt->params.p_not_found->peer_addr.addr[3];
304  scan.addr[3] = p_scan_evt->params.p_not_found->peer_addr.addr[2];
305  scan.addr[4] = p_scan_evt->params.p_not_found->peer_addr.addr[1];
306  scan.addr[5] = p_scan_evt->params.p_not_found->peer_addr.addr[0];
307  scan.rssi = p_scan_evt->params.p_not_found->rssi;
308  scan.is_coded_phy = is_coded_phy;
309  scan.primary_phy = p_scan_evt->params.p_not_found->primary_phy;
310  scan.secondary_phy = p_scan_evt->params.p_not_found->secondary_phy;
311  scan.ch_index = p_scan_evt->params.p_not_found->ch_index;
312  scan.tx_power = p_scan_evt->params.p_not_found->tx_power;
313  memcpy (scan.data, p_scan_evt->params.p_not_found->data.p_data,
314  p_scan_evt->params.p_not_found->data.len);
315  scan.data_len = p_scan_evt->params.p_not_found->data.len;
316  nrf_queue_push (&m_scan_queue, &scan);
317  m_channel->on_evt (RI_COMM_RECEIVED,
318  &scan,
319  sizeof (ri_adv_scan_t));
320  }
321 
322  break;
323 
324  default:
325  LOGW ("Unknown event\r\n");
326  }
327 }
328 
329 NRF_SDH_BLE_OBSERVER (m_scan_observer, APP_BLE_OBSERVER_PRIO, nrf_ble_scan_on_ble_evt,
330  NULL);
331 
332 rd_status_t ri_adv_tx_interval_set (const uint32_t ms)
333 {
334  rd_status_t err_code = RD_SUCCESS;
335 
336  if (MIN_ADV_INTERVAL_MS > ms || MAX_ADV_INTERVAL_MS < ms)
337  {
338  err_code |= RD_ERROR_INVALID_PARAM;
339  }
340  else
341  {
342  m_advertisement_interval_ms = ms;
343  }
344 
345  return err_code;
346 }
347 
348 rd_status_t ri_adv_tx_interval_get (uint32_t * ms)
349 {
350  rd_status_t err_code = RD_SUCCESS;
351 
352  if (NULL == ms)
353  {
354  err_code |= RD_ERROR_NULL;
355  }
356  else
357  {
358  *ms = m_advertisement_interval_ms;
359  }
360 
361  return err_code;
362 }
363 
364 rd_status_t ri_adv_manufacturer_id_set (const uint16_t id)
365 {
366  m_manufacturer_id = id;
367  return RD_SUCCESS;
368 }
369 
371 {
372  m_radio_channels = channels;
373  return RD_SUCCESS;
374 }
375 
376 static rd_status_t format_adv (const ri_comm_message_t * const p_message,
377  advertisement_t * const p_adv)
378 {
379  rd_status_t err_code = RD_SUCCESS;
380 
381  if ( (NULL == p_message) || (NULL == p_adv))
382  {
383  err_code |= RD_ERROR_NULL;
384  }
385  else
386  {
387  // Build specification for data into ble_advdata_t advdata
388  ble_advdata_t advdata = {0};
389  // Only valid flag
390  uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED
391  | BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE;
392  // Build manufacturer specific data
393  ble_advdata_manuf_data_t manuf_specific_data = {0};
394  // Build UUID data
395  ble_uuid_t m_adv_uuids[] =
396  {
397  {m_service_uuid, BLE_UUID_TYPE_BLE}
398  };
399  // Preserve const of data passed to us.
400  uint8_t manufacturer_data[RI_COMM_MESSAGE_MAX_LENGTH];
401  memcpy (manufacturer_data, p_message->data, p_message->data_length);
402  manuf_specific_data.data.p_data = manufacturer_data;
403  manuf_specific_data.data.size = p_message->data_length;
404  manuf_specific_data.company_identifier = m_manufacturer_id;
405  // Point to manufacturer data and flags set earlier
406  advdata.flags = flags;
407  advdata.p_manuf_specific_data = &manuf_specific_data;
408 
409  if (m_include_service_uuid)
410  {
411  advdata.uuids_more_available.p_uuids = m_adv_uuids;
412  advdata.uuids_more_available.uuid_cnt = 1;
413  }
414 
415  // If manufacturer data is not set, assign "UNKNOWN"
416  if (0 == m_manufacturer_id)
417  {
418  manuf_specific_data.company_identifier = 0xFFFF;
419  }
420 
421  // Encode data
422  err_code |= ruuvi_nrf5_sdk15_to_ruuvi_error (
423  ble_advdata_encode (&advdata, p_adv->data.adv_data.p_data,
424  & (p_adv->data.adv_data.len)));
425  }
426 
427  return err_code;
428 }
429 
430 static rd_status_t format_scan_rsp (advertisement_t * const p_adv)
431 {
432  rd_status_t err_code = RD_SUCCESS;
433  ble_advdata_t scanrsp = {0};
434 
435  if (NULL == p_adv)
436  {
437  err_code |= RD_ERROR_NULL;
438  }
439  // Add scan response
440  else
441  {
442  // Name will be read from the GAP data
443  scanrsp.name_type = BLE_ADVDATA_FULL_NAME;
444  uint8_t len = strlen (m_name);
445  err_code |= sd_ble_gap_device_name_set (&m_security, (uint8_t *) m_name, len);
446 
447  if (m_advertise_nus)
448  {
449 # if RUUVI_NRF5_SDK15_GATT_ENABLED
450  scanrsp.uuids_complete.uuid_cnt = 1;
451  scanrsp.uuids_complete.p_uuids = & (m_adv_uuids[0]);
452 # else
453  err_code |= RD_ERROR_NOT_SUPPORTED;
454 # endif
455  }
456 
457  // Encode data
458  err_code |= ble_advdata_encode (&scanrsp, p_adv->data.scan_rsp_data.p_data,
459  & (p_adv->data.scan_rsp_data.len));
460  }
461 
462  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
463 }
464 
465 static rd_status_t format_msg (const ri_comm_message_t * const p_message,
466  advertisement_t * const p_adv)
467 {
468  rd_status_t err_code = RD_SUCCESS;
469 
470  if ( (NULL == p_message) || (NULL == p_adv))
471  {
472  err_code |= RD_ERROR_NULL;
473  }
474  else if ( (p_message->data_length) > RI_COMM_MESSAGE_MAX_LENGTH)
475  {
476  err_code |= RD_ERROR_DATA_SIZE;
477  }
478  else
479  {
480  err_code |= format_adv (p_message, p_adv);
481 
482  if (m_scannable)
483  {
484  err_code |= format_scan_rsp (p_adv);
485  }
486  }
487 
488  return err_code;
489 }
490 
494 static rd_status_t set_phy_type (const ri_comm_message_t * const p_message,
495  advertisement_t * const p_adv)
496 {
497  rd_status_t err_code = RD_SUCCESS;
498  ri_radio_modulation_t modulation;
499  bool extended_required = false;
500  bool sec_phy_required = false;
501 
502  if ( (NULL == p_message) || (NULL == p_adv))
503  {
504  err_code |= RD_ERROR_NULL;
505  }
506  else
507  {
508  err_code |= ri_radio_get_modulation (&modulation);
509 
510  if (p_message->data_length > NONEXTENDED_ADV_MAX_LEN)
511  {
512  sec_phy_required = true;
513  extended_required = true;
514  }
515 
516  switch (modulation)
517  {
519  p_adv->params.primary_phy = BLE_GAP_PHY_CODED;
520 
521  if (sec_phy_required)
522  {
523  p_adv->params.secondary_phy = BLE_GAP_PHY_CODED;
524  }
525 
526  extended_required = true;
527  break;
528 
529  case RI_RADIO_BLE_1MBPS:
530  p_adv->params.primary_phy = BLE_GAP_PHY_1MBPS;
531 
532  if (sec_phy_required)
533  {
534  p_adv->params.secondary_phy = BLE_GAP_PHY_1MBPS;
535  }
536 
537  break;
538 
539  case RI_RADIO_BLE_2MBPS:
540  p_adv->params.primary_phy = BLE_GAP_PHY_1MBPS;
541 
542  if (sec_phy_required)
543  {
544  p_adv->params.secondary_phy = BLE_GAP_PHY_2MBPS;
545  extended_required = true;
546  }
547 
548  break;
549  }
550 
551  switch (m_type)
552  {
554  if (extended_required)
555  {
556  p_adv->params.properties.type =
557  BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
558  }
559  else
560  {
561  p_adv->params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
562  }
563 
564  break;
565 
567  if (extended_required)
568  {
569  p_adv->params.properties.type =
570  BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED;
571  }
572  else
573  {
574  p_adv->params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED;
575  }
576 
577  break;
578 
580  if (extended_required
581  && sec_phy_required
582  && p_message->data_length > NONEXTENDED_ADV_MAX_LEN)
583  {
584  // Cannot put extended payload and scan response into secondary PHY at the same time.
585  err_code |= RD_ERROR_DATA_SIZE;
586  LOGE ("Error: Too long data for a scannable packet.\r\n");
587  }
588  else
589  {
590  p_adv->params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
591  }
592 
593  break;
594 
596  if (extended_required)
597  {
598  p_adv->params.properties.type =
599  BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
600  }
601  else
602  {
603  // Cannot have non-scannable connectable event on primary PHY, fallback on extended advertisement.
604  LOGW ("Warning: Fallback to BLE 5.0 done.\r\n");
605  p_adv->params.properties.type =
606  BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
607  }
608 
609  break;
610 
611  default:
612  LOGW ("Unknown advertisement type\r\n");
613  break;
614  }
615  }
616 
617  return err_code;
618 }
619 
631 static rd_status_t ri_adv_send (ri_comm_message_t * message)
632 {
633  rd_status_t err_code = RD_SUCCESS;
634  ret_code_t nrf_code = NRF_SUCCESS;
635 
636  if (NULL == message)
637  {
638  err_code |= RD_ERROR_NULL;
639  }
640  else
641  {
642  // Create message
643  advertisement_t adv = {0};
644  adv.data.adv_data.p_data = adv.adv_data;
645  adv.data.adv_data.len = sizeof (adv.adv_data);
646 
647  if (m_scannable)
648  {
649  adv.data.scan_rsp_data.p_data = adv.scan_data;
650  adv.data.scan_rsp_data.len = sizeof (adv.scan_data);
651  }
652  else
653  {
654  adv.data.scan_rsp_data.p_data = NULL;
655  adv.data.scan_rsp_data.len = 0;
656  }
657 
658  err_code |= format_msg (message, &adv);
659  err_code |= set_phy_type (message, &adv);
660  adv.params.max_adv_evts = message->repeat_count;
661  adv.params.duration = 0; // Do not timeout, use repeat_count.
662  adv.params.filter_policy = BLE_GAP_ADV_FP_ANY;
663  adv.params.interval = MSEC_TO_UNITS (m_advertisement_interval_ms, UNIT_0_625_MS);
664  ruuvi_nrf5_sdk15_radio_channels_set (adv.params.channel_mask, m_radio_channels);
665  adv.tx_pwr = m_tx_power;
666  nrf_code |= nrf_queue_push (&m_adv_queue, &adv);
667  err_code |= prepare_tx();
668  }
669 
670  return err_code | ruuvi_nrf5_sdk15_to_ruuvi_error (nrf_code);
671 }
672 
673 static rd_status_t ri_adv_receive (ri_comm_message_t * message)
674 {
676 }
677 
678 rd_status_t ri_adv_init (ri_comm_channel_t * const channel)
679 {
680  rd_status_t err_code = RD_SUCCESS;
681 
682  if (NULL == channel)
683  {
684  err_code |= RD_ERROR_NULL;
685  }
686  else if (!ri_radio_is_init() || m_advertisement_is_init)
687  {
688  err_code |= RD_ERROR_INVALID_STATE;
689  }
690  else
691  {
692  m_advertisement_is_init = true;
693  m_channel = channel;
694  m_channel->init = ri_adv_init;
695  m_channel->uninit = ri_adv_uninit;
696  m_channel->send = ri_adv_send;
697  m_channel->read = ri_adv_receive;
698  m_scannable = false;
699  // Enable channels by default.
700  m_radio_channels.channel_37 = true;
701  m_radio_channels.channel_38 = true;
702  m_radio_channels.channel_39 = true;
703  }
704 
705  return err_code;
706 }
707 
709 {
710  rd_status_t err_code = RD_SUCCESS;
711 
712  // Stop advertising
713  if (true == m_advertising)
714  {
715  sd_ble_gap_adv_stop (m_adv_handle);
716  m_advertising = false;
717  }
718 
719  m_advertisement_is_init = false;
720  // Clear function pointers, including on event
721  memset (channel, 0, sizeof (ri_comm_channel_t));
722  m_scannable = false;
723  m_tx_power = 0;
724  // Flush TX buffer.
725  nrf_queue_reset (&m_adv_queue);
726  return err_code;
727 }
728 
729 void ri_adv_rx_ble_phy_enabled_set (const bool is_le_1m_phy_enabled,
730  const bool is_le_2m_phy_enabled,
731  const bool is_le_coded_phy_enabled)
732 {
733  m_is_rx_le_1m_phy_enabled = is_le_1m_phy_enabled;
734  m_is_rx_le_2m_phy_enabled = is_le_2m_phy_enabled;
735  m_is_rx_le_coded_phy_enabled = is_le_coded_phy_enabled;
736 }
737 
738 void ri_adv_rx_set_max_advertisement_data_length (const uint8_t max_adv_length)
739 {
740  m_max_adv_length = max_adv_length;
741 }
742 
743 rd_status_t ri_adv_scan_start (const uint32_t window_interval_ms,
744  const uint32_t window_size_ms)
745 {
746  ret_code_t status = NRF_SUCCESS;
747  rd_status_t err_code = RD_SUCCESS;
748  nrf_ble_scan_init_t scan_init_params = {0};
749  ble_gap_scan_params_t scan_params = {0};
750  uint8_t scan_phys = ruuvi_nrf5_sdk15_radio_phy_get();
751  scan_params.active = 0; // Do not scan for scan responses
752  ruuvi_nrf5_sdk15_radio_channels_set (scan_params.channel_mask, m_radio_channels);
753  scan_params.extended =
754  m_is_rx_le_2m_phy_enabled || m_is_rx_le_coded_phy_enabled;
755 #if defined(RUUVI_NRF5_SDK15_ADV_EXTENDED_ENABLED) && RUUVI_NRF5_SDK15_ADV_EXTENDED_ENABLED
756  {
757  // 2MBit/s not allowed on primary channel,
758  // extended advertisement on secondary channel is automatically
759  // scanned with all supported PHYs.
760  if (BLE_GAP_PHY_2MBPS == scan_phys)
761  {
762  scan_phys = BLE_GAP_PHY_1MBPS;
763  }
764  }
765 #endif
766  NRF_LOG_INFO ("ri_adv_scan_start: NRF modulation: 0x%02x, ext_adv=%d",
767  scan_phys, scan_params.extended);
768 
769  if (RD_SUCCESS == err_code)
770  {
771  scan_params.interval = MSEC_TO_UNITS (window_interval_ms, UNIT_0_625_MS);
772  scan_params.report_incomplete_evts = 0;
773  scan_params.scan_phys = scan_phys;
774  scan_params.window = MSEC_TO_UNITS (window_size_ms, UNIT_0_625_MS);
775  scan_params.timeout = ri_radio_num_channels_get (m_radio_channels) *
776  MSEC_TO_UNITS (window_interval_ms, UNIT_10_MS);
777  scan_init_params.p_scan_param = &scan_params;
778  status |= nrf_ble_scan_init (&m_scan, // Scan control structure
779  &scan_init_params, // Default params for NULL values.
780  on_advertisement); // Callback on data
781  status |= nrf_ble_scan_start (&m_scan);
782  }
783 
784  return ruuvi_nrf5_sdk15_to_ruuvi_error (status) | err_code;
785 }
786 
788 {
789  nrf_ble_scan_stop();
790  return RD_SUCCESS;
791 }
792 
793 rd_status_t ri_adv_tx_power_set (int8_t * dbm)
794 {
795  ret_code_t err_code = NRF_SUCCESS;
796 
797  if (NULL == dbm)
798  {
799  err_code |= NRF_ERROR_NULL;
800  }
801  else if (!m_advertisement_is_init)
802  {
803  err_code |= NRF_ERROR_INVALID_STATE;
804  }
805  else
806  {
807  if (*dbm <= -40) { m_tx_power = -40; }
808  else if (*dbm <= -20) { m_tx_power = -20; }
809  else if (*dbm <= -16) { m_tx_power = -16; }
810  else if (*dbm <= -12) { m_tx_power = -12; }
811  else if (*dbm <= -8) { m_tx_power = -8; }
812  else if (*dbm <= -4) { m_tx_power = -4; }
813  else if (*dbm <= 0) { m_tx_power = 0; }
814  else if (*dbm <= 4) { m_tx_power = 4; }
815 
816 #ifdef NRF52840_XXAA
817  else if (*dbm <= 8) { m_tx_power = 8; }
818 
819 #endif
820  else
821  {
822  err_code |= NRF_ERROR_INVALID_PARAM;
823  }
824 
825  if (RD_SUCCESS == err_code)
826  {
827  *dbm = m_tx_power;
828  }
829  }
830 
831  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
832 }
833 
834 rd_status_t ri_adv_tx_power_get (int8_t * dbm)
835 {
836  *dbm = m_tx_power;
837  return RD_SUCCESS;
838 }
839 
840 rd_status_t ri_adv_scan_response_setup (const char * const name,
841  const bool advertise_nus)
842 {
843  ret_code_t err_code = NRF_SUCCESS;
844 
845  if (NULL != name)
846  {
847  strcpy (m_name, name);
848  }
849 
850  m_scannable = true;
851  m_advertise_nus = advertise_nus;
852  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
853 }
854 
856 {
857  rd_status_t err_code = RD_SUCCESS;
858  m_type = type;
859 
860  if ( (type == NONCONNECTABLE_NONSCANNABLE)
861  || (type == CONNECTABLE_NONSCANNABLE))
862  {
863  m_scannable = false;
864  }
865  else
866  {
867  m_scannable = true;
868  }
869 
870  return err_code;
871 }
872 
874 {
875  // SD returns error if advertisement wasn't ongoing, ignore error.
876  (void) ruuvi_nrf5_sdk15_to_ruuvi_error (sd_ble_gap_adv_stop (
877  m_adv_handle));
878  m_advertising = false;
879  nrf_queue_reset (&m_adv_queue);
880  return RD_SUCCESS;
881 }
882 
883 uint16_t ri_adv_parse_manuid (uint8_t * const data,
884  const size_t data_length)
885 {
886  uint8_t * manuf_id;
887  manuf_id = ble_advdata_parse (data, data_length,
888  BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA);
889 
890  if (manuf_id == NULL)
891  {
892  return 0;
893  }
894  else
895  {
896  return (manuf_id[1] << 8 | manuf_id[0]);
897  }
898 }
899 
900 void ri_adv_enable_uuid (const bool enable_uuid)
901 {
902  m_include_service_uuid = enable_uuid;
903 }
904 
905 void ri_adv_set_service_uuid (const uint16_t uuid)
906 {
907  m_service_uuid = uuid;
908 }
909 
910 #endif
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_ERROR_NOT_IMPLEMENTED
Not implemented yet.
#define RD_ERROR_NOT_SUPPORTED
Not supported.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_DATA_SIZE
Invalid Data size.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
void ri_log(const ri_log_severity_t severity, const char *const message)
Queues messages into log.
@ RI_LOG_LEVEL_ERROR
@ RI_LOG_LEVEL_INFO
@ RI_LOG_LEVEL_DEBUG
@ RI_LOG_LEVEL_WARNING
rd_status_t ri_radio_get_modulation(ri_radio_modulation_t *const p_modulation)
Get the modulation used by application.
bool ri_radio_is_init()
Check if radio is initialized.
ri_radio_modulation_t
type of radio modulation to be used.
uint8_t ri_radio_num_channels_get(const ri_radio_channels_t channels)
Check how many radio channels are enabled.
@ RI_RADIO_BLE_1MBPS
"Normal" BLE 4 modulation
@ RI_RADIO_BLE_2MBPS
"Fast BLE". Advertising uses 1MBPS primary advertisement followed by 2 MBit/s extended advertisement.
@ RI_RADIO_BLE_125KBPS
Also known as BLE Long Range S=8.
#define RUUVI_NRF5_SDK15_BLE4_STACK_CONN_TAG
< Check if NRF_NFC is required
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
#define RI_COMM_MESSAGE_MAX_LENGTH
The maximum length for the application message for sending over BLE, which depends on whether extende...
ri_comm_evt_t
Communication event type.
@ RI_COMM_TIMEOUT
Operation timed out.
@ RI_COMM_RECEIVED
New data received, available to read with read function.
@ RI_COMM_SENT
One queued message was sent with all repetitions.
@ RI_COMM_ABORTED
Operation aborted, e.g. advertising on connection.
uint16_t ri_adv_parse_manuid(uint8_t *const data, const size_t data_length)
Parse Manufacturer ID from given Bluetooth scan data.
rd_status_t ri_adv_channels_set(const ri_radio_channels_t channels)
Set channels to use on radio. This has effect only on BLE advertising.
rd_status_t ri_adv_scan_start(const uint32_t window_interval_ms, const uint32_t window_size_ms)
setup scan window interval and window size.
ri_adv_type_t
Allowed advertisement types.
@ NONCONNECTABLE_SCANNABLE
Nonconnectable, scannable.
@ CONNECTABLE_NONSCANNABLE
Connectable, nonscannable.
@ NONCONNECTABLE_NONSCANNABLE
Nonconnectable, nonscannable.
@ CONNECTABLE_SCANNABLE
Connectable, scannable.
void ri_adv_rx_set_max_advertisement_data_length(const uint8_t max_adv_length)
Set maximum advertisement data length. This is used to limit the size of extended advertisement data.
rd_status_t ri_adv_tx_power_get(int8_t *dbm)
Get radio TX power.
rd_status_t ri_adv_manufacturer_id_set(const uint16_t id)
Set manufacturer ID of manufacturer specific advertisement.
rd_status_t ri_adv_init(ri_comm_channel_t *const channel)
Initialize Advertising module and scanning module.
rd_status_t ri_adv_scan_response_setup(const char *const name, const bool advertise_nus)
Configure advertising data with a scan response.
void ri_adv_set_service_uuid(const uint16_t uuid)
Configure Bluetooth GATT Service UUID to advertise in primary advertisement packet.
rd_status_t ri_adv_tx_interval_get(uint32_t *ms)
Getter for broadcast advertisement interval.
rd_status_t ri_adv_stop(void)
Stop ongoing advertisements.
rd_status_t ri_adv_uninit(ri_comm_channel_t *const channel)
rd_status_t ri_adv_type_set(ri_adv_type_t type)
Configure the type of advertisement.
rd_status_t ri_adv_tx_interval_set(const uint32_t ms)
rd_status_t ri_adv_tx_power_set(int8_t *dbm)
Set radio TX power.
void ri_adv_enable_uuid(const bool enable_uuid)
Set to true to enable advertising 16-bit service UUID in primary advertisement packet.
rd_status_t ri_adv_scan_stop(void)
Stop ongoing scanning.
void ri_adv_rx_ble_phy_enabled_set(const bool is_le_1m_phy_enabled, const bool is_le_2m_phy_enabled, const bool is_le_coded_phy_enabled)
Set BLE PHYs enabled or disabled for scanning.
#define LOGD(fmt,...)
bool is_coded_phy
True if Coded PHY was used.
uint8_t data[RUUVI_COMM_BLE_ADV_SCAN_LENGTH]
Full payload of the advertisement.
size_t data_len
Length of received data.
uint8_t addr[BLE_MAC_ADDRESS_LENGTH]
control API for communication via outside world
ri_comm_evt_handler_fp_t on_evt
Callback to application-level event handler, must be set in application.
ri_comm_xfer_fp_t send
Asynchronous send function.
ri_comm_init_fp_t init
Initialize and populate channel api control.
ri_comm_init_fp_t uninit
Uninitialize and depopulate channel api control.
ri_comm_xfer_fp_t read
Asynchronous read function.
Application message structure used for communication.
uint8_t data[RI_COMM_MESSAGE_MAX_LENGTH]
Data payload.
uint8_t repeat_count
Number of times to repeat the message,.
uint8_t data_length
Length of data.
Bitfield to describe related sensor data.
uint8_t channel_37
BLE channel 37, 2402 MHz.
uint8_t channel_39
BLE channel 39, 2480 MHz.
uint8_t channel_38
BLE channel 38, 2426 MHz.