1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "utils.h"
8 #include "gatt_utils.h"
9
10 #include <zephyr/bluetooth/addr.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/conn.h>
13 #include <zephyr/settings/settings.h>
14 #include <zephyr/toolchain.h>
15
16 #include <stdint.h>
17 #include <string.h>
18
client_round_0(void)19 void client_round_0(void)
20 {
21 struct bt_conn *conn;
22
23 printk("start round 0...........\n");
24
25 conn = connect_as_peripheral();
26 printk("connected: conn %p\n", conn);
27
28 gatt_discover();
29 activate_robust_caching();
30 /* subscribe to the SC indication, so we don't have to ATT read to
31 * become change-aware.
32 */
33 gatt_subscribe_to_service_changed(true);
34 read_test_char(true);
35
36 /* We should normally wait until we are bonded to write the CCC / CF
37 * characteristics, but here we bond after the fact on purpose, to
38 * simulate a client that has this exact behavior.
39 * The CCC and CF should still persist on reboot.
40 */
41 wait_bonded();
42
43 disconnect(conn);
44 }
45
client_round_1(void)46 void client_round_1(void)
47 {
48 struct bt_conn *conn;
49
50 printk("start round 1...........\n");
51
52 conn = connect_as_peripheral();
53 printk("connected: conn %p\n", conn);
54 wait_secured();
55
56 /* server should remember we are change-aware */
57 read_test_char(true);
58
59 disconnect(conn);
60 }
61
client_round_2(void)62 void client_round_2(void)
63 {
64 struct bt_conn *conn;
65
66 printk("start round 2...........\n");
67
68 conn = connect_as_peripheral();
69 printk("connected: conn %p\n", conn);
70 wait_secured();
71
72 /* We are change-unaware. wait until the Service Changed indication is
73 * received, that should then make us change-aware.
74 */
75 wait_for_sc_indication();
76 read_test_char(true);
77
78 /* We sleep just enough so that the server's `delayed store` work item
79 * is executed. We still trigger a disconnect, even though the server
80 * device will be unresponsive for this round.
81 */
82 k_sleep(K_MSEC(CONFIG_BT_SETTINGS_DELAYED_STORE_MS));
83
84 disconnect(conn);
85 }
86
client_round_3(void)87 void client_round_3(void)
88 {
89 struct bt_conn *conn;
90
91 printk("start round 3...........\n");
92
93 conn = connect_as_peripheral();
94 printk("connected: conn %p\n", conn);
95 wait_secured();
96
97 /* server should remember we are change-aware */
98 read_test_char(true);
99
100 /* Unsubscribe from the SC indication.
101 *
102 * In the next round, we will be change-unaware, so the first ATT read
103 * will fail, but the second one will succeed and we will be marked as
104 * change-aware again.
105 */
106 gatt_subscribe_to_service_changed(false);
107
108 disconnect(conn);
109 }
110
client_round_4(void)111 void client_round_4(void)
112 {
113 struct bt_conn *conn;
114
115 printk("start round 4...........\n");
116
117 conn = connect_as_peripheral();
118 printk("connected: conn %p\n", conn);
119 wait_secured();
120
121 /* GATT DB has changed again.
122 * Before disc: svc1
123 * After disc: svc1 + svc2
124 * At boot: svc1
125 * Expect a failure on the first read of the same GATT handle.
126 */
127 read_test_char(false);
128 read_test_char(true);
129
130 disconnect(conn);
131 }
132
client_round_5(void)133 void client_round_5(void)
134 {
135 printk("start round 5...........\n");
136 printk("don't need to do anything, central will "
137 "not connect to us\n");
138 }
139
client_round_6(void)140 void client_round_6(void)
141 {
142 struct bt_conn *conn;
143
144 printk("start round 6...........\n");
145 conn = connect_as_peripheral();
146 printk("connected: conn %p\n", conn);
147 wait_secured();
148
149 /* GATT DB has changed again.
150 * Expect a failure on the first read of the same GATT handle.
151 */
152 read_test_char(false);
153 read_test_char(true);
154
155 disconnect(conn);
156 }
157
client_procedure(void)158 void client_procedure(void)
159 {
160 bt_enable(NULL);
161 settings_load();
162
163 client_round_0();
164 client_round_1();
165 client_round_2();
166 client_round_3();
167 client_round_4();
168 client_round_5();
169 client_round_6();
170
171 PASS("PASS\n");
172 }
173