10 #if RUUVI_NRF5_SDK15_ADV_ENABLED
18 #include "nordic_common.h"
19 #include "nrf_ble_scan.h"
21 #include "nrf_queue.h"
24 #include "nrf_sdh_ble.h"
25 #include "ble_advdata.h"
26 #include "ble_types.h"
27 #include "sdk_errors.h"
32 #ifndef RUUVI_NRF5_SDK15_ADV_LOG_LEVEL
33 #define LOG_LEVEL RI_LOG_LEVEL_INFO
35 #define LOG_LEVEL RUUVI_NRF5_SDK15_ADV_LOG_LEVEL
37 static inline void LOG (
const char *
const msg)
42 static inline void LOGD (
const char *
const msg)
47 static inline void LOGI (
const char *
const msg)
52 static inline void LOGW (
const char *
const msg)
57 static inline void LOGE (
const char *
const msg)
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)
67 #define APP_BLE_OBSERVER_PRIO 3U
68 NRF_BLE_SCAN_DEF (m_scan);
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;
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);
87 m_advertisement_interval_ms;
88 static uint16_t m_manufacturer_id;
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;
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;
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;
117 #if RUUVI_NRF5_SDK15_GATT_ENABLED
119 static ble_uuid_t m_adv_uuids[] =
121 {BLE_UUID_NUS_SERVICE, BLE_UUID_TYPE_VENDOR_BEGIN}
127 ret_code_t nrf_code = NRF_SUCCESS;
130 if (!nrf_queue_is_empty (&m_adv_queue) && !m_advertising)
132 static advertisement_t adv;
133 nrf_queue_pop (&m_adv_queue, &adv);
135 adv.data.adv_data.p_data = adv.adv_data;
137 if (adv.data.scan_rsp_data.len > 0)
139 adv.data.scan_rsp_data.p_data = adv.scan_data;
142 nrf_code |= sd_ble_gap_adv_set_configure (&m_adv_handle,
145 nrf_code |= sd_ble_gap_tx_power_set (BLE_GAP_TX_POWER_ROLE_ADV,
148 nrf_code |= sd_ble_gap_adv_start (m_adv_handle,
151 if (NRF_SUCCESS == nrf_code)
153 m_advertising =
true;
168 m_advertising =
false;
170 if ( (NULL != m_channel) && (NULL != m_channel->
on_evt))
172 m_channel->
on_evt (evt, NULL, 0);
177 static void ble_advertising_on_ble_evt_isr (ble_evt_t
const * p_ble_evt,
void * p_context)
179 switch (p_ble_evt->header.evt_id)
181 case BLE_GAP_EVT_CONNECTED:
182 nrf_queue_reset (&m_adv_queue);
197 case BLE_GAP_EVT_DISCONNECTED:
198 nrf_queue_reset (&m_adv_queue);
203 case BLE_GAP_EVT_ADV_SET_TERMINATED:
213 typedef struct ble_adv_mac_addr_str_t
220 } ble_adv_mac_addr_str_t;
222 static ble_adv_mac_addr_str_t ble_adv_mac_addr_to_str (
const uint8_t *
const p_mac)
224 ble_adv_mac_addr_str_t mac_addr_str = {0};
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]);
234 NRF_SDH_BLE_OBSERVER (m_ble_observer, APP_BLE_OBSERVER_PRIO,
235 ble_advertising_on_ble_evt_isr, NULL);
238 static void on_advertisement (scan_evt_t
const * p_scan_evt)
240 switch (p_scan_evt->scan_evt_id)
242 case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
243 LOGI (
"Scan timeout\r\n");
249 case NRF_BLE_SCAN_EVT_FILTER_MATCH:
250 LOGD (
"Matching data\r\n");
255 case NRF_BLE_SCAN_EVT_NOT_FOUND:
256 LOGD (
"Unknown data\r\n");
258 if ( (NULL != m_channel) && (NULL != m_channel->
on_evt))
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))
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);
280 const uint8_t max_len = m_max_adv_length ? m_max_adv_length :
sizeof (scan.
data);
282 if (p_scan_evt->params.p_not_found->data.len > max_len)
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,
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,
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;
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);
325 LOGW (
"Unknown event\r\n");
329 NRF_SDH_BLE_OBSERVER (m_scan_observer, APP_BLE_OBSERVER_PRIO, nrf_ble_scan_on_ble_evt,
336 if (MIN_ADV_INTERVAL_MS > ms || MAX_ADV_INTERVAL_MS < ms)
342 m_advertisement_interval_ms = ms;
358 *ms = m_advertisement_interval_ms;
366 m_manufacturer_id = id;
372 m_radio_channels = channels;
377 advertisement_t *
const p_adv)
381 if ( (NULL == p_message) || (NULL == p_adv))
388 ble_advdata_t advdata = {0};
390 uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED
391 | BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE;
393 ble_advdata_manuf_data_t manuf_specific_data = {0};
395 ble_uuid_t m_adv_uuids[] =
397 {m_service_uuid, BLE_UUID_TYPE_BLE}
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;
406 advdata.flags = flags;
407 advdata.p_manuf_specific_data = &manuf_specific_data;
409 if (m_include_service_uuid)
411 advdata.uuids_more_available.p_uuids = m_adv_uuids;
412 advdata.uuids_more_available.uuid_cnt = 1;
416 if (0 == m_manufacturer_id)
418 manuf_specific_data.company_identifier = 0xFFFF;
423 ble_advdata_encode (&advdata, p_adv->data.adv_data.p_data,
424 & (p_adv->data.adv_data.len)));
430 static rd_status_t format_scan_rsp (advertisement_t *
const p_adv)
433 ble_advdata_t scanrsp = {0};
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);
449 # if RUUVI_NRF5_SDK15_GATT_ENABLED
450 scanrsp.uuids_complete.uuid_cnt = 1;
451 scanrsp.uuids_complete.p_uuids = & (m_adv_uuids[0]);
458 err_code |= ble_advdata_encode (&scanrsp, p_adv->data.scan_rsp_data.p_data,
459 & (p_adv->data.scan_rsp_data.len));
466 advertisement_t *
const p_adv)
470 if ( (NULL == p_message) || (NULL == p_adv))
480 err_code |= format_adv (p_message, p_adv);
484 err_code |= format_scan_rsp (p_adv);
495 advertisement_t *
const p_adv)
499 bool extended_required =
false;
500 bool sec_phy_required =
false;
502 if ( (NULL == p_message) || (NULL == p_adv))
510 if (p_message->
data_length > NONEXTENDED_ADV_MAX_LEN)
512 sec_phy_required =
true;
513 extended_required =
true;
519 p_adv->params.primary_phy = BLE_GAP_PHY_CODED;
521 if (sec_phy_required)
523 p_adv->params.secondary_phy = BLE_GAP_PHY_CODED;
526 extended_required =
true;
530 p_adv->params.primary_phy = BLE_GAP_PHY_1MBPS;
532 if (sec_phy_required)
534 p_adv->params.secondary_phy = BLE_GAP_PHY_1MBPS;
540 p_adv->params.primary_phy = BLE_GAP_PHY_1MBPS;
542 if (sec_phy_required)
544 p_adv->params.secondary_phy = BLE_GAP_PHY_2MBPS;
545 extended_required =
true;
554 if (extended_required)
556 p_adv->params.properties.type =
557 BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
561 p_adv->params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
567 if (extended_required)
569 p_adv->params.properties.type =
570 BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED;
574 p_adv->params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED;
580 if (extended_required
582 && p_message->
data_length > NONEXTENDED_ADV_MAX_LEN)
586 LOGE (
"Error: Too long data for a scannable packet.\r\n");
590 p_adv->params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
596 if (extended_required)
598 p_adv->params.properties.type =
599 BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
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;
612 LOGW (
"Unknown advertisement type\r\n");
634 ret_code_t nrf_code = NRF_SUCCESS;
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);
649 adv.data.scan_rsp_data.p_data = adv.scan_data;
650 adv.data.scan_rsp_data.len =
sizeof (adv.scan_data);
654 adv.data.scan_rsp_data.p_data = NULL;
655 adv.data.scan_rsp_data.len = 0;
658 err_code |= format_msg (message, &adv);
659 err_code |= set_phy_type (message, &adv);
661 adv.params.duration = 0;
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();
692 m_advertisement_is_init =
true;
696 m_channel->
send = ri_adv_send;
697 m_channel->
read = ri_adv_receive;
713 if (
true == m_advertising)
715 sd_ble_gap_adv_stop (m_adv_handle);
716 m_advertising =
false;
719 m_advertisement_is_init =
false;
725 nrf_queue_reset (&m_adv_queue);
730 const bool is_le_2m_phy_enabled,
731 const bool is_le_coded_phy_enabled)
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;
740 m_max_adv_length = max_adv_length;
744 const uint32_t window_size_ms)
746 ret_code_t status = NRF_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;
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
760 if (BLE_GAP_PHY_2MBPS == scan_phys)
762 scan_phys = BLE_GAP_PHY_1MBPS;
766 NRF_LOG_INFO (
"ri_adv_scan_start: NRF modulation: 0x%02x, ext_adv=%d",
767 scan_phys, scan_params.extended);
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);
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,
781 status |= nrf_ble_scan_start (&m_scan);
795 ret_code_t err_code = NRF_SUCCESS;
799 err_code |= NRF_ERROR_NULL;
801 else if (!m_advertisement_is_init)
803 err_code |= NRF_ERROR_INVALID_STATE;
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; }
817 else if (*dbm <= 8) { m_tx_power = 8; }
822 err_code |= NRF_ERROR_INVALID_PARAM;
841 const bool advertise_nus)
843 ret_code_t err_code = NRF_SUCCESS;
847 strcpy (m_name, name);
851 m_advertise_nus = advertise_nus;
878 m_advertising =
false;
879 nrf_queue_reset (&m_adv_queue);
884 const size_t data_length)
887 manuf_id = ble_advdata_parse (data, data_length,
888 BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA);
890 if (manuf_id == NULL)
896 return (manuf_id[1] << 8 | manuf_id[0]);
902 m_include_service_uuid = enable_uuid;
907 m_service_uuid = uuid;
#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.
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.
#define BLE_MAC_ADDRESS_LENGTH
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.
int8_t rssi
RSSI of advertisement.
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.