1 /**
2 * Copyright (c) 2024 Croxel, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/bluetooth.h>
8 #include <zephyr/bluetooth/conn.h>
9 #include <zephyr/bluetooth/gap.h>
10 #include <zephyr/bluetooth/hci.h>
11
12 static struct bt_conn *default_conn;
13
14 enum bt_sample_adv_evt {
15 BT_SAMPLE_EVT_CONNECTED,
16 BT_SAMPLE_EVT_DISCONNECTED,
17 BT_SAMPLE_EVT_MAX,
18 };
19
20 enum bt_sample_adv_st {
21 BT_SAMPLE_ST_ADV,
22 BT_SAMPLE_ST_CONNECTED,
23 };
24
25 static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX);
26
27 static volatile enum bt_sample_adv_st app_st = BT_SAMPLE_ST_ADV;
28
29 static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig);
30 static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
31 K_POLL_MODE_NOTIFY_ONLY, &poll_sig);
32
raise_evt(enum bt_sample_adv_evt evt)33 static void raise_evt(enum bt_sample_adv_evt evt)
34 {
35 (void)atomic_set_bit(evt_bitmask, evt);
36 k_poll_signal_raise(poll_evt.signal, 1);
37 }
38
connected_cb(struct bt_conn * conn,uint8_t err)39 static void connected_cb(struct bt_conn *conn, uint8_t err)
40 {
41 printk("Connected (err 0x%02X)\n", err);
42
43 if (err) {
44 return;
45 }
46
47 __ASSERT(!default_conn, "Attempting to override existing connection object!");
48 default_conn = bt_conn_ref(conn);
49
50 raise_evt(BT_SAMPLE_EVT_CONNECTED);
51 }
52
disconnected_cb(struct bt_conn * conn,uint8_t reason)53 static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
54 {
55 printk("Disconnected, reason 0x%02X %s\n", reason, bt_hci_err_to_str(reason));
56
57 __ASSERT(conn == default_conn, "Unexpected disconnected callback");
58
59 bt_conn_unref(default_conn);
60 default_conn = NULL;
61 }
62
recycled_cb(void)63 static void recycled_cb(void)
64 {
65 printk("Connection object available from previous conn. Disconnect is complete!\n");
66 raise_evt(BT_SAMPLE_EVT_DISCONNECTED);
67 }
68
69 BT_CONN_CB_DEFINE(conn_cb) = {
70 .connected = connected_cb,
71 .disconnected = disconnected_cb,
72 .recycled = recycled_cb,
73 };
74
start_advertising(struct bt_le_ext_adv * adv)75 static int start_advertising(struct bt_le_ext_adv *adv)
76 {
77 int err;
78
79 printk("Starting Extended Advertising\n");
80 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
81 if (err) {
82 printk("Failed to start extended advertising (err %d)\n", err);
83 }
84
85 return err;
86 }
87
88 static const struct bt_data ad[] = {
89 BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
90 };
91
main(void)92 int main(void)
93 {
94 int err;
95 struct bt_le_ext_adv *adv;
96
97 printk("Starting Extended Advertising Demo\n");
98
99 /* Initialize the Bluetooth Subsystem */
100 err = bt_enable(NULL);
101 if (err) {
102 printk("Bluetooth init failed (err %d)\n", err);
103 return err;
104 }
105
106 /* Create a connectable advertising set */
107 err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &adv);
108 if (err) {
109 printk("Failed to create advertising set (err %d)\n", err);
110 return err;
111 }
112
113 /* Set advertising data to have complete local name set */
114 err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
115 if (err) {
116 printk("Failed to set advertising data (err %d)\n", err);
117 return 0;
118 }
119
120 err = start_advertising(adv);
121 if (err) {
122 return err;
123 }
124
125 while (true) {
126 k_poll(&poll_evt, 1, K_FOREVER);
127
128 k_poll_signal_reset(poll_evt.signal);
129 poll_evt.state = K_POLL_STATE_NOT_READY;
130
131 /* Identify event and act upon if applicable */
132 if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) &&
133 app_st == BT_SAMPLE_ST_ADV) {
134
135 printk("Connected state!\n");
136 app_st = BT_SAMPLE_ST_CONNECTED;
137
138 printk("Initiating disconnect within 5 seconds...\n");
139 if (k_poll(&poll_evt, 1, K_SECONDS(5)) == 0) {
140 printk("Remote disconnected early...\n");
141 /* Don't clear event here as we want the loop to run immediately */
142 } else {
143 /* Connection still alive after 5 seconds, terminate it */
144 bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
145 }
146 } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) &&
147 app_st == BT_SAMPLE_ST_CONNECTED) {
148
149 printk("Disconnected state! Restarting advertising\n");
150 app_st = BT_SAMPLE_ST_ADV;
151 err = start_advertising(adv);
152 if (err) {
153 return err;
154 }
155 }
156 }
157
158 return err;
159 }
160