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