Software APIs
usbdev_stream.h
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 #ifndef OPENTITAN_SW_HOST_TESTS_USBDEV_USBDEV_STREAM_USBDEV_STREAM_H_
5 #define OPENTITAN_SW_HOST_TESTS_USBDEV_USBDEV_STREAM_USBDEV_STREAM_H_
6 #include <cstddef>
7 #include <cstdint>
8 #include <string>
9 #include <sys/types.h>
10 
11 /**
12  * Stream signature.
13  * Note: this needs to be transferred over a byte stream.
14  */
15 typedef struct __attribute__((packed)) usbdev_stream_sig {
16  /**
17  * Head signature word.
18  */
19  uint32_t head_sig;
20  /**
21  * Initial value of LFSR
22  * Note: for Isochronous Transfers, this is the initial value of the sender's
23  * LFSR for _this packet_.
24  */
25  uint8_t init_lfsr;
26  /**
27  * Stream number and flags.
28  */
29  uint8_t stream;
30  /**
31  * Sequence number, low part; for non-Isochronous streams this will always be
32  * zero because a signature is used only at the start of the data stream.
33  */
34  uint8_t seq_lo;
35  /**
36  * Sequence number, high part; for non-Isochronous streams this will always be
37  * zero because a signature is used only at the start of the data stream.
38  */
39  uint8_t seq_hi;
40  /**
41  * Number of bytes to be transferred.
42  */
43  uint32_t num_bytes;
44  /**
45  * Tail signature word.
46  */
47  uint32_t tail_sig;
48 } usbdev_stream_sig_t;
49 
50 // Data stream.
51 class USBDevStream {
52  public:
53  USBDevStream(unsigned id, uint32_t num_bytes, bool retrieve, bool check,
54  bool send, bool verbose);
55  virtual ~USBDevStream() {}
56 
57  /**
58  * Stream implementations.
59  */
60  enum StreamType {
61  // File descriptor access to serial port.
62  StreamType_Serial,
63  // Standard USB Endpoint/Transfer Types all accessed via libusb.
64  StreamType_Bulk,
65  StreamType_Interrupt,
66  StreamType_Isochronous,
67  StreamType_Control
68  };
69  /**
70  * Record whether or not the stream is in the process of closing
71  * (shutting down or suspending).
72  *
73  * @param closing Whether or not the stream is now closing.
74  */
75  void SetClosing(bool closing) { closing_ = closing; }
76  /**
77  * Indicate whether an additional I/O transfer may safely be scheduled
78  * on this stream, eg. it is not suspending/shutting down.
79  *
80  * @return true iff another I/O transfer may be scheduled.
81  */
82  bool CanSchedule() const { return !closing_; }
83  /**
84  * Finalize the stream, prior to shutting down.
85  */
86  virtual void Stop() = 0;
87  /**
88  * Pause the stream, prior to suspending the device.
89  */
90  virtual void Pause() = 0;
91  /**
92  * Resume streaming.
93  */
94  virtual bool Resume() = 0;
95  /**
96  * Return the Stream IDentifier of this stream.
97  */
98  unsigned ID() const { return id_; }
99  /**
100  * Return a Stream IDentifier prefix suitable for logging/reporting.
101  */
102  std::string PrefixID() {
103  std::string s("S");
104  s += std::to_string(id_);
105  s += ": ";
106  return s;
107  }
108  /**
109  * Return a summary report of the stream settings or status.
110  *
111  * @param status Indicates whether settings or status requested.
112  * @param verbose true iff a more verbose report is required.
113  * @return Status report.
114  */
115  virtual std::string Report(bool status = false,
116  bool verbose = false) const = 0;
117  /**
118  * Set Stream IDentifier and flags.
119  */
120  void SetProperties(unsigned id, bool retrieve, bool check, bool send) {
121  id_ = id;
122  retrieve_ = retrieve;
123  check_ = check;
124  send_ = send;
125  }
126  /**
127  * Service this stream.
128  *
129  * @return true iff test should continue, false indicates error.
130  */
131  virtual bool Service();
132  /**
133  * Indicates whether this stream has completed its transfer.
134  *
135  * @return true iff this stream has nothing more to do.
136  */
137  virtual bool Completed() const;
138  /**
139  * Returns the total number of bytes to be transferred by this stream.
140  *
141  * @param Number of bytes to be transferred.
142  */
143  uint32_t TransferBytes() const { return transfer_bytes_; }
144  /**
145  * Returns a count of the number of bytes received from the device
146  *
147  * @return Number of bytes received.
148  */
149  uint32_t BytesRecvd() const { return bytes_recvd_; }
150  /**
151  * Returns a count of the number of bytes sent to the device.
152  *
153  * @return Number of bytes sent.
154  */
155  uint32_t BytesSent() const { return bytes_sent_; }
156  /**
157  * Return the textual name of the given stream type.
158  *
159  * @param type Stream type.
160  * @return name of stream type.
161  */
162  static const char *StreamTypeName(StreamType type) {
163  switch (type) {
164  case StreamType_Serial:
165  return "Serial";
166  case StreamType_Bulk:
167  return "Bulk";
168  case StreamType_Interrupt:
169  return "Interrupt";
170  case StreamType_Isochronous:
171  return "Isochronous";
172  case StreamType_Control:
173  return "Control";
174  default:
175  return "<Unknown>";
176  }
177  }
178 
179  protected:
180  /**
181  * Provision the given number of bytes of contiguous space,
182  * and optionally a pointer to the start of the free space.
183  *
184  * @param space Receives the pointer to the start of the free space,
185  * or NULL iff pointer not required.
186  * @param len Amount of space (in bytes) to provision.
187  * @return true iff the operation was successful.
188  */
189  bool ProvisionSpace(uint8_t **space, uint32_t len);
190  /**
191  * Returns the amount of contiguous free space available in the buffer,
192  * and optionally a pointer to the start of the free space.
193  *
194  * @param space Receives the pointer to the start of the free space,
195  * or NULL iff pointer not required.
196  * @return The contiguous free space available (in bytes).
197  */
198  uint32_t SpaceAvailable(uint8_t **space);
199  /**
200  * Add the specified number of bytes to the circular buffer; if `data` is NULL
201  * then the bytes shall already be present in the buffer and copying is not
202  * performed.
203  *
204  * @param data The data to be added to the buffer, or NULL
205  * @param len The number of bytes to be added.
206  * @return The success of the operation.
207  */
208  bool AddData(const uint8_t *data, uint32_t len);
209  /**
210  * Record that the specified number of bytes have been added to the circular
211  * buffer. The space must already have provisioned and the data bytes shall
212  * already be in the buffer.
213  */
214  bool CommitData(uint32_t len) { return AddData(nullptr, len); }
215  /**
216  * CLear the circular buffer by removing all of its contained data bytes.
217  *
218  * Note: this is achieved by advancing the read index to match the current
219  * write index, so all committed/added data is discarded, by any write data
220  * that has only been provisioned at this point does remain valid and may
221  * still be committed subsequently.
222  */
223  void ClearBuffer();
224 
225  /**
226  * States in reception of signature.
227  */
228  typedef enum {
229  kSigStateStart = 0,
230  kSigStateCheckHead,
231  kSigStateSkipBody,
232  kSigStateCheckTail,
233  // Signature has been correctly received.
234  kSigStateReceived,
235  } sig_state_t;
236 
237  /**
238  * Reset the signature detection; Isochronous streams including a
239  * new signature at the start of each packet transferred.
240  */
241  void SigReset() {
242  sig_recvd_ = kSigStateStart;
243  sig_cnt_ = 0U;
244  }
245  /**
246  * Has valid signature been received on this stream? Note that there may be
247  * some additional validity checks required for specific= transfer types.
248  *
249  * @return true iff a signature has been received and detected.
250  */
251  bool SigReceived() const { return (sig_recvd_ == kSigStateReceived); }
252  /**
253  * Collect stream flags from the supplied signature.
254  *
255  * @param sig The latest stream signature received.
256  */
257  void SigProcess(const usbdev_stream_sig_t &sig);
258  /**
259  * Detect and parse stream/packet signature,
260  * returning a count of the number of bytes to be discarded from the start
261  * of this data. Usually this is zero, but if a valid stream signature is
262  * required, bytes must be discarded until the signature is received.
263  */
264  uint32_t SigDetect(usbdev_stream_sig_t *sig, const uint8_t *sp,
265  uint32_t nrecv);
266  /**
267  * Diagnostic utility function to report the contents of a stream/packet
268  * signature.
269  *
270  * @param sig Stream signature to be reported.
271  */
272  void SigReport(const usbdev_stream_sig_t &sig);
273  /**
274  * Generate a sequence of bytes _as if_ we'd received them correctly from the
275  * device.
276  */
277  void GenerateData(uint8_t *dp, uint32_t len);
278  /**
279  * Process the given sequence of bytes according to the current stream state.
280  */
281  bool ProcessData(uint8_t *dp, uint32_t len);
282  /**
283  * Return the number of contiguous bytes of data available in the stream
284  * buffer, and a pointer to the first byte of data. This may be fewer than the
285  * total number of bytes in the buffer, if the data wraps at the end of the
286  * circular buffer.
287  *
288  * @param data Receives the pointer to the first data byte.
289  * @return The number of contiguous data bytes available.
290  */
291  uint32_t DataAvailable(uint8_t **data);
292  /**
293  * Update the stream buffer to indicate that data has been discarded
294  * (removed from the buffer but not sent to the USB device).
295  *
296  * @param len Number of bytes of data consumed.
297  * @return true iff the buffer was successfully updated.
298  */
299  bool DiscardData(uint32_t len);
300  /**
301  * Update the stream buffer to indicate that data has been consumed.
302  *
303  * @param len Number of bytes of data consumed.
304  * @return true iff the buffer was successfully updated.
305  */
306  bool ConsumeData(uint32_t len);
307 
308  /**
309  * Size of circular buffer used for streaming.
310  */
311  static constexpr uint32_t kBufferSize = 0x10000U;
312 
313  // Utility function for collecting a byte from the stream signature, handling
314  // wrap around at the end of the circular buffer.
315  inline uint8_t sig_read8(size_t offset) {
316  uint32_t rd_idx = buf_.rd_idx + offset;
317  if (rd_idx >= kBufferSize) {
318  rd_idx -= kBufferSize;
319  }
320  return buf_.data[rd_idx];
321  }
322 
323  // Utility function for collecting a 16-bit word from the stream signature,
324  // handling wrap around at the end of the circular buffer.
325  inline uint16_t sig_read16(size_t offset) {
326  uint32_t rd_idx = buf_.rd_idx + offset;
327  if (rd_idx >= kBufferSize) {
328  rd_idx -= kBufferSize;
329  }
330  uint16_t d = buf_.data[rd_idx++];
331  if (rd_idx >= kBufferSize) {
332  rd_idx -= kBufferSize;
333  }
334  return d | (buf_.data[rd_idx++] << 8);
335  }
336 
337  // Utility function for collecting a 32-bit word from the stream signature,
338  // handling wrap around at the end of the circular buffer.
339  inline uint32_t sig_read32(size_t offset) {
340  uint32_t rd_idx = buf_.rd_idx + offset;
341  unsigned n = 4U;
342  uint32_t d = 0U;
343  while (n-- > 0U) {
344  if (rd_idx >= kBufferSize) {
345  rd_idx -= kBufferSize;
346  }
347  // Transmission of multi-byte value is little endian.
348  d = (d >> 8) | (buf_.data[rd_idx++] << 24);
349  }
350  return d;
351  }
352  /**
353  * Stream IDentifier.
354  */
355  unsigned id_;
356  /**
357  * Is the stream being closed?
358  */
359  bool closing_;
360  /**
361  * Have we received the stream signature yet?
362  */
364  unsigned sig_cnt_;
365  /**
366  * Retrieve IN data for this stream?
367  */
368  bool retrieve_;
369  /**
370  * Check the received data against expectations?
371  */
372  bool check_;
373  /**
374  * Send OUT data for this stream?
375  */
376  bool send_;
377  /**
378  * Verbose reporting?
379  */
380  bool verbose_;
381  /**
382  * Total number of bytes received.
383  */
384  uint32_t bytes_recvd_;
385  /**
386  * Total number of bytes sent.
387  */
388  uint32_t bytes_sent_;
389  /**
390  * Device-side LFSR; byte stream expected from usbdev_stream_test.
391  */
392  uint8_t tst_lfsr_;
393  /**
394  * Host/DPI-side LFSR.
395  */
396  uint8_t dpi_lfsr_;
397  /**
398  * Number of bytes to be transferred.
399  */
400  uint32_t transfer_bytes_;
401  /**
402  * Circular buffer of streamed data.
403  */
404  struct {
405  /**
406  * Offset at which to write the next received data (IN from device).
407  */
408  uint32_t wr_idx;
409  /**
410  * Offset of next byte to be read from the buffer (OUT to device).
411  */
412  uint32_t rd_idx;
413  /**
414  * Offset beyond used portion of the buffer; for packet-based transmission
415  * we wrap before the end of the circular buffer if a maximum-length packet
416  * does not fit.
417  */
418  uint32_t end_idx;
419  /**
420  * Circular buffer of data being transferred from input to output port.
421  */
422  uint8_t data[kBufferSize];
423  } buf_;
424 };
425 
426 #endif // OPENTITAN_SW_HOST_TESTS_USBDEV_USBDEV_STREAM_USBDEV_STREAM_H_