1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2020 SixOctets Systems
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <stdio.h>
10 #include <stddef.h>
11 #include <errno.h>
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/printk.h>
15 #include <zephyr/sys/byteorder.h>
16
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/hci.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/uuid.h>
21 #include <zephyr/bluetooth/gatt.h>
22
23 static int scan_start(void);
24
25 static struct bt_conn *default_conn;
26 static struct bt_uuid_16 discover_uuid = BT_UUID_INIT_16(0);
27 static struct bt_gatt_discover_params discover_params;
28 static struct bt_gatt_subscribe_params subscribe_params;
29
pow(double x,double y)30 static double pow(double x, double y)
31 {
32 double result = 1;
33
34 if (y < 0) {
35 y = -y;
36 while (y--) {
37 result /= x;
38 }
39 } else {
40 while (y--) {
41 result *= x;
42 }
43 }
44
45 return result;
46 }
47
notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)48 static uint8_t notify_func(struct bt_conn *conn,
49 struct bt_gatt_subscribe_params *params,
50 const void *data, uint16_t length)
51 {
52 double temperature;
53 uint32_t mantissa;
54 int8_t exponent;
55
56 if (!data) {
57 printk("[UNSUBSCRIBED]\n");
58 params->value_handle = 0U;
59 return BT_GATT_ITER_STOP;
60 }
61
62 /* temperature value display */
63 mantissa = sys_get_le24(&((uint8_t *)data)[1]);
64 exponent = ((uint8_t *)data)[4];
65 temperature = (double)mantissa * pow(10, exponent);
66
67 printf("Temperature %gC.\n", temperature);
68
69 return BT_GATT_ITER_CONTINUE;
70 }
71
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)72 static uint8_t discover_func(struct bt_conn *conn,
73 const struct bt_gatt_attr *attr,
74 struct bt_gatt_discover_params *params)
75 {
76 int err;
77
78 if (!attr) {
79 printk("Discover complete\n");
80 (void)memset(params, 0, sizeof(*params));
81 return BT_GATT_ITER_STOP;
82 }
83
84 printk("[ATTRIBUTE] handle %u\n", attr->handle);
85
86 if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HTS)) {
87 memcpy(&discover_uuid, BT_UUID_HTS_MEASUREMENT, sizeof(discover_uuid));
88 discover_params.uuid = &discover_uuid.uuid;
89 discover_params.start_handle = attr->handle + 1;
90 discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
91
92 err = bt_gatt_discover(conn, &discover_params);
93 if (err) {
94 printk("Discover failed (err %d)\n", err);
95 }
96 } else if (!bt_uuid_cmp(discover_params.uuid,
97 BT_UUID_HTS_MEASUREMENT)) {
98 memcpy(&discover_uuid, BT_UUID_GATT_CCC, sizeof(discover_uuid));
99 discover_params.uuid = &discover_uuid.uuid;
100 discover_params.start_handle = attr->handle + 2;
101 discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
102 subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
103
104 err = bt_gatt_discover(conn, &discover_params);
105 if (err) {
106 printk("Discover failed (err %d)\n", err);
107 }
108 } else {
109 subscribe_params.notify = notify_func;
110 subscribe_params.value = BT_GATT_CCC_INDICATE;
111 subscribe_params.ccc_handle = attr->handle;
112
113 err = bt_gatt_subscribe(conn, &subscribe_params);
114 if (err && err != -EALREADY) {
115 printk("Subscribe failed (err %d)\n", err);
116 } else {
117 printk("[SUBSCRIBED]\n");
118 }
119
120 return BT_GATT_ITER_STOP;
121 }
122
123 return BT_GATT_ITER_STOP;
124 }
125
connected(struct bt_conn * conn,uint8_t conn_err)126 static void connected(struct bt_conn *conn, uint8_t conn_err)
127 {
128 char addr[BT_ADDR_LE_STR_LEN];
129 int err;
130
131 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
132
133 if (conn_err) {
134 printk("Failed to connect to %s (%u)\n", addr, conn_err);
135
136 bt_conn_unref(default_conn);
137 default_conn = NULL;
138
139 scan_start();
140 return;
141 }
142
143 printk("Connected: %s\n", addr);
144
145 if (conn == default_conn) {
146 memcpy(&discover_uuid, BT_UUID_HTS, sizeof(discover_uuid));
147 discover_params.uuid = &discover_uuid.uuid;
148 discover_params.func = discover_func;
149 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
150 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
151 discover_params.type = BT_GATT_DISCOVER_PRIMARY;
152
153 err = bt_gatt_discover(default_conn, &discover_params);
154 if (err) {
155 printk("Discover failed(err %d)\n", err);
156 return;
157 }
158 }
159 }
160
eir_found(struct bt_data * data,void * user_data)161 static bool eir_found(struct bt_data *data, void *user_data)
162 {
163 bt_addr_le_t *addr = user_data;
164 int i;
165
166 printk("[AD]: %u data_len %u\n", data->type, data->data_len);
167
168 switch (data->type) {
169 case BT_DATA_UUID16_SOME:
170 case BT_DATA_UUID16_ALL:
171 if (data->data_len % sizeof(uint16_t) != 0U) {
172 printk("AD malformed\n");
173 return true;
174 }
175
176 for (i = 0; i < data->data_len; i += sizeof(uint16_t)) {
177 const struct bt_uuid *uuid;
178 uint16_t u16;
179 int err;
180
181 memcpy(&u16, &data->data[i], sizeof(u16));
182 uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
183 if (bt_uuid_cmp(uuid, BT_UUID_HTS)) {
184 continue;
185 }
186
187 err = bt_le_scan_stop();
188 if (err) {
189 printk("Stop LE scan failed (err %d)\n", err);
190 continue;
191 }
192
193 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
194 BT_LE_CONN_PARAM_DEFAULT,
195 &default_conn);
196 if (err) {
197 printk("Create connection failed (err %d)\n",
198 err);
199 scan_start();
200 }
201
202 return false;
203 }
204 }
205
206 return true;
207 }
208
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)209 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
210 struct net_buf_simple *ad)
211 {
212 char dev[BT_ADDR_LE_STR_LEN];
213
214 bt_addr_le_to_str(addr, dev, sizeof(dev));
215 printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
216 dev, type, ad->len, rssi);
217
218 /* We're only interested in connectable events */
219 if (type == BT_HCI_ADV_IND || type == BT_HCI_ADV_DIRECT_IND) {
220 bt_data_parse(ad, eir_found, (void *)addr);
221 }
222 }
223
scan_start(void)224 static int scan_start(void)
225 {
226 /* Use active scanning and disable duplicate filtering to handle any
227 * devices that might update their advertising data at runtime.
228 */
229 struct bt_le_scan_param scan_param = {
230 .type = BT_LE_SCAN_TYPE_ACTIVE,
231 .options = BT_LE_SCAN_OPT_NONE,
232 .interval = BT_GAP_SCAN_FAST_INTERVAL,
233 .window = BT_GAP_SCAN_FAST_WINDOW,
234 };
235
236 return bt_le_scan_start(&scan_param, device_found);
237 }
238
disconnected(struct bt_conn * conn,uint8_t reason)239 static void disconnected(struct bt_conn *conn, uint8_t reason)
240 {
241 char addr[BT_ADDR_LE_STR_LEN];
242 int err;
243
244 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
245
246 printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
247
248 if (default_conn != conn) {
249 return;
250 }
251
252 bt_conn_unref(default_conn);
253 default_conn = NULL;
254
255 err = scan_start();
256 if (err) {
257 printk("Scanning failed to start (err %d)\n", err);
258 }
259 }
260
261 BT_CONN_CB_DEFINE(conn_callbacks) = {
262 .connected = connected,
263 .disconnected = disconnected,
264 };
265
main(void)266 int main(void)
267 {
268 int err;
269
270 err = bt_enable(NULL);
271 if (err) {
272 printk("Bluetooth init failed (err %d)\n", err);
273 return 0;
274 }
275
276 printk("Bluetooth initialized\n");
277
278 err = scan_start();
279
280 if (err) {
281 printk("Scanning failed to start (err %d)\n", err);
282 return 0;
283 }
284
285 printk("Scanning successfully started\n");
286 return 0;
287 }
288