Last active
August 29, 2015 14:03
-
-
Save CodaFi/81f6b38e8ab684e0c099 to your computer and use it in GitHub Desktop.
Accelerometer data from the sudden motion sensor.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NUIAccelerometer.h | |
// NUIKit | |
// | |
// Created by Robert Widmann on 7/5/14. | |
// Copyright (c) 2014 CodaFi. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <NUIKit/NUIKitDefines.h> | |
/// A structure that contains the acceleration values for all 3 axes. | |
typedef struct NUIAccelerationData { | |
double x, y, z; | |
} NUIAccelerationData; | |
/// Defines acceleration data where all of the values are 0. | |
NUIKIT_EXTERN const NUIAccelerationData NUIAccelerationDataZero; | |
/// The NUIAccelerometer class lets you register to receive acceleration-related data from the | |
/// onboard hardware. As a device moves, its hardware reports linear acceleration changes along the | |
/// primary axes in three-dimensional space. You can use this data to detect both the current | |
/// orientation of the device (relative to the ground) and any instantaneous changes to that | |
/// orientation. You might use instantaneous changes as input to a game or to initiate some action | |
/// in your application. | |
/// | |
/// You do not create accelerometer data directly. Instead, you use the shared NUIAccelerometer | |
/// object to specify the interval at which you want to receive events, a callback queue, and a | |
/// callback handler. | |
/// | |
/// For some Macintosh models (notably desktops), a Sudden Motion Sensor may not be available. In | |
/// addition, laptops and desktops that contain SSDs often lack sudden motion sensors. In that case | |
/// any attempts to initialize an NUIAccelerometer object will fail and return nil. | |
@interface NUIAccelerometer : NSObject { | |
@private | |
dispatch_queue_t _queue; | |
dispatch_source_t _timer; | |
struct { | |
unsigned int started:1; | |
} _accelerometerFlags; | |
} | |
/// Returns the shared accelerometer object. | |
/// | |
/// If the system does not support an accelerometer, or one is not provided, this method returns nil. | |
+ (NUIAccelerometer *)sharedAccelerometer; | |
/// The interval at which to deliver acceleration data to the delegate. | |
/// | |
/// This property is measured in seconds. While the value of this property is not capped at any | |
/// lower or upper bound, it is important to specify a value that is not too frequent, as repeatedly | |
/// polling the hardware can be taxing on battery life. | |
@property (nonatomic) NSTimeInterval updateInterval; | |
/// A Boolean value that indicates whether an accelerometer is available on the device. | |
@property (nonatomic, readonly, getter=isAccelerometerAvailable) BOOL accelerometerAvailable; | |
/// A Boolean value that indicates whether accelerometer updates are currently happening. | |
/// | |
/// This property indicates whether -startAccelerometerUpdatesToQueue:withHandler: or | |
/// -startAccelerometerUpdates has been called since the last time stopAccelerometerUpdates was | |
/// called. | |
@property (nonatomic, readonly, getter=isAccelerometerActive) BOOL accelerometerActive; | |
/// The latest sample of accelerometer data. | |
/// | |
/// If no accelerometer data is available, the value of this property is NUIAccelerationDataZero. | |
/// An app that is receiving accelerometer data after calling -startAccelerometerUpdates | |
/// periodically checks the value of this property and processes the acceleration data. | |
@property (nonatomic, readonly) NUIAccelerationData accelerometerData; | |
/// Starts accelerometer updates without a handler. | |
/// | |
/// Invoking this method is the same as providing a nil queue and nil handler to | |
/// -startAccelerometerUpdatesToQueue:withHandler:. | |
- (void)startAccelerometerUpdates; | |
/// Starts accelerometer updates on an operation queue and with a specified handler. | |
/// | |
/// If no queue is provided, an internal background queue will be created. If no handler block is | |
/// provided, the accelerometerData property will continue to update until accelerometer updates | |
/// are stopped. | |
- (void)startAccelerometerUpdatesToQueue:(dispatch_queue_t)queue withHandler:(void (^)(NUIAccelerationData accelerometerData, NSTimeInterval timestamp))handler; | |
/// Stops accelerometer updates. | |
- (void)stopAccelerometerUpdates; | |
@end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NUIAccelerometer.m | |
// NUIKit | |
// | |
// Created by Robert Widmann on 7/5/14. | |
// Copyright (c) 2014 CodaFi. All rights reserved. | |
// | |
#import "NUIAccelerometer.h" | |
#import <IOKit/IOKitLib.h> | |
const NUIAccelerationData NUIAccelerationDataZero = (NUIAccelerationData){0}; | |
static mach_port_t NUIAccelerometerSensorPort; | |
@interface NUIAccelerometer () | |
@property (nonatomic) NUIAccelerationData accelerometerData; | |
@end | |
@implementation NUIAccelerometer | |
+ (void)initialize { | |
if (self.class != NUIAccelerometer.class) { | |
return; | |
} | |
} | |
+ (NUIAccelerometer *)sharedAccelerometer { | |
static NUIAccelerometer *instance; | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
instance = [[NUIAccelerometer alloc] initOnce]; | |
}); | |
return instance; | |
} | |
- (instancetype)init { | |
NSAssert(0, @"Manually initializing an accelerometer is forbidden. Use +[NUIAccelerometer sharedAccelerometer] instead."); | |
return nil; | |
} | |
- (instancetype)initOnce { | |
self = [super init]; | |
if (self.isAccelerometerAvailable) { | |
return self; | |
} | |
NUI_RELEASE_MRCONLY(self); | |
return nil; | |
} | |
- (void)dealloc { | |
[self stopAccelerometerUpdates]; | |
NUI_DEALLOC_MRCONLY; | |
} | |
- (void)startAccelerometerUpdates { | |
[self startAccelerometerUpdatesToQueue:NULL withHandler:NULL]; | |
} | |
- (void)startAccelerometerUpdatesToQueue:(dispatch_queue_t)queue withHandler:(void (^)(NUIAccelerationData, NSTimeInterval))handler { | |
if (_accelerometerFlags.started || self.updateInterval <= 0.0) { | |
return; | |
} | |
_accelerometerFlags.started = true; | |
[self stopAccelerometerUpdates]; | |
if (queue != nil && handler != NULL) { | |
dispatch_retain(queue); | |
_queue = queue; | |
} else { | |
_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_PRIORITY_DEFAULT); | |
} | |
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _queue); | |
if (handler == NULL) { | |
NUI_WEAKIFY(self); | |
handler = ^(NUIAccelerationData data, NSTimeInterval _) { | |
NUI_STRONGIFY(self); | |
self.accelerometerData = data; | |
}; | |
} | |
NUI_WEAKIFY(self); | |
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, self.updateInterval * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); | |
dispatch_source_set_event_handler(_timer, ^{ | |
NUI_STRONGIFY(self); | |
NUIAccelerationData inputStructure, outputStructure; | |
size_t inSize = sizeof(NUIAccelerationData), outSize = sizeof(NUIAccelerationData); | |
int result = IOConnectCallStructMethod(NUIDefaultAccelerometerSensorPort(), 5, &inputStructure, inSize, &outputStructure, &outSize); | |
if(result != KERN_SUCCESS) { | |
return; | |
} | |
self.accelerometerData = outputStructure; | |
handler(outputStructure, CACurrentMediaTime()); | |
}); | |
} | |
- (void)stopAccelerometerUpdates { | |
if (_timer != NULL) { | |
dispatch_source_cancel(_timer); | |
dispatch_release(_timer); | |
_timer = NULL; | |
} | |
if (_queue) { | |
dispatch_release(_queue); | |
_queue = NULL; | |
} | |
_accelerometerFlags.started = false; | |
} | |
- (void)setUpdateInterval:(NSTimeInterval)updateInterval { | |
if (!_accelerometerFlags.started) { | |
_updateInterval = updateInterval; | |
} | |
} | |
- (BOOL)isAccelerometerAvailable { | |
return NUIDefaultAccelerometerSensorPort() != 0; | |
} | |
- (BOOL)isAccelerometerActive { | |
return _accelerometerFlags.started; | |
} | |
static mach_port_t NUIDefaultAccelerometerSensorPort() { | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
mach_port_t dataPort; | |
io_iterator_t iterator; | |
io_object_t aDevice; | |
int r; | |
r = IOMasterPort(MACH_PORT_NULL, &dataPort); | |
if (r != KERN_SUCCESS) { | |
NSCAssert(0, @"NUIAccelerometer Internal Error: Could not grab the master port."); | |
return; | |
} | |
CFMutableDictionaryRef servicesMatching = IOServiceMatching("SMCMotionSensor"); | |
r = IOServiceGetMatchingServices(kIOMasterPortDefault, servicesMatching, &iterator); | |
if (r != KERN_SUCCESS) { | |
return; | |
} | |
aDevice = IOIteratorNext(iterator); | |
IOObjectRelease(iterator); | |
if(aDevice == 0) { | |
return; | |
} | |
r = IOServiceOpen(aDevice, mach_task_self(), 0, &dataPort); | |
IOObjectRelease(aDevice); | |
if(r != KERN_SUCCESS) { | |
NSCAssert(0, @"NUIAccelerometer Internal Error: Could not open connection to accelerometer."); | |
return; | |
} | |
NUIAccelerometerSensorPort = dataPort; | |
}); | |
return NUIAccelerometerSensorPort; | |
} | |
- (NSString *)description { | |
return [NSString stringWithFormat:@"<%@: %p; update interval %.4g;", self.class, self, self.updateInterval]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NUIKitDefines.h | |
// NUIKit | |
// | |
// Created by Robert Widmann on 7/7/13. | |
// Copyright (c) 2013 CodaFi. All rights reserved. | |
// Released under the MIT license. | |
// | |
#import <Availability.h> | |
#ifdef __cplusplus | |
#define NUIKIT_EXTERN extern "C" | |
#define NUIKIT_PRIVATE_EXTERN __attribute__((visibility("hidden"))) extern "C" | |
#define NUIKIT_PRIVATE __attribute__((visibility("hidden"))) | |
#else | |
#define NUIKIT_EXTERN extern | |
#define NUIKIT_PRIVATE_EXTERN __attribute__((visibility("hidden"))) extern | |
#define NUIKIT_PRIVATE __attribute__((visibility("hidden"))) | |
#endif | |
#define NUIKIT_STATIC_INLINE static inline | |
#ifndef NUI_RELEASE_MRCONLY | |
#if __has_feature(objc_arc) | |
#define NUI_RELEASE_MRCONLY(x) x = nil | |
#else | |
#define NUI_RELEASE_MRCONLY(x) [x release], x = nil | |
#endif | |
#endif | |
#ifndef NUI_AUTORELEASE_MRCONLY | |
#if __has_feature(objc_arc) | |
#define NUI_AUTORELEASE_MRCONLY(x) | |
#else | |
#define NUI_AUTORELEASE_MRCONLY(x) [x autorelease] | |
#endif | |
#endif | |
#ifndef NUI_RETAIN_MRCONLY | |
#if __has_feature(objc_arc) | |
#define NUI_RETAIN_MRCONLY(x) x | |
#else | |
#define NUI_RETAIN_MRCONLY(x) [x retain] | |
#endif | |
#endif | |
#ifndef NUI_BRIDGE | |
#if __has_feature(objc_arc) | |
#define NUI_BRIDGE(x) (__bridge x) | |
#else | |
#define NUI_BRIDGE(x) (x) | |
#endif | |
#endif | |
#ifndef NUI_DEALLOC_MRCONLY | |
#if __has_feature(objc_arc) | |
#define NUI_DEALLOC_MRCONLY | |
#else | |
#define NUI_DEALLOC_MRCONLY [super dealloc] | |
#endif | |
#endif | |
#ifndef NUI_SAFE_ATOMIC_RETVAL | |
#if __has_feature(objc_arc) | |
#define NUI_SAFE_ATOMIC_RETVAL(x) x | |
#else | |
#define NUI_SAFE_ATOMIC_RETVAL(x) [[x retain]autorelease] | |
#endif | |
#endif | |
#ifndef NUI_WEAKIFY | |
#if __has_feature(objc_arc) | |
#define NUI_WEAKIFY(x) __weak __typeof__(x) _nui_weakSelf = x | |
#else | |
#define NUI_WEAKIFY(x) __block __typeof__(x) _nui_weakSelf = x | |
#endif | |
#endif | |
#ifndef NUI_STRONGIFY | |
#if __has_feature(objc_arc) | |
#define NUI_STRONGIFY(x) __strong __typeof__(x) x = _nui_weakSelf | |
#else | |
#define NUI_STRONGIFY(x) __typeof__(x) x = _nui_weakSelf | |
#endif | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment