15 #include "sw/device/lib/testing/usb_testutils_streams.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
19 #include "sw/device/lib/testing/usb_testutils_controlep.h"
20 #include "sw/device/lib/testing/usb_testutils_diags.h"
22 #define MODULE_ID MAKE_MODULE_ID('u', 't', 's')
25 #define CFG_DSCR_LEN_MAX \
27 USBUTILS_STREAMS_MAX * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN))
36 } read_method = kReadMethodStandard;
42 kWriteMethodStandard = 1u,
44 } write_method = kWriteMethodStandard;
49 static bool log_traffic =
false;
53 static uint8_t packet_length(
const usbdev_stream_t *s, uint32_t bytes_done,
54 uint8_t *bufsz_lfsr) {
58 uint8_t bytes_left = USBDEV_MAX_PACKET_SIZE;
60 if (s->
xfr_type != kUsbTransferTypeIsochronous) {
61 if (bytes_done < s->transfer_bytes &&
70 if (s->
flags & kUsbdevStreamFlagMaxPackets) {
71 num_bytes = bytes_left;
75 const unsigned sig_bytes =
sizeof(usbdev_stream_sig_t);
77 case kUsbTransferTypeIsochronous: {
80 const unsigned max_bytes = USBDEV_MAX_PACKET_SIZE - sig_bytes;
81 num_bytes = sig_bytes + (*bufsz_lfsr % (max_bytes + 1u));
84 num_bytes = sig_bytes;
88 num_bytes = *bufsz_lfsr % (bytes_left + 1u);
90 *bufsz_lfsr = LFSR_ADVANCE(*bufsz_lfsr);
93 return (uint8_t)num_bytes;
97 static void buffer_dump(
const uint8_t *data,
size_t n) {
100 .words_per_line = 0x20u,
118 usbdev_stream_sig_t sig;
119 sig.head_sig = USBDEV_STREAM_SIGNATURE_HEAD;
120 sig.init_lfsr = s->
tx.
lfsr;
121 sig.stream = s->
id | (uint8_t)s->
flags;
122 sig.seq_lo = (uint8_t)s->
tx.
seq;
123 sig.seq_hi = (uint8_t)(s->
tx.
seq >> 8);
124 sig.num_bytes = tx_left;
125 sig.tail_sig = USBDEV_STREAM_SIGNATURE_TAIL;
130 if (s->
verbose && log_traffic) {
131 buffer_dump((uint8_t *)&sig,
sizeof(sig));
134 size_t bytes_written;
135 switch (write_method) {
136 #if USBUTILS_MEM_FASTER
137 case kWriteMethodFaster:
144 ctx->
usbdev->dev, buf, (uint8_t *)&sig,
sizeof(sig), &bytes_written));
145 CHECK(bytes_written ==
sizeof(sig));
151 return (uint8_t)bytes_written;
164 if (sig->head_sig != USBDEV_STREAM_SIGNATURE_HEAD ||
165 sig->tail_sig != USBDEV_STREAM_SIGNATURE_TAIL ||
167 (sig->stream & 0xfU) != s->
id) {
168 LOG_INFO(
"buffer_sig_check failed: ");
173 uint16_t seq = (uint16_t)((sig->seq_hi << 8) | sig->seq_lo);
174 if (seq < s->rx_seq) {
175 LOG_INFO(
"buffer_sig_check: sequence number regressed from 0x%x to 0x%x",
181 uint16_t rx_seq = s->
rx_seq;
195 rxtx_lfsr = LFSR_ADVANCE(rxtx_lfsr);
199 }
while (rx_seq < seq);
203 rx_lfsr = sig->init_lfsr;
208 if (rx_lfsr != sig->init_lfsr) {
210 "buffer_sig_check: S%u unexpected host-side LFSR value (0x%x but "
212 s->
id, sig->init_lfsr, rx_lfsr);
221 if (len != exp_len) {
223 "buffer_sig_check: S%u unexpected packet length (0x%x but expected "
225 s->
id, len, exp_len);
241 alignas(uint32_t) uint8_t data[USBDEV_MAX_PACKET_SIZE];
243 CHECK(num_bytes <= buf->remaining_bytes);
244 CHECK(num_bytes <=
sizeof(data));
250 uint8_t lfsr = s->
tx.
lfsr;
252 const uint8_t *edp = &data[num_bytes];
256 lfsr = LFSR_ADVANCE(lfsr);
266 if (s->
verbose && log_traffic) {
267 buffer_dump(data, num_bytes);
270 size_t bytes_written;
271 switch (write_method) {
272 #if USBUTILS_MEM_FASTER
273 case kWriteMethodFaster:
280 num_bytes, &bytes_written));
281 CHECK(bytes_written == num_bytes);
292 uint8_t len = packet_info.
length;
295 alignas(uint32_t) uint8_t data[USBDEV_MAX_PACKET_SIZE];
297 CHECK(len <=
sizeof(data));
305 switch (read_method) {
306 #if USBUTILS_MEM_FASTER
308 case kReadMethodFaster:
314 &buf, data, len, &bytes_read));
317 CHECK(bytes_read == len);
319 if (s->
verbose && log_traffic) {
320 buffer_dump(data, bytes_read);
327 case kUsbTransferTypeIsochronous: {
330 const usbdev_stream_sig_t *sig = (usbdev_stream_sig_t *)data;
331 bool ok = buffer_sig_check(ctx, s, sig, len);
332 CHECK(ok,
"S%u: Received packet invalid", s->
id);
334 offset =
sizeof(*sig);
337 case kUsbTransferTypeInterrupt:
339 case kUsbTransferTypeBulk: {
346 const uint8_t *esp = &data[bytes_read];
347 const uint8_t *sp = &data[offset];
351 uint8_t expected = rxtx_lfsr ^ rx_lfsr;
352 CHECK(expected == *sp,
353 "S%u: Unexpected received data 0x%02x : (LFSRs 0x%02x 0x%02x)",
354 s->
id, *sp, rxtx_lfsr, rx_lfsr);
356 rxtx_lfsr = LFSR_ADVANCE(rxtx_lfsr);
357 rx_lfsr = LFSR_ADVANCE(rx_lfsr);
370 CHECK(s->
xfr_type == kUsbTransferTypeControl);
382 static status_t strm_tx_done(
void *cb_v, usb_testutils_xfr_result_t result) {
391 uint8_t tx_ep = s->
tx_ep;
395 LOG_INFO(
"strm_tx_done called. %u (%u total) buffers(s) are queued",
399 TRY_CHECK(nqueued > 0);
410 for (
unsigned idx = 1u; idx < nqueued; idx++) {
441 LOG_INFO(
"Stream %u: Received buffer of %u bytes(s)", s->
id,
446 buffer_check(ctx, s, packet_info, buf);
451 if (read_method != kReadMethodNone && packet_info.
length > 0) {
452 alignas(uint32_t) uint8_t data[USBDEV_MAX_PACKET_SIZE];
453 size_t len = packet_info.
length;
456 switch (read_method) {
457 #if USBUTILS_MEM_FASTER
459 case kReadMethodFaster:
466 data, len, &bytes_read));
485 if (nstreams > USBUTILS_STREAMS_MAX) {
492 for (
unsigned s = 0U; s < nstreams; s++) {
499 (uint8_t)((USBUTILS_STREAMS_TXBUF_MAX + nstreams - 1) / nstreams);
521 usb_testutils_transfer_type_t xfr_type,
522 uint8_t ep_in, uint8_t ep_out,
523 uint32_t transfer_bytes,
524 usbdev_stream_flags_t flags,
bool verbose) {
526 TRY_CHECK(
id < USBUTILS_STREAMS_MAX);
540 s->
sending = ((flags & kUsbdevStreamFlagRetrieve) != 0U);
541 s->
generating = ((flags & kUsbdevStreamFlagCheck) != 0U);
560 s->
tx.
lfsr = USBTST_LFSR_SEED(
id);
562 s->
rx_lfsr = USBDPI_LFSR_SEED(
id);
582 CHECK_STATUS_OK(usb_testutils_in_endpoint_setup(
583 ctx->
usbdev, ep_in, xfr_type, cb, strm_tx_done, NULL, NULL));
586 CHECK_STATUS_OK(usb_testutils_out_endpoint_setup(
587 ctx->
usbdev, ep_out, xfr_type, kUsbdevOutStream, cb, strm_rx, NULL));
597 TRY_CHECK(
id < USBUTILS_STREAMS_MAX);
603 uint8_t tx_ep = s->
tx_ep;
608 bool tx_more = (s->
xfr_type == kUsbTransferTypeIsochronous) ||
612 nqueued < ctx->tx_bufs_limit[tx_ep] &&
614 USBUTILS_STREAMS_TXBUF_MAX) {
623 static unsigned bufs_sent = 0u;
624 uint8_t bytes_added = 0u;
633 bytes_added = buffer_sig_create(ctx, s, &buf);
649 if (bytes_added < num_bytes) {
650 buffer_fill(ctx, s, &buf, (uint8_t)(num_bytes - bytes_added));
658 ctx->
tx_bufs[tx_ep][nqueued].buf = buf;
670 "Stream %u: %uth buffer (of 0x%x byte(s)) awaiting transmission",
671 s->
id, bufs_sent, num_bytes);
682 status_t usb_testutils_streams_init(
684 const usb_testutils_transfer_type_t xfr_types[], uint32_t num_bytes,
685 usbdev_stream_flags_t flags,
bool verbose) {
686 TRY_CHECK(nstreams <= USBUTILS_STREAMS_MAX);
687 TRY_CHECK(nstreams <= UINT8_MAX);
690 for (uint8_t
id = 0U;
id < nstreams;
id++) {
692 const uint8_t ep_in =
id + 1U;
694 const uint8_t ep_out =
id + 1U;
695 TRY(usb_testutils_stream_init(ctx,
id, xfr_types[
id], ep_in, ep_out,
696 num_bytes, flags, verbose));
700 TRY_CHECK(usb_testutils_streams_count_set(ctx, nstreams));
705 status_t usb_testutils_streams_typed_init(
707 unsigned nstreams,
const usb_testutils_transfer_type_t xfr_types[],
708 uint32_t num_bytes, usbdev_stream_flags_t flags,
bool verbose,
710 TRY_CHECK(nstreams <= USBUTILS_STREAMS_MAX);
718 size_t cfg_len = USB_CFG_DSCR_LEN +
719 nstreams * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN);
720 TRY_CHECK(cfg && cfg_len <= len);
723 uint8_t head[CFG_DSCR_LEN_MAX] = {
724 USB_CFG_DSCR_HEAD((uint16_t)cfg_len, (uint8_t)nstreams)};
725 memcpy(cfg, head, USB_CFG_DSCR_LEN);
726 cfg += USB_CFG_DSCR_LEN;
729 for (uint8_t
id = 0U;
id < nstreams;
id++) {
730 usb_testutils_transfer_type_t xfr_type = xfr_types[id];
733 *types |= xfr_type << (
id * 2U);
736 uint8_t ep_in = (uint8_t)(
id + 1U);
737 uint8_t ep_out = (uint8_t)(
id + 1U);
738 TRY(usb_testutils_stream_init(ctx,
id, xfr_type, ep_in, ep_out, num_bytes,
742 uint8_t bInterval = (xfr_type == kUsbTransferTypeIsochronous ||
743 xfr_type == kUsbTransferTypeInterrupt);
746 uint8_t int_dscr[USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN] = {
747 VEND_INTERFACE_DSCR(
id, 2, 0x50, 1),
748 USB_EP_DSCR(0, ep_out, (uint8_t)xfr_type, USBDEV_MAX_PACKET_SIZE,
750 USB_EP_DSCR(1, ep_in, (uint8_t)xfr_type, USBDEV_MAX_PACKET_SIZE,
755 memcpy(cfg, int_dscr,
sizeof(int_dscr));
756 cfg +=
sizeof(int_dscr);
762 static const char *xfr_name[] = {
768 TRY_CHECK(xfr_type <
ARRAYSIZE(xfr_name));
769 LOG_INFO(
"S%u: IN %u:OUT %u : %s - 0x%x bytes flags 0x%x",
id, ep_in,
770 ep_out, xfr_name[xfr_type], num_bytes, flags);
775 TRY_CHECK(usb_testutils_streams_count_set(ctx, nstreams));
781 TRY_CHECK(ctx->
nstreams <= UINT8_MAX);
783 for (uint8_t
id = 0U;
id < ctx->
nstreams;
id++) {
784 TRY(usb_testutils_stream_service(ctx,
id));
788 CHECK_STATUS_OK(usb_testutils_poll(ctx->
usbdev));
794 uint8_t *buf,
unsigned size,
797 if (!ctx || !buf || !used ||
799 return INVALID_ARGUMENT();
807 for (uint8_t
id = 0U;
id < ctx->
nstreams;
id++) {
810 memcpy(dp, s,
sizeof(*s));
813 LOG_INFO(
"S%u: suspend seq %u, lfsr %x <- commit seq %u, lfsr %x",
id,
818 *used = (unsigned)(dp - buf);
830 const uint8_t *data,
unsigned len) {
832 if (!ctx || !data || len < 1U) {
833 return INVALID_ARGUMENT();
839 return FAILED_PRECONDITION();
843 const uint8_t *dp = data;
844 unsigned nstreams = *dp++;
846 return INVALID_ARGUMENT();
849 for (uint8_t
id = 0U;
id < nstreams;
id++) {
854 LOG_INFO(
"S%u: resume seq %u, lfsr %x <- commit seq %u, lfsr %x",
id,
865 TRY_CHECK(usb_testutils_streams_count_set(ctx, nstreams));
871 uint8_t
id, uint32_t *num_bytes,
872 uint32_t *tx_bytes, uint32_t *rx_bytes) {
875 return INVALID_ARGUMENT();
895 for (uint8_t
id = 0;
id < ctx->
nstreams;
id++) {
896 if (!usb_testutils_stream_completed(ctx,
id)) {