Skip to content

Commit

Permalink
Demo app shows iPhone and Air Guitar accelerometer data.
Browse files Browse the repository at this point in the history
  • Loading branch information
ronaldmannak committed Jul 22, 2012
1 parent 202d055 commit 2ab94b1
Show file tree
Hide file tree
Showing 18 changed files with 668 additions and 53 deletions.
8 changes: 8 additions & 0 deletions AirGuitarSDK/AirGuitarSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
F8E211C215BB2B250074CEBB /* AGAccessory.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E211C015BB2B250074CEBB /* AGAccessory.m */; };
F8E211C515BB2C170074CEBB /* AGAccessoryManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F8E211C315BB2C170074CEBB /* AGAccessoryManager.h */; };
F8E211C615BB2C170074CEBB /* AGAccessoryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E211C415BB2C170074CEBB /* AGAccessoryManager.m */; };
F8E211EC15BB8FA60074CEBB /* BoardMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = F8E211EA15BB8FA60074CEBB /* BoardMessage.h */; };
F8E211ED15BB8FA60074CEBB /* BoardMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E211EB15BB8FA60074CEBB /* BoardMessage.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -53,6 +55,8 @@
F8E211C015BB2B250074CEBB /* AGAccessory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AGAccessory.m; sourceTree = "<group>"; };
F8E211C315BB2C170074CEBB /* AGAccessoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AGAccessoryManager.h; sourceTree = "<group>"; };
F8E211C415BB2C170074CEBB /* AGAccessoryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AGAccessoryManager.m; sourceTree = "<group>"; };
F8E211EA15BB8FA60074CEBB /* BoardMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoardMessage.h; sourceTree = "<group>"; };
F8E211EB15BB8FA60074CEBB /* BoardMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BoardMessage.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -114,6 +118,8 @@
F8E2116D15BA69EC0074CEBB /* AirGuitarSDK.m */,
F8E211BF15BB2B250074CEBB /* AGAccessory.h */,
F8E211C015BB2B250074CEBB /* AGAccessory.m */,
F8E211EA15BB8FA60074CEBB /* BoardMessage.h */,
F8E211EB15BB8FA60074CEBB /* BoardMessage.m */,
F8E211C315BB2C170074CEBB /* AGAccessoryManager.h */,
F8E211C415BB2C170074CEBB /* AGAccessoryManager.m */,
F8E211A415BB25B90074CEBB /* AGMotionManager.h */,
Expand Down Expand Up @@ -161,6 +167,7 @@
F8E211BE15BB29EC0074CEBB /* AirGuitarSDK.m in Headers */,
F8E211C115BB2B250074CEBB /* AGAccessory.h in Headers */,
F8E211C515BB2C170074CEBB /* AGAccessoryManager.h in Headers */,
F8E211EC15BB8FA60074CEBB /* BoardMessage.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -266,6 +273,7 @@
F8E211A715BB25B90074CEBB /* AGMotionManager.m in Sources */,
F8E211C215BB2B250074CEBB /* AGAccessory.m in Sources */,
F8E211C615BB2C170074CEBB /* AGAccessoryManager.m in Sources */,
F8E211ED15BB8FA60074CEBB /* BoardMessage.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
Expand Down
15 changes: 14 additions & 1 deletion AirGuitarSDK/AirGuitarSDK/AGAccessory.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@
#import <Foundation/Foundation.h>
#import <ExternalAccessory/ExternalAccessory.h>

@interface AGAccessory : EAAccessory
@class AGAccessory;

@protocol AGAccessoryProtocol
- (void) accessory: (AGAccessory *) accessory x: (double) x y: (double) y z: (double) z;
@end

@interface AGAccessory : NSObject <NSStreamDelegate>

@property (nonatomic, weak) id <AGAccessoryProtocol> delegate;

// Add XYZ acceleration data

@property (nonatomic, strong) EASession *session;
@property (nonatomic, weak) EAAccessory *accessory;

- (id)initWithAccessory: (EAAccessory *)accessory protocol: (NSString *) protocolString;

@end
183 changes: 183 additions & 0 deletions AirGuitarSDK/AirGuitarSDK/AGAccessory.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,190 @@
//

#import "AGAccessory.h"
#import "AGAccessoryManager.h"
#import "BoardMessage.h"

#define MAX_MESSAGE_LENGTH 1024
#define RECEIVE_BUFFER_LENGTH 1024*4

@interface AGAccessory () {
NSMutableData *_writeData;
NSMutableData *_readData;
}
@end

@implementation AGAccessory

- (id)initWithAccessory: (EAAccessory *)accessory protocol: (NSString *) protocolString {
self = [super init];
if (self) {

// Open session
_session = [[EASession alloc] initWithAccessory:accessory forProtocol:protocolString];
_accessory = accessory;

if (_session) {
[[_session inputStream] setDelegate:self];
[[_session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session inputStream] open];

[[_session outputStream] setDelegate:self];
[[_session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session outputStream] open];

[self enableAccelerometerData: YES];
}
else NSLog(@"creating session failed");

}
return self;
}

- (void)dealloc {
DLog(@"deallocing AGAccessory");
[[_session inputStream] close];
[[_session inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session inputStream] setDelegate:nil];
[[_session outputStream] close];
[[_session outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session outputStream] setDelegate:nil];
_session = nil;

_writeData = nil;
_readData = nil;
}


#pragma mark - Setting Air Guitar accessory


- (void) enableAccelerometerData:(BOOL)enable{
BoardMessage * message = [BoardMessage analogInLiveEnable:enable];
if ([[_session outputStream] hasSpaceAvailable]) {
[[_session outputStream] write: [message getMsgDataPtr] maxLength: [message length]];
}
}

#pragma mark - NSStream functions

// low level write method - write data to the accessory while there is space available and data to write
- (void)_writeData {
while (([[_session outputStream] hasSpaceAvailable]) && ([_writeData length] > 0))
{
NSInteger bytesWritten = [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]];
if (bytesWritten == -1)
{
NSLog(@"write error");
break;
}
else if (bytesWritten > 0)
{
[_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
}
}
}

// low level read method - read data while there is data and space available in the input buffer
- (void)_readData {

/* #define EAD_INPUT_BUFFER_SIZE 128
uint8_t buf[EAD_INPUT_BUFFER_SIZE];
while ([[_session inputStream] hasBytesAvailable])
{
NSInteger bytesRead = [[_session inputStream] read:buf maxLength:EAD_INPUT_BUFFER_SIZE];
if (_readData == nil) {
_readData = [[NSMutableData alloc] init];
}
[_readData appendBytes:(void *)buf length:bytesRead];
//NSLog(@"read %d bytes from input stream", bytesRead);
}
DLog(@"reading data: %@", _readData); */



