v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
usb.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * Sifteo SDK
4  *
5  * Copyright <c> 2013 Sifteo, Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #pragma once
27 #ifdef NOT_USERSPACE
28 # error This is a userspace-only header, not allowed by the current build.
29 #endif
30 
31 #include <sifteo/abi.h>
32 
33 namespace Sifteo {
34 
59 class Usb {
60 public:
61 
71  static bool isConnected() {
72  return _SYS_usb_isConnected();
73  }
74 };
75 
76 
84 struct UsbPacket {
85  _SYSUsbPacket sys;
86 
87  // Implicit conversions
88  operator _SYSUsbPacket* () { return &sys; }
89  operator const _SYSUsbPacket* () const { return &sys; }
90 
92  static unsigned capacity() {
93  return _SYS_USB_PACKET_BYTES;
94  }
95 
97  void clear() {
98  resize(0);
99  setType(0);
100  }
101 
103  unsigned size() const {
104  return sys.length;
105  }
106 
108  void resize(unsigned bytes) {
109  ASSERT(bytes <= capacity());
110  sys.length = bytes;
111  }
112 
114  bool empty() const {
115  return size() == 0;
116  }
117 
119  uint8_t *bytes() {
120  return sys.bytes;
121  }
122  const uint8_t *bytes() const {
123  return sys.bytes;
124  }
125 
127  unsigned type() const {
128  return sys.type;
129  }
130 
132  void setType(unsigned type) {
133  ASSERT(type <= 0xfffffff);
134  sys.type = type;
135  }
136 };
137 
138 
158 template < unsigned tCapacity >
159 struct UsbQueue {
160  struct SysType {
161  union {
162  _SYSIoQueueHeader header;
163  uint32_t header32;
164  };
165  _SYSUsbPacket packets[tCapacity + 1];
166  } sys;
167 
168  // Implicit conversions
169  operator _SYSUsbQueue* () { return reinterpret_cast<_SYSUsbQueue*>(&sys); }
170  operator const _SYSUsbQueue* () const { return reinterpret_cast<const _SYSUsbQueue*>(&sys); }
171 
172  unsigned capacity() const {
173  return tCapacity;
174  }
175 
177  void clear()
178  {
179  unsigned lastIndex = tCapacity;
180 
181  STATIC_ASSERT(sizeof sys.header == sizeof sys.header32);
182  STATIC_ASSERT(lastIndex >= 1);
183  STATIC_ASSERT(lastIndex <= 255);
184 
185  sys.header32 = lastIndex << 16;
186 
187  ASSERT(sys.header.head == 0);
188  ASSERT(sys.header.tail == 0);
189  ASSERT(sys.header.last == lastIndex);
190  }
191 
193  bool full() const {
194  unsigned size = tCapacity + 1;
195  return (sys.header.tail + 1) % size == sys.header.head;
196  }
197 
199  bool empty() const {
200  return sys.header.tail == sys.header.head;
201  }
202 
213  void read(UsbPacket &buffer)
214  {
215  buffer = peek();
216  pop();
217  }
218 
230  const UsbPacket &peek() const
231  {
232  ASSERT(!empty());
233  unsigned head = sys.header.head;
234  ASSERT(head <= tCapacity);
235  return *reinterpret_cast<const UsbPacket *>(&sys.packets[head]);
236  }
237 
244  void pop()
245  {
246  ASSERT(!empty());
247  unsigned head = sys.header.head + 1;
248  if (head > tCapacity)
249  head = 0;
250  sys.header.head = head;
251  }
252 
263  void write(const UsbPacket &buffer)
264  {
265  reserve() = buffer;
266  commit();
267  }
268 
282  {
283  ASSERT(!full());
284  unsigned tail = sys.header.tail;
285  ASSERT(tail <= tCapacity);
286  return *reinterpret_cast<UsbPacket *>(&sys.packets[tail]);
287  }
288 
295  void commit()
296  {
297  ASSERT(!full());
298  unsigned tail = sys.header.tail + 1;
299  if (tail > tCapacity)
300  tail = 0;
301  sys.header.tail = tail;
302 
303  /*
304  * Poke the system to look at our queue, in case it's ready to
305  * transmit immediately. Has no effect if this queue isn't
306  * attached as the current TX pipe.
307  *
308  * This wakeup is only necessary when the queue transitions
309  * from empty to full, but we have no way of knowing for sure when
310  * this happens. If we see that the queue is non-empty when we
311  * commit(), there's no way to know that the system hasn't dequeued
312  * the packet during this function's execution.
313  */
314  _SYS_usb_queueWriteHint();
315  }
316 };
317 
318 
347 template < unsigned tSendCapacity = 4, unsigned tReceiveCapacity = 4 >
348 struct UsbPipe {
349 
352 
355 
373  void attach() {
374  sendQueue.clear();
375  receiveQueue.clear();
376  _SYS_usb_setPipe(sendQueue, receiveQueue);
377  }
378 
386  void detach() {
387  _SYS_usb_setPipe(0, 0);
388  }
389 
399  bool write(const UsbPacket &buffer)
400  {
401  if (!sendQueue.full()) {
402  sendQueue.write(buffer);
403  return true;
404  }
405  return false;
406  }
407 
414  bool read(UsbPacket &buffer)
415  {
416  if (!receiveQueue.empty()) {
417  receiveQueue.read(buffer);
418  return true;
419  }
420  return false;
421  }
422 
424  bool readAvailable() const {
425  return !receiveQueue.empty();
426  }
427 
429  bool writeAvailable() const {
430  return !sendQueue.full();
431  }
432 };
433 
434 
449 {
450  _SYSUsbCounters current;
451  _SYSUsbCounters base;
452 
459  void reset() {
460  _SYS_usb_counters(&base, sizeof base);
461  }
462 
466  void capture() {
467  _SYS_usb_counters(&current, sizeof current);
468  }
469 
471  uint32_t receivedPackets() {
472  return current.rxPackets - base.rxPackets;
473  }
474 
476  uint32_t sentPackets() {
477  return current.txPackets - base.txPackets;
478  }
479 
481  uint32_t receivedBytes() {
482  return current.rxBytes - base.rxBytes;
483  }
484 
486  uint32_t sentBytes() {
487  return current.txBytes - base.txBytes;
488  }
489 
497  uint32_t userPacketsDropped() {
498  return current.rxUserDropped - base.rxUserDropped;
499  }
500 };
501 
502 
507 } // namespace Sifteo
A memory buffer which holds a queue of USB packets.
Definition: usb.h:159
uint32_t sentPackets()
Total sent packets.
Definition: usb.h:476
unsigned size() const
Retrieve the size of this packet, in bytes.
Definition: usb.h:103
bool writeAvailable() const
Does this queue have room to write at least one packet?
Definition: usb.h:429
bool readAvailable() const
Does this queue have at least one packet to read?
Definition: usb.h:424
void resize(unsigned bytes)
Change the size of this packet, in bytes.
Definition: usb.h:108
void attach()
Attach this pipe to the system.
Definition: usb.h:373
bool full() const
Is the queue full?
Definition: usb.h:193
#define ASSERT(_x)
Runtime debug assertion.
Definition: macros.h:205
UsbQueue< tSendCapacity > sendQueue
Queue for packets we're waiting to send.
Definition: usb.h:351
const UsbPacket & peek() const
Access the oldest queued packet without copying it.
Definition: usb.h:230
void pop()
Dequeue the oldest packet.
Definition: usb.h:244
Diagnostic counters for the USB subsystem.
Definition: usb.h:448
void capture()
Update the state of all counters.
Definition: usb.h:466
uint32_t receivedPackets()
Total received packets.
Definition: usb.h:471
bool empty() const
Is the queue empty?
Definition: usb.h:199
A container for one Usb packet's data.
Definition: usb.h:84
unsigned type() const
Return the packet's 28-bit type code.
Definition: usb.h:127
bool write(const UsbPacket &buffer)
Write one packet to the send queue, if space is available.
Definition: usb.h:399
A memory buffer for bidirectional USB communications.
Definition: usb.h:348
void reset()
Reset all counters back to zero.
Definition: usb.h:459
uint8_t * bytes()
Return a pointer to this packet's payload bytes.
Definition: usb.h:119
void clear()
Set the packet's length and type to zero.
Definition: usb.h:97
uint32_t receivedBytes()
Total received bytes.
Definition: usb.h:481
bool read(UsbPacket &buffer)
If a packet is available in the queue, read it.
Definition: usb.h:414
static bool isConnected()
Is a device currently connected to a host via USB?
Definition: usb.h:71
void setType(unsigned type)
Set a packet's 28-bit type.
Definition: usb.h:132
static unsigned capacity()
Retrieve the capacity of a packet, in bytes. (19)
Definition: usb.h:92
Global USB operations.
Definition: usb.h:59
uint32_t sentBytes()
Total sent bytes.
Definition: usb.h:486
void write(const UsbPacket &buffer)
Copy a new packet into the queue, from a provided buffer.
Definition: usb.h:263
bool empty() const
Is this packet's payload empty?
Definition: usb.h:114
void detach()
Detach all pipes from the system.
Definition: usb.h:386
UsbQueue< tReceiveCapacity > receiveQueue
Queue for packets that have been received but not yet processed.
Definition: usb.h:354
Definition: array.h:34
UsbPacket & reserve()
Access a buffer slot where a new packet can be written.
Definition: usb.h:281
void read(UsbPacket &buffer)
Read the oldest queued packet into a provided buffer.
Definition: usb.h:213
uint32_t userPacketsDropped()
Total user-defined packets dropped.
Definition: usb.h:497
void clear()
Initializes this queue's header, and marks it as empty.
Definition: usb.h:177
#define STATIC_ASSERT(_x)
Definition: macros.h:342
void commit()
Finish writing a packet that was started with reserve()
Definition: usb.h:295