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