(iOS) Move all bluetooth processing to WiiMoteHelper.m; delete BTstackManager.m

This commit is contained in:
meancoot 2013-03-22 09:47:04 -04:00
parent 1c332e42f8
commit 95259d4b86
5 changed files with 186 additions and 961 deletions

View File

@ -21,7 +21,6 @@
963F5AC316CC522F009BBD19 /* RASettingsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5ABF16CC522F009BBD19 /* RASettingsList.m */; };
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; };
966B9CA216E418B7005B61E1 /* BTDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9C9116E418B7005B61E1 /* BTDevice.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
966B9CA416E418B7005B61E1 /* BTstackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9C9C16E418B7005B61E1 /* BTstackManager.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
966B9CA616E418B7005B61E1 /* wiimote.c in Sources */ = {isa = PBXBuildFile; fileRef = 966B9C9E16E418B7005B61E1 /* wiimote.c */; };
966B9CA716E418B7005B61E1 /* WiiMoteHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CA116E418B7005B61E1 /* WiiMoteHelper.m */; };
966B9CAE16E41C07005B61E1 /* browser.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CAA16E41C07005B61E1 /* browser.m */; };
@ -73,8 +72,6 @@
966B9C9816E418B7005B61E1 /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = run_loop.h; sourceTree = "<group>"; };
966B9C9916E418B7005B61E1 /* sdp_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdp_util.h; sourceTree = "<group>"; };
966B9C9A16E418B7005B61E1 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
966B9C9B16E418B7005B61E1 /* BTstackManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTstackManager.h; sourceTree = "<group>"; };
966B9C9C16E418B7005B61E1 /* BTstackManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTstackManager.m; sourceTree = "<group>"; };
966B9C9E16E418B7005B61E1 /* wiimote.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wiimote.c; sourceTree = "<group>"; };
966B9C9F16E418B7005B61E1 /* wiimote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wiimote.h; sourceTree = "<group>"; };
966B9CA016E418B7005B61E1 /* WiiMoteHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WiiMoteHelper.h; sourceTree = "<group>"; };
@ -158,8 +155,6 @@
966B9C9016E418B7005B61E1 /* BTDevice.h */,
966B9C9116E418B7005B61E1 /* BTDevice.m */,
966B9C9416E418B7005B61E1 /* btstack */,
966B9C9B16E418B7005B61E1 /* BTstackManager.h */,
966B9C9C16E418B7005B61E1 /* BTstackManager.m */,
966B9C9E16E418B7005B61E1 /* wiimote.c */,
966B9C9F16E418B7005B61E1 /* wiimote.h */,
966B9CA016E418B7005B61E1 /* WiiMoteHelper.h */,
@ -404,7 +399,6 @@
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */,
96096DD816D1ABAF00BF4499 /* RAModuleInfoList.m in Sources */,
966B9CA216E418B7005B61E1 /* BTDevice.m in Sources */,
966B9CA416E418B7005B61E1 /* BTstackManager.m in Sources */,
966B9CA616E418B7005B61E1 /* wiimote.c in Sources */,
966B9CA716E418B7005B61E1 /* WiiMoteHelper.m in Sources */,
966B9CAE16E41C07005B61E1 /* browser.m in Sources */,

View File

@ -1,188 +0,0 @@
/*
* Copyright (C) 2009 by Matthias Ringwald
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#pragma once
#import <Foundation/Foundation.h>
#import <stdint.h>
#import "btstack/btstack.h"
#define PREFS_REMOTE_NAME @"RemoteName"
#define PREFS_LINK_KEY @"LinkKey"
#define BTstackManagerID @"ch.ringwald.btstack"
@class BTDevice;
/*
* Information on devices is stored in a system-wide plist
* it is maintained by BTstackManager
* this includes the link keys
*/
// TODO enumerate BTstackError type
typedef int BTstackError;
typedef enum {
kDeactivated = 1,
kW4SysBTState,
kW4SysBTDisabled,
kW4Activated,
kActivated,
kW4Deactivated,
kSleeping,
#if 0
kW4DisoveryStopped,
kW4AuthenticationEnableCommand
#endif
} ManagerState;
typedef enum {
kInactive = 1,
kW4InquiryMode,
kInquiry,
kRemoteName,
// stopping
kW4InquiryModeBeforeStop,
kW4InquiryStop,
kW4RemoteNameBeforeStop,
} DiscoveryState;
@protocol BTstackManagerDelegate;
@protocol BTstackManagerListener;
@interface BTstackManager : NSObject {
@private
NSObject<BTstackManagerDelegate>* _delegate;
NSMutableArray *discoveredDevices;
NSMutableSet *listeners;
BOOL connectedToDaemon;
ManagerState state;
DiscoveryState discoveryState;
int discoveryDeviceIndex;
#if 0
// current connection - kind a ugly
uint8_t connType; // 0 = L2CAP, 1 = RFCOMM
bd_addr_t connAddr;
uint16_t connPSM;
uint16_t connChan;
uint8_t connAuth;
#endif
}
// shared instance
+(BTstackManager *) sharedInstance;
// listeners
-(void) addListener:(id<BTstackManagerListener>)listener;
-(void) removeListener:(id<BTstackManagerListener>)listener;
// Activation
-(BTstackError) activate;
-(BTstackError) deactivate;
-(BOOL) isActivating;
-(BOOL) isActive;
// Discovery
-(BTstackError) startDiscovery;
-(BTstackError) stopDiscovery;
-(int) numberOfDevicesFound;
-(BTDevice*) deviceAtIndex:(int)index;
-(BOOL) isDiscoveryActive;
// Link Key Management
-(void) dropLinkKeyForAddress:(bd_addr_t*) address;
// Connections
-(BTstackError) createL2CAPChannelAtAddress:(bd_addr_t*) address withPSM:(uint16_t)psm authenticated:(BOOL)authentication;
-(BTstackError) closeL2CAPChannelWithID:(uint16_t) channelID;
-(BTstackError) sendL2CAPPacketForChannelID:(uint16_t)channelID;
-(BTstackError) createRFCOMMConnectionAtAddress:(bd_addr_t*) address withChannel:(uint16_t)channel authenticated:(BOOL)authentication;
-(BTstackError) closeRFCOMMConnectionWithID:(uint16_t) connectionID;
-(BTstackError) sendRFCOMMPacketForChannelID:(uint16_t)connectionID;
// TODO add l2cap and rfcomm incoming commands
@property (nonatomic, assign) NSObject<BTstackManagerDelegate>* delegate;
@property (nonatomic, retain) NSMutableArray *discoveredDevices;
@property (nonatomic, retain) NSMutableSet *listeners;
@end
@protocol BTstackManagerDelegate
@optional
// Activation callbacks
-(BOOL) disableSystemBluetoothBTstackManager:(BTstackManager*) manager; // default: YES
// Connection events
-(NSString*) btstackManager:(BTstackManager*) manager pinForAddress:(bd_addr_t)addr; // default: "0000"
// direct access
-(void) btstackManager:(BTstackManager*) manager
handlePacketWithType:(uint8_t) packet_type
forChannel:(uint16_t) channel
andData:(uint8_t *)packet
withLen:(uint16_t) size;
@end
@protocol BTstackManagerListener
@optional
// Activation events
-(void) activatedBTstackManager:(BTstackManager*) manager;
-(void) btstackManager:(BTstackManager*)manager activationFailed:(BTstackError)error;
-(void) deactivatedBTstackManager:(BTstackManager*) manager;
// Power management events
-(void) sleepModeEnterBTstackManager:(BTstackManager*) manager;
-(void) sleepModeExtitBTstackManager:(BTstackManager*) manager;
// Discovery events: general
-(void) btstackManager:(BTstackManager*)manager deviceInfo:(BTDevice*)device;
-(void) btstackManager:(BTstackManager*)manager discoveryQueryRemoteName:(int)deviceIndex;
-(void) discoveryStoppedBTstackManager:(BTstackManager*) manager;
-(void) discoveryInquiryBTstackManager:(BTstackManager*) manager;
// Connection
-(void) l2capChannelCreatedAtAddress:(bd_addr_t)addr withPSM:(uint16_t)psm asID:(uint16_t)channelID;
-(void) l2capChannelCreateFailedAtAddress:(bd_addr_t)addr withPSM:(uint16_t)psm error:(BTstackError)error;
-(void) l2capChannelClosedForChannelID:(uint16_t)channelID;
-(void) l2capDataReceivedForChannelID:(uint16_t)channelID withData:(uint8_t *)packet ofLen:(uint16_t)size;
-(void) rfcommConnectionCreatedAtAddress:(bd_addr_t)addr forChannel:(uint16_t)channel asID:(uint16_t)connectionID;
-(void) rfcommConnectionCreateFailedAtAddress:(bd_addr_t)addr forChannel:(uint16_t)channel error:(BTstackError)error;
-(void) rfcommConnectionClosedForConnectionID:(uint16_t)connectionID;
-(void) rfcommDataReceivedForConnectionID:(uint16_t)connectionID withData:(uint8_t *)packet ofLen:(uint16_t)size;
// TODO add l2cap and rfcomm incoming events
@end

