1 /* Copyright (c) 2023 Nordic Semiconductor ASA
2 * SPDX-License-Identifier: Apache-2.0
3 */
4
5 #include <stdint.h>
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/kernel/thread.h>
9 #include <zephyr/net/buf.h>
10
11 #include <zephyr/logging/log.h>
12
13 #include <zephyr/ztest.h>
14 #include <zephyr/ztest_assert.h>
15 #include <zephyr/ztest_test.h>
16
17 #include <zephyr/drivers/bluetooth.h>
18 #include <zephyr/drivers/uart/serial_test.h>
19
20 LOG_MODULE_REGISTER(test, LOG_LEVEL_DBG);
21
22 /* This is a mock UART. Using `serial_vnd_...` on this simulates
23 * traffic from the external Host.
24 */
25 static const struct device *const zephyr_bt_c2h_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_c2h_uart));
26
27 /* The DUT is Sandwiched between the mock serial interface and a mock
28 * controller. {{{
29 */
30 #define DT_DRV_COMPAT zephyr_bt_hci_test
31
32 struct drv_data {
33 bt_hci_recv_t recv;
34 };
35
36 static void serial_vnd_data_callback(const struct device *dev, void *user_data);
37 static int drv_send(const struct device *dev, struct net_buf *buf);
38 static int drv_open(const struct device *dev, bt_hci_recv_t recv);
39
40 static const struct bt_hci_driver_api drv_api = {
41 .open = drv_open,
42 .send = drv_send,
43 };
44
drv_init(const struct device * dev)45 static int drv_init(const struct device *dev)
46 {
47 serial_vnd_set_callback(zephyr_bt_c2h_uart, serial_vnd_data_callback, NULL);
48 return 0;
49 }
50
51 #define TEST_DEVICE_INIT(inst) \
52 static struct drv_data drv_data_##inst = { \
53 }; \
54 DEVICE_DT_INST_DEFINE(inst, drv_init, NULL, &drv_data_##inst, NULL, \
55 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv_api)
56
57 DT_INST_FOREACH_STATUS_OKAY(TEST_DEVICE_INIT)
58
59 /* }}} */
60
61 /* Start the DUT "main thread". The settings for this thread are selected as
62 * true as possible to the real main thread. {{{
63 */
64 static struct k_thread hci_uart_thread;
65 static K_THREAD_PINNED_STACK_DEFINE(hci_uart_thread_stack, CONFIG_MAIN_STACK_SIZE);
hci_uart_thread_entry(void * p1,void * p2,void * p3)66 static void hci_uart_thread_entry(void *p1, void *p2, void *p3)
67 {
68 extern void hci_uart_main(void);
69 hci_uart_main();
70 }
sys_init_spawn_hci_uart(void)71 static int sys_init_spawn_hci_uart(void)
72 {
73 k_thread_name_set(&hci_uart_thread, "hci_uart_main");
74 k_thread_create(&hci_uart_thread, hci_uart_thread_stack,
75 K_THREAD_STACK_SIZEOF(hci_uart_thread_stack), hci_uart_thread_entry, NULL,
76 NULL, NULL, CONFIG_MAIN_THREAD_PRIORITY, 0, K_NO_WAIT);
77 return 0;
78 }
79 SYS_INIT(sys_init_spawn_hci_uart, POST_KERNEL, 64);
80 /* }}} */
81
82 /* Mock controller callbacks. {{{ */
83
drv_open(const struct device * dev,bt_hci_recv_t recv)84 static int drv_open(const struct device *dev, bt_hci_recv_t recv)
85 {
86 struct drv_data *drv = dev->data;
87
88 LOG_DBG("drv_open");
89
90 drv->recv = recv;
91
92 return 0;
93 }
94
95 /** This FIFO holds the references to all h2c packets the DUT has sent
96 * to the controller using #bt_send.
97 *
98 * Each test should mock a controller by calling #net_buf_get on this
99 * FIFO and simulate a controller's #bt_hci_driver::drv_send. The mocks
100 * should use #bt_recv to send c2h packets to the DUT.
101 */
102 K_FIFO_DEFINE(drv_send_fifo); /* elem T: net_buf */
drv_send(const struct device * dev,struct net_buf * buf)103 static int drv_send(const struct device *dev, struct net_buf *buf)
104 {
105 LOG_DBG("buf %p type %d len %u", buf, bt_buf_get_type(buf), buf->len);
106 LOG_HEXDUMP_DBG(buf->data, buf->len, "buf");
107
108 __ASSERT_NO_MSG(buf);
109 net_buf_put(&drv_send_fifo, buf);
110 return 0;
111 }
112
113 /* }}} */
114
115 /* Mock UART c2h TX handler. {{{ */
116
serial_vnd_data_callback(const struct device * dev,void * user_data)117 static void serial_vnd_data_callback(const struct device *dev, void *user_data)
118 {
119 uint32_t size = serial_vnd_out_data_size_get(dev);
120 uint8_t data[size];
121
122 serial_vnd_read_out_data(dev, data, size);
123 LOG_HEXDUMP_DBG(data, size, "uart tx");
124
125 /* If a test needs to look at the c2h UART traffic, it can be
126 * captured here.
127 */
128 }
129
130 /* }}} */
131
132 #define HCI_NORMAL_CMD_BUF_COUNT (CONFIG_BT_BUF_CMD_TX_COUNT - 1)
133 #define TEST_PARAM_HOST_COMPLETE_COUNT 10
134 #define TIMEOUT_PRESUME_STUCK K_SECONDS(1)
135
136 /** Corresponds to:
137 * - #bt_hci_cmd_hdr
138 */
139 const uint8_t h4_msg_cmd_dummy1[] = {
140 0x01, /* H4: opcode = CMD */
141 0x01, 0x00, /* H4: CMD: opcode = 1 */
142 0x00, /* H4: CMD: len = 0 */
143 };
144
145 /** Corresponds to:
146 * - #bt_hci_cmd_hdr
147 * - #bt_hci_cp_host_num_completed_packets
148 */
149 const uint8_t h4_msg_cmd_host_num_complete[] = {
150 0x01, /* H4: opcode = CMD */
151 0x35, 0x0c, /* H4: CMD: opcode = BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS */
152 0x05, /* H4: CMD: len = 5 */
153 0x01, /* H4: CMD: num_handles = 1 */
154 0x00, 0x00, /* H4: CMD: connection_handle = 0 */
155 0x01, 0x00, /* H4: CMD: num_complete = 1 */
156 };
157
158 /** Corresponds to:
159 * - #bt_hci_evt_hdr
160 * - #bt_hci_evt_cmd_complete
161 */
162 const uint8_t hci_msg_rx_evt_cmd_complete[] = {
163 BT_HCI_EVT_CMD_COMPLETE, /* EVT: opcode */
164 0x03, /* EVT: len */
165 0x01, /* EVT: CMDC: ncmd = 1 */
166 /* EVT: CMDC: opcode */
167 0x00,
168 0x00,
169 };
170
171 ZTEST_SUITE(hci_uart, NULL, NULL, NULL, NULL, NULL);
ZTEST(hci_uart,test_h2c_cmd_flow_control)172 ZTEST(hci_uart, test_h2c_cmd_flow_control)
173 {
174 /* This test assumes the DUT does not care about the contents of
175 * the HCI messages, other than the HCI type/endpoint and the
176 * size. This allows the test to cheat and skip the HCI Reset,
177 * connection setup etc and use dummy command-packets.
178 */
179
180 /* Send commands, saturating the controller's command pipeline. */
181 for (uint16_t i = 0; i < HCI_NORMAL_CMD_BUF_COUNT; i++) {
182 int write_size = serial_vnd_queue_in_data(zephyr_bt_c2h_uart, h4_msg_cmd_dummy1,
183 sizeof(h4_msg_cmd_dummy1));
184 __ASSERT_NO_MSG(write_size == sizeof(h4_msg_cmd_dummy1));
185 }
186
187 /* At this point, the HCI flow control limit for the cmd
188 * endpoint has been reached. It will remain so until the
189 * controller mock has sent a 'HCI Command Complete' event.
190 *
191 * But the 'HCI Host Number of Completed Packets' command is
192 * exempt from HCI flow control. (It's like it has its own
193 * endpoint, that has no flow control.)
194 *
195 * We now send several 'HCI Host Number of Completed Packets'
196 * packets before handling any commands in the controller. This
197 * tests whether the DUT is able to engage the lower transport
198 * flow controller (i.e. UART flow-control) or somehow handle
199 * the special packets out-of-order in real-time.
200 */
201 for (uint16_t i = 0; i < TEST_PARAM_HOST_COMPLETE_COUNT; i++) {
202 int write_size =
203 serial_vnd_queue_in_data(zephyr_bt_c2h_uart, h4_msg_cmd_host_num_complete,
204 sizeof(h4_msg_cmd_host_num_complete));
205 __ASSERT_NO_MSG(write_size == sizeof(h4_msg_cmd_host_num_complete));
206 }
207
208 LOG_DBG("All h2c packets queued on UART");
209
210 /* Then, we check that all packets are delivered without loss. */
211
212 /* Expect all the normal commands first. */
213 for (uint16_t i = 0; i < HCI_NORMAL_CMD_BUF_COUNT; i++) {
214 /* The mock controller processes a command. */
215 {
216 struct net_buf *buf = net_buf_get(&drv_send_fifo, TIMEOUT_PRESUME_STUCK);
217
218 zassert_not_null(buf);
219 zassert_equal(buf->len, sizeof(h4_msg_cmd_dummy1) - 1, "Wrong length");
220 zassert_mem_equal(buf->data, &h4_msg_cmd_dummy1[1],
221 sizeof(h4_msg_cmd_dummy1) - 1);
222 net_buf_unref(buf);
223 }
224
225 /* The controller sends a HCI Command Complete response. */
226 {
227 const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
228 struct drv_data *drv = dev->data;
229 int err;
230 struct net_buf *buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT);
231
232 zassert_not_null(buf);
233 net_buf_add_mem(buf, hci_msg_rx_evt_cmd_complete,
234 sizeof(hci_msg_rx_evt_cmd_complete));
235 err = drv->recv(dev, buf);
236 zassert_equal(err, 0, "bt_recv failed");
237 }
238 }
239
240 /* Expect all the 'HCI Host Number of Completed Packets'. */
241 for (uint16_t i = 0; i < TEST_PARAM_HOST_COMPLETE_COUNT; i++) {
242 /* The mock controller processes a 'HCI Host Number of Completed Packets'. */
243 {
244 struct net_buf *buf = net_buf_get(&drv_send_fifo, TIMEOUT_PRESUME_STUCK);
245
246 zassert_not_null(buf);
247 zassert_equal(buf->len, sizeof(h4_msg_cmd_host_num_complete) - 1,
248 "Wrong length");
249 zassert_mem_equal(buf->data, &h4_msg_cmd_host_num_complete[1],
250 sizeof(h4_msg_cmd_dummy1) - 2);
251 net_buf_unref(buf);
252 }
253
254 /* There is no response to 'HCI Host Number of Completed Packets'. */
255 }
256
257 LOG_DBG("All h2c packets received by controller.");
258 }
259