1 /*
2  * Copyright (c) 2022 Michal Morsisko
3  * Copyright (c) 2015-2016 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/sys/reboot.h>
15 #include <zephyr/settings/settings.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/conn.h>
19 #include <zephyr/bluetooth/uuid.h>
20 #include <zephyr/bluetooth/gatt.h>
21 
22 /* Custom Service Variables */
23 #define BT_UUID_CUSTOM_SERVICE_VAL \
24 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)
25 
26 static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128(
27 	BT_UUID_CUSTOM_SERVICE_VAL);
28 
29 static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128(
30 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1));
31 
32 static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128(
33 	BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2));
34 
35 static int stored_value;
36 static struct bt_le_adv_param adv_param;
37 static bt_addr_le_t bond_addr;
38 
read_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)39 static ssize_t read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
40 		       uint16_t len, uint16_t offset)
41 {
42 	int *value = &stored_value;
43 
44 	return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
45 				 sizeof(stored_value));
46 }
47 
write_cb(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)48 static ssize_t write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
49 			uint16_t len, uint16_t offset, uint8_t flags)
50 {
51 	int *value = &stored_value;
52 
53 	if (offset + len > sizeof(stored_value)) {
54 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
55 	}
56 
57 	memcpy(value + offset, buf, len);
58 
59 	return len;
60 }
61 
62 /* Vendor Primary Service Declaration */
63 BT_GATT_SERVICE_DEFINE(primary_service,
64 	BT_GATT_PRIMARY_SERVICE(&primary_service_uuid),
65 	BT_GATT_CHARACTERISTIC(&read_characteristic_uuid.uuid,
66 			       BT_GATT_CHRC_READ,
67 			       BT_GATT_PERM_READ,
68 			       read_cb, NULL, NULL),
69 	BT_GATT_CHARACTERISTIC(&write_characteristic_uuid.uuid,
70 			       BT_GATT_CHRC_WRITE,
71 			       BT_GATT_PERM_WRITE_ENCRYPT,
72 			       NULL, write_cb, NULL),
73 );
74 
75 static const struct bt_data ad[] = {
76 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
77 	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL),
78 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
79 };
80 
connected(struct bt_conn * conn,uint8_t err)81 static void connected(struct bt_conn *conn, uint8_t err)
82 {
83 	if (err) {
84 		printk("Connection failed err 0x%02x %s\n", err, bt_hci_err_to_str(err));
85 	} else {
86 		printk("Connected\n");
87 	}
88 }
89 
disconnected(struct bt_conn * conn,uint8_t reason)90 static void disconnected(struct bt_conn *conn, uint8_t reason)
91 {
92 	printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
93 }
94 
95 BT_CONN_CB_DEFINE(conn_callbacks) = {
96 	.connected = connected,
97 	.disconnected = disconnected
98 };
99 
copy_last_bonded_addr(const struct bt_bond_info * info,void * data)100 static void copy_last_bonded_addr(const struct bt_bond_info *info, void *data)
101 {
102 	bt_addr_le_copy(&bond_addr, &info->addr);
103 }
104 
bt_ready(void)105 static void bt_ready(void)
106 {
107 	int err;
108 	char addr[BT_ADDR_LE_STR_LEN];
109 
110 	printk("Bluetooth initialized\n");
111 
112 	if (IS_ENABLED(CONFIG_SETTINGS)) {
113 		settings_load();
114 	}
115 
116 	bt_addr_le_copy(&bond_addr, BT_ADDR_LE_NONE);
117 	bt_foreach_bond(BT_ID_DEFAULT, copy_last_bonded_addr, NULL);
118 
119 	/* Address is equal to BT_ADDR_LE_NONE if compare returns 0.
120 	 * This means there is no bond yet.
121 	 */
122 	if (bt_addr_le_cmp(&bond_addr, BT_ADDR_LE_NONE) != 0) {
123 		bt_addr_le_to_str(&bond_addr, addr, sizeof(addr));
124 		printk("Direct advertising to %s\n", addr);
125 
126 		adv_param = *BT_LE_ADV_CONN_DIR_LOW_DUTY(&bond_addr);
127 		adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA;
128 		err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0);
129 	} else {
130 		err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
131 	}
132 
133 	if (err) {
134 		printk("Advertising failed to start (err %d)\n", err);
135 	} else {
136 		printk("Advertising successfully started\n");
137 	}
138 }
139 
pairing_complete(struct bt_conn * conn,bool bonded)140 void pairing_complete(struct bt_conn *conn, bool bonded)
141 {
142 	printk("Pairing completed. Rebooting in 5 seconds...\n");
143 
144 	k_sleep(K_SECONDS(5));
145 	sys_reboot(SYS_REBOOT_WARM);
146 }
147 
148 static struct bt_conn_auth_info_cb bt_conn_auth_info = {
149 	.pairing_complete = pairing_complete
150 };
151 
main(void)152 int main(void)
153 {
154 	int err;
155 
156 	err = bt_enable(NULL);
157 	if (err) {
158 		printk("Bluetooth init failed (err %d)\n", err);
159 		return 0;
160 	}
161 
162 	bt_ready();
163 	bt_conn_auth_info_cb_register(&bt_conn_auth_info);
164 
165 	while (1) {
166 		k_sleep(K_FOREVER);
167 	}
168 	return 0;
169 }
170