1 /**
2 * Copyright (c) 2024 Croxel, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/bluetooth/bluetooth.h>
9 #include <zephyr/bluetooth/conn.h>
10 #include <zephyr/bluetooth/hci.h>
11
12 #define NAME_LEN 30
13
14 static struct bt_conn *default_conn;
15 bt_addr_le_t ext_addr;
16
17 enum bt_sample_scan_evt {
18 BT_SAMPLE_EVT_EXT_ADV_FOUND,
19 BT_SAMPLE_EVT_CONNECTED,
20 BT_SAMPLE_EVT_DISCONNECTED,
21 BT_SAMPLE_EVT_SCAN_DUE,
22 BT_SAMPLE_EVT_MAX,
23 };
24
25 enum bt_sample_scan_st {
26 BT_SAMPLE_ST_SCANNING,
27 BT_SAMPLE_ST_CONNECTING,
28 BT_SAMPLE_ST_CONNECTED,
29 BT_SAMPLE_ST_COOLDOWN,
30 };
31
32 static volatile enum bt_sample_scan_st app_st = BT_SAMPLE_ST_SCANNING;
33
34 static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX);
35
36 static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig);
37 static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
38 K_POLL_MODE_NOTIFY_ONLY, &poll_sig);
39
raise_evt(enum bt_sample_scan_evt evt)40 static void raise_evt(enum bt_sample_scan_evt evt)
41 {
42 (void)atomic_set_bit(evt_bitmask, evt);
43 k_poll_signal_raise(poll_evt.signal, 1);
44 }
45
connected_cb(struct bt_conn * conn,uint8_t err)46 static void connected_cb(struct bt_conn *conn, uint8_t err)
47 {
48 printk("Connected (err 0x%02X)\n", err);
49
50 if (err) {
51 bt_conn_unref(default_conn);
52 default_conn = NULL;
53 return;
54 }
55
56 raise_evt(BT_SAMPLE_EVT_CONNECTED);
57 }
58
disconnected_cb(struct bt_conn * conn,uint8_t reason)59 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
60 {
61 bt_conn_unref(default_conn);
62 default_conn = NULL;
63
64 printk("Disconnected, reason 0x%02X %s\n", reason, bt_hci_err_to_str(reason));
65 }
66
recycled_cb(void)67 static void recycled_cb(void)
68 {
69 printk("Connection object available from previous conn. Disconnect is complete!\n");
70 raise_evt(BT_SAMPLE_EVT_DISCONNECTED);
71 }
72
73 BT_CONN_CB_DEFINE(conn_cb) = {
74 .connected = connected_cb,
75 .disconnected = disconnected_cb,
76 .recycled = recycled_cb,
77 };
78
79
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)80 static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
81 {
82 if (info->adv_type == BT_GAP_ADV_TYPE_EXT_ADV &&
83 info->adv_props & BT_GAP_ADV_PROP_EXT_ADV &&
84 info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
85 /* Attempt connection request for device with extended advertisements */
86 memcpy(&ext_addr, info->addr, sizeof(ext_addr));
87 raise_evt(BT_SAMPLE_EVT_EXT_ADV_FOUND);
88 }
89 }
90
91 static struct bt_le_scan_cb scan_callbacks = {
92 .recv = scan_recv,
93 };
94
attempt_connection(void)95 static inline int attempt_connection(void)
96 {
97 int err;
98
99 printk("Stopping scan\n");
100 err = bt_le_scan_stop();
101 if (err) {
102 printk("Failed to stop scan: %d\n", err);
103 return err;
104 }
105
106 err = bt_conn_le_create(&ext_addr, BT_CONN_LE_CREATE_CONN,
107 BT_LE_CONN_PARAM_DEFAULT, &default_conn);
108 if (err) {
109 printk("Failed to establish conn: %d\n", err);
110 return err;
111 }
112
113 return 0;
114 }
115
start_scanning(void)116 static inline int start_scanning(void)
117 {
118 int err;
119
120 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
121 if (err) {
122 printk("failed (err %d)\n", err);
123 }
124
125 return err;
126 }
127
main(void)128 int main(void)
129 {
130 int err;
131
132 printk("Starting Extended Advertising Demo [Scanner]\n");
133
134 /* Initialize the Bluetooth Subsystem */
135 err = bt_enable(NULL);
136 if (err) {
137 printk("Bluetooth init failed (err %d)\n", err);
138 return 0;
139 }
140
141 bt_le_scan_cb_register(&scan_callbacks);
142
143 err = start_scanning();
144 if (err) {
145 return err;
146 }
147
148 while (true) {
149 (void)k_poll(&poll_evt, 1, K_FOREVER);
150
151 k_poll_signal_reset(poll_evt.signal);
152 poll_evt.state = K_POLL_STATE_NOT_READY;
153
154 /* Identify event and act upon if applicable */
155 if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_EXT_ADV_FOUND) &&
156 app_st == BT_SAMPLE_ST_SCANNING) {
157
158 printk("Found extended advertisement packet!\n");
159 app_st = BT_SAMPLE_ST_CONNECTING;
160 err = attempt_connection();
161 if (err) {
162 return err;
163 }
164
165 } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) &&
166 (app_st == BT_SAMPLE_ST_CONNECTING)) {
167
168 printk("Connected state!\n");
169 app_st = BT_SAMPLE_ST_CONNECTED;
170
171 } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) &&
172 (app_st == BT_SAMPLE_ST_CONNECTED)) {
173
174 printk("Disconnected, cooldown for 5 seconds!\n");
175 app_st = BT_SAMPLE_ST_COOLDOWN;
176
177 /* Wait a few seconds before starting to re-scan again... */
178 k_sleep(K_SECONDS(5));
179
180 raise_evt(BT_SAMPLE_EVT_SCAN_DUE);
181
182 } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_SCAN_DUE) &&
183 (app_st == BT_SAMPLE_ST_COOLDOWN)) {
184
185 printk("Starting to scan for extended adv\n");
186 app_st = BT_SAMPLE_ST_SCANNING;
187 err = start_scanning();
188 if (err) {
189 return err;
190 }
191
192 }
193 }
194
195 return 0;
196 }
197