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