v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
motion.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * Sifteo SDK
4  *
5  * Copyright <c> 2012 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 #include <sifteo/cube.h>
33 #include <sifteo/math.h>
34 
35 namespace Sifteo {
36 
79 template < unsigned tSize = 32 >
80 struct MotionBuffer {
81  struct SysType {
82  _SYSMotionBufferHeader header;
83  _SYSByte4 samples[tSize];
84  } sys;
85 
87  static const unsigned TICK_NS = _SYS_MOTION_TIMESTAMP_NS;
88 
90  static const unsigned TICK_US = _SYS_MOTION_TIMESTAMP_NS / 1000;
91 
93  static const unsigned TICK_HZ = _SYS_MOTION_TIMESTAMP_HZ;
94 
95  // Implicit conversions
96  operator _SYSMotionBuffer* () { return reinterpret_cast<_SYSMotionBuffer*>(&sys); }
97  operator const _SYSMotionBuffer* () const { return reinterpret_cast<const _SYSMotionBuffer*>(&sys); }
98 
119  void attach(_SYSCubeID id, unsigned hz=100)
120  {
121  STATIC_ASSERT(id < _SYS_NUM_CUBE_SLOTS);
122  STATIC_ASSERT(tSize <= _SYS_MOTION_MAX_ENTRIES);
123  bzero(sys);
124  sys.header.last = tSize - 1;
125  sys.header.rate = TICK_HZ / hz;
126 
127  /*
128  * If this ASSERT fails, the buffer is too close to the top of RAM. This
129  * usually means you've allocated the MotionBuffer on the stack, which isn't
130  * recommended. See the warning in the MotionBuffer class comments.
131  */
132  ASSERT(reinterpret_cast<uintptr_t>(this) + sizeof(_SYSMotionBuffer) <= 0x18000);
133 
134  _SYS_setMotionBuffer(id, *this);
135  }
136 
155  Int3 integrate(unsigned duration)
156  {
157  _SYSInt3 result;
158  _SYS_motion_integrate(*this, duration, &result);
159  return vec(result.x, result.y, result.z);
160  }
161 };
162 
175 private:
176  _SYSMotionBuffer *buffer;
177  uint32_t tickCounter;
178  Byte3 lastAccel;
179  uint8_t head;
180 
181 public:
183  static const unsigned TICK_NS = MotionBuffer<>::TICK_NS;
184 
186  static const unsigned TICK_US = MotionBuffer<>::TICK_US;
187 
189  static const unsigned TICK_HZ = MotionBuffer<>::TICK_HZ;
190 
199  MotionIterator(_SYSMotionBuffer *buffer)
200  : buffer(buffer), tickCounter(0), lastAccel(vec(0,0,0)),
201  head(buffer->header.tail) {}
202 
210  bool next()
211  {
212  unsigned tail = buffer->header.tail;
213  unsigned last = buffer->header.last;
214  unsigned head = this->head;
215 
216  if (head > last)
217  head = 0;
218 
219  if (head == tail)
220  return false;
221 
222  _SYSByte4 sample = buffer->samples[head];
223  this->head = head + 1;
224 
225  lastAccel = vec(sample.x, sample.y, sample.z);
226  tickCounter += unsigned(uint8_t(sample.w)) + 1;
227 
228  return true;
229  }
230 
237  Byte3 accel() const {
238  return lastAccel;
239  }
240 
251  uint32_t ticks() const {
252  return tickCounter;
253  }
254 
264  float seconds() const {
265  return ticks() * (1.0f / TICK_HZ);
266  }
267 
272  void setTicks(uint32_t value) {
273  tickCounter = value;
274  }
275 
286  void adjustTicks(int32_t value) {
287  tickCounter += value;
288  }
289 };
290 
300 public:
301  _SYSMotionMedian sys;
302 
303  // Implicit conversions
304  operator _SYSMotionMedian* () { return &sys; }
305  operator const _SYSMotionMedian* () const { return &sys; }
306 
326  void calculate(_SYSMotionBuffer *mbuf, unsigned duration) {
327  _SYS_motion_median(mbuf, duration, *this);
328  }
329 
332 
334  MotionMedian(_SYSMotionBuffer *mbuf, unsigned duration) {
335  calculate(mbuf, duration);
336  }
337 
339  Byte3 median() const {
340  return vec(sys.axes[0].median, sys.axes[1].median, sys.axes[2].median);
341  }
342 
344  Byte3 minimum() const {
345  return vec(sys.axes[0].minimum, sys.axes[1].minimum, sys.axes[2].minimum);
346  }
347 
349  Byte3 maximum() const {
350  return vec(sys.axes[0].maximum, sys.axes[1].maximum, sys.axes[2].maximum);
351  }
352 
354  Int3 range() const {
355  return Int3(maximum()) - Int3(minimum());
356  }
357 };
358 
359 
371 public:
372  static const int kFilterLatency = MotionBuffer<>::TICK_HZ / 30;
373  static const int kTiltThresholdMin = 15;
374  static const int kTiltThresholdMax = 26;
375  static const int kShakeThresholdMin = 1000;
376  static const int kShakeThresholdMax = 50000;
377 
387 
397 
405 
407  bool shake;
408 
415  void attach(_SYSCubeID id)
416  {
417  buffer.attach(id);
418  bzero(median);
419  bzero(tilt);
420  shake = false;
421  }
422 
430  Byte3 physicalTilt() const {
431  return tilt;
432  }
433 
444  Byte3 virtualTilt(Side orientation) const {
445  return tilt.zRotateI(orientation);
446  }
447 
451  enum ChangeFlags {
452  Shake_Begin = 1 << 0,
453  Shake_End = 1 << 1,
455 
456  Tilt_XNeg = 1 << 2,
457  Tilt_XZero = 1 << 3,
458  Tilt_XPos = 1 << 4,
460 
461  Tilt_YNeg = 1 << 5,
462  Tilt_YZero = 1 << 6,
463  Tilt_YPos = 1 << 7,
465 
466  Tilt_ZNeg = 1 << 8,
467  Tilt_ZZero = 1 << 9,
468  Tilt_ZPos = 1 << 10,
470 
472  };
473 
488  unsigned update(int latency = kFilterLatency)
489  {
490  unsigned changed = 0;
491 
492  median.calculate(buffer, latency);
493  auto m = median.median();
494  int wobble = median.range().len2();
495 
496  // Shake hysteresis
497  if (wobble >= kShakeThresholdMax) {
498  if (!shake) changed |= Shake_Begin;
499  shake = true;
500 
501  } else if (wobble < kShakeThresholdMin) {
502  if (shake) changed |= Shake_End;
503  shake = false;
504 
505  // Only update tilt state when wobble is low.
506  // Each tilt axis has hysteresis.
507 
508  if (m.x <= -kTiltThresholdMax) {
509  if (tilt.x != -1) changed |= Tilt_XNeg;
510  tilt.x = -1;
511  } else if (m.x >= kTiltThresholdMax) {
512  if (tilt.x != 1) changed |= Tilt_XPos;
513  tilt.x = 1;
514  } else if (abs(m.x) < kTiltThresholdMin) {
515  if (tilt.x != 0) changed |= Tilt_XZero;
516  tilt.x = 0;
517  }
518 
519  if (m.y <= -kTiltThresholdMax) {
520  if (tilt.y != -1) changed |= Tilt_YNeg;
521  tilt.y = -1;
522  } else if (m.y >= kTiltThresholdMax) {
523  if (tilt.y != 1) changed |= Tilt_YPos;
524  tilt.y = 1;
525  } else if (abs(m.y) < kTiltThresholdMin) {
526  if (tilt.y != 0) changed |= Tilt_YZero;
527  tilt.y = 0;
528  }
529 
530  if (m.z <= -kTiltThresholdMax) {
531  if (tilt.z != -1) changed |= Tilt_ZNeg;
532  tilt.z = -1;
533  } else if (m.z >= kTiltThresholdMax) {
534  if (tilt.z != 1) changed |= Tilt_ZPos;
535  tilt.z = 1;
536  } else if (abs(m.z) < kTiltThresholdMin) {
537  if (tilt.z != 0) changed |= Tilt_ZZero;
538  tilt.z = 0;
539  }
540  }
541 
542  return changed;
543  }
544 };
545 
546 
551 }; // namespace Sifteo
T x
Vector component X.
Definition: math.h:724
'tilt.x' has changed to -1
Definition: motion.h:456
'tilt.z' has changed to 0
Definition: motion.h:467
Calculate median, minimum, and maximum statistics from a MotionBuffer.
Definition: motion.h:299
Byte3 median() const
Return the median itself, as a vector.
Definition: motion.h:339
'tilt.x' has changed to +1
Definition: motion.h:458
Byte3 virtualTilt(Side orientation) const
Return the virtual tilt reading for the attached cube.
Definition: motion.h:444
T z
Vector component Z.
Definition: math.h:726
Byte3 maximum() const
Return the maximum values for each axis, as a vector.
Definition: motion.h:349
'shake' has changed
Definition: motion.h:454
#define ASSERT(_x)
Runtime debug assertion.
Definition: macros.h:205
Int3 range() const
Return the difference between maximum and minimum, as a vector.
Definition: motion.h:354
A standard recognizer for shake and tilt gestures.
Definition: motion.h:370
static const unsigned TICK_NS
Duration of the MotionBuffer's timestamp unit, in nanoseconds.
Definition: motion.h:87
Side
An enumeration which names the four sides of a Sifteo cube.
Definition: cube.h:54
static const unsigned TICK_NS
Duration of the MotionBuffer's timestamp unit, in nanoseconds.
Definition: motion.h:183
void bzero(void *s, unsigned count)
Write 'n' zero bytes to memory.
Definition: memory.h:114
ChangeFlags
Change flags, returned by update() to indicate what just changed.
Definition: motion.h:451
'tilt.y' has changed to -1
Definition: motion.h:461
T len2() const
Calculate the scalar length (magnitude) of this vector, squared.
Definition: math.h:747
static const unsigned TICK_US
Duration of the MotionBuffer's timestamp unit, in microseconds.
Definition: motion.h:186
static const unsigned TICK_HZ
Reciprocal of the MotionBuffer's timestamp unit, in Hertz.
Definition: motion.h:93
static const unsigned TICK_US
Duration of the MotionBuffer's timestamp unit, in microseconds.
Definition: motion.h:90
'tilt' has changed
Definition: motion.h:471
Byte3 physicalTilt() const
Return the physical tilt reading for the attached cube.
Definition: motion.h:430
T abs(const T &value)
For any type, return the absolute value.
Definition: math.h:90
Byte3 tilt
The most recent tilt value.
Definition: motion.h:404
static const unsigned TICK_HZ
Reciprocal of the MotionBuffer's timestamp unit, in Hertz.
Definition: motion.h:189
bool shake
The most recent binary shake state.
Definition: motion.h:407
T y
Vector component Y.
Definition: math.h:725
Int3 integrate(unsigned duration)
Calculate a numerical integral over recent motion data.
Definition: motion.h:155
float seconds() const
Return the timestamp at the iterator's current position, in seconds.
Definition: motion.h:264
'tilt.y' has changed to +1
Definition: motion.h:463
void attach(_SYSCubeID id)
Initialize this TiltShakeRecognizer and attach it to a cube.
Definition: motion.h:415
MotionIterator(_SYSMotionBuffer *buffer)
Construct a new MotionIterator, attached to the provided MotionBuffer.
Definition: motion.h:199
'tilt.z' has changed
Definition: motion.h:469
void attach(_SYSCubeID id, unsigned hz=100)
Initialize the MotionBuffer and attach it to a cube.
Definition: motion.h:119
'shake' has changed to 'true'
Definition: motion.h:452
void adjustTicks(int32_t value)
Add a value to the tick counter.
Definition: motion.h:286
MotionMedian()
Construct an uninitialized MotionMedian.
Definition: motion.h:331
Definition: array.h:34
void setTicks(uint32_t value)
Modify the tick counter.
Definition: motion.h:272
uint32_t ticks() const
Return the timestamp at the iterator's current position, in ticks.
Definition: motion.h:251
Vector3< int > Int3
Typedef for a 2-vector of ints.
Definition: math.h:840
Vector3< T > zRotateI(int angle) const
Rotate this vector about the Z axis counterclockwise by an integer multiple of 90 degrees...
Definition: math.h:800
Byte3 accel() const
Return the acceleration sample at the iterator's current position.
Definition: motion.h:237
MotionMedian(_SYSMotionBuffer *mbuf, unsigned duration)
Construct a MotionMedian with data calculated from the supplied MotionBuffer.
Definition: motion.h:334
Generalized three-element cartesian coordinate vector.
Definition: math.h:723
unsigned update(int latency=kFilterLatency)
Update the state of the TiltShakeRecognizer.
Definition: motion.h:488
Byte3 minimum() const
Return the minimum values for each axis, as a vector.
Definition: motion.h:344
'tilt.y' has changed to 0
Definition: motion.h:462
Utility for reading low-level motion events from a MotionBuffer.
Definition: motion.h:174
'shake' has changed to 'false'
Definition: motion.h:453
'tilt.z' has changed to -1
Definition: motion.h:466
'tilt.x' has changed
Definition: motion.h:459
'tilt.z' has changed to +1
Definition: motion.h:468
#define STATIC_ASSERT(_x)
Definition: macros.h:342
MotionMedian median
The most recent median data calculated by the TiltShakeRecognizer.
Definition: motion.h:396
void calculate(_SYSMotionBuffer *mbuf, unsigned duration)
Calculate the component-wise median of recent motion data.
Definition: motion.h:326
bool next()
Advance to the next motion sample, if possible.
Definition: motion.h:210
'tilt.x' has changed to 0
Definition: motion.h:457
MotionBuffer buffer
The MotionBuffer used by this TiltShakeRecognizer.
Definition: motion.h:386
Vector2< T > vec(T x, T y)
Create a Vector2, from a set of (x,y) coordinates.
Definition: math.h:658
'tilt.y' has changed
Definition: motion.h:464
A memory buffer which holds captured motion data.
Definition: motion.h:80