/
CMMotionManagerSim.m
354 lines (270 loc) · 9.79 KB
/
CMMotionManagerSim.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
* CMMotionManagerSim.m
*
* Created by Lloyd Hughes on 10/04/2013
*
* Based off of the original work by
* Created by Otto Chrons on 9/26/08.
* Copyright 2008 Seastringo Oy. All rights reserved.
*/
#import "CMMotionManagerSim.h"
// when compiling to ARM (iPhone device), hide everything and use system defaults
// if you wish to use simulation mode even on the device, remove the #if/#endif
#if !TARGET_CPU_ARM
#import <netdb.h>
#define kAccelerometerSimulationPort 10553
@implementation CMAccelerationSimulation
@synthesize acceleration;
@synthesize timestamp;
-(CMAccelerationSimulation*)init:(NSTimeInterval)aTimeStamp X:(double)ax Y:(double)ay Z:(double)az
{
self.timestamp = aTimeStamp;
acceleration.x = ax;
acceleration.y = ay;
acceleration.z = az;
return self;
}
@end
@implementation CMMagneticSimulation
@synthesize magneticField;
@synthesize timestamp;
-(CMMagneticSimulation*)init:(NSTimeInterval)aTimeStamp X:(double)ax Y:(double)ay Z:(double)az
{
self.timestamp = aTimeStamp;
magneticField.x = ax;
magneticField.y = ay;
magneticField.z = az;
return self;
}
@end
@implementation CMRotationSimulation
@synthesize rotationRate;
@synthesize timestamp;
-(CMRotationSimulation*)init:(NSTimeInterval)aTimeStamp X:(double)ax Y:(double)ay Z:(double)az
{
self.timestamp = aTimeStamp;
rotationRate.x = ax;
rotationRate.y = ay;
rotationRate.z = az;
return self;
}
@end
@implementation CMAttitudeSimulation
@synthesize timestamp;
@synthesize roll;
@synthesize pitch;
@synthesize yaw;
-(CMAttitudeSimulation*)init:(NSTimeInterval)aTimeStamp pitch:(double)pitch yaw:(double)yaw roll:(double)roll
{
self.timestamp = aTimeStamp;
self.pitch = pitch;
self.yaw = yaw;
self.roll = roll;
return self;
}
@end
@implementation CMDeviceMotionSimulation
@synthesize timestamp;
@synthesize attitude;
@synthesize gravity;
@synthesize magneticField;
@synthesize rotationRate;
@synthesize userAcceleration;
-(CMDeviceMotionSimulation*)init:(NSTimeInterval)aTimeStamp rot:(CMRotationSimulation*)rot att:(CMAttitudeSimulation*)att acc:(CMAccelerationSimulation*)acc
{
self.timestamp = aTimeStamp;
rotationRate = rot.rotationRate;
userAcceleration = acc.acceleration;
attitude = att;
return self;
}
@end
@implementation CMMotionManager (Simulation)
// override the static method and return our simulated version instead
- (BOOL) isAccelerometerAvailable{
return YES;
}
- (BOOL) isGyroAvailable{
return YES;
}
- (BOOL) isMagnetometerAvailable{
return YES;
}
- (BOOL) isDeviceMotionAvailable{
return YES;
}
@end
@implementation CMMotionManagerSim : CMMotionManager
@synthesize attData;
@synthesize deviceData;
@synthesize accelerometerData;
@synthesize gyroData;
@synthesize deviceMotion;
// this is straight from developer guide example for multi-threaded notifications
- (void) setUpThreadingSupport {
if ( notifications ) return;
notifications = [[NSMutableArray alloc] init];
notificationLock = [[NSLock alloc] init];
notificationThread = [[NSThread currentThread] retain];
notificationPort = [[NSMachPort alloc] init];
[notificationPort setDelegate:self];
[[NSRunLoop currentRunLoop] addPort:notificationPort
forMode:(NSString *) kCFRunLoopCommonModes];
}
// this is straight from developer guide example
- (void)startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMAccelerometerHandler)handler{
accelHandler = [handler copy];
accelOn = true;
}
- (void)startGyroUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMGyroHandler)handler {
gyroHandler = [handler copy];
gyroOn = true;
}
- (void)startMagnetometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMMagnetometerHandler)handler {
magHandler = [handler copy];
magOn = true;
}
- (void)startDeviceMotionUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMDeviceMotionHandler)handler {
deviceHandler = [handler copy];
accelOn = true;
gyroOn=true;
magOn=true;
deviceOn = true;
}
- (BOOL) isMagnetometerActive {
return magOn;
}
- (BOOL) isAccelerometerActive {
return accelOn;
}
- (BOOL) isGyroActive {
return gyroOn;
}
- (void) processNotification:(NSNotification *) notification {
if( [NSThread currentThread] != notificationThread ) {
// Forward the notification to the correct thread, this is the socket thread
NSDate* date = [[NSDate alloc] init];
[notificationLock lock];
[notifications addObject:notification];
[notificationLock unlock];
[notificationPort sendBeforeDate:date
components:nil
from:nil
reserved:0];
[date release];
}
else {
// now we are in the main thread
// Process the notification here;
NSString *data = (NSString*)[notification object];
// parse the data, no error handling!
NSArray *components = [data componentsSeparatedByString:@","];
NSString *type = [[components objectAtIndex:0] retain];
if (([type isEqualToString:@"ACC: 0"]) && accelHandler && accelOn){
[accelerometerData init:[[components objectAtIndex:1] doubleValue]
X:[[components objectAtIndex:2] doubleValue]
Y:[[components objectAtIndex:3] doubleValue]
Z:[[components objectAtIndex:4] doubleValue]];
accelHandler(accelerometerData, nil);
}
else if (([type isEqualToString:@"GYRO: 0"]) && gyroHandler && gyroOn){
[gyroData init:[[components objectAtIndex:1] doubleValue]
X:[[components objectAtIndex:2] doubleValue]
Y:[[components objectAtIndex:3] doubleValue]
Z:[[components objectAtIndex:4] doubleValue]];
gyroHandler(gyroData, nil);
}
else if (([type isEqualToString:@"MAG: 0"]) && magHandler && magOn){
[magnetometerData init:[[components objectAtIndex:1] doubleValue]
X:[[components objectAtIndex:2] doubleValue]
Y:[[components objectAtIndex:3] doubleValue]
Z:[[components objectAtIndex:4] doubleValue]];
magHandler(magnetometerData, nil);
}
else if (([type isEqualToString:@"DEV: 0"]) && deviceHandler && deviceOn){
[accelerometerData init:[[components objectAtIndex:1] doubleValue]
X:[[components objectAtIndex:2] doubleValue]
Y:[[components objectAtIndex:3] doubleValue]
Z:[[components objectAtIndex:4] doubleValue]];
[gyroData init:[[components objectAtIndex:1] doubleValue]
X:[[components objectAtIndex:5] doubleValue]
Y:[[components objectAtIndex:6] doubleValue]
Z:[[components objectAtIndex:7] doubleValue]];
[attData init:[[components objectAtIndex:1] doubleValue]
pitch:[[components objectAtIndex:8] doubleValue]
yaw:[[components objectAtIndex:9] doubleValue]
roll:[[components objectAtIndex:10] doubleValue]];
[deviceData init:[[components objectAtIndex:1] doubleValue]
rot:gyroData
att:attData
acc:accelerometerData];
deviceHandler(deviceData, nil);
}
else { }
}
}
// this is straight from developer guide example
- (void) handleMachMessage:(void *) msg {
[notificationLock lock];
while ( [notifications count] ) {
NSNotification *notification = [[notifications objectAtIndex:0] retain];
[notifications removeObjectAtIndex:0];
[notificationLock unlock];
[self processNotification:notification];
[notification release];
[notificationLock lock];
};
[notificationLock unlock];
}
- (void)threadLoop:(id)object
{
char buffer[1024];
// we never exit...
while(1) {
int count = recv( udpSocket, buffer, sizeof(buffer), 0 );
if( count > 0 )
{
// got data, let's pass it on
buffer[count] = 0;
NSString *str = [[NSString alloc] initWithUTF8String:buffer];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ThreadAccelNotification" object:str];
[str release];
}
}
}
// initialize our version of the accelerometer
- (CMMotionManagerSim *)init
{
[super init];
accelerometerData = [CMAccelerationSimulation alloc];
gyroData = [CMRotationSimulation alloc];
attData = [CMAttitudeSimulation alloc];
deviceData = [CMDeviceMotionSimulation alloc];
isExiting = false;
gyroOn = magOn = accelOn = NO;
// couldn't get the CFSocket version to work with UDP and runloop, so used Berkely sockets and a thread instead
udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
// listen on all interfaces
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_port = htons(kAccelerometerSimulationPort);
bind(udpSocket, (const struct sockaddr*)&sin, sizeof(sin));
// create a separate thread for receiving UDP packets
thread = [[NSThread alloc] initWithTarget:self
selector:@selector(threadLoop:)
object:nil];
[thread start];
// cross-thread communication setup
[self setUpThreadingSupport];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(processNotification:)
name:@"ThreadAccelNotification"
object:nil];
return self;
}
@end
#endif