u_int8_t buffer[MAX_MESSAGE_LENGTH];
NSInteger length = 0;
BoardMessage *message;
static u_int8_t receiveBufferLength = 0;
static u_int8_t receiveBuffer[RECEIVE_BUFFER_LENGTH];

// needs to be read
// read into a buffer first as there is no guarantee this will land on a message boundry
if (receiveBufferLength + MAX_MESSAGE_LENGTH <= RECEIVE_BUFFER_LENGTH) {
length = [[_session inputStream] read:buffer maxLength:MAX_MESSAGE_LENGTH];
if (length) {
memcpy(receiveBuffer+receiveBufferLength, buffer, length);
receiveBufferLength = receiveBufferLength + length;
}
}

// parse the message buffer for as long as possible
do {
message = [BoardMessage parse:receiveBuffer length:receiveBufferLength];
if (message) {
receiveBufferLength = receiveBufferLength - message.length;
if (receiveBufferLength > 0) {
memmove(receiveBuffer, receiveBuffer+message.length, receiveBufferLength);
}
[self parseAccessoryAcceleremeterMessage:message];
}
} while (message != nil);
}

- (void) parseAccessoryAcceleremeterMessage: (BoardMessage *) message {

BoardMessage *boardMessage = (BoardMessage *)message; // TODO

int analogChannelsToRead=[boardMessage getByte:0];
int dataIndex;
int x,y,z;
dataIndex=1;

if (analogChannelsToRead==3){
u_int8_t channelNumber=[boardMessage getByte:dataIndex++];
x=([boardMessage getByte:dataIndex++]<<8) + [boardMessage getByte:dataIndex++];

channelNumber = [boardMessage getByte:dataIndex++];
y=([boardMessage getByte:dataIndex++]<<8) + [boardMessage getByte:dataIndex++];

channelNumber = [boardMessage getByte:dataIndex++];
z=([boardMessage getByte:dataIndex++]<<8) + [boardMessage getByte:dataIndex++];

float rawX =(x-512.f)/64.f;
float rawY =(y-512.f)/64.f;
float rawZ =(z-512.f)/64.f;

[_delegate accessory: self x: rawX y:rawY z:rawZ];
}
}

#pragma mark NSStreamDelegateEventExtensions

// asynchronous NSStream handleEvent method
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
[self _readData];
break;
case NSStreamEventHasSpaceAvailable:
[self _writeData];
break;
case NSStreamEventErrorOccurred:
break;
case NSStreamEventEndEncountered:
break;
default:
break;
}
}


@synthesize delegate = _delegate,
session = _session,
accessory = _accessory;
@end
7 changes: 6 additions & 1 deletion AirGuitarSDK/AirGuitarSDK/AGAccessoryManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@
#import <Foundation/Foundation.h>
#import <ExternalAccessory/ExternalAccessory.h>


@interface AGAccessoryManager : NSObject

@property (nonatomic, readonly) NSMutableArray *connectedAGAccessories;
/* list of all connected Air Guitar compatible devices */
@property (nonatomic, readonly) NSMutableDictionary *connectedAGAccessories;

/* list of supported protocols. Not implemented yet. For now, only com.yobble.airguitar is supported */
@property (nonatomic, readonly) NSArray *compatibleProtocolStrings;

