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