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(&parameters, 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