Software APIs
usb_testutils_simpleserial.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 #include "sw/device/lib/testing/usb_testutils_simpleserial.h"
6 
8 #include "sw/device/lib/testing/test_framework/check.h"
9 #include "sw/device/lib/testing/usb_testutils.h"
10 
11 // "uts" is used by usb_testutils_streams.c
12 #define MODULE_ID MAKE_MODULE_ID('u', 't', 'i')
13 
14 #define MAX_GATHER 16
15 
16 static status_t ss_rx(void *ssctx_v, dif_usbdev_rx_packet_info_t packet_info,
17  dif_usbdev_buffer_t buffer) {
19  usb_testutils_ctx_t *ctx = ssctx->ctx;
20 
21  while (packet_info.length--) {
22  uint8_t data;
23  size_t bytes_written;
24  TRY(dif_usbdev_buffer_read(ctx->dev, ctx->buffer_pool, &buffer, &data,
25  sizeof(data), &bytes_written));
26  ssctx->got_byte(data);
27  }
28  return OK_STATUS();
29 }
30 
31 static status_t ss_tx_done(void *ssctx_v, usb_testutils_xfr_result_t result) {
33 
34  ssctx->sending = false;
35  return OK_STATUS();
36 }
37 
38 // Called periodically by the main loop to ensure characters don't
39 // stick around too long
40 static status_t ss_flush(void *ssctx_v) {
42  usb_testutils_ctx_t *ctx = ssctx->ctx;
43  if (ssctx->cur_cpos <= 0 || ssctx->sending) {
44  return OK_STATUS();
45  }
46  if ((ssctx->cur_cpos & 0x3) != 0) {
47  size_t bytes_written;
48  TRY(dif_usbdev_buffer_write(ctx->dev, &ssctx->cur_buf, ssctx->chold.data_b,
49  ssctx->cur_cpos & 0x3, &bytes_written));
50  }
51  TRY(dif_usbdev_send(ctx->dev, ssctx->ep, &ssctx->cur_buf));
52  ssctx->sending = true;
53  ssctx->cur_cpos = -1; // given it to the hardware
54  return OK_STATUS();
55 }
56 
57 // Simple send byte will gather data for a while and send
58 status_t usb_testutils_simpleserial_send_byte(usb_testutils_ss_ctx_t *ssctx,
59  uint8_t c) {
60  usb_testutils_ctx_t *ctx = ssctx->ctx;
61  if (ssctx->cur_cpos == -1) {
62  TRY(dif_usbdev_buffer_request(ctx->dev, ctx->buffer_pool, &ssctx->cur_buf));
63  ssctx->cur_cpos = 0;
64  } else if (ssctx->cur_cpos >= MAX_GATHER && ssctx->sending) {
65  return OK_STATUS(false);
66  }
67  ssctx->chold.data_b[ssctx->cur_cpos++ & 0x3] = c;
68  if ((ssctx->cur_cpos & 0x3) == 0) {
69  size_t bytes_written;
70  TRY(dif_usbdev_buffer_write(ctx->dev, &ssctx->cur_buf, ssctx->chold.data_b,
71  /*src_len=*/4, &bytes_written));
72  if (ssctx->cur_cpos >= MAX_GATHER && !ssctx->sending) {
73  TRY(dif_usbdev_send(ctx->dev, ssctx->ep, &ssctx->cur_buf));
74  ssctx->sending = true;
75  ssctx->cur_cpos = -1; // given it to the hardware
76  }
77  }
78  return OK_STATUS(true);
79 }
80 
81 status_t usb_testutils_simpleserial_init(usb_testutils_ss_ctx_t *ssctx,
82  usb_testutils_ctx_t *ctx, uint8_t ep,
83  void (*got_byte)(uint8_t)) {
84  TRY(usb_testutils_endpoint_setup(ctx, ep, kUsbTransferTypeBulk,
85  kUsbTransferTypeBulk, kUsbdevOutStream,
86  ssctx, ss_tx_done, ss_rx, ss_flush, NULL));
87  ssctx->ctx = ctx;
88  ssctx->ep = ep;
89  ssctx->sending = false;
90  ssctx->got_byte = got_byte;
91  ssctx->cur_cpos = -1;
92  return OK_STATUS();
93 }