1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2024 Giancarlo Stasi
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/sys/byteorder.h>
10 #include <zephyr/bluetooth/hci_vs.h>
11 #include <zephyr/bluetooth/addr.h>
12
13 BUILD_ASSERT(IS_ENABLED(CONFIG_BT_HAS_HCI_VS),
14 "This app requires Zephyr-specific HCI vendor extensions");
15
16 #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
17 #define DEVICE_NAME_LENGTH (sizeof(DEVICE_NAME) - 1)
18
19 /* Advertising Interval: the longer, the less energy consumption.
20 * Units: 0.625 milliseconds.
21 * The Minimum Advertising Interval and Maximum Advertising Interval should not be the same value
22 * (as stated in Bluetooth Core Spec 5.2, section 7.8.5)
23 */
24 #define ADV_MIN_INTERVAL BT_GAP_ADV_SLOW_INT_MIN
25 #define ADV_MAX_INTERVAL BT_GAP_ADV_SLOW_INT_MAX
26
27 #define ADV_OPTIONS (BT_LE_ADV_OPT_SCANNABLE | BT_LE_ADV_OPT_NOTIFY_SCAN_REQ)
28
29 static uint8_t scan_data[] = {'V', 'S', ' ', 'S', 'a', 'm', 'p', 'l', 'e'};
30
31 static const struct bt_le_adv_param parameters = {
32 .options = ADV_OPTIONS,
33 .interval_min = ADV_MIN_INTERVAL,
34 .interval_max = ADV_MAX_INTERVAL,
35 };
36
37 static const struct bt_data adv_data[] = {
38 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
39 BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LENGTH),
40 };
41
42 static const struct bt_data scan_rsp_data[] = {
43 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
44 BT_DATA(BT_DATA_MANUFACTURER_DATA, scan_data, sizeof(scan_data)),
45 };
46
bt_addr_le_str(const bt_addr_le_t * addr)47 static const char *bt_addr_le_str(const bt_addr_le_t *addr)
48 {
49 static char str[BT_ADDR_LE_STR_LEN];
50
51 bt_addr_le_to_str(addr, str, sizeof(str));
52
53 return str;
54 }
55
56 /* Bluetooth specification doesn't allow the scan request event with legacy advertisements.
57 * Ref: Bluetooth Core Specification v5.4, section 7.7.65.19 "LE Scan Request Received event" :
58 * "This event shall only be generated if advertising was enabled using the
59 * HCI_LE_Set_Extended_Advertising_Enable command."
60 * Added a Vendor Specific command to add this feature and save RAM.
61 */
enable_legacy_adv_scan_request_event(bool enable)62 static void enable_legacy_adv_scan_request_event(bool enable)
63 {
64 struct bt_hci_cp_vs_set_scan_req_reports *cp;
65 struct net_buf *buf;
66 int err;
67
68 buf = bt_hci_cmd_create(BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS, sizeof(*cp));
69 if (!buf) {
70 printk("%s: Unable to allocate HCI command buffer\n", __func__);
71 return;
72 }
73
74 cp = net_buf_add(buf, sizeof(*cp));
75 cp->enable = (uint8_t) enable;
76
77 err = bt_hci_cmd_send(BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS, buf);
78 if (err) {
79 printk("Set legacy cb err: %d\n", err);
80 return;
81 }
82 }
83
vs_scanned(struct net_buf_simple * buf)84 static bool vs_scanned(struct net_buf_simple *buf)
85 {
86 struct bt_hci_evt_vs_scan_req_rx *evt;
87 struct bt_hci_evt_vs *vs;
88
89 vs = net_buf_simple_pull_mem(buf, sizeof(*vs));
90 evt = (void *)buf->data;
91
92 printk("%s subevent 0x%02x peer %s rssi %d\n", __func__,
93 vs->subevent, bt_addr_le_str(&evt->addr), evt->rssi);
94
95 return true;
96 }
97
start_advertising(void)98 static int start_advertising(void)
99 {
100 int err;
101
102 err = bt_hci_register_vnd_evt_cb(vs_scanned);
103 if (err) {
104 printk("VS user callback register err %d\n", err);
105 return err;
106 }
107
108 enable_legacy_adv_scan_request_event(true);
109 err = bt_le_adv_start(¶meters, adv_data, ARRAY_SIZE(adv_data),
110 scan_rsp_data, ARRAY_SIZE(scan_rsp_data));
111 if (err) {
112 printk("Start legacy adv err %d\n", err);
113 return err;
114 }
115
116 printk("Advertising successfully started (%s)\n", CONFIG_BT_DEVICE_NAME);
117
118 return 0;
119 }
120
bt_ready(int err)121 static void bt_ready(int err)
122 {
123 if (err) {
124 printk("Bluetooth init failed (err %d)\n", err);
125 return;
126 }
127
128 printk("Bluetooth initialized\n");
129
130 err = start_advertising();
131
132 if (err) {
133 printk("Advertising failed to start (err %d)\n", err);
134 return;
135 }
136
137 printk("Vendor-Specific Scan Request sample started\n");
138 }
139
main(void)140 int main(void)
141 {
142 int err;
143
144 printk("Starting Vendor-Specific Scan Request sample\n");
145
146 /* Initialize the Bluetooth Subsystem */
147 err = bt_enable(bt_ready);
148 if (err) {
149 printk("Bluetooth init failed (err %d)\n", err);
150 }
151
152 printk("Main function end, leave stack running for scans\n");
153
154 return 0;
155 }
156