/* If YES, AGAccessoryManager will send our connect and disconnect notications to app. */
@property (nonatomic) BOOL shouldSendNotifications;
Expand Down
66 changes: 39 additions & 27 deletions AirGuitarSDK/AirGuitarSDK/AGAccessoryManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "AGAccessoryManager.h"
#import "AGAccessory.h"

#define AG_PROTOCOL_STRING @"com.yobble.airguitar"

Expand All @@ -29,10 +30,26 @@ + (id)sharedAccessoryManager {
- (id)init {
self = [super init];
if (self) {
_connectedAGAccessories = [[NSMutableArray alloc] initWithCapacity:3];

[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
_connectedAGAccessories = [[NSMutableDictionary alloc] initWithCapacity:3];
_compatibleProtocolStrings = [NSArray arrayWithObjects: AG_PROTOCOL_STRING, nil]; // Future addition

// Check if an Air Guitar compatible device is already connected
for (EAAccessory *connectedAccessory in [EAAccessoryManager sharedAccessoryManager].connectedAccessories) {
if ([[connectedAccessory protocolStrings] containsObject:AG_PROTOCOL_STRING]) {

AGAccessory *accessory = [[AGAccessory alloc] initWithAccessory:connectedAccessory protocol:AG_PROTOCOL_STRING];
NSString *key = [NSString stringWithFormat:@"%d", connectedAccessory.connectionID];
[_connectedAGAccessories setObject:accessory forKey:key];

if (_shouldSendNotifications) {
[[NSNotificationCenter defaultCenter]
postNotificationName:@"AGAccessoryDidConnect"
object:accessory];
}
DLog(@"Connected at init: %@", _connectedAGAccessories);
}
}

// Register for all connect and disconnect
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessoryDidConnect:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessoryDidDisconnect:) name:EAAccessoryDidDisconnectNotification object:nil];
Expand All @@ -55,13 +72,17 @@ - (void)accessoryDidConnect: (NSNotification *)notification {
// Check if an Air Guitar compatible accessory was connected
if ([[connectedAccessory protocolStrings] containsObject:AG_PROTOCOL_STRING]) {

[_connectedAGAccessories addObject:connectedAccessory];
// TODO: establishconnection
// Create new AGAccessory object
AGAccessory *accessory = [[AGAccessory alloc] initWithAccessory:connectedAccessory protocol:AG_PROTOCOL_STRING];
NSString *key = [NSString stringWithFormat:@"%d", connectedAccessory.connectionID];
[_connectedAGAccessories setObject:accessory forKey:key];

if (_shouldSendNotifications) {
// TODO: fire new notification

[[NSNotificationCenter defaultCenter]
postNotificationName:@"AGAccessoryDidConnect"
object:accessory];
}
NSLog(@"Connected List: %@", _connectedAGAccessories);
DLog(@"Connected List: %@", _connectedAGAccessories);
}
}

Expand All @@ -72,30 +93,21 @@ - (void)accessoryDidDisconnect: (NSNotification *)notification {
// Return if a non-Air Guitar accessory was disconnected
if (![[disconnectedAccessory protocolStrings] containsObject:AG_PROTOCOL_STRING]) return;

// Delete AGAAccessory object
[_connectedAGAccessories removeObject:disconnectedAccessory];
// Remove the disconnected accessory from the connectedAGAccessory dictionary
NSString *key = [NSString stringWithFormat:@"%d", disconnectedAccessory.connectionID];
[_connectedAGAccessories removeObjectForKey:key];
if (_shouldSendNotifications) {
// TODO: fire new notification
[[NSNotificationCenter defaultCenter]
postNotificationName:@"AGAccessoryDidDisconnect"
object:nil];
}

// Remove the disconnected accessory from the connectedAGAccessory array
int disconnectedAccessoryIndex = 0;
for(EAAccessory *accessory in _connectedAGAccessories) {
if ([disconnectedAccessory connectionID] == [accessory connectionID]) {
break;
}
disconnectedAccessoryIndex++;
}

if (disconnectedAccessoryIndex < [_connectedAGAccessories count]) {
[_connectedAGAccessories removeObjectAtIndex:disconnectedAccessoryIndex];
NSLog(@"Connected List: %@", _connectedAGAccessories);
} else {
NSLog(@"could not find disconnected accessory in accessory list");
}
DLog(@"Disconnected device: %@", disconnectedAccessory);
DLog(@"Connected List: %@", _connectedAGAccessories);
}

@synthesize shouldSendNotifications = _shouldSendNotifications,
connectedAGAccessories = _connectedAGAccessories;
connectedAGAccessories = _connectedAGAccessories,
compatibleProtocolStrings = _compatibleProtocolStrings;

@end
6 changes: 6 additions & 0 deletions AirGuitarSDK/AirGuitarSDK/AirGuitarSDK-Prefix.pch
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif

#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
Loading

0 comments on commit 2ab94b1

Please sign in to comment.