v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
usb.h
1 /*
2  * This file is part of the public interface to the Sifteo SDK.
3  * Copyright <c> 2013 Sifteo, Inc. All rights reserved.
4  */
5 
6 #pragma once
7 #ifdef NOT_USERSPACE
8 # error This is a userspace-only header, not allowed by the current build.
9 #endif
10 
11 #include <sifteo/abi.h>
12 
13 namespace Sifteo {
14 
39 class Usb {
40 public:
41 
51  static bool isConnected() {
52  return _SYS_usb_isConnected();
53  }
54 };
55 
56 
64 struct UsbPacket {
65  _SYSUsbPacket sys;
66 
67  // Implicit conversions
68  operator _SYSUsbPacket* () { return &sys; }
69  operator const _SYSUsbPacket* () const { return &sys; }
70 
72  static unsigned capacity() {
73  return _SYS_USB_PACKET_BYTES;
74  }
75 
77  void clear() {
78  resize(0);
79  setType(0);
80  }
81 
83  unsigned size() const {
84  return sys.length;
85  }
86 
88  void resize(unsigned bytes) {
89  ASSERT(bytes <= capacity());
90  sys.length = bytes;
91  }
92 
94  bool empty() const {
95  return size() == 0;
96  }
97 
99  uint8_t *bytes() {
100  return sys.bytes;
101  }
102  const uint8_t *bytes() const {
103  return sys.bytes;
104  }
105 
107  unsigned type() const {
108  return sys.type;
109  }
110 
112  void setType(unsigned type) {
113  ASSERT(type <= 0xfffffff);
114  sys.type = type;
115  }
116 };
117 
118 
138 template < unsigned tCapacity >
139 struct UsbQueue {
140  struct SysType {
141  union {
142  _SYSIoQueueHeader header;
143  uint32_t header32;
144  };
145  _SYSUsbPacket packets[tCapacity + 1];
146  } sys;
147 
148  // Implicit conversions
149  operator _SYSUsbQueue* () { return reinterpret_cast<_SYSUsbQueue*>(&sys); }
150  operator const _SYSUsbQueue* () const { return reinterpret_cast<const _SYSUsbQueue*>(&sys); }
151 
152  unsigned capacity() const {
153  return tCapacity;
154  }
155 
157  void clear()
158  {
159  unsigned lastIndex = tCapacity;
160 
161  STATIC_ASSERT(sizeof sys.header == sizeof sys.header32);
162  STATIC_ASSERT(lastIndex >= 1);
163  STATIC_ASSERT(lastIndex <= 255);
164 
165  sys.header32 = lastIndex << 16;
166 
167  ASSERT(sys.header.head == 0);
168  ASSERT(sys.header.tail == 0);
169  ASSERT(sys.header.last == lastIndex);
170  }
171 
173  bool full() const {
174  unsigned size = tCapacity + 1;
175  return (sys.header.tail + 1) % size == sys.header.head;
176  }
177 
179  bool empty() const {
180  return sys.header.tail == sys.header.head;
181  }
182 
193  void read(UsbPacket &buffer)
194  {
195  buffer = peek();
196  pop();
197  }
198 
210  const UsbPacket &peek() const
211  {
212  ASSERT(!empty());
213  unsigned head = sys.header.head;
214  ASSERT(head <= tCapacity);
215  return *reinterpret_cast<const UsbPacket *>(&sys.packets[head]);
216  }
217 
224  void pop()
225  {
226  ASSERT(!empty());
227  unsigned head = sys.header.head + 1;
228  if (head > tCapacity)
229  head = 0;
230  sys.header.head = head;
231  }
232 
243  void write(const UsbPacket &buffer)
244  {
245  reserve() = buffer;
246  commit();
247  }
248 
262  {
263  ASSERT(!full());
264  unsigned tail = sys.header.tail;
265  ASSERT(tail <= tCapacity);
266  return *reinterpret_cast<UsbPacket *>(&sys.packets[tail]);
267  }
268 
275  void commit()
276  {
277  ASSERT(!full());
278  unsigned tail = sys.header.tail + 1;
279  if (tail > tCapacity)
280  tail = 0;
281  sys.header.tail = tail;
282 
283  /*
284  * Poke the system to look at our queue, in case it's ready to
285  * transmit immediately. Has no effect if this queue isn't
286  * attached as the current TX pipe.
287  *
288  * This wakeup is only necessary when the queue transitions
289  * from empty to full, but we have no way of knowing for sure when
290  * this happens. If we see that the queue is non-empty when we
291  * commit(), there's no way to know that the system hasn't dequeued
292  * the packet during this function's execution.
293  */
294  _SYS_usb_queueWriteHint();
295  }
296 };
297 
298 
327 template < unsigned tSendCapacity = 4, unsigned tReceiveCapacity = 4 >
328 struct UsbPipe {
329 
332 
335 
353  void attach() {
354  sendQueue.clear();
356  _SYS_usb_setPipe(sendQueue, receiveQueue);
357  }
358 
366  void detach() {
367  _SYS_usb_setPipe(0, 0);
368  }
369 
379  bool write(const UsbPacket &buffer)
380  {
381  if (!sendQueue.full()) {
382  sendQueue.write(buffer);
383  return true;
384  }
385  return false;
386  }
387 
394  bool read(UsbPacket &buffer)
395  {
396  if (!receiveQueue.empty()) {
397  receiveQueue.read(buffer);
398  return true;
399  }
400  return false;
401  }
402 
404  bool readAvailable() const {
405  return !receiveQueue.empty();
406  }
407 
409  bool writeAvailable() const {
410  return !sendQueue.full();
411  }
412 };
413 
414 
429 {
430  _SYSUsbCounters current;
431  _SYSUsbCounters base;
432 
439  void reset() {
440  _SYS_usb_counters(&base, sizeof base);
441  }
442 
446  void capture() {
447  _SYS_usb_counters(&current, sizeof current);
448  }
449 
451  uint32_t receivedPackets() {
452  return current.rxPackets - base.rxPackets;
453  }
454 
456  uint32_t sentPackets() {
457  return current.txPackets - base.txPackets;
458  }
459 
461  uint32_t receivedBytes() {
462  return current.rxBytes - base.rxBytes;
463  }
464 
466  uint32_t sentBytes() {
467  return current.txBytes - base.txBytes;
468  }
469 
477  uint32_t userPacketsDropped() {
478  return current.rxUserDropped - base.rxUserDropped;
479  }
480 };
481 
482 
487 } // namespace Sifteo