1 /*
2  * Copyright (c) 2024 Demant A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/kernel.h>
7 
8 #include "bs_types.h"
9 #include "bs_tracing.h"
10 #include "time_machine.h"
11 #include "bstests.h"
12 
13 #include <zephyr/types.h>
14 #include <stddef.h>
15 #include <errno.h>
16 
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/hci.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/uuid.h>
21 #include <zephyr/bluetooth/gatt.h>
22 #include <zephyr/bluetooth/services/bas.h>
23 #include <zephyr/sys/byteorder.h>
24 
25 #include "testlib/conn.h"
26 #include "testlib/scan.h"
27 #include "testlib/log_utils.h"
28 
29 #include "babblekit/flags.h"
30 #include "babblekit/sync.h"
31 #include "babblekit/testcase.h"
32 
33 #include <zephyr/logging/log.h>
34 LOG_MODULE_DECLARE(bt_bsim_bas, CONFIG_BT_BAS_LOG_LEVEL);
35 
36 static struct bt_conn *default_conn;
37 
38 static struct k_work_delayable update_bas_char_work;
39 
40 /*
41  * Battery Service test:
42  *   We expect a central to connect to us.
43  */
44 
45 #define WAIT_TIME 10 /*seconds*/
46 
47 extern enum bst_result_t bst_result;
48 
test_bas_peripheral_init(void)49 static void test_bas_peripheral_init(void)
50 {
51 	bst_ticker_set_next_tick_absolute(WAIT_TIME * 1e6);
52 	bst_result = In_progress;
53 }
54 
test_bas_peripheral_tick(bs_time_t HW_device_time)55 static void test_bas_peripheral_tick(bs_time_t HW_device_time)
56 {
57 	/*
58 	 * If in WAIT_TIME seconds the testcase did not already pass
59 	 * (and finish) we consider it failed
60 	 */
61 	if (bst_result != Passed) {
62 		TEST_FAIL("test_bas_peripheral failed (not passed after %i seconds)\n", WAIT_TIME);
63 	}
64 }
65 
66 static const struct bt_data ad[] = {
67 	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
68 	BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)),
69 	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
70 };
71 
connected(struct bt_conn * conn,uint8_t err)72 static void connected(struct bt_conn *conn, uint8_t err)
73 {
74 	if (err) {
75 		TEST_FAIL("Connection failed (err 0x%02x)\n", err);
76 	} else {
77 		default_conn = bt_conn_ref(conn);
78 
79 		LOG_DBG("Peripheral Connected\n");
80 	}
81 }
82 
disconnected(struct bt_conn * conn,uint8_t reason)83 static void disconnected(struct bt_conn *conn, uint8_t reason)
84 {
85 	LOG_DBG("Peripheral %s (reason 0x%02x)\n", __func__, reason);
86 
87 	if (default_conn) {
88 		bt_conn_unref(default_conn);
89 		default_conn = NULL;
90 	}
91 }
92 
93 static struct bt_conn_cb conn_callbacks = {
94 	.connected = connected,
95 	.disconnected = disconnected,
96 };
97 
bt_ready(void)98 static void bt_ready(void)
99 {
100 	int err;
101 
102 	LOG_DBG("Peripheral Bluetooth initialized\n");
103 
104 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
105 	if (err) {
106 		TEST_FAIL("Advertising failed to start (err %d)\n", err);
107 		return;
108 	}
109 
110 	LOG_DBG("Advertising successfully started");
111 }
112 
update_bas_char(void)113 static void update_bas_char(void)
114 {
115 	LOG_DBG("[PERIPHERAL] setting battery level");
116 	bt_bas_set_battery_level(90);
117 	LOG_DBG("[PERIPHERAL] setting battery present");
118 	bt_bas_bls_set_battery_present(BT_BAS_BLS_BATTERY_PRESENT);
119 	LOG_DBG("[PERIPHERAL] setting battery charge level");
120 	bt_bas_bls_set_battery_charge_level(BT_BAS_BLS_CHARGE_LEVEL_CRITICAL);
121 	LOG_DBG("[PERIPHERAL] setting battery service required true");
122 	bt_bas_bls_set_service_required(BT_BAS_BLS_SERVICE_REQUIRED_TRUE);
123 	LOG_DBG("[PERIPHERAL] setting battery service charge type ");
124 	bt_bas_bls_set_battery_charge_type(BT_BAS_BLS_CHARGE_TYPE_FLOAT);
125 }
126 
127 /* Work handler function */
update_bas_char_work_handler(struct k_work * work)128 void update_bas_char_work_handler(struct k_work *work)
129 {
130 	update_bas_char();
131 	k_work_reschedule(&update_bas_char_work, K_SECONDS(1));
132 }
133 
test_bas_peripheral_main(void)134 static void test_bas_peripheral_main(void)
135 {
136 	int err;
137 
138 	bt_conn_cb_register(&conn_callbacks);
139 
140 	/* Mark test as in progress. */
141 	TEST_START("peripheral");
142 
143 	/* Initialize device sync library */
144 	bk_sync_init();
145 
146 	/* Initialize Bluetooth */
147 	err = bt_enable(NULL);
148 	TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
149 
150 	LOG_DBG("Bluetooth initialized");
151 
152 	bt_ready();
153 
154 	/* Initialize the update bas char work handler */
155 	k_work_init_delayable(&update_bas_char_work, update_bas_char_work_handler);
156 
157 	/* Schedule the update bas char work for delayed execution */
158 	k_work_schedule(&update_bas_char_work, K_SECONDS(1));
159 
160 	/* Main thread waits for the sync signal from other device */
161 	bk_sync_wait();
162 
163 	/*
164 	 * Once BLS Additional status service required flag is set to false,
165 	 * BCS Immediate service flag is also set to false. BCS char is
166 	 * read from central.
167 	 */
168 	bt_bas_bls_set_service_required(BT_BAS_BLS_SERVICE_REQUIRED_FALSE);
169 	bk_sync_wait();
170 
171 	bst_result = Passed;
172 	TEST_PASS_AND_EXIT("Peripheral Test Passed");
173 }
174 
175 static const struct bst_test_instance test_bas_peripheral[] = {
176 	{
177 		.test_id = "peripheral",
178 		.test_descr = "Battery Service test. It expects that a central device can be found "
179 			      "The test will pass if ind/ntf can be sent without crash. ",
180 		.test_pre_init_f = test_bas_peripheral_init,
181 		.test_tick_f = test_bas_peripheral_tick,
182 		.test_main_f = test_bas_peripheral_main,
183 	},
184 	BSTEST_END_MARKER,
185 };
186 
test_bas_peripheral_install(struct bst_test_list * tests)187 struct bst_test_list *test_bas_peripheral_install(struct bst_test_list *tests)
188 {
189 	tests = bst_add_tests(tests, test_bas_peripheral);
190 	return tests;
191 }
192