View File

@ -1,592 +0,0 @@
/*
* Copyright (C) 2009 by Matthias Ringwald
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "btdynamic.h"
#import "BTstackManager.h"
#import "btstack/btstack.h"
#import "BTDevice.h"
#define INQUIRY_INTERVAL 3
static BTstackManager * btstackManager = nil;
@interface BTstackManager (privat)
- (void)handlePacketWithType:(uint8_t) packet_type forChannel:(uint16_t) channel andData:(uint8_t *)packet withLen:(uint16_t) size;
@end
// needed for libBTstack
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
[btstackManager handlePacketWithType:packet_type forChannel:channel andData:packet withLen:size];
}
@implementation BTstackManager
@synthesize delegate = _delegate;
@synthesize listeners;
@synthesize discoveredDevices;
-(BTstackManager *) init {
self = [super init];
if (!self) return self;
state = kDeactivated;
discoveryState = kInactive;
connectedToDaemon = NO;
// device discovery
[self setDiscoveredDevices: [[NSMutableArray alloc] init]];
// delegate and listener
_delegate = nil;
[self setListeners:[[NSMutableSet alloc] init]];
// Use Cocoa run loop
run_loop_init_ptr(RUN_LOOP_COCOA);
// our packet handler
bt_register_packet_handler_ptr(packet_handler);
return self;
}
+(BTstackManager *) sharedInstance {
if (!btstackManager) {
btstackManager = [[BTstackManager alloc] init];
}
return btstackManager;
}
// listeners
-(void) addListener:(id<BTstackManagerListener>)listener{
[listeners addObject:listener];
}
-(void) removeListener:(id<BTstackManagerListener>)listener{
[listeners removeObject:listener];
}
// send events
-(void) sendActivated {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(activatedBTstackManager:)]){
[listener activatedBTstackManager:self];
}
}
}
-(void) sendActivationFailed:(BTstackError)error {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(btstackManager:activationFailed:)]){
[listener btstackManager:self activationFailed:error];
}
}
}
-(void) sendDeactivated {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(deactivatedBTstackManager:)]){
[listener deactivatedBTstackManager:self];
}
}
}
-(void) sendSleepEnter {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(sleepModeEnterBTstackManager:)]){
[listener sleepModeEnterBTstackManager:self];
}
}
}
-(void) sendSleepExit {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(sleepModeExtitBTstackManager:)]){
[listener sleepModeExtitBTstackManager:self];
}
}
}
-(void) sendDiscoveryStoppedEvent {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(discoveryStoppedBTstackManager:)]){
[listener discoveryStoppedBTstackManager:self];
}
}
}
-(void) sendDiscoveryInquiry{
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(discoveryInquiryBTstackManager:)]){
[listener discoveryInquiryBTstackManager:self];
}
}
}
-(void) sendDiscoveryQueryRemoteName:(int)index {
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(btstackManager:discoveryQueryRemoteName:)]){
[listener btstackManager:self discoveryQueryRemoteName:index];
}
}
}
-(void) sendDeviceInfo:(BTDevice*) device{
for (NSObject<BTstackManagerListener>* listener in listeners) {
if ([listener respondsToSelector:@selector(btstackManager:deviceInfo:)]){
[listener btstackManager:self deviceInfo:device];
}
}
}
// Activation
-(BTstackError) activate {
BTstackError err = 0;
if (!connectedToDaemon) {
err = bt_open_ptr();
if (err) return BTSTACK_CONNECTION_TO_BTDAEMON_FAILED;
}
connectedToDaemon = YES;
// check system BT
state = kW4SysBTState;
bt_send_cmd_ptr(btstack_get_system_bluetooth_enabled_ptr);
return err;
}
-(BTstackError) deactivate {
if (!connectedToDaemon) return BTSTACK_CONNECTION_TO_BTDAEMON_FAILED;
state = kW4Deactivated;
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_OFF);
return 0;
}
-(BOOL) isActive {
return state == kActivated;
}
-(BOOL) isActivating {
switch (state){
case kW4SysBTState:
case kW4SysBTDisabled:
case kW4Activated:
return YES;
default:
return NO;
}
}
-(BOOL) isDiscoveryActive {
return state == kActivated && (discoveryState != kInactive);
}
// Discovery
-(BTstackError) startDiscovery {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
discoveryState = kW4InquiryMode;
bt_send_cmd_ptr(hci_write_inquiry_mode_ptr, 0x01); // with RSSI
return 0;
};
-(BTstackError) stopDiscovery{
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
switch (discoveryState){
case kInactive:
[self sendDiscoveryStoppedEvent];
break;
case kW4InquiryMode:
discoveryState = kW4InquiryModeBeforeStop;
break;
case kInquiry:
discoveryState = kW4InquiryStop;
bt_send_cmd_ptr(hci_inquiry_cancel_ptr);
break;
case kRemoteName: {
discoveryState = kW4RemoteNameBeforeStop;
BTDevice *device = [discoveredDevices objectAtIndex:discoveryDeviceIndex];
bt_send_cmd_ptr(hci_remote_name_request_cancel_ptr, [device address]);
break;
}
default:
NSLog(@"[BTstackManager stopDiscovery] invalid discoveryState %u", discoveryState);
[self sendDiscoveryStoppedEvent];
break;
}
return 0;
};
-(int) numberOfDevicesFound{
return [discoveredDevices count];
};
-(BTDevice*) deviceAtIndex:(int)index{
return (BTDevice*) [discoveredDevices objectAtIndex:index];
};
-(BTDevice*) deviceForAddress:(bd_addr_t*) address{
for (BTDevice *device in discoveredDevices){
// NSLog(@"compare %@ to %@", [BTDevice stringForAddress:address], [device addressString]);
if ( BD_ADDR_CMP(address, [device address]) == 0){
return device;
}
}
return nil;
}
- (void) activationHandleEvent:(uint8_t *)packet withLen:(uint16_t) size {
switch (state) {
case kW4SysBTState:
case kW4SysBTDisabled:
// BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED
if ( packet[0] == BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED){
if (packet[2]){
// system bt on - first time try to disable it
if ( state == kW4SysBTState) {
if (_delegate == nil
|| ![_delegate respondsToSelector:@selector(disableSystemBluetoothBTstackManager:)]
|| [_delegate disableSystemBluetoothBTstackManager:self]){
state = kW4SysBTDisabled;
bt_send_cmd_ptr(btstack_set_system_bluetooth_enabled_ptr, 0);
} else {
state = kDeactivated;
[self sendActivationFailed:BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH];
}
} else {
state = kDeactivated;
[self sendActivationFailed:BTSTACK_ACTIVATION_FAILED_UNKNOWN];
}
} else {
state = kW4Activated;
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_ON);
}
}
break;
case kW4Activated:
switch (packet[0]){
case BTSTACK_EVENT_STATE:
if (packet[2] == HCI_STATE_WORKING) {
state = kActivated;
[self sendActivated];
}
break;
case BTSTACK_EVENT_POWERON_FAILED:
state = kDeactivated;
[self sendActivationFailed:BTSTACK_ACTIVATION_POWERON_FAILED];
break;
default:
break;
}
break;
case kW4Deactivated:
if (packet[0] != BTSTACK_EVENT_STATE && packet[2] == HCI_STATE_OFF){
state = kDeactivated;
[self sendDeactivated];
}
break;
case kActivated:
if (packet[0] != BTSTACK_EVENT_STATE && packet[2] == HCI_STATE_FALLING_ASLEEP){
state = kSleeping;
[self sendSleepEnter];
}
break;
case kSleeping:
if (packet[0] != BTSTACK_EVENT_STATE && packet[2] == HCI_STATE_WORKING){
state = kActivated;
[self sendSleepExit];
}
break;
default:
break;
}
}
-(void) discoveryRemoteName{
BOOL found = NO;
while ( discoveryDeviceIndex < [discoveredDevices count]){
BTDevice *device = [discoveredDevices objectAtIndex:discoveryDeviceIndex];
if (device.name) {
discoveryDeviceIndex ++;
continue;
}
bt_send_cmd_ptr(hci_remote_name_request_ptr, [device address], device.pageScanRepetitionMode,
0, device.clockOffset | 0x8000);
[self sendDiscoveryQueryRemoteName:discoveryDeviceIndex];
found = YES;
break;
}
if (!found) {
// printf("Queried all devices, restart.\n");
discoveryState = kInquiry;
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
[self sendDiscoveryInquiry];
}
}
- (NSString *) createRemoteNameFromRemoteNameEvent:(uint8_t *) packet {
// get lenght: first null byte or max 248 chars
int nameLen = 0;
while (nameLen < 248 && packet[9+nameLen]) nameLen++;
// Bluetooth specification mandates UTF-8 encoding...
NSString *name = [[NSString alloc] initWithBytes:&packet[9] length:nameLen encoding:NSUTF8StringEncoding];
// but fallback to latin-1 for non-standard products like old Microsoft Wireless Presenter
if (!name){
name = [[NSString alloc] initWithBytes:&packet[9] length:nameLen encoding:NSISOLatin1StringEncoding];
}
return name;
}
- (void) handleRemoteNameCached: (uint8_t *) packet {
bd_addr_t addr;
bt_flip_addr_ptr(addr, &packet[3]);
// NSLog(@"Get remote name done for %@", [BTDevice stringForAddress:&addr]);
BTDevice* device = [self deviceForAddress:&addr];
if (!device) return;
[device setName:[self createRemoteNameFromRemoteNameEvent:packet]];
[self sendDeviceInfo:device];
}
- (void) handleRemoteName: (uint8_t *) packet {
bd_addr_t addr;
bt_flip_addr_ptr(addr, &packet[3]);
// NSLog(@"Get remote name done for %@", [BTDevice stringForAddress:&addr]);
BTDevice* device = [self deviceForAddress:&addr];
if (!device) return;
[device setName:[self createRemoteNameFromRemoteNameEvent:packet]];
[self sendDeviceInfo:device];
discoveryDeviceIndex++;
[self discoveryRemoteName];
}
-(void) discoveryHandleEvent:(uint8_t *)packet withLen:(uint16_t) size {
bd_addr_t addr;
int i;
int numResponses;
switch (discoveryState) {
case kInactive:
break;
case kW4InquiryMode:
if (packet[0] == HCI_EVENT_COMMAND_COMPLETE && COMMAND_COMPLETE_EVENT(packet, (*hci_write_inquiry_mode_ptr)) ) {
discoveryState = kInquiry;
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
[self sendDiscoveryInquiry];
}
break;
case kInquiry:
switch (packet[0]){
case HCI_EVENT_INQUIRY_RESULT:
numResponses = packet[2];
for (i=0; i<numResponses ; i++){
bt_flip_addr_ptr(addr, &packet[3+i*6]);
// NSLog(@"found %@", [BTDevice stringForAddress:&addr]);
BTDevice* device = [self deviceForAddress:&addr];
if (!device) {
device = [[BTDevice alloc] init];
[discoveredDevices addObject:device];
[device setAddress:&addr];
}
// update
device.pageScanRepetitionMode = packet [3 + numResponses*(6) + i*1];
device.classOfDevice = READ_BT_24(packet, 3 + numResponses*(6+1+1+1) + i*3);
device.clockOffset = READ_BT_16(packet, 3 + numResponses*(6+1+1+1+3) + i*2) & 0x7fff;
device.rssi = 0;
[self sendDeviceInfo:device];
}
break;
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
numResponses = packet[2];
for (i=0; i<numResponses ;i++){
bt_flip_addr_ptr(addr, &packet[3+i*6]);
// NSLog(@"found %@", [BTDevice stringForAddress:&addr]);
BTDevice* device = [self deviceForAddress:&addr];
if (!device) {
device = [[BTDevice alloc] init];
[discoveredDevices addObject:device];
[device setAddress:&addr];
}
device.pageScanRepetitionMode = packet [3 + numResponses*(6) + i*1];
device.classOfDevice = READ_BT_24(packet, 3 + numResponses*(6+1+1) + i*3);
device.clockOffset = READ_BT_16(packet, 3 + numResponses*(6+1+1+3) + i*2) & 0x7fff;
device.rssi = packet [3 + numResponses*(6+1+1+3+2) + i*1];
[self sendDeviceInfo:device];
}
break;
case BTSTACK_EVENT_REMOTE_NAME_CACHED:
[self handleRemoteNameCached:packet];
break;
case HCI_EVENT_INQUIRY_COMPLETE:
// printf("Inquiry scan done.\n");
discoveryState = kRemoteName;
discoveryDeviceIndex = 0;
[self discoveryRemoteName];
break;
}
break;
case kRemoteName:
if (packet[0] == HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE){
[self handleRemoteName:packet];
}
break;
case kW4InquiryModeBeforeStop:
if (packet[0] == HCI_EVENT_COMMAND_COMPLETE && COMMAND_COMPLETE_EVENT(packet, (*hci_write_inquiry_mode_ptr)) ) {
discoveryState = kInactive;
[self sendDiscoveryStoppedEvent];
}
break;
case kW4InquiryStop:
if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE
|| COMMAND_COMPLETE_EVENT(packet, (*hci_inquiry_cancel_ptr))) {
discoveryState = kInactive;
[self sendDiscoveryStoppedEvent];
}
break;
case kW4RemoteNameBeforeStop:
if (packet[0] == HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
|| COMMAND_COMPLETE_EVENT(packet, (*hci_remote_name_request_cancel_ptr))){
discoveryState = kInactive;
[self sendDiscoveryStoppedEvent];
}
break;
default:
break;
}
}
-(void) dropLinkKeyForAddress:(bd_addr_t*) address {
bt_send_cmd_ptr(hci_delete_stored_link_key_ptr, address, 0);
// NSLog(@"Removing link key for %@", devAddress);
}
-(void) handlePacketWithType:(uint8_t)packet_type forChannel:(uint16_t)channel andData:(uint8_t *)packet withLen:(uint16_t) size {
switch (state) {
case kDeactivated:
break;
// Activation
case kW4SysBTState:
case kW4SysBTDisabled:
case kW4Activated:
case kW4Deactivated:
case kSleeping:
if (packet_type != HCI_EVENT_PACKET) break;
[self activationHandleEvent:packet withLen:size];
break;
// Pairing + Discovery
case kActivated:
if (packet_type != HCI_EVENT_PACKET) break;
switch (packet[0]){
case BTSTACK_EVENT_STATE:
[self activationHandleEvent:packet withLen:size];
break;
default:
break;
}
[self discoveryHandleEvent:packet withLen:size];
break;
default:
break;
}
if ([_delegate respondsToSelector:@selector(btstackManager:handlePacketWithType:forChannel:andData:withLen:)]){
[_delegate btstackManager:self handlePacketWithType:packet_type forChannel:channel andData:packet withLen:size];
}
}
// Connections
-(BTstackError) createL2CAPChannelAtAddress:(bd_addr_t*) address withPSM:(uint16_t)psm authenticated:(BOOL)authentication {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
if (state != kActivated) return BTSTACK_BUSY;
#if 0
// ...f (state
// store params
connType = 0;
BD_ADDR_COPY(&connAddr, address);
connPSM = psm;
connAuth = authentication;
// send write authentication enabled
bt_send_cmd_ptr(&hci_write_authentication_enable, authentication);
state = kW4AuthenticationEnableCommand;
#endif
return 0;
};
-(BTstackError) sendL2CAPPacketForChannelID:(uint16_t)channelID {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
return 0;
};
-(BTstackError) closeL2CAPChannelWithID:(uint16_t) channelID {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
return 0;
};
-(BTstackError) createRFCOMMConnectionAtAddress:(bd_addr_t*) address withChannel:(uint16_t)channel authenticated:(BOOL)authentication {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
if (state != kActivated) return BTSTACK_BUSY;
#if 0
// store params
connType = 1;
BD_ADDR_COPY(&connAddr, address);
connChan = channel;
connAuth = authentication;
#endif
return 0;
};
-(BTstackError) sendRFCOMMPacketForChannelID:(uint16_t)connectionID {
if (state < kActivated) return BTSTACK_NOT_ACTIVATED;
return 0;
};
-(BTstackError) closeRFCOMMConnectionWithID:(uint16_t) connectionID {
if (state <kActivated) return BTSTACK_NOT_ACTIVATED;
return 0;
};
@end

View File

@ -31,9 +31,7 @@
#import <UIKit/UIKit.h>
#import "BTstackManager.h"
@interface WiiMoteHelper : NSObject<BTstackManagerDelegate, BTstackManagerListener>
@interface WiiMoteHelper : NSObject
+ (BOOL)haveBluetooth;
+ (void)startBluetooth;
+ (BOOL)isBluetoothRunning;

View File

@ -38,198 +38,105 @@
#import "WiiMoteHelper.h"
#import "BTDevice.h"
#import "BTstackManager.h"
static WiiMoteHelper* instance;
static BTDevice *device;
static bool btstackOpen;
static bool btOK;
@implementation WiiMoteHelper
+ (BOOL)haveBluetooth
{
if (!btstackOpen)
btstackOpen = load_btstack();
return btstackOpen;
}
static BTDevice* discoveredDevice;
+ (void)startBluetooth
{
if (btstackOpen)
{
instance = instance ? instance : [WiiMoteHelper new];
if (!btOK)
{
BTstackManager* bt = [BTstackManager sharedInstance];
[bt setDelegate:instance];
[bt addListener:instance];
btOK = [bt activate] == 0;
}
}
}
+ (BOOL)isBluetoothRunning
{
return btstackOpen && btOK;
}
+ (void)stopBluetooth
{
if (btstackOpen)
{
myosd_num_of_joys = 0;
if (btOK)
{
BTstackManager* bt = [BTstackManager sharedInstance];
[bt deactivate];
[bt setDelegate:nil];
[bt removeListener:instance];
btOK = false;
}
instance = nil;
}
}
// BTStackManagerListener
-(void) activatedBTstackManager:(BTstackManager*) manager
{
[[BTstackManager sharedInstance] startDiscovery];
}
-(void) btstackManager:(BTstackManager*)manager deviceInfo:(BTDevice*)newDevice
{
if ([newDevice name] && [[newDevice name] hasPrefix:@"Nintendo RVL-CNT-01"])
{
device = newDevice;
[[BTstackManager sharedInstance] stopDiscovery];
}
}
-(void) discoveryStoppedBTstackManager:(BTstackManager*) manager
{
bt_send_cmd_ptr(hci_write_authentication_enable_ptr, 0);
}
// BTStackManagerDelegate
-(void) btstackManager:(BTstackManager*) manager
handlePacketWithType:(uint8_t)packet_type
forChannel:(uint16_t)channel
andData:(uint8_t*)packet
withLen:(uint16_t)size
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
bd_addr_t event_addr;
switch (packet_type)
{
case L2CAP_DATA_PACKET://0x06
{
struct wiimote_t *wm = wiimote_get_by_source_cid(channel);
if (wm != NULL)
{
byte* msg = packet + 2;
byte event = packet[1];
switch (event)
{
case WM_RPT_BTN:
{
wiimote_pressed_buttons(wm, msg);
break;
}
case WM_RPT_READ:
{
/* data read */
wiimote_pressed_buttons(wm, msg);
byte len = ((msg[2] & 0xF0) >> 4) + 1;
byte *data = (msg + 5);
if(wiimote_handshake(wm, WM_RPT_READ, data, len))
{
if (device != nil)
{
[device setConnectionState:kBluetoothConnectionConnected];
device = nil;
}
}
return;
}
case WM_RPT_CTRL_STATUS:
{
wiimote_pressed_buttons(wm, msg);
//handshake stuff!
if(wiimote_handshake(wm,WM_RPT_CTRL_STATUS,msg,-1))
{
[device setConnectionState:kBluetoothConnectionConnected];
if (device != nil)
{
[device setConnectionState:kBluetoothConnectionConnected];
device = nil;
}
}
return;
}
case WM_RPT_BTN_EXP:
{
/* button - expansion */
wiimote_pressed_buttons(wm, msg);
wiimote_handle_expansion(wm, msg+2);
break;
}
case WM_RPT_WRITE:
{
/* write feedback - safe to skip */
break;
}
default:
{
printf("Unknown event, can not handle it [Code 0x%x].", event);
return;
}
}
}
break;
}
case HCI_EVENT_PACKET://0x04
// Connection
case HCI_EVENT_PACKET:
{
switch (packet[0])
{
case HCI_EVENT_COMMAND_COMPLETE:
// Bluetooth is active, search for remote
case BTSTACK_EVENT_STATE:
{
if (COMMAND_COMPLETE_EVENT(packet, (*hci_write_authentication_enable_ptr)))
bt_send_cmd_ptr(l2cap_create_channel_ptr, [device address], PSM_HID_INTERRUPT);
break;
if (packet[2] == HCI_STATE_WORKING)
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
break;
}
case HCI_EVENT_PIN_CODE_REQUEST:
// Identifies devices found during inquiry, does not signal the end of the inquiry.
case HCI_EVENT_INQUIRY_RESULT:
{
bt_flip_addr_ptr(event_addr, &packet[2]);
if (BD_ADDR_CMP([device address], event_addr)) break;
// inform about pin code request
NSLog(@"HCI_EVENT_PIN_CODE_REQUEST\n");
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, event_addr, 6, &packet[2]); // use inverse bd_addr as PIN
for (int i = 0; i != packet[2]; i ++)
{
if (!discoveredDevice)
{
bt_flip_addr_ptr(event_addr, &packet[3 + i * 6]);
discoveredDevice = [[BTDevice alloc] init];
[discoveredDevice setAddress:&event_addr];
}
// update
discoveredDevice.pageScanRepetitionMode = packet [3 + packet[2] * (6) + i*1];
discoveredDevice.classOfDevice = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1) + i*3);
discoveredDevice.clockOffset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3) + i*2) & 0x7fff;
discoveredDevice.rssi = 0;
}
break;
}
// The inquiry has ended
case HCI_EVENT_INQUIRY_COMPLETE:
{
// If we a device, ask for its name
if (discoveredDevice)
bt_send_cmd_ptr(hci_remote_name_request_ptr, [discoveredDevice address], discoveredDevice.pageScanRepetitionMode,
0, discoveredDevice.clockOffset | 0x8000);
// Keep looking
else
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 0);
break;
}
// Received the name of a device
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
{
bt_flip_addr_ptr(event_addr, &packet[3]);
if (discoveredDevice && BD_ADDR_CMP(event_addr, discoveredDevice.address) == 0)
{
char cname[249];
strncpy(cname, (const char*)&packet[9], 248);
cname[248] = 0;
NSString* name = [NSString stringWithUTF8String:cname];
[discoveredDevice setName:name];
// We found a WiiMote, pair with it
if ([name hasPrefix:@"Nintendo RVL-CNT-01"])
bt_send_cmd_ptr(l2cap_create_channel_ptr, [discoveredDevice address], PSM_HID_INTERRUPT);
}
break;
}
// Send PIN for pairing
case HCI_EVENT_PIN_CODE_REQUEST:
{
bt_flip_addr_ptr(event_addr, &packet[2]);
if (discoveredDevice && BD_ADDR_CMP(event_addr, discoveredDevice.address) == 0)
{
// WiiMote: Use inverse bd_addr as PIN
if (discoveredDevice.name && [discoveredDevice.name hasPrefix:@"Nintendo RVL-CNT-01"])
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, event_addr, 6, &packet[2]);
}
break;
}
// WiiMote connections
case L2CAP_EVENT_CHANNEL_OPENED:
{
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
@ -273,11 +180,117 @@ static bool btOK;
uint16_t source_cid = READ_BT_16(packet, 2);
bd_addr_t addr;
wiimote_remove(source_cid,&addr);
wiimote_remove(source_cid, &addr);
break;
}
}
}
// WiiMote handling
case L2CAP_DATA_PACKET:
{
struct wiimote_t *wm = wiimote_get_by_source_cid(channel);
if (wm)
{
byte* msg = packet + 2;
switch (packet[1])
{
case WM_RPT_BTN:
{
wiimote_pressed_buttons(wm, msg);
break;
}
case WM_RPT_READ:
{
wiimote_pressed_buttons(wm, msg);
byte len = ((msg[2] & 0xF0) >> 4) + 1;
byte *data = (msg + 5);
wiimote_handshake(wm, WM_RPT_READ, data, len);
return;
}
case WM_RPT_CTRL_STATUS:
{
wiimote_pressed_buttons(wm, msg);
wiimote_handshake(wm,WM_RPT_CTRL_STATUS,msg,-1);
return;
}
case WM_RPT_BTN_EXP:
{
wiimote_pressed_buttons(wm, msg);
wiimote_handle_expansion(wm, msg+2);
break;
}
}
}
break;
}
}
}
@implementation WiiMoteHelper
+ (BOOL)haveBluetooth
{
if (!btstackOpen)
{
btstackOpen = load_btstack();
if (btstackOpen)
{
run_loop_init_ptr(RUN_LOOP_COCOA);
bt_register_packet_handler_ptr(packet_handler);
}
}
return btstackOpen;
}
+ (void)startBluetooth
{
if (btstackOpen)
{
instance = instance ? instance : [WiiMoteHelper new];
if (!btOK)
{
if (bt_open_ptr())
{
btOK = false;
return;
}
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_ON);
btOK = true;
}
}
}
+ (BOOL)isBluetoothRunning
{
return btstackOpen && btOK;
}
+ (void)stopBluetooth
{
if (btstackOpen)
{
myosd_num_of_joys = 0;
if (btOK)
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_OFF);
btOK = false;
instance = nil;
}
}
@end