1 /*
2 * Copyright (c) 2015-2016 Intel Corporation
3 * Copyright (c) 2017-2019 Oticon A/S
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <zephyr/kernel.h>
8
9 #include "bs_types.h"
10 #include "bs_tracing.h"
11 #include "time_machine.h"
12 #include "bstests.h"
13
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <errno.h>
17 #include <zephyr/sys/printk.h>
18
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/hci.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/uuid.h>
23 #include <zephyr/bluetooth/gatt.h>
24 #include <zephyr/bluetooth/services/bas.h>
25 #include <zephyr/bluetooth/services/hrs.h>
26
27 #include <zephyr/sys/byteorder.h>
28
29 static struct bt_conn *default_conn;
30
31 /*
32 * Basic connection test:
33 * We expect a central to connect to us.
34 *
35 * The thread code is mostly a copy of the peripheral_hr sample device
36 */
37
38 #define WAIT_TIME 5 /*seconds*/
39 #define WAIT_TIME_REPEAT 22 /*seconds*/
40 extern enum bst_result_t bst_result;
41 static uint8_t repeat_connect;
42
43 #define FAIL(...) \
44 do { \
45 bst_result = Failed; \
46 bs_trace_error_time_line(__VA_ARGS__); \
47 } while (0)
48
49 #define PASS(...) \
50 do { \
51 bst_result = Passed; \
52 bs_trace_info_time(1, __VA_ARGS__); \
53 } while (0)
54
test_con2_init(void)55 static void test_con2_init(void)
56 {
57 bst_ticker_set_next_tick_absolute(WAIT_TIME*1e6);
58 bst_result = In_progress;
59 }
60
test_con2_repeat_init(void)61 static void test_con2_repeat_init(void)
62 {
63 bst_ticker_set_next_tick_absolute(WAIT_TIME_REPEAT*1e6);
64 bst_result = In_progress;
65 }
66
test_con2_tick(bs_time_t HW_device_time)67 static void test_con2_tick(bs_time_t HW_device_time)
68 {
69 /*
70 * If in WAIT_TIME seconds the testcase did not already pass
71 * (and finish) we consider it failed
72 */
73 if (bst_result != Passed) {
74 FAIL("test_connect2 failed (not passed after %i seconds)\n",
75 WAIT_TIME);
76 }
77 }
78
test_con2_repeat_tick(bs_time_t HW_device_time)79 static void test_con2_repeat_tick(bs_time_t HW_device_time)
80 {
81 /*
82 * If in WAIT_TIME seconds the testcase did not already pass
83 * (and finish) we consider it failed
84 */
85 if (bst_result != Passed) {
86 FAIL("test_connect2 failed (not passed after %i seconds)\n",
87 WAIT_TIME_REPEAT);
88 }
89 }
90
91 static const struct bt_data ad[] = {
92 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
93 BT_DATA_BYTES(BT_DATA_UUID16_ALL,
94 BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
95 BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
96 BT_UUID_16_ENCODE(BT_UUID_CTS_VAL)),
97 };
98
connected(struct bt_conn * conn,uint8_t err)99 static void connected(struct bt_conn *conn, uint8_t err)
100 {
101 if (err) {
102 FAIL("Connection failed (err 0x%02x)\n", err);
103 } else {
104 default_conn = bt_conn_ref(conn);
105
106 printk("Peripheral Connected\n");
107 repeat_connect++;
108
109 if (repeat_connect >= 20) { /* We consider it passed */
110 PASS("Peripheral Repeat20 Testcase passed\n");
111 }
112 }
113 }
114
disconnected(struct bt_conn * conn,uint8_t reason)115 static void disconnected(struct bt_conn *conn, uint8_t reason)
116 {
117 printk("Peripheral disconnected (reason 0x%02x)\n", reason);
118
119 if (default_conn) {
120 bt_conn_unref(default_conn);
121 default_conn = NULL;
122 }
123 }
124
125 static struct bt_conn_cb conn_callbacks = {
126 .connected = connected,
127 .disconnected = disconnected,
128 };
129
bt_ready(void)130 static void bt_ready(void)
131 {
132 int err;
133
134 printk("Peripheral Bluetooth initialized\n");
135
136 err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
137 if (err) {
138 FAIL("Advertising failed to start (err %d)\n", err);
139 return;
140 }
141
142 printk("Advertising successfully started\n");
143 }
144
bas_notify(void)145 static void bas_notify(void)
146 {
147 uint8_t battery_level = bt_bas_get_battery_level();
148
149 battery_level--;
150
151 if (!battery_level) {
152 battery_level = 100U;
153 }
154
155 bt_bas_set_battery_level(battery_level);
156 }
157
hrs_notify(void)158 static void hrs_notify(void)
159 {
160 static uint8_t heartrate = 90U;
161
162 /* Heartrate measurements simulation */
163 heartrate++;
164 if (heartrate == 160U) {
165 heartrate = 90U;
166 }
167
168 bt_hrs_notify(heartrate);
169 }
170
test_con2_main(void)171 static void test_con2_main(void)
172 {
173 static int notify_count;
174 int err;
175
176 bt_conn_cb_register(&conn_callbacks);
177
178 err = bt_enable(NULL);
179 if (err) {
180 FAIL("Bluetooth init failed (err %d)\n", err);
181 return;
182 }
183
184 bt_ready();
185
186 /* Implement notification. At the moment there is no suitable way
187 * of starting delayed work so we do it here
188 */
189 while (1) {
190 k_sleep(K_SECONDS(1));
191
192 /* Heartrate measurements simulation */
193 hrs_notify();
194
195 /* Battery level simulation */
196 bas_notify();
197
198 if (notify_count++ == 1) { /* We consider it passed */
199 PASS("Peripheral Testcase passed\n");
200 }
201 }
202 }
203
test_con2_repeat_main(void)204 static void test_con2_repeat_main(void)
205 {
206 int err;
207
208 bt_conn_cb_register(&conn_callbacks);
209
210 err = bt_enable(NULL);
211 if (err) {
212 FAIL("Bluetooth init failed (err %d)\n", err);
213 return;
214 }
215
216 bt_ready();
217
218 while (1) {
219 k_sleep(K_SECONDS(1));
220 }
221 }
222
223 static const struct bst_test_instance test_connect[] = {
224 {
225 .test_id = "peripheral",
226 .test_descr = "Basic connection test. It expects that a "
227 "central device can be found. The test will "
228 "pass if notifications can be sent without "
229 "crash.",
230 .test_pre_init_f = test_con2_init,
231 .test_tick_f = test_con2_tick,
232 .test_main_f = test_con2_main
233 },
234 {
235 .test_id = "peripheral_repeat20",
236 .test_descr = "Multiple connections test. It expects that a "
237 "central device connects 20 times. The test will "
238 "pass if 20 connections are succeed in less than 22 seconds",
239 .test_pre_init_f = test_con2_repeat_init,
240 .test_tick_f = test_con2_repeat_tick,
241 .test_main_f = test_con2_repeat_main
242 },
243 BSTEST_END_MARKER
244 };
245
test_connect2_install(struct bst_test_list * tests)246 struct bst_test_list *test_connect2_install(struct bst_test_list *tests)
247 {
248 tests = bst_add_tests(tests, test_connect);
249 return tests;
250 }
251