Software APIs
usbdev_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 // USB device test
6 //
7 // This test is a stripped down version of the hello_usbdev example application.
8 // It requires interaction with the USB DPI model mimicking the host and thus
9 // can only be run in the Verilator simulation. The test initializes the USB
10 // device and configures USB Endpoint 1 as a simpleserial endpoint. The test
11 // then starts polling the USB device for data sent by the host. Any data
12 // received on Endpoint 1 is stored in a buffer and printed via UART.
13 //
14 // The DPI model mimicks the USB host. After device initialization, it detects
15 // the assertion of the pullup and first assigns an address to the device. It
16 // then sends various USB transactions to the device including two OUT
17 // transactions with a data payload of "Hi!" to Endpoint 1. If these two OUT
18 // transactions are succesfully received by the device, the test passes.
19 
24 #include "sw/device/lib/testing/pinmux_testutils.h"
25 #include "sw/device/lib/testing/test_framework/check.h"
27 #include "sw/device/lib/testing/usb_testutils.h"
28 #include "sw/device/lib/testing/usb_testutils_controlep.h"
29 #include "sw/device/lib/testing/usb_testutils_diags.h"
30 #include "sw/device/lib/testing/usb_testutils_simpleserial.h"
31 
32 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
33 
34 /**
35  * Configuration values for USB.
36  */
37 static const uint8_t config_descriptors[] = {
38  USB_CFG_DSCR_HEAD(
39  USB_CFG_DSCR_LEN + 2 * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN),
40  2),
41  VEND_INTERFACE_DSCR(0, 2, 0x50, 1),
42  USB_BULK_EP_DSCR(0, 1, 32, 0),
43  USB_BULK_EP_DSCR(1, 1, 32, 4),
44  VEND_INTERFACE_DSCR(1, 2, 0x50, 1),
45  USB_BULK_EP_DSCR(0, 2, 32, 0),
46  USB_BULK_EP_DSCR(1, 2, 32, 4),
47 };
48 
49 /**
50  * Test descriptor
51  */
52 static const uint8_t test_descriptor[] = {
53  USB_TESTUTILS_TEST_DSCR(0, 0, 0, 0, 0)};
54 
55 /**
56  * USB device context types.
57  */
58 static usb_testutils_ctx_t usbdev;
59 static usb_testutils_controlep_ctx_t usbdev_control;
60 static usb_testutils_ss_ctx_t simple_serial;
61 
62 /**
63  * Pinmux handle
64  */
65 static dif_pinmux_t pinmux;
66 
67 /**
68  * Makes `c` into a printable character, replacing it with `replacement`
69  * as necessary.
70  */
71 static char make_printable(char c, char replacement) {
72  if (c == 0xa || c == 0xd) {
73  return c;
74  }
75 
76  if (c < ' ' || c > '~') {
77  c = replacement;
78  }
79  return c;
80 }
81 
82 static const size_t kExpectedUsbCharsRecved = 6;
83 static const char kExpectedUsbRecved[7] = "Hi!Hi!";
84 static size_t usb_chars_recved_total;
85 static char buffer[7];
86 
87 /**
88  * Callback for processing USB reciept.
89  */
90 static void usb_receipt_callback(uint8_t c) {
91  c = make_printable(c, '?');
92  base_printf("%c", c);
93  if (usb_chars_recved_total < kExpectedUsbCharsRecved) {
94  buffer[usb_chars_recved_total] = c;
95  ++usb_chars_recved_total;
96  }
97 }
98 
99 OTTF_DEFINE_TEST_CONFIG();
100 
101 bool test_main(void) {
102  LOG_INFO("Running USBDEV test");
103 
104  CHECK_DIF_OK(dif_pinmux_init(
106  pinmux_testutils_init(&pinmux);
107  CHECK_DIF_OK(dif_pinmux_input_select(
110 
111  // Call `usbdev_init` here so that DPI will not start until the
112  // simulation has finished all of the printing, which takes a while
113  // if `--trace` was passed in.
114  CHECK_STATUS_OK(usb_testutils_init(&usbdev, /*pinflip=*/false,
115  /*en_diff_rcvr=*/true,
116  /*tx_use_d_se0=*/false));
117  CHECK_STATUS_OK(usb_testutils_controlep_init(
118  &usbdev_control, &usbdev, 0, config_descriptors,
119  sizeof(config_descriptors), test_descriptor, sizeof(test_descriptor)));
120 
121  // Proceed only when the device has been configured; this allows host-side
122  // software to establish communication.
123  CHECK_STATUS_OK(
124  usb_testutils_controlep_config_wait(&usbdev_control, &usbdev));
125 
126  // Set up a serial port.
127  CHECK_STATUS_OK(usb_testutils_simpleserial_init(&simple_serial, &usbdev, 1U,
128  usb_receipt_callback));
129 
130  USBUTILS_USER_PROMPT("Echo characters now...eg. 'cat /dev/ttyUSB0'");
131 
132  // Send a "Hi!Hi!" sign on message.
133  for (int idx = 0; idx < kExpectedUsbCharsRecved; idx++) {
134  CHECK_STATUS_OK(usb_testutils_simpleserial_send_byte(
135  &simple_serial, kExpectedUsbRecved[idx]));
136  }
137 
138  // Await the same message as a response; this allows a simple 'cat <port>'
139  // command to form the host side because of character echo.
140  while (usb_chars_recved_total < kExpectedUsbCharsRecved) {
141  CHECK_STATUS_OK(usb_testutils_poll(&usbdev));
142  }
143 
144  base_printf("\r\n");
145  for (int i = 0; i < kExpectedUsbCharsRecved; i++) {
146  CHECK(buffer[i] == kExpectedUsbRecved[i],
147  "Received char #%d mismatched: exp = %x, actual = %x", i,
148  kExpectedUsbRecved[i], buffer[i]);
149  }
150  LOG_INFO("USB received %d characters: %s", usb_chars_recved_total, buffer);
151 
152  CHECK_STATUS_OK(usb_testutils_fin(&usbdev));
153 
154  return true;
155 }