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 DEVICE_API(bt_hci, 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_create(&hci_uart_thread, hci_uart_thread_stack,
74  			K_THREAD_STACK_SIZEOF(hci_uart_thread_stack), hci_uart_thread_entry, NULL,
75  			NULL, NULL, CONFIG_MAIN_THREAD_PRIORITY, 0, K_NO_WAIT);
76  	k_thread_name_set(&hci_uart_thread, "hci_uart_main");
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  	k_fifo_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 = k_fifo_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 = k_fifo_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