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 signed_value;
36 static struct bt_le_adv_param adv_param;
37 static bt_addr_le_t bond_addr;
38
read_signed(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)39 static ssize_t read_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr,
40 void *buf, uint16_t len, uint16_t offset)
41 {
42 int *value = &signed_value;
43
44 return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
45 sizeof(signed_value));
46 }
47
write_signed(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_signed(struct bt_conn *conn, const struct bt_gatt_attr *attr,
49 const void *buf, uint16_t len, uint16_t offset,
50 uint8_t flags)
51 {
52 int *value = &signed_value;
53
54 if (offset + len > sizeof(signed_value)) {
55 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
56 }
57
58 memcpy(value + offset, buf, len);
59
60 return len;
61 }
62
63 /* Vendor Primary Service Declaration */
64 BT_GATT_SERVICE_DEFINE(primary_service,
65 BT_GATT_PRIMARY_SERVICE(&primary_service_uuid),
66 BT_GATT_CHARACTERISTIC(&read_characteristic_uuid.uuid,
67 BT_GATT_CHRC_READ,
68 BT_GATT_PERM_READ,
69 read_signed, NULL, NULL),
70 BT_GATT_CHARACTERISTIC(&write_characteristic_uuid.uuid,
71 BT_GATT_CHRC_WRITE,
72 BT_GATT_PERM_WRITE_ENCRYPT,
73 NULL, write_signed, NULL),
74 );
75
76 static const struct bt_data ad[] = {
77 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
78 BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL),
79 BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
80 };
81
connected(struct bt_conn * conn,uint8_t err)82 static void connected(struct bt_conn *conn, uint8_t err)
83 {
84 if (err) {
85 printk("Connection failed err 0x%02x %s\n", err, bt_hci_err_to_str(err));
86 } else {
87 printk("Connected\n");
88 }
89 }
90
disconnected(struct bt_conn * conn,uint8_t reason)91 static void disconnected(struct bt_conn *conn, uint8_t reason)
92 {
93 printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
94 }
95
96 BT_CONN_CB_DEFINE(conn_callbacks) = {
97 .connected = connected,
98 .disconnected = disconnected
99 };
100
copy_last_bonded_addr(const struct bt_bond_info * info,void * data)101 static void copy_last_bonded_addr(const struct bt_bond_info *info, void *data)
102 {
103 bt_addr_le_copy(&bond_addr, &info->addr);
104 }
105
bt_ready(void)106 static void bt_ready(void)
107 {
108 int err;
109 char addr[BT_ADDR_LE_STR_LEN];
110
111 printk("Bluetooth initialized\n");
112
113 if (IS_ENABLED(CONFIG_SETTINGS)) {
114 settings_load();
115 }
116
117 bt_addr_le_copy(&bond_addr, BT_ADDR_LE_NONE);
118 bt_foreach_bond(BT_ID_DEFAULT, copy_last_bonded_addr, NULL);
119
120 /* Address is equal to BT_ADDR_LE_NONE if compare returns 0.
121 * This means there is no bond yet.
122 */
123 if (bt_addr_le_cmp(&bond_addr, BT_ADDR_LE_NONE) != 0) {
124 bt_addr_le_to_str(&bond_addr, addr, sizeof(addr));
125 printk("Direct advertising to %s\n", addr);
126
127 adv_param = *BT_LE_ADV_CONN_DIR_LOW_DUTY(&bond_addr);
128 adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA;
129 err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0);
130 } else {
131 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
132 }
133
134 if (err) {
135 printk("Advertising failed to start (err %d)\n", err);
136 } else {
137 printk("Advertising successfully started\n");
138 }
139 }
140
pairing_complete(struct bt_conn * conn,bool bonded)141 void pairing_complete(struct bt_conn *conn, bool bonded)
142 {
143 printk("Pairing completed. Rebooting in 5 seconds...\n");
144
145 k_sleep(K_SECONDS(5));
146 sys_reboot(SYS_REBOOT_WARM);
147 }
148
149 static struct bt_conn_auth_info_cb bt_conn_auth_info = {
150 .pairing_complete = pairing_complete
151 };
152
main(void)153 int main(void)
154 {
155 int err;
156
157 err = bt_enable(NULL);
158 if (err) {
159 printk("Bluetooth init failed (err %d)\n", err);
160 return 0;
161 }
162
163 bt_ready();
164 bt_conn_auth_info_cb_register(&bt_conn_auth_info);
165
166 while (1) {
167 k_sleep(K_FOREVER);
168 }
169 return 0;
170 }
171