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