v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
bluetooth.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 
52 class Bluetooth {
53 public:
54 
66  static bool isAvailable()
67  {
68  if ((_SYS_getFeatures() & _SYS_FEATURE_BLUETOOTH) == 0) {
69  return false;
70  }
71 
72  return _SYS_bt_isAvailable();
73  }
74 
88  static bool isConnected()
89  {
90  return _SYS_bt_isConnected();
91  }
92 
115  static void advertiseState(const uint8_t *bytes, unsigned length)
116  {
117  _SYS_bt_advertiseState(bytes, length);
118  };
119 
128  template <typename T>
129  static void advertiseState(const T &object)
130  {
131  advertiseState(reinterpret_cast<const uint8_t*>(&object), sizeof object);
132  }
133 };
134 
135 
144  _SYSBluetoothPacket sys;
145 
146  // Implicit conversions
147  operator _SYSBluetoothPacket* () { return &sys; }
148  operator const _SYSBluetoothPacket* () const { return &sys; }
149 
151  static unsigned capacity() {
152  return _SYS_BT_PACKET_BYTES;
153  }
154 
156  void clear() {
157  resize(0);
158  setType(0);
159  }
160 
162  unsigned size() const {
163  return sys.length;
164  }
165 
167  void resize(unsigned bytes) {
168  ASSERT(bytes <= capacity());
169  sys.length = bytes;
170  }
171 
173  bool empty() const {
174  return size() == 0;
175  }
176 
178  uint8_t *bytes() {
179  return sys.bytes;
180  }
181  const uint8_t *bytes() const {
182  return sys.bytes;
183  }
184 
186  unsigned type() const {
187  return sys.type;
188  }
189 
191  void setType(unsigned type) {
192  ASSERT(type <= 127);
193  sys.type = type;
194  }
195 };
196 
197 
215 template < unsigned tCapacity >
217  struct SysType {
218  union {
219  _SYSBluetoothQueueHeader header;
220  uint32_t header32;
221  };
222  _SYSBluetoothPacket packets[tCapacity + 1];
223  } sys;
224 
225  // Implicit conversions
226  operator _SYSBluetoothQueue* () { return reinterpret_cast<_SYSBluetoothQueue*>(&sys); }
227  operator const _SYSBluetoothQueue* () const { return reinterpret_cast<const _SYSBluetoothQueue*>(&sys); }
228 
230  void clear()
231  {
232  unsigned lastIndex = tCapacity;
233 
234  STATIC_ASSERT(sizeof sys.header == sizeof sys.header32);
235  STATIC_ASSERT(lastIndex >= 1);
236  STATIC_ASSERT(lastIndex <= 255);
237 
238  sys.header32 = lastIndex << 16;
239 
240  ASSERT(sys.header.head == 0);
241  ASSERT(sys.header.tail == 0);
242  ASSERT(sys.header.last == lastIndex);
243  }
244 
255  unsigned count() const
256  {
257  unsigned size = tCapacity + 1;
258  unsigned head = sys.header.head;
259  unsigned tail = sys.header.tail;
260  ASSERT(head < size);
261  ASSERT(tail < size);
262  return (tail - head) % size;
263  }
264 
266  unsigned readAvailable() const
267  {
268  return count();
269  }
270 
272  unsigned writeAvailable() const
273  {
274  return tCapacity - count();
275  }
276 
287  void read(BluetoothPacket &buffer)
288  {
289  buffer = peek();
290  pop();
291  }
292 
304  const BluetoothPacket &peek() const
305  {
306  ASSERT(readAvailable() > 0);
307  unsigned head = sys.header.head;
308  ASSERT(head <= tCapacity);
309  return *reinterpret_cast<const BluetoothPacket *>(&sys.packets[head]);
310  }
311 
318  void pop()
319  {
320  ASSERT(readAvailable() > 0);
321  unsigned head = sys.header.head + 1;
322  if (head > tCapacity)
323  head = 0;
324  sys.header.head = head;
325 
326  /*
327  * Notify the system that we have more space for reading. This may
328  * communicate additional flow control tokens to our peer if this
329  * queue is the current read pipe.
330  *
331  * This is only absolutely necessary if the queue transitioned
332  * from being totally full to being less-than-totally full, but
333  * we'd also like to give the system a chance to send flow control
334  * tokens speculatively if it wants.
335  */
336  _SYS_bt_queueReadHint();
337  }
338 
349  void write(const BluetoothPacket &buffer)
350  {
351  reserve() = buffer;
352  commit();
353  }
354 
368  {
369  ASSERT(writeAvailable() > 0);
370  unsigned tail = sys.header.tail;
371  ASSERT(tail <= tCapacity);
372  return *reinterpret_cast<BluetoothPacket *>(&sys.packets[tail]);
373  }
374 
381  void commit()
382  {
383  ASSERT(writeAvailable() > 0);
384  unsigned tail = sys.header.tail + 1;
385  if (tail > tCapacity)
386  tail = 0;
387  sys.header.tail = tail;
388 
389  /*
390  * Poke the system to look at our queue, in case it's ready to
391  * transmit immediately. Has no effect if this queue isn't
392  * attached as the current TX pipe.
393  *
394  * This wakeup is only necessary when the queue transitions
395  * from empty to full, but we have no way of knowing for sure when
396  * this happens. If we see that the queue is non-empty when we
397  * commit(), there's no way to know that the system hasn't dequeued
398  * the packet during this function's execution.
399  */
400  _SYS_bt_queueWriteHint();
401  }
402 };
403 
404 
445 template < unsigned tSendCapacity = 4, unsigned tReceiveCapacity = 4 >
447 
450 
453 
471  void attach() {
472  sendQueue.clear();
474  _SYS_bt_setPipe(sendQueue, receiveQueue);
475  }
476 
484  void detach() {
485  _SYS_bt_setPipe(0, 0);
486  }
487 
497  bool write(const BluetoothPacket &buffer)
498  {
499  if (sendQueue.writeAvailable()) {
500  sendQueue.write(buffer);
501  return true;
502  }
503  return false;
504  }
505 
512  bool read(BluetoothPacket &buffer)
513  {
514  if (receiveQueue.readAvailable()) {
515  receiveQueue.read(buffer);
516  return true;
517  }
518  return false;
519  }
520 
522  unsigned readAvailable() const
523  {
524  return receiveQueue.readAvailable();
525  }
526 
528  unsigned writeAvailable() const
529  {
530  return sendQueue.writeAvailable();
531  }
532 };
533 
534 
549 {
550  _SYSBluetoothCounters current;
551  _SYSBluetoothCounters base;
552 
559  void reset() {
560  _SYS_bt_counters(&base, sizeof base);
561  }
562 
566  void capture() {
567  _SYS_bt_counters(&current, sizeof current);
568  }
569 
571  uint32_t receivedPackets() {
572  return current.rxPackets - base.rxPackets;
573  }
574 
576  uint32_t sentPackets() {
577  return current.txPackets - base.txPackets;
578  }
579 
581  uint32_t receivedBytes() {
582  return current.rxBytes - base.rxBytes;
583  }
584 
586  uint32_t sentBytes() {
587  return current.txBytes - base.txBytes;
588  }
589 
597  uint32_t userPacketsDropped() {
598  return current.rxUserDropped - base.rxUserDropped;
599  }
600 };
601 
602 
607 } // namespace Sifteo